Exemplo n.º 1
0
    def __create_droisoned_info(self):
        """Create drunk/poisoned information for the undertaker info"""

        executed_player = globvars.master_state.game.today_executed_player

        # If someone has been executed
        if executed_player:

            tb_townsfolk_all = BOTCUtils.get_role_list(TroubleBrewing, Townsfolk)
            tb_outsider_all = BOTCUtils.get_role_list(TroubleBrewing, Outsider)
            tb_minion_all = BOTCUtils.get_role_list(TroubleBrewing, Minion)
            tb_demon_all = BOTCUtils.get_role_list(TroubleBrewing, Demon)

            executed_player.role.set_new_social_self(executed_player)

            # The executed player has a good role. The droisoned undertaker will see a
            # bad role.
            if executed_player.role.social_self.is_good():
                pool = tb_minion_all + tb_demon_all
                ret = random.choice(pool)
                return ret

            # The executed player has a bad role. The droisoned undertaker will see
            # a good role.
            else:
                pool = tb_townsfolk_all + tb_outsider_all
                pool = [character for character in pool if character.name != Undertaker().name]
                ret = random.choice(pool)
                return ret

        # If no one is executed, then send none
        else:
            return None
    def exec_init_setup(self, townsfolk_obj_list, outsider_obj_list, minion_obj_list, demon_obj_list):
        """Add two outsiders to the setup, remove two townsfolks from the setup"""

        random.shuffle(townsfolk_obj_list)

        # Remove two townsfolks
        townsfolk_obj_list.pop()
        townsfolk_obj_list.pop()

        # If the single remaining townsfolk is a washerwoman, then remove it
        if len(townsfolk_obj_list) == 1:
            if townsfolk_obj_list[0].name == TBRole.washerwoman.value:
                tb_townsfolk_all = BOTCUtils.get_role_list(TroubleBrewing, Townsfolk)
                all_not_washer = [character for character in tb_townsfolk_all if character.name != TBRole.washerwoman.value]
                townsfolk_obj_list = [random.choice(all_not_washer)]

        tb_outsider_all = BOTCUtils.get_role_list(TroubleBrewing, Outsider)
        random.shuffle(tb_outsider_all)

        count = 0

        for outsider in tb_outsider_all:
            if count >= 2:
                break
            else:
                if str(outsider) not in [str(role) for role in outsider_obj_list]:
                    outsider_obj_list.append(outsider)
                    count += 1

        return [townsfolk_obj_list, outsider_obj_list, minion_obj_list, demon_obj_list]
Exemplo n.º 3
0
    async def info_add(self, ctx, *, args: str):
        invoking_player = BOTCUtils.get_player_from_id(ctx.author.id)

        args = re.split(' +', args)

        # Ensure that we have enough values in the list
        args += ['', '']

        try:
            target_phase = int(args[0])
            target_player = None
            args.pop(0)
        except ValueError:
            target_player = BOTCUtils.get_player_from_string(args[0])
            if target_player is not None:
                args.pop(0)

            try:
                target_phase = int(args[0])
                args.pop(0)
            except ValueError:
                target_phase = None

        # Remove the two dummy elements
        args.pop()
        args.pop()

        rem = ' '.join(args)

        if not rem.strip():
            if target_phase is None:
                if target_player is None:
                    raise commands.MissingRequiredArgument(Parameter('info', Parameter.POSITIONAL_ONLY))
                else:
                    # Added info was a player name
                    rem = str(target_player)
                    target_player = None
            else:
                # Added info was a number (empath for example)
                rem = str(target_phase)
                target_phase = None

        if target_phase is not None and target_phase > globvars.master_state.game._chrono.cycle:
            raise commands.BadArgument()

        if target_player is not None:
            globvars.master_state.game.note_manager.info(target_player, rem, invoking_player, target_phase)
        else:
            if globvars.master_state.game._chrono.phase == Phase.night:
                raise NotNight("Command is allowed during night phase only (BoTC)")
            globvars.master_state.game.note_manager.info(invoking_player, rem, None, target_phase)

        await ctx.send(info_add_feedback_str.format(BotEmoji.check))
