Example #1
0
    async def removetraveler(self, ctx: Context, traveler: str):
        """Remove a traveler from the game.

        traveler: The traveler to remove.
        """
        # convert the traveler
        traveler_actual = await to_player(ctx, traveler)

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

        # remove them from the seating order
        ctx.bot.game.seating_order.remove(traveler_actual)

        # announcement
        msg = await safe_send(
            ctx.bot.channel,
            ("{townsfolk}, {traveler} has left the town. "
             "Let's wish {pronoun} goodbye!").format(
                 pronoun=load_preferences(traveler_actual).pronouns[1],
                 townsfolk=ctx.bot.player_role.mention,
                 traveler=traveler_actual.nick,
             ),
        )
        await msg.pin()
        await safe_send(
            ctx, f"Successfully removed traveler {traveler_actual.nick}.")
Example #2
0
def _permission_to_edit(ctx: Context, idn: int, script: Script):
    """Determine if the user represented by the ID can edit the script."""
    if idn in script.editors:
        return True

    else:
        message_text = f"You do not have permission to edit {script.name}. "
        if script.editors != []:
            editors, plural = script.editor_names(ctx)
            s = "s" if plural else ""
            verb = "are" if plural else "is"

            if plural:
                pronoun = "them"
            else:
                pronoun = load_preferences(ctx.bot.get_user(
                    script.editors[0])).pronouns[1]

            message_text += (
                f"Its editor{s} {verb} {editors}. Contact {pronoun} for more info."
            )

        else:
            message_text += ("If you believe the script is incorrect, "
                             "please contact nihilistkitten#6937 or an admin.")

        raise commands.BadArgument(message_text)
Example #3
0
        async def inner_wrapper(*args, **kwargs):
            if args[0].parent.functioning(args[1]):
                return await func(*args, **kwargs)
            if safe_bug_report(args[1]):
                if args[0].parent.ghost(args[1]):
                    status = "dead"
                elif args[0].parent.is_status(args[1], "drunk"):
                    status = "drunk"
                elif args[0].parent.is_status(args[1], "poisoned"):
                    status = "poisoned"
                else:
                    status = "not functioning"
                if run_if_drunkpoisoned and status in ("drunk", "poisoned"):
                    kwargs["enabled"] = False
                    kwargs["epithet_string"] = f"({status})"
                    return await func(*args, **kwargs)
                pronouns = load_preferences(args[0].parent).pronouns
                await safe_send(
                    args[1],
                    "Skipping {epithet}, as {pronoun} {verb} {status}.".format(
                        epithet=args[0].parent.epithet,
                        pronoun=pronouns[0],
                        verb=("is", "are")[pronouns[5]],
                        status=status,
                    ),
                )

            # this return is hella janky but basically we want this to work for any
            # of the character methods (ex morning, evening) and they have different
            # return types so we need to grab whatever the generic return is.
            # the character initializes with no parent to let us check in the method
            # if it's actually being called or just being called to get the return
            # so we can hide side effects in an "if self.parent" block
            return await getattr(Character(None), func.__name__)(*args[1:],
                                                                 **kwargs)
Example #4
0
    def nick(self) -> str:
        """Determine the name the bot will call the player.

        Their nickname if set in preferences, else server nickname, else discord name.
        """
        return load_preferences(
            self.member).nick  # the preferences object defaults to obj.nick =
Example #5
0
    async def morning(
        self, ctx: Context, skip: bool = False
    ) -> Tuple[List["Player"], List[str]]:
        """Call at the start of each day. Processes night actions.

        Parameters
        ----------
        ctx : Context
            The invocation context.

        Returns
        -------
        List[Player]
            Players killed by the character.
        str
            A non-kill message to broadcast at the start of the day.
        """
        # check that this isn't a dummy call from a wrapper to figure out the return
        # see the commenting of tools.if_functioning for more info
        if self.parent:
            await safe_send(
                ctx,
                (
                    "Skipping {epithet}, as "
                    "{posessive} ability is not handled by the bot."
                ).format(
                    epithet=self.parent.epithet,
                    posessive=load_preferences(self.parent).pronouns[2],
                ),
            )
        return [], []
Example #6
0
    async def setnick(self, ctx: Context, *, nick: str):
        """Set your nickname for bot messages.

        nick: The name you want to use.

        This input is case-sensitive.
        """
        preferences = load_preferences(ctx.message.author)
        preferences.nick = nick
        preferences.save_preferences()
        await safe_send(ctx, f"Successfully set your nickname to {nick}.")
Example #7
0
    async def removealias(self, ctx: Context, alias: str):
        """Remove a personal alias for a command.

        alias: The alias to remove.
        """
        preferences = load_preferences(ctx.message.author)
        try:
            del preferences.aliases[alias]
            preferences.save_preferences()
            await safe_send(ctx, f"Successfully deleted your alias {alias}.")
        except KeyError:
            raise commands.BadArgument(f"You do not have an alias {alias}.")
