async def on_being_executed(self, executed_player): """Funtion that runs after the player has been executed. Overriding the parent behaviour. Check for presence of scarlet woman and promote her to demonhood if applicable. """ if executed_player.is_alive(): # If 5 or more players alive (not counting travelers), scarlet woman gets # promoted to demonhood if globvars.master_state.game.nb_alive_players >= 5: from botc.gamemodes.troublebrewing import ScarletWoman # This list of scarletwomen could contain dead players scarletwomen = BOTCUtils.get_players_from_role_name(ScarletWoman()._role_enum) if scarletwomen: # We only want the alive, and not poisoned scarlet women alive_scarletwomen = [player for player in scarletwomen if player.is_alive() and not player.is_droisoned()] if alive_scarletwomen: promoted = random.choice(alive_scarletwomen) promoted._old_role_obj = promoted._role_obj await promoted.exec_change_role(Imp()) embed = self.__make_demonhood_promo_embed(promoted) try: await promoted.user.send(embed = embed) except discord.Forbidden: pass await executed_player.exec_real_death() game = globvars.master_state.game game.today_executed_player = executed_player
async def process_night_ability(self, player): """Process night actions for the imp character. @player : the Imp player (Player object) """ # We only do any of the following if the imp 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 imp has submitted an action. We call the execution function immediately if action: assert action.action_type == ActionTypes.kill, f"Wrong action type {action} in imp" targets = action.target_player killed_player = targets[0] await self.exec_kill(player, killed_player) # The imp has not submitted an action. We will randomize the action and make # the imp kill one random player that is not the imp. 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
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(TroubleBrewing, Townsfolk) all_outsiders = BOTCUtils.get_role_list(TroubleBrewing, 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">>> Imp: Received three demon bluffs {bluff_1}, {bluff_2} and {bluff_3}." ) return (bluff_1, bluff_2, bluff_3)
async def _starpass(self, demon_player): """Starpassing ability works when the demon is killed by himself at night""" # If 5 or more players alive (not counting travelers), scarlet woman has priority # over the promotion to demonhood if globvars.master_state.game.nb_alive_players >= 5: from botc.gamemodes.troublebrewing import ScarletWoman # This list of scarletwomen could contain dead players scarletwomen = BOTCUtils.get_players_from_role_name(ScarletWoman()._role_enum) if scarletwomen: # We only want the alive, and not poisoned scarlet women alive_scarletwomen = [player for player in scarletwomen if player.is_alive() and not player.is_droisoned()] if alive_scarletwomen: promoted = random.choice(alive_scarletwomen) promoted._old_role_obj = promoted._role_obj await promoted.exec_change_role(Imp()) embed = self.__make_demonhood_promo_embed(promoted) try: await promoted.user.send(embed = embed) except discord.Forbidden: pass return # Otherwise, any random minion is selected # This list of minions could contain dead players minions = BOTCUtils.get_all_minions() if minions: # We only want the alive players. alive_minions = [player for player in minions if player.is_alive()] if alive_minions: promoted = random.choice(alive_minions) promoted._old_role_obj = promoted._role_obj await promoted.exec_change_role(Imp()) embed = self.__make_demonhood_promo_embed(promoted) try: await promoted.user.send(embed = embed) except discord.Forbidden: pass
async def modkill(self, ctx, *, player: PlayerConverter): """Modkill command""" if player.role.social_self.category == Category.demon: if player.is_alive(): # If 5 or more players alive (not counting travelers), scarlet woman gets # promoted to demonhood if globvars.master_state.game.nb_alive_players >= 5: from botc.gamemodes.troublebrewing import ScarletWoman # This list of scarletwomen could contain dead players scarletwomen = BOTCUtils.get_players_from_role_name( ScarletWoman()._role_enum) if scarletwomen: # We only want the alive, and not poisoned scarlet women alive_scarletwomen = [ player for player in scarletwomen if player.is_alive() and not player.is_droisoned() ] if alive_scarletwomen: promoted = random.choice(alive_scarletwomen) promoted._old_role_obj = promoted._role_obj await promoted.exec_change_role(Imp()) if not DISABLE_DMS: embed = Imp._make_demonhood_promo_embed( Imp(), promoted) try: await promoted.user.send(embed=embed) except discord.Forbidden: pass await player.exec_real_death() player.ghost_vote = 0 if not NO_INVALIDATE: globvars.master_state.game.invalidated = True feedback = game_text["doc"]["modkill"]["feedback"] await ctx.send(feedback.format(check_emoji, player.game_nametag))
async def exec_slay(self, slayer_player, slain_player): """Execute the slay action (immediate effect)""" # Remove the unique use ability from the player's inventory slayer_player.role.ego_self.inventory.remove_item_from_inventory(Flags.slayer_unique_attempt) slayer_player.add_persistent_reminder_token('botc/assets/tb_reminder_tokens_cropped/slayer_used.png') # The ability succeeds when the slayer is not droisoned and the slain player is registering # as a demon with their social self if not slayer_player.is_droisoned(): if slain_player.role.social_self.category == Category.demon: string = LorePicker().pick(LorePicker().SLAY_SUCCESS) string = string.format( slayer = slayer_player.game_nametag, slain = slain_player.game_nametag ) if slain_player.is_alive(): # Add information to replay globvars.master_state.game.replay += f"- {slayer_player.user.name} (Slayer) "\ f"slays {slain_player.user.name} ({slain_player.role.true_self}, "\ f"registering as {slain_player.role.social_self})\n" # If 5 or more players alive (not counting travelers), scarlet woman gets # promoted to demonhood if globvars.master_state.game.nb_alive_players >= 5: from botc.gamemodes.troublebrewing import ScarletWoman # This list of scarletwomen could contain dead players scarletwomen = BOTCUtils.get_players_from_role_name(ScarletWoman()._role_enum) if scarletwomen: # We only want the alive, and not poisoned scarlet women alive_scarletwomen = [player for player in scarletwomen if player.is_alive() and not player.is_droisoned()] if alive_scarletwomen: promoted = random.choice(alive_scarletwomen) # Add information to replay globvars.master_state.game.replay += f"- {promoted.user.name} "\ "(Scarlet Woman) becomes Imp\n" promoted._old_role_obj = promoted._role_obj await promoted.exec_change_role(Imp()) if not DISABLE_DMS: embed = Imp._make_demonhood_promo_embed(Imp(), promoted) try: await promoted.user.send(embed = embed) except discord.Forbidden: pass try: await slain_player.exec_real_death() except AlreadyDead: pass await botutils.send_lobby(string) return # Add information to replay drunk = "Drunk " if slayer_player.role.true_self.name == Drunk().name else "" globvars.master_state.game.replay += f"- {slayer_player.user.name} ({drunk}Slayer) "\ f"unsuccessfully slays {slain_player.user.name} "\ f"({slain_player.role.true_self}, registering "\ f"as {slain_player.role.social_self})\n" # The ability fails no matter what for a droisoned slayer, or if the slain player # is not a demon string = LorePicker().pick(LorePicker().SLAY_FAIL) string = string.format( slayer = slayer_player.game_nametag, slain = slain_player.game_nametag ) await botutils.send_lobby(string)
async def _starpass(self, demon_player): """Starpassing ability works when the demon is killed by himself at night""" # If imp starpasses to poisoner, the poisoned player should be no longer poisoned for player in globvars.master_state.game.sitting_order: for status in player.status_effects: if status.effect == StatusList.poison: status.manually_disable() # If 5 or more players alive (not counting travelers), scarlet woman has priority # over the promotion to demonhood if globvars.master_state.game.nb_alive_players >= 5: from botc.gamemodes.troublebrewing import ScarletWoman # This list of scarletwomen could contain dead players scarletwomen = BOTCUtils.get_players_from_role_name( ScarletWoman()._role_enum) if scarletwomen: # We only want the alive, and not poisoned scarlet women alive_scarletwomen = [ player for player in scarletwomen if player.is_alive() and not player.is_droisoned() ] if alive_scarletwomen: promoted = random.choice(alive_scarletwomen) # Add information to replay globvars.master_state.game.replay += f"- {promoted.user.name} (Scarlet Woman) "\ "becomes Imp\n" promoted._old_role_obj = promoted._role_obj await promoted.exec_change_role(Imp()) promoted.add_persistent_reminder_token( 'botc/assets/tb_reminder_tokens_cropped/sw_demon.png') if DISABLE_DMS: return embed = self._make_demonhood_promo_embed(promoted) try: await promoted.user.send(embed=embed) except discord.Forbidden: pass return # Otherwise, any random minion is selected # This list of minions could contain dead players minions = BOTCUtils.get_all_minions() if minions: # We only want the alive players. alive_minions = [player for player in minions if player.is_alive()] if alive_minions: promoted = random.choice(alive_minions) # Add information to replay globvars.master_state.game.replay += f"- {promoted.user.name} "\ f"({promoted.role.true_self}) becomes Imp\n" promoted._old_role_obj = promoted._role_obj await promoted.exec_change_role(Imp()) promoted.add_persistent_reminder_token( 'botc/assets/tb_reminder_tokens_cropped/sw_demon.png') if DISABLE_DMS: return embed = self._make_demonhood_promo_embed(promoted) try: await promoted.user.send(embed=embed) except discord.Forbidden: pass