206 lines
6.9 KiB
Python
206 lines
6.9 KiB
Python
"""
|
|
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")
|