Example #8
0
 async def wrapper(*args, **kwargs):
     if not args[0].parent.is_status(args[1], "used_ability"):
         return await func(*args, **kwargs)
     if safe_bug_report(args[1]):
         pronouns = load_preferences(args[0].parent).pronouns
         await safe_send(
             args[1],
             ("Skipping {epithet}, as "
              "{subjective} {verb} used {posessive} ability.").format(
                  epithet=args[0].parent.epithet,
                  subjective=pronouns[0],
                  verb=["has", "have"][pronouns[5]],
                  posessive=pronouns[2],
              ),
         )
     return await getattr(Character(None), func.__name__)(*args[1:],
                                                          **kwargs)
Example #9
0
 async def wrapper(character: Character, ctx: "GameContext", *args,
                   **kwargs):
     if not character.parent.is_status(ctx.bot.game, "used_ability"):
         return await func(character, ctx, *args, **kwargs)
     if safe_bug_report(ctx):
         pronouns = load_preferences(character.parent).pronouns
         await safe_send(
             ctx,
             ("Skipping {epithet}, as "
              "{subjective} {verb} used {posessive} ability.").format(
                  epithet=character.parent.epithet,
                  subjective=pronouns[0],
                  verb=["has", "have"][pronouns[5]],
                  posessive=pronouns[2],
              ),
         )
     return await getattr(Character(None), func.__name__)(  # type: ignore
         ctx, *args, **kwargs)
Example #10
0
 async def _generate_vote_end_message(self):
     """Generate the vote end message."""
     result = self.votes >= self.majority
     voters = list_to_plural_string([x.nick for x in self.voted], "no one")
     result_type = ["executed", "exiled"][self.traveler]
     pronouns = load_preferences(self.nominee).pronouns
     message_text = (
         "{votes} votes on {nominee_nick} (nominated by {nominator_nick}):"
         " {voters}. {pronoun_string}{nt} about to be {result_type}.")
     message_text = message_text.format(
         nt=[" not", ""][result],
         voters=voters[0],
         votes=self.votes,
         nominee_nick=self.nominee.nick,
         nominator_nick=self.nominator.nick,
         result_type=result_type,
         pronoun_string=pronouns[0].capitalize() +
         [" is", " are"][pronouns[5]],
     )
     return message_text, result
Example #11
0
    async def emergencyvote(
        self,
        ctx: Context,
        vote: str,
        time: int,
        specific: str = "yes",
    ):
        """Change your emergency vote.

        vote: The vote you want to set, yes or no.
        time: The time in minutes for the vote to trigger.
        specific: Whether this emergency is bot-specific, yes or no. Defaults to yes.
        """
        vote_actual = to_bool(vote, "vote")
        specific_actual = to_bool(specific, "argument")
        preferences = load_preferences(ctx.message.author)
        if specific_actual:
            preferences.specific_emergencys[ctx.bot.user.id] = (vote_actual,
                                                                time)
            preferences.save_preferences()
            await safe_send(
                ctx,
                ("Successfully set a emergency vote of {vote} "
                 "in {time} minutes for {botName}.").format(
                     vote=("no", "yes")[vote_actual],
                     time=str(time),
                     botName=ctx.bot.server.get_member(
                         ctx.bot.user.id).display_name,
                 ),
            )
        else:
            preferences.emergency_vote = (vote_actual, time)
            preferences.save_preferences()
            await safe_send(
                ctx,
                ("Successfully set a generic emergency vote of "
                 "{vote} in {time} minutes.").format(vote=("no",
                                                           "yes")[vote_actual],
                                                     time=str(time)),
            )
    async def removeemergencyvote(self, ctx: Context, specific: str = "yes"):
        """Remove your emergency vote.

        specific: Whether to remove the bot-specific emergency vote or the generic one.
        """
        specific_actual = to_bool(specific, "argument")
        preferences = load_preferences(ctx.message.author)
        if specific_actual:
            try:
                del preferences.specific_emergencys[ctx.bot.user.id]
                preferences.save_preferences()
                await safe_send(
                    ctx,
                    (
                        "Successfully removed your bot-specific emergency vote. "
                        "Please note any generic emergency vote will now apply."
                    ),
                )
            except KeyError:
                await safe_send(
                    ctx,
                    "You do not have a specific emergency vote with {botName}.".format(
                        botName=ctx.bot.server.get_member(ctx.bot.user.id).display_name
                    ),
                )
        else:
            if preferences.emergency_vote[1] is not None:
                preferences.emergency_vote = (0, None)
                preferences.save_preferences()
                await safe_send(
                    ctx,
                    (
                        "Successfully removed your generic emergency vote. "
                        "Please note any bot-specific emergency votes will still apply."
                    ),
                )
            else:
                await safe_send(ctx, "You do not have a generic emergency vote.")