Exemplo n.º 4
0
    async def exec_learn(self, ravenkeeper_player, learn_player):
        """Execute the learn action (dawn ability interaction)"""

        if DISABLE_DMS:
            return

        # Correct info
        if not ravenkeeper_player.is_droisoned():
            learned_character_type = learn_player.role.social_self

        # Droisoned info
        else:
            real_character_type = learn_player.role.true_self
            # If the real character type is good
            if real_character_type.is_good():
                tb_minion_all = BOTCUtils.get_role_list(TroubleBrewing, Minion)
                tb_demon_all = BOTCUtils.get_role_list(TroubleBrewing, Demon)
                pool = tb_minion_all + tb_demon_all
                learned_character_type = random.choice(pool)
            # If the real character type is bad
            else:
                tb_townsfolk_all = BOTCUtils.get_role_list(
                    TroubleBrewing, Townsfolk)
                tb_outsider_all = BOTCUtils.get_role_list(
                    TroubleBrewing, Outsider)
                pool = tb_townsfolk_all + tb_outsider_all
                learned_character_type = random.choice(pool)

        link = learned_character_type._art_link_cropped
        recipient = ravenkeeper_player.user

        # Add information to replay
        drunk = "Drunk " if ravenkeeper_player.role.true_self.name == Drunk(
        ).name else ""
        globvars.master_state.game.replay += f"- {recipient.name} ({drunk}Ravenkeeper) learns "\
                                    f"that {learn_player.user.name} is {learned_character_type}\n"

        msg = f"***{recipient.name}#{recipient.discriminator}***, the **{self.name}**:"
        msg += "\n"
        msg += self.emoji + " " + self.instruction
        msg += "\n"
        msg += ravenkeeper_reply.format(learned_character_type.name)

        embed = discord.Embed(description=msg)
        embed.set_thumbnail(url=link)
        embed.set_footer(text=copyrights_str)
        embed.timestamp = datetime.datetime.utcnow()

        try:
            await recipient.send(embed=embed)
        except discord.Forbidden:
            pass
Exemplo n.º 5
0
    async def notes_add(self, ctx, *, args):
        invoking_player = BOTCUtils.get_player_from_id(ctx.author.id)

        args = re.split(' +', args)

        target_player = BOTCUtils.get_player_from_string(args[0])
        if target_player is None:
            target_player = invoking_player
            note = ' '.join(args)
        else:
            args.pop(0)
            note = ' '.join(args)

        globvars.master_state.game.note_manager.note(target_player, note, invoking_player)
        await ctx.send(notes_add_feedback_str.format(BotEmoji.check))
Exemplo n.º 6
0
def check_if_player_really_dead(ctx):
    """Check if the player is dead using real state"""
    player = BOTCUtils.get_player_from_id(ctx.author.id)
    if player.is_dead():
        return True
    else:
        raise DeadOnlyCommand("Command reserved for Dead Players (BoTC)")
Exemplo n.º 7
0
def check_if_player_really_alive(ctx):
    """Check if the player is alive using real state"""
    player = BOTCUtils.get_player_from_id(ctx.author.id)
    if player.is_alive():
        return True
    else:
        raise AliveOnlyCommand("Command reserved for Alive Players (BoTC)")
Exemplo n.º 8
0
def check_if_not_player(ctx):
    """Return true if user is not player"""
    player = BOTCUtils.get_player_from_id(ctx.author.id)
    if player:
        raise IsAPlayer("Command not allowed: user is a player (BoTC).")
    else:
        return True
Exemplo n.º 9
0
 async def read(self, ctx, *, read: PlayerParser()):
     """Read command
     usage: read <player> and <player> and...
     characters: fortune teller
     """
     player = BOTCUtils.get_player_from_id(ctx.author.id)
     await player.role.ego_self.register_read(player, read)
Exemplo n.º 10
0
 async def kill(self, ctx, *, killed: PlayerParser()):
     """Kill command
     usage: kill <player> and <player> and...
     characters: imp
     """
     player = BOTCUtils.get_player_from_id(ctx.author.id)
     await player.role.ego_self.register_kill(player, killed)
