Пример #1
0
	async def unjoin(self, ctx, *members: typing.Union[discord.Member, discord.Role]):
		if not members:
			members = (ctx.author,)

		playing_role = here(ctx).playing_role

		async def remove_player(member):
			room = here(ctx)
			if room.in_round and (member in room.game.players):
				await ctx.send(f"{member.mention} will leave after this round finishes.")
				room.add_member_to_leaver_queue(member)
			elif room.in_round and (member in room.queued_joiners):
				room.remove_member_from_joiner_queue(member)
				await ctx.send(f"{member.mention} will no longer join after this round.")
			elif member in room.room_players:
				room.remove_player(member)
				await ctx.send(f"{member.display_name} is no longer playing.")
				await member.remove_roles(playing_role)
			else:
				await ctx.send(f"{ctx.author.mention} {member.display_name} was already not playing.")

		for member_or_role in members:
			if isinstance(member_or_role, discord.Role):
				if member_or_role == here(ctx).playing_role:
					for player in here(ctx).room_players:
						await remove_player(player)
				else:
					raise commands.CheckFailure(f"Cannot remove `{member_or_role.name}`. Must be the current room's player role `{playing_role}`.")
				for player in here(ctx).room_players:
					await remove_player(player)
			else:
				await remove_player(member_or_role)
Пример #2
0
    async def guess_team_helper(self,
                                ctx,
                                guesser,
                                guessed_players,
                                veto_timeout_override=False):

        here(ctx).resolve_team_guess(
            guesser,
            guessed_players,
            veto_timeout_override=veto_timeout_override)
        guessed_players_string = names_list_string(guessed_players)

        if (not here(ctx).game.include_veto_phase) or veto_timeout_override:
            # Full resolve
            correct = here(ctx).game.check_team_guess(guesser, guessed_players)
            correct_string = {True: "right", False: "wrong"}[correct]
            await ctx.send(
                f"**{guesser.display_name}** (team **{here(ctx).game.get_secret_word(guesser)}**) guessed {guessed_players_string} for the their team, which is __{correct_string}__.  Winning team: **{here(ctx).game.winning_word}**"
            )
            await self.reveal_teams(ctx)
            await self.end_round_and_clean_up(ctx)

        else:
            # Enter veto phase
            await ctx.send(
                f"**{guesser.display_name}** guessed {guessed_players_string} for the their team. Entering veto phase."
            )
            await self.enter_veto_phase(ctx)
Пример #3
0
    async def guessword(self, ctx, word: str):
        guesser = ctx.author

        if word not in here(ctx).game.words:
            raise commands.CheckFailure(
                f"`{word}` not in word list. Check spelling and capitalization. You can edit your message or enter a new one."
            )

        correct = here(ctx).resolve_word_guess(guesser, word)
        correct_string = {True: "right", False: "wrong"}[correct]
        await ctx.send(
            f"**{guesser.display_name}** (team **{here(ctx).game.get_secret_word(guesser)}**) guessed **{word}** for the opposing word, which is __{correct_string}__. Winning team: **{here(ctx).game.winning_word}**"
        )

        # If this overrode a veto, say whether it would have succeeded
        if here(ctx).game.in_veto_phase:
            orig_guesser, orig_guessed_players = here(
                ctx).game.vetoable_team_guess

            orig_guessed_players_string = names_list_string(
                orig_guessed_players)

            correct = here(ctx).game.check_team_guess(orig_guesser,
                                                      orig_guessed_players)
            correct_string = {True: "right", False: "wrong"}[correct]
            await ctx.send(
                f"(The original guess by **{orig_guesser.display_name}** (team **{here(ctx).game.get_secret_word(orig_guesser)}**) of {orig_guessed_players_string} would have been _{correct_string}_.)"
            )

        await self.reveal_teams(ctx)
        await self.end_round_and_clean_up(ctx)
