aboutsummaryrefslogtreecommitdiffstats
path: root/bot/seasons/evergreen/travia_quiz.py
diff options
context:
space:
mode:
Diffstat (limited to 'bot/seasons/evergreen/travia_quiz.py')
-rw-r--r--bot/seasons/evergreen/travia_quiz.py225
1 files changed, 225 insertions, 0 deletions
diff --git a/bot/seasons/evergreen/travia_quiz.py b/bot/seasons/evergreen/travia_quiz.py
new file mode 100644
index 00000000..84a16654
--- /dev/null
+++ b/bot/seasons/evergreen/travia_quiz.py
@@ -0,0 +1,225 @@
+import asyncio
+import json
+import logging
+import random
+from pathlib import Path
+
+import discord
+from discord.ext import commands
+from fuzzywuzzy import fuzz
+
+from bot.constants import Roles
+
+
+logger = logging.getLogger(__name__)
+
+
+annoyed_expressions = ["-_-", "-.-"]
+
+wrong_ans_responses = [
+ "No one gave the correct answer",
+ "Losers",
+ "You guys really need to learn"
+]
+
+game_rules = [
+ "No cheating!",
+ "Idk what rules to put in here haha."
+
+]
+
+
+class TriviaQuiz(commands.Cog):
+ """A cog for all quiz commands."""
+
+ def __init__(self, bot):
+ self.bot = bot
+ self.questions = self.load_questions()
+ self.game_status = {}
+ self.game_owners = {}
+ self.question_limit = 3
+ self.categories = {
+ "general": "Test your general knwoledge",
+ "retro": "Questions related to retro gaming."
+ }
+
+ @staticmethod
+ def load_questions() -> dict:
+ """Load the questions from json file."""
+ p = Path("bot", "resources", "evergreen", "trivia_quiz.json")
+ with p.open() as json_data:
+ questions = json.load(json_data)
+ return questions
+
+ @commands.command(name="quiz")
+ async def start(self, ctx, option: str, category: str = "retro") -> None:
+ """
+ Start/Stop a quiz!
+
+ arguments:
+ option:
+ - start : to start a quiz in a channel
+ - stop : stop the quiz running in that channel.
+
+ Questions for the quiz can be selected from the following categories:
+ - general : Test your general knowledge. (default)
+ - Retro : questions related to retro gaming.
+ """
+ category = category.lower()
+ player_data = {} # a dict to store players and their points.
+
+ if ctx.channel.id not in self.game_status:
+ self.game_status[ctx.channel.id] = None
+
+ if option == "start":
+ if self.game_status[ctx.channel.id] is True:
+ return await ctx.send("Game already running.")
+ else:
+ self.game_owners[ctx.channel.id] = ctx.author
+ self.game_status[ctx.channel.id] = True
+ start_embed = discord.Embed(colour=discord.Colour.red())
+ start_embed.title = "Quiz game Starting!!"
+ start_embed.description = "Each game consists of 5 questions.\n"
+ start_embed.description += "**Rules :**\n"
+ for rule in game_rules:
+ start_embed.description += f"- {rule}\n"
+ start_embed.set_footer(text="2 hints per question sent after every 10s")
+ await ctx.send(embed=start_embed) # send an embed with the rules
+
+ elif option == "stop":
+ if self.game_status[ctx.channel.id] is False:
+ return await ctx.send("No game running, nothing to stop here.")
+ else:
+ if (
+ ctx.author == self.game_owners[ctx.channel.id] or
+ Roles.moderator in [role.id for role in ctx.author.roles]
+ ):
+ await self.declare_winner(ctx.channel, player_data)
+ self.game_status[ctx.channel.id] = False
+ else:
+ await ctx.send(f"{ctx.author.mention}, you are not authorised to stop this game :ghost: !")
+ else:
+ self.game_status[ctx.channel.id] = False
+ return await ctx.send("start or stop only")
+
+ unanswerd = 0
+ done_question = []
+ hint_no = 0
+ answer = None
+ hints = None
+ while self.game_status[ctx.channel.id] is True:
+ if len(done_question) > self.question_limit and hint_no == 0:
+ await ctx.send("The round ends here.")
+ await self.declare_winner(ctx.channel, player_data)
+ break
+ if unanswerd > 3:
+ await ctx.send("Game stopped due to inactivity.")
+ await self.declare_winner(ctx.channel, player_data)
+ break
+ if category not in self.categories:
+ embed = self.category_embed
+ await ctx.send(embed=embed)
+ break
+ topic = self.questions[category]
+ if hint_no == 0:
+ while True:
+ question_dict = random.choice(topic)
+ if question_dict["id"] not in done_question:
+ done_question.append(question_dict["id"])
+ break
+ q = question_dict["question"]
+ answer = question_dict["answer"]
+ hints = question_dict["hints"]
+
+ embed = discord.Embed(colour=discord.Colour.gold())
+ embed.title = f"Question #{len(done_question)}"
+ embed.description = q
+ await ctx.send(embed=embed)
+
+ def check(m):
+ ratio = fuzz.ratio(answer.lower(), m.content)
+ return ratio > 80 and m.channel == ctx.channel
+ try:
+ msg = await self.bot.wait_for('message', check=check, timeout=10)
+ except Exception as e:
+ if self.game_status[ctx.channel.id] is False:
+ break
+ if isinstance(e, asyncio.TimeoutError):
+ if hint_no < 2:
+ await ctx.send(f"**Hint #{hint_no+1}\n**{hints[hint_no]}")
+ hint_no += 1
+ else:
+ response = random.choice(wrong_ans_responses)
+ expression = random.choice(annoyed_expressions)
+ await ctx.send(f"{response} {expression}, the correct answer is **{answer}**.")
+ hint_no = 0
+ unanswerd += 1
+ await self.send_score(ctx.channel, player_data)
+
+ else:
+ points = 100 - 25*hint_no
+ if msg.author in player_data:
+ player_data[msg.author] += points
+ else:
+ player_data[msg.author] = points
+ hint_no = 0
+ unanswerd = 0
+ await ctx.send(f"{msg.author.mention} got the correct answer :tada: {points} points for ya.")
+ await ctx.send(f"Correct answer is **{answer}**")
+ await self.send_score(ctx.channel, player_data)
+
+ @staticmethod
+ async def send_score(channel, player_data):
+ """A function which sends the score."""
+ embed = discord.Embed(colour=discord.Colour.blue())
+ embed.title = "Score Board"
+ embed.description = ""
+ for k, v in player_data.items():
+ embed.description += f"{k} : {v}\n"
+ await channel.send(embed=embed)
+
+ @staticmethod
+ async def declare_winner(channel, player_data):
+ """A function declare the winner of the quiz."""
+
+ if player_data:
+ highest_points = max(list(player_data.values()))
+ no_of_winners = list(player_data.values()).count(highest_points)
+
+ # Check if more than 1 player has highest points.
+ if no_of_winners > 1:
+ winners = []
+ points_copy = list(player_data.values()).copy()
+ for _ in range(no_of_winners):
+ index = points_copy.index(highest_points)
+ winners.append(list(player_data.keys())[index])
+ points_copy[index] = 0
+ winners_mention = None
+ for winner in winners:
+ winners_mention += f"{winner.mention} "
+
+ else:
+ author_index = list(player_data.values()).index(highest_points)
+ winner = list(player_data.keys())[author_index]
+ winners_mention = winner.mention
+ await channel.send(
+ f"Congratz {winners_mention} :tada: "
+ f"You have won this quiz game with a grand total of {highest_points} points!!"
+ )
+
+ @property
+ def category_embed(self) -> discord.Embed:
+ """A function which returns an embed showing all avilable categories."""
+ embed = discord.Embed(colour=discord.Colour.blue())
+ embed.title = "The available question categories are:"
+ embed.description = ""
+ for cat, description in self.categories.items():
+ embed.description += f"**- {cat.capitalize()}**\n{description.capitalize()}\n"
+ embed.set_footer(text="If not category is chosen, then a random one will be selected.")
+ return embed
+
+
+def setup(bot):
+ """Loading the cog."""
+ bot.add_cog(TriviaQuiz(bot))
+ logger.debug("TriviaQuiz cog loaded!")