Exemplo n.º 11
0
    def exec_init_setup(self, townsfolk_obj_list, outsider_obj_list,
                        minion_obj_list, demon_obj_list):
        """Add two outsiders to the setup, remove two townsfolks from the setup"""

        random.shuffle(townsfolk_obj_list)
        townsfolk_obj_list.pop()
        townsfolk_obj_list.pop()
        tb_outsider_all = BOTCUtils.get_role_list(TroubleBrewing, Outsider)
        random.shuffle(tb_outsider_all)

        count = 0

        for outsider in tb_outsider_all:
            if count >= 2:
                break
            else:
                if str(outsider) not in [
                        str(role) for role in outsider_obj_list
                ]:
                    outsider_obj_list.append(outsider)
                    count += 1

        return [
            townsfolk_obj_list, outsider_obj_list, minion_obj_list,
            demon_obj_list
        ]
 async def poison(self, ctx, *, poisoned: PlayerParser()):
     """Poison command
     usage: poison <player> and <player> and...
     characters: poisoner
     """
     player = BOTCUtils.get_player_from_id(ctx.author.id)
     await player.role.ego_self.register_poison(player, poisoned)
 async def whisper(self, ctx, recipient: PlayerConverter(), *, content: WhisperConverter()):
     """Whisper command"""
     player = BOTCUtils.get_player_from_id(ctx.author.id)
     try:
         msg = from_str.format(
             botutils.BotEmoji.unread_message,
             player.game_nametag,
             content
         )
         await recipient.user.send(msg)
     except discord.Forbidden:
         msg = recipient_blocked.format(botutils.BotEmoji.warning_sign)
         await ctx.send(msg)
     else:
         msg = to_str.format(
             botutils.BotEmoji.whisper,
             recipient.game_nametag,
             content
         )
         await ctx.send(msg)
         announcement_msg = whisper_announcement.format(
             botutils.BotEmoji.opened_letter,
             player.game_nametag,
             recipient.game_nametag,
         )
         lobby_message = await botutils.send_lobby(announcement_msg)
         await asyncio.sleep(WHISPER_SHOW_TIME)
         await lobby_message.delete()
Exemplo n.º 14
0
 async def protect(self, ctx, *, protected: PlayerParser()):
     """Protect command
     usage: protect <player> and <player> and...
     characters: monk
     """
     player = BOTCUtils.get_player_from_id(ctx.author.id)
     await player.role.ego_self.register_protect(player, protected)
 async def learn(self, ctx, *, learned: PlayerParser()):
     """Learn command
     usage: learn <player> and <player> and...
     characters: ravenkeeper
     """
     player = BOTCUtils.get_player_from_id(ctx.author.id)
     await player.role.ego_self.register_learn(player, learned)
Exemplo n.º 16
0
 async def slay(self, ctx, *, slain: PlayerParser()):
     """Slay command
     usage: slay <player> and <player> and...
     characters: slayer
     """
     player = BOTCUtils.get_player_from_id(ctx.author.id)
     await player.role.ego_self.register_slay(player, slain)
Exemplo n.º 17
0
 async def serve(self, ctx, *, master: PlayerParser()):
     """Serve command: 
     usage: serve <player> and <player> and...
     characters: butler
     """
     player = BOTCUtils.get_player_from_id(ctx.author.id)
     await player.role.ego_self.register_serve(player, master)
    async def process_night_ability(self, player):
        """Process night actions for the butler character.
        @player : the Butler player (Player object)
        """

        phase = globvars.master_state.game._chrono.phase_id
        action = player.action_grid.retrieve_an_action(phase)
        # The butler has submitted an action. We call the execution function immediately
        if action:
            assert action.action_type == ActionTypes.serve, f"Wrong action type {action} in butler"
            targets = action.target_player
            master_player = targets[0]
            await self.exec_serve(player, master_player)
        # The butler has not submitted an action. We randomize the master for him,
        # DM him the choice of the master, and then call the execution function
        else:
            master_player = BOTCUtils.get_random_player_excluding(player)
            await self.exec_serve(player, master_player)
            msg = botutils.BotEmoji.butterfly
            msg += " "
            msg += action_assign.format(master_player.game_nametag)
            try:
                await player.user.send(msg)
            except discord.Forbidden:
                pass
Exemplo n.º 19
0
    async def send_n1_end_message(self, recipient):
        """Send two possible players for a particular minion character."""

        player = BOTCUtils.get_player_from_id(recipient.id)

        if DISABLE_DMS:
            return

        # Dead players do not receive anything
        if not player.is_alive():
            return

        link = self.registered_minion_type.art_link

        # Construct the message to send
        msg = f"***{recipient.name}#{recipient.discriminator}***, the **{self.name}**:"
        msg += "\n"
        msg += self.emoji + " " + self.instruction
        msg += "\n"
        msg += investigator_init.format(self.registered_minion_type.name)
        msg += "```basic\n"
        msg += f"{self.two_player_list[0].user.display_name} ({self.two_player_list[0].user.id})\n"
        msg += f"{self.two_player_list[1].user.display_name} ({self.two_player_list[1].user.id})\n"
        msg += "```"

        embed = discord.Embed(description=msg)
        embed.set_thumbnail(url=link)
        embed.set_footer(text=copyrights_str)
        embed.timestamp = datetime.datetime.utcnow()

        try:
            await recipient.send(embed=embed)
        except discord.Forbidden:
            pass