Пример #4
0
    async def numwords(self, ctx, *, num: int = None):
        if num is not None:
            if not 2 <= num <= 100:
                raise commands.CheckFailure(f"Invalid number of words {num}.")
            here(ctx).num_words = num

        num = here(ctx).num_words
        await ctx.send(f"Number of words: {num}")
Пример #5
0
    async def start_round(self, ctx):
        here(ctx).start_round()

        await self.display_round_intro(ctx)
        await self.display_and_pin_wordlist(ctx)

        for player in here(ctx).game.players:
            await self.message_player_secret_word(ctx, player)
Пример #6
0
    async def maxguess(self, ctx, *, size: int = None):
        if size is not None:
            if not 1 <= size <= 99:
                raise commands.CheckFailure(f"Invalid team guess size {size}.")
            here(ctx).max_guess = size
            await self.message_in_round(ctx)

        size = here(ctx).max_guess
        await ctx.send(
            f"Guess team subset of size {size} (counting yourself) in games with {2*size + 1}+ players."
        )
Пример #7
0
    async def numwords(self, ctx, *, num: int = None):
        if num is not None:
            if not ((2 <= num <= 100) or (num == 0)):
                raise commands.CheckFailure(f"Invalid number of words {num}.")
            here(ctx).num_words = num
            await self.message_in_round(ctx)

        num = here(ctx).num_words

        if num == 0:
            await ctx.send(
                f"Number of words: 0 (automatically double the number of players)"
            )
        else:
            await ctx.send(f"Number of words: {num}")
Пример #8
0
    async def vetodur(self, ctx, *, duration: int = None):
        if duration is not None:
            if not 0 <= duration <= 999:
                raise commands.CheckFailure(f"Invalid duration {duration}.")
            here(ctx).veto_duration = duration
            await self.message_in_round(ctx)

        duration = here(ctx).veto_duration

        if duration == 0:
            description = "0 (no veto round)"
        else:
            description = f"{duration} seconds"

        await ctx.send(f"Veto duration: {description}")
Пример #9
0
    async def guessword(self, ctx, word: str):
        guesser = ctx.author

        room = here(ctx)
        game = room.game

        if word not in game.words:
            raise commands.CheckFailure(
                f"`{word}` not in word list. Check spelling and capitalization. You can edit your message or enter a new one."
            )

        correct = room.resolve_word_guess(guesser, word)
        correct_string = {True: "right", False: "wrong"}[correct]
        await ctx.send(
            f"**{guesser.display_name}** (team **{game.get_secret_word(guesser)}**) guessed **{word}** for the opposing word, which is __{correct_string}__. Winning team: **{game.winning_word}**"
        )

        # If this overrode a veto, say whether it would have succeeded
        if game.in_veto_phase:
            orig_guesser, orig_guessed_players = game.vetoable_team_guess
            correctness_message = self.team_guess_correctness_message(
                ctx, orig_guesser, orig_guessed_players, is_hypothetical=True)

            await ctx.send(correctness_message)

        await self.reveal_teams(ctx)
        await self.end_round_and_clean_up(ctx)
Пример #10
0
    async def join(self, ctx, *members: discord.Member):
        if not members:
            members = (ctx.author, )

        room = here(ctx)

        for member in members:
            current_players = room.room_players

            if member.bot:
                await ctx.send(
                    f"{ctx.author.mention} {member.display_name} is a bot.")
            elif room.in_round and (member in room.queued_leavers):
                room.remove_member_from_leaver_queue(member)
                await ctx.send(
                    f"{member.mention} will no longer leave after this round.")
            elif member in current_players:
                await ctx.send(
                    f"{ctx.author.mention} {member.display_name} was already playing."
                )
            elif room.in_round:
                await ctx.send(
                    f"{member.mention} will join and be pinged after this round ends."
                )
                room.add_member_to_joiner_queue(member)
            else:
                room.add_player(member)
                if room.playing_role:
                    await member.add_roles(room.playing_role)
                await ctx.send(f"{member.mention} is now playing")
