Exemple #1
0
def _check_valid_nominator(ctx: Context, nominator: Player, nominee: Player):
    """Check that nominator is a valid nominator, else raise an exception."""
    if not (
        nominator.can_nominate(ctx)
        or nominee.character_type(ctx) == "traveler"
        or nominator.character_type(ctx) == "storyteller"
    ):
        raise ValueError("nominator already nominated")
Exemple #2
0
def _check_valid_nominee(game: "Game", nominator: Player, nominee: Player):
    """Check that the nominee is a valid nominee, else raise an exception."""
    if nominee.is_status(game, "storyteller"):  # atheist nominations
        for st in game.storytellers:
            if not st.can_be_nominated(game, nominator):
                raise commands.BadArgument(
                    "The storytellers cannot be nominated today.")
    elif not nominee.can_be_nominated(game, nominator):
        raise commands.BadArgument(
            f"{nominee.nick} cannot be nominated today.")
Exemple #3
0
def _check_valid_nominee(ctx: Context, nominator: Player, nominee: Player):
    """Check that the nominee is a valid nominee, else raise an exception."""
    if nominee.character_type(ctx) == "storyteller":  # atheist nominations
        for st in ctx.bot.game.storytellers:
            if not st.can_be_nominated(ctx, nominator):
                raise commands.BadArgument(
                    "The storytellers cannot be nominated today."
                )
    elif not nominee.can_be_nominated(ctx, nominator):
        raise commands.BadArgument(f"{nominee.nick} cannot be nominated today.")
Exemple #4
0
async def _effect_adder(
    ctx: Context, player: Player, effect: Type[Effect.Effect], source: Player = None
):
    """Add effect to player."""
    source = source or player
    effect_object = player.add_effect(ctx, effect, source)
    if source == player or source.character_type(ctx) == "storyteller":
        source_text = ""
    else:
        source_text = f"with source {source.nick} "
    await safe_send(
        ctx,
        f"Successfully added effect {effect_object.name} {source_text}to {player.nick}.",
    )
Exemple #5
0
async def _effect_adder(
    ctx: "GameContext",
    player: Player,
    effect: Type[Effect.Effect],
    source: Player = None,
):
    """Add effect to player."""
    source = source or player
    effect_object = player.add_effect(ctx.bot.game, effect, source)
    if source == player or source.is_status(ctx.bot.game, "storyteller"):
        source_text = ""
    else:
        source_text = f"with source {source.nick} "
    await safe_send(
        ctx, f"Added effect {effect_object.name} {source_text}to {player.nick}.",
    )
Exemple #6
0
    async def nomination(
        self,
        ctx: "Context",
        nominee: Player,
        nominator: Player,
        enabled: bool = True,
        epithet_string: str = "",
    ) -> bool:
        """Handle Virgin nomination.

        If nominee is the Virgin and nominator is a townsfolk, execute nominator.
        """
        if nominee == self.parent:
            self.parent.add_effect(ctx, UsedAbility, self.parent)
            if enabled and nominator.is_status(ctx, "townsfolk", registers=True):
                await safe_send(
                    ctx.bot.channel,
                    generate_nomination_message_text(
                        ctx, nominator, nominee, traveler=False, proceed=False
                    ),
                )
                await nominator.execute(ctx)
                return False
        return True
Exemple #7
0
def _check_valid_nominator(game: "Game", nominator: Player, nominee: Player):
    """Check that nominator is a valid nominator, else raise an exception."""
    if not (nominator.can_nominate(game) or nominee.is_status(
            game, "traveler") or nominator.is_status(game, "storyteller")):
        raise AlreadyNomniatedError
Exemple #8
0
def _update_storyteller_list(bot, after, before):
    """Add new storytellers to the Storyteller list."""
    if bot.storyteller_role not in before.roles and bot.storyteller_role in after.roles:
        bot.game.storytellers.append(Player(after, Storyteller, None))
    bot.backup()