Exemplo n.º 20
0
    async def process_night_ability(self, player):
        """Process night actions for the zombuul character.
        @player : the Zombuul player (Player object)
        """

        # We only do any of the following if the zombuul is alive. Otherwise skip everything.
        if player.is_alive():

            phase = globvars.master_state.game._chrono.phase_id
            action = player.action_grid.retrieve_an_action(phase)
            # The zombuul has submitted an action. We call the execution function immediately
            if action:
                assert action.action_type == ActionTypes.kill, f"Wrong action type {action} in zombuul"
                targets = action.target_player
                killed_player = targets[0]
                await self.exec_kill(player, killed_player)
            # The zombuul has not submitted an action. We will randomize the action and make
            # the zombuul kill one random player that is not the zombuul.
            else:
                if player.is_alive():
                    killed_player = BOTCUtils.get_random_player_excluding(
                        player)
                    await self.exec_kill(player, killed_player)
                    msg = botutils.BotEmoji.butterfly
                    msg += " "
                    msg += action_assign.format(killed_player.game_nametag)
                    try:
                        await player.user.send(msg)
                    except discord.Forbidden:
                        pass
                else:
                    pass
Exemplo n.º 21
0
    async def send_regular_night_start_dm(self, recipient):
        """Send the query for night action for each regular night (not the first one)"""

        if DISABLE_DMS:
            return

        import globvars

        player = BOTCUtils.get_player_from_id(recipient.id)

        if player.is_alive():

            # Construct the message to send
            msg = f"***{recipient.name}#{recipient.discriminator}***, the **{self.name}**:"
            msg += "\n"
            msg += self.emoji + " " + self.instruction
            msg += "\n"

            embed = discord.Embed(description=msg)
            embed.timestamp = datetime.datetime.utcnow()
            embed.set_footer(text=copyrights_str)

            msg2 = self.action
            msg2 += globvars.master_state.game.create_sitting_order_stats_string(
            )
            embed.add_field(name=butterfly + " **「 Your Action 」**",
                            value=msg2,
                            inline=False)

            try:
                await recipient.send(embed=embed)
            except discord.Forbidden:
                pass
Exemplo n.º 22
0
    async def send_n1_end_message(self, recipient):
        """Send the number of pairs of evils sitting together."""

        from botc.BOTCUtils import get_number_image

        player = BOTCUtils.get_player_from_id(recipient.id)

        # Dead players do not receive anything
        if not player.is_alive():
            return

        # Poisoned info
        if player.is_droisoned():
            evil_pair_count = self.__create_droisoned_info()
        # Good info
        else:
            evil_pair_count = self.get_nb_pairs_of_evils()
        link = get_number_image(evil_pair_count)

        msg = f"***{recipient.name}#{recipient.discriminator}***, the **{self.name}**:"
        msg += "\n"
        msg += self.emoji + " " + self.instruction
        msg += "\n"
        msg += chef_init.format(evil_pair_count)

        embed = discord.Embed(description=msg)
        embed.set_thumbnail(url=link)
        embed.set_footer(text=copyrights_str)
        embed.timestamp = datetime.datetime.utcnow()

        try:
            await recipient.send(embed=embed)
        except discord.Forbidden:
            pass
