def _update_player_members(bot, after): """Update player members when they change.""" try: player = get_player(bot.game, after) player.member = after except PlayerNotFoundError: pass
async def stnominate(self, ctx: Context, nominee: str): """Nominate a player for execution. nominee: The player to nominate. If you want to simulate a nomination by a player, use proxynominate. """ await ctx.bot.game.current_day.nominate( ctx, nominee, get_player(ctx.bot.game, ctx.message.author.id)) await safe_send(ctx, f"Successfully nominated.")
async def prevote(self, ctx: Context, vote: str): """Prevote in an ongoing nomination. vote: The prevote to queue. When it's your turn to vote, this will automatically submit the queued vote. """ actual_vt = int(to_bool(vote, "vote")) await ctx.bot.game.current_day.current_vote.prevote( ctx, get_player(ctx.bot.game, ctx.author.id), actual_vt)
async def to_player( ctx: Context, argument: str, all_members: bool = False, includes_storytellers: bool = False, only_one: bool = False, condition: Callable[["Player", Context], bool] = lambda x, y: True, **kwargs, ) -> "Player": """Convert a string to a player with a matching name. Functionally just a wrapper of to_member that converts the output to a player. The match does not have to be exact. The string must be contained in player.nick, player.display_name, or player.name. Parameters ---------- ctx : Context The invocation context. argument : str The string to match to a script. all_members : bool Whether to include all server members or just game players. includes_storytellers : bool If all_members, whether to include storytellers. only_one : bool Whether to require exactly one initial match. condition: Callable[["Player", Context], bool] A condition to require the player to meet. If the condition is not met, should raise a commands.BadArgument exception. The condition may also take kwargs if necessary. Returns ------- Player The matching player. """ try: player = get_player( ctx.bot.game, ( await to_member( ctx, argument, all_members, includes_storytellers, only_one ) ).id, ) if condition(player, ctx, **kwargs): return player except ValueError as e: if str(e) == "player not found": raise commands.BadArgument( f"Multiple players match {argument}. Please try again." ) raise
async def history(self, ctx: Context, *, player: str): """View your message history. player: The player to view your message history with. """ player_actual = await to_player(ctx, player) await safe_send( ctx, get_player(ctx.bot.game, ctx.author.id, False).message_history_with(player_actual), )
def _update_player_members(bot, after): """Update player members when they change.""" try: player = get_player(bot.game, after) player.member = after except TypeError as e: if str(e) != "no current game": raise except ValueError as e: if str(e) != "player not found": raise
async def history(self, ctx: "GameContext", *, player: str = None): """View your message history. player: The player to view your message history with. If none, this will list all possible players. """ player = player or "" player_actual = await to_player(ctx, player) await safe_send( ctx, get_player(ctx.bot.game, ctx.author.id, False).message_history_with(player_actual), )
async def skip(self, ctx: "DayContext"): """Skip your right to nominate for the current day. You will still be able to nominate. However, if all players nominate or skip, the storytellers may end the day. """ author_player = get_player(ctx.bot.game, ctx.author.id, False) if author_player.can_nominate(ctx.bot.game): await author_player.add_nomination(ctx, skip=True) await safe_send(ctx.bot.channel, f"{author_player.nick} has skipped.") else: raise commands.BadArgument("You cannot nominate today.")
async def nominate(self, ctx: "DayContext", *, nominee: str): """Nominate a player for execution. nominee: The player to be nominated, or "the storytellers". """ try: await ctx.bot.game.current_day.nominate( ctx, nominee, get_player(ctx.bot.game, ctx.message.author.id)) # if they can't nominate # raised by current_day.nominate except AlreadyNomniatedError: return await safe_send(ctx, "You cannot nominate today.")
async def pm(self, ctx: Context, *, recipient: str): """Message a player or storyteller. recipient: The player or storyteller to recieve the message. You will be asked about the content of the message. You can cancel by saying "cancel". """ recipient_actual = await to_player(ctx, recipient, includes_storytellers=True) await recipient_actual.message( ctx, get_player(ctx.bot.game, ctx.message.author.id))
def predicate(ctx: "Context") -> bool: """Check if the command author is a player. Parameters ---------- ctx : Context The invocation context. Returns ------- bool True if the command succeeds, else raises an exception. """ if ctx.bot.game: try: get_player(ctx.bot.game, ctx.message.author.id, include_storytellers=False) return True except PlayerNotFoundError: pass raise commands.CheckFailure(message="Sorry! Only players can do that.")
async def on_message(self, message): """Handle messages.""" if message.author.bot: return if not message.channel == self.bot.channel: return if self.bot.game is None or self.bot.game.current_day is None: return try: player = get_player(self.bot.game, message.author.id, False) await player.make_active(self.bot.game) except PlayerNotFoundError: pass
async def pm(self, ctx: "DayContext", *, recipient: str = None): """Message a player or storyteller. recipient: The player or storyteller to recieve the message. If none, this will list all possible recipients. You will be asked about the content of the message. You can cancel by saying "cancel". """ recipient = recipient or "" recipient_actual = await to_player(ctx, recipient, includes_storytellers=True) await recipient_actual.message( ctx, get_player(ctx.bot.game, ctx.message.author.id))
async def on_message(self, message): """Handle messages.""" if message.author.bot: return if not message.channel == self.bot.channel: return if self.bot.game is None or self.bot.game.current_day is None: return try: player = get_player(self.bot.game, message.author.id, False) await player.make_active(self.bot.game) except TypeError as e: if str(e) != "no current game": raise except ValueError as e: if str(e) != "player not found": raise
async def reply(self, ctx: Context): """Reply to the previously recieved message. You will be asked about the content of the message. You can cancel by saying "cancel". """ author_player = get_player(ctx.bot.game, ctx.message.author.id) most_recent_time = ctx.bot.game.seating_order_message.created_at most_recent_author = None # type: Optional[Player] for message in author_player.message_history: if message["from"] != author_player: if message["time"] > most_recent_time: most_recent_time = message["time"] most_recent_author = message["from"] if not most_recent_author: await safe_send(ctx, "No messages to reply to.") else: await most_recent_author.message(ctx, author_player)
async def vote(self, ctx: Context, *, vote: str): """Vote in an ongoing nomination. vote: The vote to submit. """ vote_actual = to_bool(vote, "vote") player = get_player(ctx.bot.game, ctx.message.author.id) # verify it's their turn to vote if ctx.bot.game.current_day.current_vote.to_vote != player: await safe_send( ctx, ("It is {actual_voter}'s vote, not yours, silly! " "(Unless this is a bug. In which case I'm silly. " "I hope I'm not silly.)").format( actual_voter=ctx.bot.game.current_day.current_vote. to_vote.nick), ) # do the vote await ctx.bot.game.current_day.current_vote.vote( ctx, player, vote_actual)
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