Пример #11
0
    async def guess_team_helper(self,
                                ctx,
                                guesser,
                                guessed_players,
                                veto_timeout_override=False):

        room = here(ctx)
        game = room.game

        room.resolve_team_guess(guesser,
                                guessed_players,
                                veto_timeout_override=veto_timeout_override)

        if (not game.include_veto_phase) or veto_timeout_override:
            # Full resolve

            correctness_message = self.team_guess_correctness_message(
                ctx, guesser, guessed_players)

            await ctx.send(correctness_message)
            await self.reveal_teams(ctx)
            await self.end_round_and_clean_up(ctx)

        else:
            # Enter veto phase
            guessed_players_string = names_list_string(guessed_players)
            await ctx.send(
                f"**{guesser.display_name}** guessed {guessed_players_string} for their team. Entering veto phase."
            )
            await self.enter_veto_phase(ctx)
Пример #12
0
 async def end_veto_round(self, ctx):
     await ctx.send("Veto phase over. Original guess goes through.")
     (guesser, guessed_players) = here(ctx).game.vetoable_team_guess
     await self.guess_team_helper(ctx,
                                  guesser,
                                  guessed_players,
                                  veto_timeout_override=True)
Пример #13
0
    async def message_player_secret_word(self, ctx, player):
        secret_word = here(ctx).game.get_secret_word(player)
        return_url = link_to_channel(ctx.channel)

        await player.send(
            f"Round {here(ctx).round_num}: Your secret word is    **{secret_word}**    (back to #{ctx.channel.name}: {return_url})"
        )
Пример #14
0
    async def guessteam(self, ctx, *players: discord.Member):
        guessed_players = players
        guessed_players = list(guessed_players)

        guesser = ctx.author
        players_set = set(here(ctx).game.players)

        if not set(guessed_players) <= players_set:
            extra_players = list(set(guessed_players) - players_set)
            extra_player_names = [
                player.display_name for player in extra_players
            ]
            extra_player_name_string = " and ".join(extra_player_names)
            phrase = {
                False: "is not a player",
                True: "are not players"
            }[len(extra_players) > 1]
            raise commands.CheckFailure(
                f"{extra_player_name_string} {phrase}. Use @ to autocomplete names to avoid typos. Names are case-sensitive. You can edit your message or enter a new one."
            )

        # As a convenience, include the guesser in their own team guess
        if guesser not in guessed_players:
            guessed_players = [guesser] + guessed_players

        await self.guess_team_helper(ctx, guesser, guessed_players)
Пример #15
0
    async def skew(self, ctx, *, skew_chance: float = None):
        if skew_chance is not None:
            if not 0.0 <= skew_chance <= 1.0:
                raise commands.CheckFailure(f"Invalid chance {skew_chance}.")
            here(ctx).skew_chance = skew_chance
            await self.message_in_round(ctx)

        skew_chance = here(ctx).skew_chance

        if skew_chance == 0.0:
            description = "0% (never skew)"
        elif skew_chance == 1.0:
            description = "100% (always skew -- did you mean 0 maybe?)"
        else:
            description = f"{skew_chance:.1%}"

        await ctx.send(f"Skew chance: {description}")
Пример #16
0
    async def howguess(self, ctx):
        guess_message = "Use `!gw word` to guess the opposing team's word.\nUse `!gt [teammates]` to guess your team. Write their names space-separated; you can use `@` to autocomplete. You can omit yourself."
        await ctx.send(guess_message)

        # If not in DM and round is ongoing, display additional info
        if not isinstance(ctx.channel,
                          discord.channel.DMChannel) and here(ctx).in_round:
            await self.bot.get_cog("Status").show_team_sizes_message(ctx)