Example #13
0
    async def process_commands(self, message: discord.Message):
        """Process commands registered to the bot.

        Modified to handle custom aliases.
        """
        if message.author.bot:
            return

        if not (message.guild is None or message.channel == self.channel):
            return

        ctx = await self.get_context(message)

        preferences = load_preferences(message.author)
        if ctx.invoked_with in preferences.aliases:
            ctx.command = self.all_commands.get(
                preferences.aliases[ctx.invoked_with].split(" ")[0])
            if " " in preferences.aliases[ctx.invoked_with]:
                for cmd in preferences.aliases[ctx.invoked_with].split(
                        " ")[1:]:
                    ctx.command = ctx.command.get_command(cmd)

        await self.invoke(ctx)
Example #14
0
def _generate_possibilities(argument: str,
                            possibilities: List[Member]) -> List[Member]:
    """Determine all members with marching nicknames or usernames.

    Parameters
    ----------
    argument : str
        The string to be matched.
    possibilities : List[Member]
        The possible members to search for matches.

    Returns
    -------
    List[Member]
        The matching members.
    """
    out = []
    for person in possibilities:
        if (argument.lower() in load_preferences(person).nick.lower()
                or argument.lower() in person.display_name.lower()
                or argument.lower() in person.name.lower()):
            out.append(person)
    return out
Example #15
0
    async def makealias(self,
                        ctx: Context,
                        alias: str,
                        command: str,
                        *,
                        subcommand: str = ""):
        """Create a personal alias for a command.

        alias: The alias to be created.
        command: The command to create the alias for.
        """
        preferences = load_preferences(ctx.message.author)
        cmd = ctx.bot.all_commands.get(command)
        if cmd is None:
            await safe_send(
                ctx,
                "Command not found: {command}.".format(
                    command=command + (" " if subcommand else "") +
                    subcommand),
            )
        elif subcommand:
            if cmd.get_command(subcommand) is None:
                await safe_send(
                    ctx,
                    "Command not found: {command}.".format(command=command +
                                                           " " + subcommand),
                )
        else:
            preferences.aliases[alias] = (command +
                                          (" " if subcommand else "") +
                                          subcommand)
            preferences.save_preferences()
            await safe_send(
                ctx,
                "Successfully created alias `{alias}` for command `{command}`."
                .format(alias=alias, command=preferences.aliases[alias]),
            )
Example #16
0
    async def setpronouns(
        self,
        ctx: Context,
        subjective: str,
        objective: str,
        adjective: str,
        posessive: str,
        reflexive: str,
        plural: str = "no",
    ):
        """Set your pronouns for bot messages.

        subjective: The subjective pronoun, for instance 'they' or 'she'.
        objective: The objective pronoun, for instance 'them' or 'her'.
        adjective: The posessive adjective, for instance 'their' or 'her'.
        posessive: The posessive pronoun, for instance 'theirs' or 'hers'.
        reflexive: The reflexive pronoun, for instance 'themselves' or 'herself'.
        plural: Whether the bot should use plural grammar with your pronouns.
            For instance, 'they are about to die' or 'she is about to die'.

        You can also fill in the blank:
            [subjective] is/are the Imp.
            The Imp is [objective].  # TODO: this is apparently bad grammar
            It is [adjective] character.
            The character is [posessive].
            [subjective] made the Minion a Demon by targeting [reflexive].

        For example:
            They are the Imp.
            The Imp is them.
            It is their character.
            The character is theirs.
            They made the Minion a Demon by targetting themselves.

        These inputs are case-insensitive.

        If you use this to mock trans people, I will blacklist you from using the bot. <3
        """
        plural_actual = to_bool(plural, "argument")

        preferences = load_preferences(ctx.message.author)
        preferences.pronouns = (
            subjective,
            objective,
            adjective,
            posessive,
            reflexive,
            plural_actual,
        )
        preferences.save_preferences()
        await safe_send(
            ctx,
            ("Successfully set your pronouns! "
             "You are valid and thank you for trusting me with them!\n"
             "Here's a quick example so you can make sure you got the grammar right:"
             "\n{subjective} {verb} the Imp."
             "\nThe Imp is {objective}."
             "\nIt is {adjective} character."
             "\nThe character is {posessive}."
             "\n{subjective} made the Minion a Demon by targeting {reflexive}."
             ).format(
                 reflexive=reflexive,
                 subjective=subjective.capitalize(),
                 verb=["is", "are"][plural_actual],
                 objective=objective,
                 adjective=adjective,
                 posessive=posessive,
             ),
        )
Example #17
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