""" Contains code for trivia games. *Classes* --------- Trivia Contains all the code for the trivia commands. """ import urllib # Used to get data from api import json # Used to read data from api import random # Used to shuffle answers import asyncio # Used to sleep from discord_slash.context import SlashContext # Used for type hints class Trivia(): """ Contains the code for trivia games. *Methods* --------- triviaStart(channel: str) -> str, str, str triviaAnswer(user: str, channel: str, command: str) -> str triviaCountPoints(channel: str) triviaParse(ctx: SlashContext, answer: str) """ def __init__(self, bot): """Initialize the class.""" self.bot = bot def triviaStart(self, channel: str): """ Start a game of trivia. Downloads a question with answers, shuffles the wrong answers with the correct answer and returns the questions and answers. Also saves the question in the database. *Parameters* ------------ channel: str The id of the channel to start the game in *Returns* --------- sendMessage: str The message to return to the user. """ triviaQuestions = self.bot.database["trivia questions"] question = triviaQuestions.find_one({"_id": channel}) self.bot.log(f"Trying to find a trivia question for {channel}") if question is None: apiUrl = "https://opentdb.com/api.php?amount=10&type=multiple" with urllib.request.urlopen(apiUrl) as response: data = json.loads(response.read()) question = data["results"][0]["question"] self.bot.log(f"Found the question \"{question}\"") answers = data["results"][0]["incorrect_answers"] answers.append(data["results"][0]["correct_answer"]) random.shuffle(answers) correctAnswer = data["results"][0]["correct_answer"] correctAnswer = answers.index(correctAnswer) + 97 newQuestion = { "_id": channel, "answer": str(chr(correctAnswer)), "players": {} } triviaQuestions.insert_one(newQuestion) replacements = { "'": "\'", """: "\"", "“": "\"", "”": "\"", "é": "é" } question = data["results"][0]["question"] for key, value in replacements.items(): question = question.replace(key, value) for answer in answers: for key, value in replacements.items(): answer = answer.replace(key, value) return question, answers, correctAnswer else: log_message = "There was already a trivia question for that channel" self.bot.log(log_message) return self.bot.long_strings["Trivia going on"], "", "" def triviaAnswer(self, user: str, channel: str, command: str): """ Answer the current trivia question. *Parameters* ------------ user: str The id of the user who answered. channel: str The id of the channel the game is in. command: str The user's answer. *Returns* --------- sendMessage: str The message to send if the function failed. """ triviaQuestions = self.bot.database["trivia questions"] question = triviaQuestions.find_one({"_id": channel}) if command not in ["a", "b", "c", "d"]: self.bot.log("I didn't quite understand that") return "I didn't quite understand that" elif question is None: self.bot.log("There's no question right now") return "There's no question right now" elif user in question["players"]: self.bot.log(f"{user} has already answered this question") return f"{user} has already answered this question" else: self.bot.log(f"{user} answered the question in {channel}") updater = {"$set": {f"players.{user}": command}} triviaQuestions.update_one({"_id": channel}, updater) return None def triviaCountPoints(self, channel: str): """ Add money to every winner's account. *Parameters* ------------ channel: str The id of the channel the game is in. """ triviaQuestions = self.bot.database["trivia questions"] question = triviaQuestions.find_one({"_id": channel}) self.bot.log("Counting points for question in "+channel) if question is not None: for player, answer in question["players"].items(): if answer == question["answer"]: self.bot.money.addMoney(player, 1) else: self.bot.log("Couldn't find the questio") return None async def triviaParse(self, ctx: SlashContext, answer: str): """ Parse a trivia command. *Parameters* ------------ ctx: SlashContext The context of the command. answer: str The answer, if any. """ await self.bot.defer(ctx) channelId = str(ctx.channel_id) if answer == "": question, options, correctAnswer = self.triviaStart(channelId) if options != "": results = "**"+question+"**\n" for x, option in enumerate(options): results += chr(x+97) + ") "+option+"\n" await ctx.send(results) await asyncio.sleep(60) self.triviaCountPoints(channelId) delete_gameParams = ["trivia questions", channelId] self.bot.database_funcs.delete_game(*delete_gameParams) self.bot.log("Time's up for the trivia question", channelId) sendMessage = self.bot.long_strings["Trivia time up"] formatParams = [chr(correctAnswer), options[correctAnswer-97]] sendMessage = sendMessage.format(*formatParams) await ctx.send(sendMessage) else: await ctx.send(question, hidden=True) elif answer in ["a", "b", "c", "d"]: userId = f"#{ctx.author.id}" response = self.triviaAnswer(userId, channelId, answer) if response is None: user_name = ctx.author.display_name await ctx.send(f"{user_name} answered **{answer}**") else: await ctx.send(response) else: self.bot.log("I didn't understand that", channelId) await ctx.send("I didn't understand that")