diff options
Diffstat (limited to '')
| -rw-r--r-- | bot/exts/events/trivianight/_questions.py | 48 | ||||
| -rw-r--r-- | bot/exts/events/trivianight/_scoreboard.py | 41 | ||||
| -rw-r--r-- | bot/exts/events/trivianight/trivianight.py | 55 | 
3 files changed, 125 insertions, 19 deletions
| diff --git a/bot/exts/events/trivianight/_questions.py b/bot/exts/events/trivianight/_questions.py index 2bbff1d7..eaabed4f 100644 --- a/bot/exts/events/trivianight/_questions.py +++ b/bot/exts/events/trivianight/_questions.py @@ -32,7 +32,13 @@ class QuestionButton(Button):          super().__init__(label=label, style=discord.ButtonStyle.green)      async def callback(self, interaction: Interaction) -> None: -        """When a user interacts with the button, this will be called.""" +        """ +        When a user interacts with the button, this will be called. + +        Parameters: +            - interaction: an instance of discord.Interaction representing the interaction between the user and the +            button. +        """          original_message = interaction.message          original_embed = original_message.embeds[0] @@ -84,8 +90,13 @@ class QuestionView(View):          self.active_question = False -    def create_current_question(self) -> Union[Embed, None]: -        """Helper function to create the embed for the current question.""" +    def create_current_question(self) -> tuple[Embed, int]: +        """ +        Helper function to create the embed for the current question. + +        Returns an embed containing the question along with each answer choice in the form of a view, +        along with the integer representing the time limit of the current question. +        """          self.current_labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[:len(self.current_question["answers"])]          question_embed = Embed(              title=f"Question {self.current_question['number']}", @@ -110,8 +121,16 @@ class QuestionView(View):          return question_embed, time_limit -    def end_question(self) -> tuple[dict, Embed]: -        """Returns the dictionaries from the corresponding buttons for those who got it correct.""" +    def end_question(self) -> tuple[dict, Embed, int, int]: +        """ +        Ends the question and displays the statistics on who got the question correct, awards points, etc. + +        Returns: +            - a dictionary containing all the people who answered and whether or not they got it correct +            - an embed displaying the correct answers and the % of people that chose each answer. +            - an integer showing the time limit of the current question in seconds +            - an integer showing the amount of points the question will award* to those that got it correct +        """          labels = self.current_labels          label = labels[self.current_question["answers"].index(self.current_question["correct"])]          return_dict = {name: (*info, info[0] == label) for name, info in self.users_picked.items()} @@ -165,7 +184,13 @@ class Questions:          self.questions = []      def set_questions(self, questions: list) -> None: -        """Setting `self.questions` dynamically via a function to set it.""" +        """ +        Setting `self.questions` dynamically via a function to set it. + +        Parameters: +            - questions: a list representing all the questions, which is essentially the JSON provided +            to load the questions +        """          self.questions = questions      def next_question(self, number: int = None) -> Union[Embed, None]: @@ -173,6 +198,9 @@ class Questions:          Chooses a random unvisited question from the question bank.          If the number parameter is specified, it'll head to that specific question. + +        Parameters: +            - number: An optional integer representing the question number (only used for `.trivianight question` calls)          """          if all("visited" in question.keys() for question in self.questions) and number is None:              return Embed( @@ -227,7 +255,13 @@ class Questions:          return self.view.create_current_question(), self.view      def end_question(self) -> Embed: -        """Terminates answering of the question and displays the correct answer.""" +        """ +        Terminates answering of the question and displays the correct answer. + +        The function returns an embed containing the information about the question such as the following: +            - % of people that chose each option +            - the correct answer +        """          scores, answer_embed, time_limit, total_points = self.view.end_question()          for user, score in scores.items():              time_taken = score[2] diff --git a/bot/exts/events/trivianight/_scoreboard.py b/bot/exts/events/trivianight/_scoreboard.py index 635660a2..40f93475 100644 --- a/bot/exts/events/trivianight/_scoreboard.py +++ b/bot/exts/events/trivianight/_scoreboard.py @@ -20,7 +20,13 @@ class ScoreboardView(View):          self.speed = {}      async def create_main_leaderboard(self) -> Embed: -        """Helper function that iterates through `self.points` to generate the main leaderboard embed.""" +        """ +        Helper function that iterates through `self.points` to generate the main leaderboard embed. + +        The main leaderboard would be formatted like the following: +        **1**. @mention of the user (# of points) +        along with the 29 other users who made it onto the leaderboard. +        """          formatted_string = ""          self.points = dict(sorted(self.points.items(), key=lambda item: item[-1], reverse=True))          self.speed = dict(sorted(self.speed.items(), key=lambda item: item[-1])) @@ -44,7 +50,13 @@ class ScoreboardView(View):          return main_embed      async def _create_speed_embed(self) -> Embed: -        """Helper function that iterates through `self.speed` to generate a leaderboard embed.""" +        """ +        Helper function that iterates through `self.speed` to generate a leaderboard embed. + +        The speed leaderboard would be formatted like the following: +        **1**. @mention of the user ([average speed as a float with the precision of one decimal point]s) +        along with the 29 other users who made it onto the leaderboard. +        """          formatted_string = ""          for current_placement, (user, time_taken) in enumerate(self.speed.items()): @@ -65,7 +77,12 @@ class ScoreboardView(View):          return speed_embed      def _get_rank(self, member: Member) -> Embed: -        """Gets the member's rank for the points leaderboard and speed leaderboard.""" +        """ +        Gets the member's rank for the points leaderboard and speed leaderboard. + +        Parameters: +            - member: An instance of discord.Member representing the person who is trying to get their rank. +        """          rank_embed = Embed(title=f"Ranks for {member.display_name}", color=Colours.python_blue)          # These are stored as strings so that the last digit can be determined to choose the suffix          try: @@ -99,12 +116,26 @@ class ScoreboardView(View):      @discord.ui.button(label="Scoreboard for Speed", style=ButtonStyle.green)      async def speed_leaderboard(self, button: Button, interaction: Interaction) -> None: -        """Send an ephemeral message with the speed leaderboard embed.""" +        """ +        Send an ephemeral message with the speed leaderboard embed. + +        Parameters: +            - button: The discord.ui.Button instance representing the `Speed Leaderboard` button. +            - interaction: The discord.Interaction instance containing information on the interaction between the user +            and the button. +        """          await interaction.response.send_message(embed=await self._create_speed_embed(), ephemeral=True)      @discord.ui.button(label="What's my rank?", style=ButtonStyle.blurple)      async def rank_button(self, button: Button, interaction: Interaction) -> None: -        """Send an ephemeral message with the user's rank for the overall points/average speed.""" +        """ +        Send an ephemeral message with the user's rank for the overall points/average speed. + +        Parameters: +            - button: The discord.ui.Button instance representing the `What's my rank?` button. +            - interaction: The discord.Interaction instance containing information on the interaction between the user +            and the button. +        """          await interaction.response.send_message(embed=self._get_rank(interaction.user), ephemeral=True) diff --git a/bot/exts/events/trivianight/trivianight.py b/bot/exts/events/trivianight/trivianight.py index ed2bfdbe..a86bd73f 100644 --- a/bot/exts/events/trivianight/trivianight.py +++ b/bot/exts/events/trivianight/trivianight.py @@ -37,7 +37,12 @@ class TriviaNight(commands.Cog):      @staticmethod      def unicodeify(text: str) -> str: -        """Takes `text` and adds zero-width spaces to prevent copy and pasting the question.""" +        """ +        Takes `text` and adds zero-width spaces to prevent copy and pasting the question. + +        Parameters: +            - text: A string that represents the question description to 'unicodeify' +        """          return "".join(              f"{letter}\u200b" if letter not in ('\n', '\t', '`', 'p', 'y') else letter              for idx, letter in enumerate(text) @@ -45,7 +50,11 @@ class TriviaNight(commands.Cog):      @commands.group(aliases=["tn"], invoke_without_command=True)      async def trivianight(self, ctx: commands.Context) -> None: -        """No-op subcommand group for organizing different commands.""" +        """ +        The command group for the Python Discord Trivia Night. + +        If invoked without a subcommand (i.e. simply .trivianight), it will explain what the Trivia Night event is. +        """          cog_description = Embed(              title="What is .trivianight?",              description=( @@ -88,6 +97,8 @@ class TriviaNight(commands.Cog):                  json_text = (await message.attachments[0].read()).decode("utf8")              else:                  json_text = message.content.replace("```", "").replace("json", "").replace("\n", "") +        else: +            json_text = to_load.replace("```", "").replace("json", "").replace("\n", "")          try:              serialized_json = loads(json_text) @@ -128,7 +139,12 @@ class TriviaNight(commands.Cog):      @trivianight.command()      @commands.has_any_role(*TRIVIA_NIGHT_ROLES)      async def next(self, ctx: commands.Context) -> None: -        """Gets a random question from the unanswered question list and lets user choose the answer.""" +        """ +        Gets a random question from the unanswered question list and lets the user(s) choose the answer. + +        This command will continuously count down until the time limit of the question is exhausted. +        However, if `.trivianight stop` is invoked, the counting down is interrupted to show the final results. +        """          if self.questions.view.active_question is True:              error_embed = Embed(                  title=choice(NEGATIVE_REPLIES), @@ -162,7 +178,15 @@ class TriviaNight(commands.Cog):      @trivianight.command()      @commands.has_any_role(*TRIVIA_NIGHT_ROLES)      async def question(self, ctx: commands.Context, question_number: int) -> None: -        """Gets a question from the question bank depending on the question number provided.""" +        """ +        Gets a question from the question bank depending on the question number provided. + +        The logic of this command is similar to `.trivianight next`, with the only difference being that you need to +        specify the question number. + +        Parameters: +            - question_number: An integer represents the question number to go to (i.e. .trivianight question 5). +        """          question = self.questions.next_question(question_number)          if isinstance(question, Embed):              await ctx.send(embed=question) @@ -187,7 +211,12 @@ class TriviaNight(commands.Cog):      @trivianight.command()      @commands.has_any_role(*TRIVIA_NIGHT_ROLES)      async def list(self, ctx: commands.Context) -> None: -        """Displays all the questions from the question bank.""" +        """ +        Displays all the questions from the question bank. + +        Questions are displayed in the following format: +        Q(number): Question description | :white_check_mark: if the question was used otherwise :x:. +        """          question_list = self.questions.list_questions()          if isinstance(question_list, Embed):              await ctx.send(embed=question_list) @@ -197,7 +226,11 @@ class TriviaNight(commands.Cog):      @trivianight.command()      @commands.has_any_role(*TRIVIA_NIGHT_ROLES)      async def stop(self, ctx: commands.Context) -> None: -        """End the ongoing question to show the correct question.""" +        """ +        End the ongoing question to show the correct question. + +        This command should be used if the question should be ended early or if the time limit fails +        """          if self.questions.view.active_question is False:              error_embed = Embed(                  title=choice(NEGATIVE_REPLIES), @@ -212,7 +245,15 @@ class TriviaNight(commands.Cog):      @trivianight.command()      @commands.has_any_role(*TRIVIA_NIGHT_ROLES)      async def end(self, ctx: commands.Context) -> None: -        """Ends the trivia night event and displays the scoreboard.""" +        """ +        Ends the trivia night event and displays the scoreboard view. + +        The scoreboard view consists of the two scoreboards with the 30 players who got the highest points and the +        30 players who had the fastest average response time to a question where they got the question right. + +        The scoreboard view also has a button where the user can see their own rank, points and average speed if they +        didn't make it onto the leaderboard. +        """          scoreboard_embed, scoreboard_view = await self.scoreboard.display()          await ctx.send(embed=scoreboard_embed, view=scoreboard_view) | 
