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
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
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)
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)")
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 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)
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)")
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
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 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)
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
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)
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()
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)
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)
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
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
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
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).")
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))
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))
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))
async def notes(self, ctx, *, args = None): invoking_player = BOTCUtils.get_player_from_id(ctx.author.id) if args is None: # Claims summary if isinstance(ctx.channel, discord.channel.DMChannel): await botutils.send_long_message(ctx.channel, globvars.master_state.game.note_manager.format_notes(invoking_player), make_code=True, delete_after=CLAIM_SHOW_TIME) else: await botutils.send_long_message(ctx.channel, globvars.master_state.game.note_manager.format_notes(), make_code=True, delete_after=CLAIM_SHOW_TIME) return else: if isinstance(ctx.channel, discord.channel.DMChannel): await self.notes_add.callback(self, ctx, args=args)
async def kill_error(self, ctx, error): emoji = documentation["cmd_warnings"]["x_emoji"] # Incorrect character -> RoleCannotUseCommand if isinstance(error, RoleCannotUseCommand): return # If it passed all the checks but raised an error in the character class elif isinstance(error, AbilityForbidden): error = getattr(error, 'original', error) await ctx.send(error) elif isinstance(error, commands.BadArgument): return # Non-registered or quit player -> NotAPlayer elif isinstance(error, NotAPlayer): return # Incorrect channel -> NotDMChannel elif isinstance(error, NotDMChannel): return # Incorrect argument -> commands.BadArgument elif isinstance(error, commands.BadArgument): return # Incorrect phase -> NotNight elif isinstance(error, NotNight): try: await ctx.author.send( documentation["cmd_warnings"]["night_only"].format( ctx.author.mention, emoji)) except discord.Forbidden: pass # Player not alive -> AliveOnlyCommand elif isinstance(error, AliveOnlyCommand): try: await ctx.author.send( documentation["cmd_warnings"]["alive_only"].format( ctx.author.mention, emoji)) except discord.Forbidden: pass # Missing argument -> commands.MissingRequiredArgument elif isinstance(error, commands.MissingRequiredArgument): player = BOTCUtils.get_player_from_id(ctx.author.id) msg = player.role.ego_self.emoji + " " + player.role.ego_self.instruction + " " + player.role.ego_self.action try: await ctx.author.send(msg) except discord.Forbidden: pass else: try: raise error except Exception: await ctx.send(error_str) await botutils.log(botutils.Level.error, traceback.format_exc())
async def info_remove(self, ctx, player_or_id: Union[int, PlayerConverter] = None, id: PlayerConverter() = None): invoking_player = BOTCUtils.get_player_from_id(ctx.author.id) if isinstance(player_or_id, int): id = player_or_id player_or_id = None if player_or_id 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_info(invoking_player, id) else: globvars.master_state.game.note_manager.rm_info(player_or_id, id, invoking_player) await ctx.send(info_remove_feedback_str.format(BotEmoji.check))
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))
async def send_regular_night_end_dm(self, recipient): """Send the character of the executed player today.""" if DISABLE_DMS: return player = BOTCUtils.get_player_from_id(recipient.id) # Dead players do not receive anything if not player.is_alive(): return executed_player = globvars.master_state.game.today_executed_player if player.is_droisoned(): # Poisoned info character_of_executed = self.__create_droisoned_info() else: if executed_player: executed_player.role.set_new_social_self(executed_player) character_of_executed = executed_player.role.social_self else: character_of_executed = None if not character_of_executed: return # Add information to replay drunk = "Drunk " if player.role.true_self.name == Drunk().name else "" globvars.master_state.game.replay += f"- {recipient.name} ({drunk}Undertaker) learns that "\ f"{executed_player.user.name} is {character_of_executed}\n" executed_player.add_reminder_token('botc/assets/tb_reminder_tokens_cropped/undertaker_dead.png') msg = f"***{recipient.name}#{recipient.discriminator}***, the **{self.name}**:" msg += "\n" msg += self.emoji + " " + self.instruction msg += "\n" msg += undertaker_nightly.format(character_of_executed.name) embed = discord.Embed(description = msg) embed.set_thumbnail(url = character_of_executed._art_link_cropped) embed.set_footer(text = copyrights_str) embed.timestamp = datetime.datetime.utcnow() try: await recipient.send(embed = embed) except discord.Forbidden: pass
async def send_regular_night_end_dm(self, recipient): """Send the character of the executed player today.""" 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(): character_of_executed = self.__create_droisoned_info() else: import globvars executed_player = globvars.master_state.game.today_executed_player if executed_player: executed_player.role.set_new_social_self(executed_player) character_of_executed = executed_player.role.social_self else: character_of_executed = None msg = f"***{recipient.name}#{recipient.discriminator}***, the **{self.name}**:" msg += "\n" msg += self.emoji + " " + self.instruction msg += "\n" if character_of_executed: msg += undertaker_nightly.format(character_of_executed.name) else: msg += undertaker_none embed = discord.Embed(description=msg) if character_of_executed: embed.set_thumbnail(url=character_of_executed._art_link_cropped) embed.set_footer(text=copyrights_str) embed.timestamp = datetime.datetime.utcnow() try: await recipient.send(embed=embed) except discord.Forbidden: pass
async def send_n1_end_message(self, recipient): """Send two possible players for a particular townsfolk character.""" 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(): two_player_list = self.__create_droisoned_info(player) # Good info else: two_player_list = self.get_two_possible_townsfolks(recipient) registered_townsfolk_type = two_player_list[2] link = registered_townsfolk_type.art_link assert registered_townsfolk_type.category == Category.townsfolk, "Washerwoman did not receive a townsfolk character" # Get rid of the last element two_player_list.pop() # Construct the message to send msg = f"***{recipient.name}#{recipient.discriminator}***, the **{self.name}**:" msg += "\n" msg += self.emoji + " " + self.instruction msg += "\n" msg += washerwoman_init.format(registered_townsfolk_type.name) msg += "```basic\n" msg += f"{two_player_list[0].user.display_name} ({two_player_list[0].user.id})\n" msg += f"{two_player_list[1].user.display_name} ({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
async def send_n1_end_message(self, recipient): """Send the number of alive evil neighbours""" if DISABLE_DMS: return 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(): nb_evils = self.__create_droisoned_info() # Good info else: nb_evils = self.get_nb_evil_neighbours(recipient) link = get_number_image(nb_evils) # Add information to replay drunk = "Drunk " if player.role.true_self.name == Drunk().name else "" globvars.master_state.game.replay += f"- {recipient.name} ({drunk}Empath) learns of "\ f"{nb_evils} alive evil neighbour(s)\n" msg = f"***{recipient.name}#{recipient.discriminator}***, the **{self.name}**:" msg += "\n" msg += self.emoji + " " + self.instruction msg += "\n" msg += empath_nightly.format(nb_evils) 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