Exemplo n.º 23
0
    def get_demon_bluffs(self):
        """Get the list of 3 demon bluffs"""

        # 3 demon bluffs: 2 townsfolk characters + 1 outsider character
        # Exclusing all characters taken by other players, as well as the drunk's ego_self
        all_townsfolks = BOTCUtils.get_role_list(BadMoonRising, Townsfolk)
        all_outsiders = BOTCUtils.get_role_list(BadMoonRising, Outsider)
        taken_townsfolks = [
            player.role.name
            for player in globvars.master_state.game.setup.townsfolks
        ]
        taken_outsiders = [
            player.role.name
            for player in globvars.master_state.game.setup.outsiders
        ]

        possible_townsfolk_bluffs = [
            character for character in all_townsfolks
            if character.name not in taken_townsfolks
        ]
        possible_outsider_bluffs = [
            character for character in all_outsiders
            if character.name not in taken_outsiders
        ]
        random.shuffle(possible_townsfolk_bluffs)
        random.shuffle(possible_outsider_bluffs)

        # For the first two bluffs, we want a townsfolk, definitely
        bluff_1 = possible_townsfolk_bluffs.pop()
        bluff_2 = possible_townsfolk_bluffs.pop()

        # For the third bluff, if the outsider list is not empty, we will take an outsider. Otherwise
        # it's 40% chance outsider, 60% chance townsfolk
        if possible_outsider_bluffs:
            town_or_out = random.choices(["t", "o"], weights=[0.6, 0.4])
            if town_or_out[0] == "t":
                bluff_3 = possible_townsfolk_bluffs.pop()
            else:
                bluff_3 = possible_outsider_bluffs.pop()
        else:
            bluff_3 = possible_townsfolk_bluffs.pop()

        globvars.logging.info(
            f">>> Zombull: Received three demon bluffs {bluff_1}, {bluff_2} and {bluff_3}."
        )
        return (bluff_1, bluff_2, bluff_3)
Exemplo n.º 24
0
    async def getrole(self, ctx):
        player = BOTCUtils.get_player_from_id(ctx.author.id)

        if not isinstance(ctx.channel, discord.channel.DMChannel):
            await ctx.send(game_text["doc"]["getrole"]["feedback"].format(
                ctx.author.mention, BotEmoji.check))

        await player.role.ego_self.send_opening_dm_embed(player.user)
Exemplo n.º 25
0
def can_use_serve(user_id):
    """Return true if the user can use the command "serve"
    Characters that can serve: 
    - Butler
    """
    from botc.gamemodes.troublebrewing._utils import TBRole
    player = BOTCUtils.get_player_from_id(user_id)
    if player.role.ego_self.name in [TBRole.butler.value]:
        return True
    return False
Exemplo n.º 26
0
def can_use_protect(user_id):
    """Return true if the user can use the command "protect"
    Characters that can poison:
    - Monk
    """
    from botc.gamemodes.troublebrewing._utils import TBRole
    player = BOTCUtils.get_player_from_id(user_id)
    if player.role.ego_self.name in [TBRole.monk.value]:
        return True
    return False
Exemplo n.º 27
0
def can_use_read(user_id):
    """Return true if the user can use the command "read"
    Characters that can poison:
    - Fortune teller
    """
    from botc.gamemodes.troublebrewing._utils import TBRole
    player = BOTCUtils.get_player_from_id(user_id)
    if player.role.ego_self.name in [TBRole.fortuneteller.value]:
        return True
    return False
Exemplo n.º 28
0
def check_if_is_player(ctx):
    """Return true if user is a player, and not in fleaved state"""
    player = BOTCUtils.get_player_from_id(ctx.author.id)
    if player:
        if player.is_fleaved():
            raise NotAPlayer(
                "Command not allowed: user has quit the game (BoTC).")
        else:
            return True
    else:
        raise NotAPlayer("Command not allowed: user is not a player (BoTC).")
Exemplo n.º 29
0
    async def claim_remove(self, ctx, player: PlayerConverter = None):
        invoking_player = BOTCUtils.get_player_from_id(ctx.author.id)

        if player is None:
            if globvars.master_state.game._chrono.phase == Phase.night:
                raise NotNight("Command is allowed during night phase only (BoTC)")
            globvars.master_state.game.note_manager.rm_claim(invoking_player)
            await botutils.send_lobby(remove_claim_str.format(ctx.author.mention), delete_after = CLAIM_SHOW_TIME)
        else:
            globvars.master_state.game.note_manager.rm_claim(player, invoking_player)

        await ctx.send(private_remove_claim_str.format(BotEmoji.check))
Exemplo n.º 30
0
    async def notes_remove(self, ctx, player_or_id: Union[PlayerConverter, int], id: int = None):
        invoking_player = BOTCUtils.get_player_from_id(ctx.author.id)

        if isinstance(player_or_id, Player):
            if id is None:
                raise MissingRequiredArgument(Parameter('id', Parameter.POSITIONAL_ONLY))
        else:
            id = player_or_id
            player_or_id = invoking_player

        globvars.master_state.game.note_manager.rm_note(player_or_id, id, invoking_player)
        await ctx.send(notes_remove_feedback_str.format(BotEmoji.check))