Exemple #9
0
    async def start_game(self, ctx: "Context", script: "Script"):
        """Handle startgame logic."""
        await safe_send(ctx, f"Starting a {script.name} game.")

        # ask for the list of players
        users = await to_member_list(
            ctx,
            (await get_input(
                ctx,
                ("What is the seating order? (Separate "
                 "users with line breaks. Do not include "
                 "travelers.)"),
            )).split("\n"),
        )

        # ask for the list of characters
        characters = to_character_list(
            ctx,
            (await get_input(
                ctx,
                ("What are the corresponding characters? "
                 "(Separate characters with line breaks.)"),
            )).split("\n"),
            script,
        )

        with ctx.typing():  # doing a lot of computation here

            # verify 1:1 user:character ratio
            if len(users) != len(characters):
                raise commands.BadArgument(
                    "There are a different number of players and characters.")

            # role cleanup
            await self._startgame_role_cleanup(users)

            # generate seating order
            seating_order = [
                Player(person, characters[index], index)
                for index, person in enumerate(users)
            ]

            # script message
            posts = []
            for content in list(script.info(ctx)):
                posts.append(await safe_send(self.channel, content))

            for post in posts[::-1]:  # Reverse the order so the pins are right
                await post.pin()

            # welcome message
            await safe_send(
                self.channel,
                (f"{self.player_role.mention}, "
                 "welcome to Blood on the Clocktower! Go to "
                 "sleep."),
            )

            # Seating order message
            seating_order_message = await safe_send(
                self.channel,
                generate_game_info_message(seating_order, ctx),
            )
            await seating_order_message.pin()

            # storytellers
            storytellers = [
                Player(person, Storyteller, None)
                for person in self.storyteller_role.members
            ]

            # start the game
            self.game = Game(seating_order, seating_order_message, script,
                             storytellers)

            # complete
            return
Exemple #10
0
    async def addtraveler(
        self,
        ctx: Context,
        traveler: str,
        upwards_neighbor: str,
        alignment: str,
        *,
        character: str,
    ):
        """Add a traveler to the game.

        traveler: The player to join the game.
        character: Their traveler character.
        upwards_neighbor: The player above them in the seating order.
        alignment: The traveler's alignment; 'good' or 'evil'.
        """
        # convert the traveler
        traveler_actual = await to_member(ctx, traveler)

        # check alignment is valid
        if not alignment.lower() in ["good", "evil"]:
            raise commands.BadArgument(
                "The alignment must be 'good' or 'evil' exactly.")

        # check if person is in the game
        try:
            get_player(ctx.bot.game, traveler_actual.id)
            raise commands.BadArgument(
                f"{load_preferences(traveler_actual).nick} is already in the game."
            )

        except ValueError as e:

            if str(e) == "player not found":

                # find the character
                character_actual = to_character(ctx, character)

                # determine the position
                upwards_neighbor_actual = await to_player(
                    ctx, upwards_neighbor)

                # make the Player
                player = Player(
                    traveler_actual,
                    character_actual,
                    upwards_neighbor_actual.position + 1,
                )

                # check that the character is a traveler
                if not player.character_type(ctx) == "traveler":
                    raise commands.BadArgument(
                        f"{player.character.name} is not a traveler.")

                # add the alignment
                if alignment.lower() == "good":
                    player.add_effect(ctx, Good, player)
                elif alignment.lower() == "evil":
                    player.add_effect(ctx, Evil, player)

                # add the player role
                await traveler_actual.add_roles(ctx.bot.player_role)

                # add them to the seating order
                ctx.bot.game.seating_order.insert(
                    upwards_neighbor_actual.position + 1, player)

                # announcement
                await safe_send(
                    ctx.bot.channel,
                    ("{townsfolk}, {player} has joined the town as the {traveler}. "
                     "Let's tell {pronoun} hello!").format(
                         traveler=player.character.name,
                         pronoun=load_preferences(player).pronouns[1],
                         townsfolk=ctx.bot.player_role.mention,
                         player=player.nick,
                     ),
                )

                # rules
                msg = await safe_send(
                    ctx.bot.channel,
                    f"\n**{player.character.name}** - {player.character.rules_text}",
                )
                await msg.pin()
                await safe_send(
                    ctx,
                    f"Successfully added {player.nick} as the {player.character.name}.",
                )

            else:
                raise