Пример #17
0
    async def enter_veto_phase(self, ctx):
        assert here(ctx).game.include_veto_phase

        veto_time = here(ctx).veto_duration
        await ctx.send(
            f"You have **{veto_time} seconds** to guess a word and override this team guess, or it will resolve."
        )

        warning_time = 10

        # The below probably be better done with `bot.wait_for`.
        # We track if the same round is still ongoing by whether the round number hasn't changed.

        initial_round_num = here(ctx).round_num

        if veto_time > warning_time:
            await asyncio.sleep(veto_time - warning_time)

            if (here(ctx).game is not None) and (initial_round_num
                                                 == here(ctx).round_num):
                await ctx.send(f"**{warning_time} seconds** to guess!")

        await asyncio.sleep(min(warning_time, veto_time))
        if (here(ctx).game is not None) and (initial_round_num
                                             == here(ctx).round_num):
            await self.end_veto_round(ctx)
Пример #18
0
    async def display_round_intro(self, ctx):
        room = here(ctx)
        assert room.in_round, "Can't display intro with no round ongoing."

        await ctx.send(f"__Round {room.round_num}__")
        await self.bot.get_cog("Status").players(ctx)

        start_message = "You've been messaged your secret word -- to see it, click the Home icon in the very top left. Use `!howguess` to show the commands to guess. Clue away!"
        await ctx.send(start_message)
Пример #19
0
    async def display_round_intro(self, ctx):
        assert here(ctx).in_round, "Can't display intro with no round ongoing."

        player_mention_string = names_string(here(ctx).game.players)
        num_players = len(here(ctx).game.players)
        await ctx.send(
            f"**Round {here(ctx).round_num}**\nPlayers ({num_players}): {player_mention_string}"
        )

        team_sizes_string = " or ".join(
            [str(size) for size in sorted(set(here(ctx).game.team_sizes))])

        if here(ctx).game.team_guess_size is not None:
            team_guess_size_comment = f", of which you guess a subset of {here(ctx).game.team_guess_size} (counting yourself)"
        else:
            team_guess_size_comment = ""

        team_sizes_message = f"Teams are of size {team_sizes_string}{team_guess_size_comment}."
        await ctx.send(team_sizes_message)

        start_message = "You've been messaged your secret word. Use `!howguess` to show the commands to guess. Clue away!"
        await ctx.send(start_message)
Пример #20
0
    async def reveal_teams(self, ctx):
        words = here(ctx).game.teams.keys()

        def is_winning_word(word):
            return word == here(ctx).game.winning_word

        words_with_winner_first = sorted(words,
                                         key=is_winning_word,
                                         reverse=True)
        team_strings = [
            f"**{word}**: {names_string(here(ctx).game.teams[word])}"
            for word in words_with_winner_first
        ]
        await ctx.send("   ||   ".join(team_strings))
Пример #21
0
		async def remove_player(member):
			room = here(ctx)
			if room.in_round and (member in room.game.players):
				await ctx.send(f"{member.mention} will leave after this round finishes.")
				room.add_member_to_leaver_queue(member)
			elif room.in_round and (member in room.queued_joiners):
				room.remove_member_from_joiner_queue(member)
				await ctx.send(f"{member.mention} will no longer join after this round.")
			elif member in room.room_players:
				room.remove_player(member)
				await ctx.send(f"{member.display_name} is no longer playing.")
				await member.remove_roles(playing_role)
			else:
				await ctx.send(f"{ctx.author.mention} {member.display_name} was already not playing.")
Пример #22
0
    def team_guess_correctness_message(self,
                                       ctx,
                                       guesser,
                                       guessed_players,
                                       is_hypothetical=False):
        game = here(ctx).game
        guesser_word = game.get_secret_word(guesser)
        correct_team = game.players_with_word(guesser_word)

        def player_name_formatted_by_correctness(player):

            if player in correct_team:
                # Bold
                return f"**{player.display_name}**"
            else:
                # Bold italics
                return f"***{player.display_name}***"

        missing_players = set(correct_team) - set(guessed_players)
        if bool(missing_players):
            must_guess_exact = game.team_guess_size is None
            if must_guess_exact:
                label = "missing"
            else:
                label = "unguessed"
            missing_player_string = f" ({label}: " + ", ".join(
                [f"**{player.display_name}**"
                 for player in missing_players]) + ")"
        else:
            missing_player_string = ""

        guessed_players_marked_string = "[" + ", ".join([
            player_name_formatted_by_correctness(player)
            for player in guessed_players
        ]) + "]"

        correct = game.check_team_guess(guesser, guessed_players)
        correct_string = {True: "right", False: "wrong"}[correct]
        winning_word = {
            True: guesser_word,
            False: game.opposing_word(guesser_word)
        }[correct]

        if not is_hypothetical:
            correctness_message = f"**{guesser.display_name}** (team **{guesser_word}**) guessed {guessed_players_marked_string} for their team, which is __{correct_string}__{missing_player_string}. Winning team: **{winning_word}**."
        else:
            correctness_message = f"(The original guess by **{guesser.display_name}** (team **{guesser_word}**) of {guessed_players_marked_string} would have been __{correct_string}__{missing_player_string}, with winning team **{winning_word}**.)"
        return correctness_message
Пример #23
0
    async def players(self, ctx):
        room = here(ctx)

        if room.in_round:
            game = room.game
            players = game.players

            player_mention_string = names_string_formatted(players)
            num_players = len(players)
            await ctx.send(
                f"__Players__ ({num_players}): {player_mention_string}")

            await self.show_team_sizes_message(ctx)

        else:
            players = room.room_players
            player_mention_string = names_string_formatted(players)
            num_players = len(players)
            await ctx.send(f"Players ({num_players}): {player_mention_string}")
Пример #24
0
    async def show_team_sizes_message(self, ctx):
        room = here(ctx)
        game = room.game

        team_sizes_string = " or ".join(
            [str(size) for size in sorted(set(game.possible_team_sizes))])

        if game.team_guess_size is not None:
            team_guess_size_comment = f", of which you guess a subset of {game.team_guess_size} (counting yourself)"
        else:
            team_guess_size_comment = ". Guess your whole team exactly"

        if game.might_skew:
            skew_comment = f" ({game.skew_chance:.1%} chance skewed)"
        else:
            skew_comment = ""

        team_sizes_message = f"Teams are of **size {team_sizes_string}**{skew_comment}{team_guess_size_comment}."
        await ctx.send(team_sizes_message)
Пример #25
0
    async def enter_veto_phase(self, ctx):
        assert here(ctx).game.include_veto_phase

        veto_time = here(ctx).veto_duration
        await ctx.send(
            f"You have **{veto_time} seconds** to guess a word and override the preceding team guess, or it will resolve."
        )

        warning_time = 10

        initial_round_num = here(ctx).round_num

        if veto_time > warning_time:
            await asyncio.sleep(veto_time - warning_time)

            if (here(ctx).game is not None) and (initial_round_num
                                                 == here(ctx).round_num):
                await ctx.send(f"**{warning_time} seconds** to guess!")

        await asyncio.sleep(min(warning_time, veto_time))
        if (here(ctx).game is not None) and (initial_round_num
                                             == here(ctx).round_num):
            await self.end_veto_round(ctx)
Пример #26
0
 async def status(self, ctx):
     await ctx.send(here(ctx).status_string)
Пример #27
0
 async def unpause(self, ctx):
     here(ctx).unpause()
     await ctx.send(f"{ctx.author.mention} Resumed the round.")
Пример #28
0
 async def pause(self, ctx):
     here(ctx).pause()
     await ctx.send(
         f"{ctx.author.mention} Paused the round. Use `!unpause` to resume."
     )
Пример #29
0
 async def end_round_and_clean_up(self, ctx):
     here(ctx).end_round()
     lobby_cog = self.bot.get_cog("Lobby")
     await lobby_cog.resolve_joiner_queue(ctx)
     await lobby_cog.resolve_leaver_queue(ctx)
Пример #30
0
 def is_winning_word(word):
     return word == here(ctx).game.winning_word