Beispiel #1
0
    async def donate(self, ctx):
        """Support the continued development of Spirit!"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        e = discord.Embed(colour=constants.BLUE)

        text = (
            "Spirit is a work of love that has taken countless hours to develop. Your donation "
            +
            "will go towards server hosting costs, development tools, and if you donate "
            +
            "monthly, will also earn you some special privelges on the Spirit Discord server!\n\n"
            + "Donate once: https://www.paypal.me/spiritbot\n" +
            "Donate monthly: https://www.patreon.com/spiritbot")
        reward_1 = "- Colored name on the Spirit Discord server"
        reward_2 = (
            "- Patron role and colored name on the Spirit Discord server\n" +
            "- Access to the developer blog on Patreon and the Spirit Discord server\n"
            +
            "- Access to a patron only channel on the Spirit Discord server which includes sneak peeks of new features!"
        )
        reward_3 = ("- All rewards from the previous tier\n" +
                    "- Your own personalized message built right into Spirit!")

        e.description = text
        e.add_field(name="$1/Month", value=reward_1)
        e.add_field(name="$5/Month", value=reward_2)
        e.add_field(name="$10/Month", value=reward_3)

        await manager.say(e, embed=True, delete=False)
        await manager.clear()
Beispiel #2
0
    async def countdown(self, ctx):
        """Show time until upcoming Destiny 2 releases"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        pst_now = datetime.now(tz=pytz.timezone('US/Pacific'))
        text = ""

        for name, date in constants.RELEASE_DATES:
            diff = date - pst_now
            days = diff.days + 1
            if days == 0:
                text += "{}: Today!\n".format(name)
            elif days == 1:
                text += "{}: Tomorrow!\n".format(name)
            elif days > 1:
                text += "{}: {} days\n".format(name, days)

        if not text:
            text = "There are no concrete dates for our next adventure..."

        countdown = discord.Embed(title="Destiny 2 Countdown",
                                  color=constants.BLUE)
        countdown.description = text
        await manager.say(countdown, embed=True, delete=False)
        await manager.clear()
Beispiel #3
0
    async def seteventrole(self, ctx, *, event_role):
        """Set the lowest role that is able to create events (Manage Server only)

        By default, creating events requires the user to have Administrator permissions.
        But if an event role is set, then any user that is of the event role or higher may
        create events.

        **Note:** Mentioning the role directly with this command will not work. You must provide
        only the name of the role without mentioning it. The role name is also case sensitive!
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel,
                                 [ctx.message])

        guild_event_role = None
        for role in ctx.guild.roles:
            if role.name in (event_role, "@{}".format(event_role)):
                guild_event_role = role

        if not guild_event_role:
            await manager.say(
                "I couldn't find a role called **{}** on this server.\n".
                format(event_role) +
                "Note that you must provide only the name of the role. " +
                "Mentioning it with the @ sign won't work. The role name is also "
                + "case sensitive!")
            return await manager.clear()

        with DBase() as db:
            db.set_event_role_id(ctx.guild.id, guild_event_role.id)

        await manager.say("The event role has been set to: **{}**".format(
            format_role_name(guild_event_role)))
        return await manager.clear()
Beispiel #4
0
    async def togglecleanup(self, ctx):
        """
        Toggle command message cleanup on/off (Manage Server only)

        When enabled, command message spam will be deleted a few seconds
        after a command has been invoked. This feature is designed to
        keep bot related spam to a minimum. Only non important messages will
        be deleted if this is enabled; messages like the help message or the
        roster, for example, will not be removed.
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel,
                                 [ctx.message])

        with DBase() as db:
            db.toggle_cleanup(ctx.guild.id)
            rows = db.get_cleanup(ctx.guild.id)

        if len(rows) and len(rows[0]):
            cleanup = rows[0][0]
        else:
            raise ValueError("Could not retrieve 'cleanup' from database")

        status = 'enabled' if cleanup else 'disabled'
        await manager.say("Command message cleanup is now *{}*".format(status))
        return await manager.clear()
Beispiel #5
0
    async def on_command_error(self, ctx, error):
        """Command error handler"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel,
                                 [ctx.message])

        if isinstance(error, commands.CommandNotFound):
            pass

        elif isinstance(error, commands.MissingRequiredArgument):
            pass

        elif isinstance(error, commands.NotOwner):
            pass

        elif isinstance(error, commands.NoPrivateMessage):
            await manager.say(
                "You can't use that command in a private message",
                mention=False)

        elif isinstance(error, commands.CheckFailure):
            await manager.say(
                "You don't have the required permissions to do that")

        elif isinstance(error, commands.CommandInvokeError):
            if isinstance(error.original, discord.errors.Forbidden):
                pass
            else:
                raise error

        else:
            raise error

        await manager.clear()
Beispiel #6
0
    async def on_raw_reaction_add(self, emoji, message_id, channel_id, user_id):
        """If a reaction represents a user RSVP, update the DB and event message"""
        channel = self.bot.get_channel(channel_id)
        if isinstance(channel, discord.abc.PrivateChannel):
            return

        try:
            message = await channel.get_message(message_id)
        except discord.errors.Forbidden as e:
            # Don't have permission to read this message
            return

        guild = channel.guild
        member = guild.get_member(user_id)
        manager = MessageManager(self.bot, member, channel)
        deleted = None

        # We check that the user is not the message author as to not count
        # the initial reactions added by the bot as being indicative of attendance
        if is_event(message) and member != message.author:
            title = message.embeds[0].title
            if emoji.name == "\N{WHITE HEAVY CHECK MARK}":
                await self.set_attendance(member, guild, 1, title, message)
            elif emoji.name == "\N{CROSS MARK}":
                await self.set_attendance(member, guild, 0, title, message)
            elif emoji.name == "\N{SKULL}":
                deleted =  await self.delete_event(guild, title, member, channel)

            if not deleted:
                await message.remove_reaction(emoji, member)
            await manager.clear()
Beispiel #7
0
    async def feedback(self, ctx, *, message):
        """
        Send a message to the bot's developer

        Ex. '!feedback Your bot is awesome!'

        This command was adapted from RoboDanny by Rapptz - https://www.github.com/Rapptz/RoboDanny
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix, [ctx.message])

        e = discord.Embed(title='Feedback', colour=constants.BLUE)
        e.set_author(name=str(ctx.author), icon_url=ctx.author.avatar_url)
        e.description = message
        e.timestamp = ctx.message.created_at

        if ctx.guild is not None:
            e.add_field(name='Server', value='{} (ID: {})'.format(ctx.guild.name, ctx.guild.id), inline=False)

        e.add_field(name='Channel', value='{} (ID: {})'.format(ctx.channel, ctx.channel.id), inline=False)
        e.set_footer(text='Author ID: {}'.format(ctx.author.id))

        feedback_channel = self.bot.get_channel(359848505654771715)
        if feedback_channel:
            await feedback_channel.send(embed=e)
        else:
            asal = await self.bot.get_user_info("118926942404608003")
            await asal.send(embed=e)

        await manager.say("Your feedback has been sent to the developer!")
        await manager.clear()
Beispiel #8
0
    async def pm(self, ctx, user_id: int, *message):
        """Send a PM via the bot to a user given their ID"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix, [ctx.message])
        user = self.bot.get_user(user_id)

        if ctx.author.id not in constants.MODS:
            return

        if len(message) == 0:
            await manager.say("You forgot to include your message!")
            return await manager.clear()

        response = "You have received a message from my developer:\n\n**"
        for word in message:
            response += "{} ".format(word)
        response += ("**\n\nYour response will not be tracked here. If you wish "
                   + "to speak with him further, join the official **{} Support** "
                   + "server - https://discord.gg/GXCFpkr").format(self.bot.user.name)

        try:
            await user.send(response)
        except:
            await manager.say('Could not PM user with ID {}'.format(user_id))
        else:
            await manager.say('PM successfully sent.')
        await manager.clear()
Beispiel #9
0
    async def show(self, ctx):
        """
        Display the roster

        The roster includes the name, Destiny 2 class,
        and timezone of server members. Note that only
        users who have set a role or timezone will be
        displayed on the roster.
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, [ctx.message])
        roster_groups = []

        with DBase() as db:
            roster = db.get_roster(ctx.guild.id)

        if len(roster) != 0:

            text = "```\n"
            for row in roster:

                # Add a single entry to the roster message
                member = ctx.guild.get_member(row[0])
                if member:
                    name = member.display_name
                    formatted_name = (name[:16] + '..') if len(name) > 16 else name
                    role = row[1] if row[1] else "---"
                    time_zone = row[2] if row[2] else "---"
                    text += '{:18} {:6} {:7}\n'.format(formatted_name, time_zone, role)

                # If the message is too big, place it into a group
                if len(text) > 2000:
                    text += "```"
                    roster_groups.append(text)
                    text = "```\n"

            # Add any remaining entries into a roster group
            if len(text) > 5:
                text += "```"
                roster_groups.append(text)

            # Send the initial roster message
            embed_msg = discord.Embed(color=constants.BLUE)
            embed_msg.title="{} Roster".format(ctx.guild.name)
            embed_msg.description = roster_groups[0]
            await manager.say(embed_msg, embed=True, delete=False)

            # Send additional roster messages if the roster is too long
            for group in roster_groups[1:]:
                embed_msg = discord.Embed(color=constants.BLUE)
                embed_msg.title="{} Roster (continued)".format(ctx.guild.name)
                embed_msg.description = group
                await manager.say(embed_msg, embed=True, delete=False)

        else:
            await manager.say("No roster exists yet. Use '{}roster settimezone' or '{}roster ".format(ctx.prefix, ctx.prefix)
                            + "setclass' to add the first entry!")
        await manager.clear()
Beispiel #10
0
    async def about(self, ctx):
        """Display information about the bot itself

        This command was adapted from RoboDanny by Rapptz - https://www.github.com/Rapptz/RoboDanny
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        e = discord.Embed(title='Spirit v{}'.format(constants.VERSION),
                          colour=constants.BLUE)

        e.description = (
            "[Invite Spirit](https://discordapp.com/oauth2/authorize?client_id=335084645743984641&scope=bot&permissions=523344)\n"
            + "[Spirit Support Server](https://discord.gg/GXCFpkr)")

        owner = self.bot.get_user(118926942404608003)
        e.set_author(name=str(owner), icon_url=owner.avatar_url)

        # statistics
        total_members = sum(1 for _ in self.bot.get_all_members())
        total_online = len({
            m.id
            for m in self.bot.get_all_members()
            if m.status is discord.Status.online
        })
        total_unique = len(self.bot.users)

        voice_channels = []
        text_channels = []
        for guild in self.bot.guilds:
            voice_channels.extend(guild.voice_channels)
            text_channels.extend(guild.text_channels)

        text = len(text_channels)
        voice = len(voice_channels)

        e.add_field(name='Members',
                    value='{} total\n{} unique\n{} unique online'.format(
                        total_members, total_unique, total_online))
        e.add_field(name='Channels',
                    value='{} total\n{} text\n{} voice'.format(
                        text + voice, text, voice))

        memory_usage = "%0.2f" % (self.process.memory_full_info().uss /
                                  1024**2)
        cpu_usage = "%0.2f" % (self.process.cpu_percent() / psutil.cpu_count())
        e.add_field(name='Process',
                    value='{} MiB\n{}% CPU'.format(memory_usage, cpu_usage))

        e.add_field(name='Guilds', value=len(self.bot.guilds))
        e.add_field(name='Commands Run', value=self.bot.command_count)
        e.add_field(name='Uptime', value=self.get_bot_uptime(brief=True))

        e.set_footer(text='Made with discord.py',
                     icon_url='http://i.imgur.com/5BFecvA.png')
        await manager.say(e, embed=True, delete=False)
        await manager.clear()
Beispiel #11
0
    async def nightfall(self, ctx):
        """Display the weekly nightfall info"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        await ctx.channel.trigger_typing()

        try:
            weekly = await self.destiny.api.get_public_milestones()
        except pydest.PydestException as e:
            await manager.say(
                "Sorry, I can't seem retrieve the nightfall info right now")
            return await manager.clear()

        if weekly['ErrorCode'] != 1:
            await manager.say(
                "Sorry, I can't seem retrieve the nightfall info right now")
            return await manager.clear()

        nightfall_hash = weekly['Response']['2171429505']['availableQuests'][
            0]['activity']['activityHash']
        nightfall = await self.destiny.decode_hash(
            nightfall_hash, 'DestinyActivityDefinition')

        challenges = ""
        for entry in nightfall['challenges']:
            challenge = await self.destiny.decode_hash(
                entry['objectiveHash'], 'DestinyObjectiveDefinition')
            challenge_name = challenge['displayProperties']['name']
            challenge_description = challenge['displayProperties'][
                'description']
            challenges += "**{}** - {}\n".format(challenge_name,
                                                 challenge_description)

        modifiers = ""
        for entry in weekly['Response']['2171429505']['availableQuests'][0][
                'activity']['modifierHashes']:
            modifier = await self.destiny.decode_hash(
                entry, 'DestinyActivityModifierDefinition')
            modifier_name = modifier['displayProperties']['name']
            modifier_description = modifier['displayProperties']['description']
            modifiers += "**{}** - {}\n".format(modifier_name,
                                                modifier_description)

        e = discord.Embed(title='{}'.format(
            nightfall['displayProperties']['name']),
                          colour=constants.BLUE)
        e.description = "*{}*".format(
            nightfall['displayProperties']['description'])
        e.set_thumbnail(url=('https://www.bungie.net' +
                             nightfall['displayProperties']['icon']))
        e.add_field(name='Challenges', value=challenges)
        e.add_field(name='Modifiers', value=modifiers)

        await manager.say(e, embed=True, delete=False)
        await manager.clear()
Beispiel #12
0
    async def setprefix(self, ctx, new_prefix):
        """
        Change the server's command prefix (Manage Server only)
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])

        if len(new_prefix) > 5:
            await manager.say("Prefix must be less than 6 characters.")
            return await manager.clear()

        self.bot.db.set_prefix(ctx.guild.id, new_prefix)
        await manager.say("Command prefix has been changed to " + new_prefix)
        return await manager.clear()
Beispiel #13
0
    async def seteventrole_error(self, ctx, error):
        if isinstance(error, commands.MissingRequiredArgument):
            manager = MessageManager(self.bot, ctx.author, ctx.channel,
                                     [ctx.message])
            event_role = get_event_role(ctx.guild)

            if not event_role:
                role_display = 'None (anyone can make events)'
            else:
                role_display = format_role_name(event_role)

            await manager.say(
                "The current event role is: **{}**\n\n".format(role_display) +
                "To change the event role, use '{}settings seteventrole <role_name>'"
                .format(ctx.prefix))
            await manager.clear()
Beispiel #14
0
    async def seteventdeleterole_error(self, ctx, error):
        if isinstance(error, commands.MissingRequiredArgument):
            manager = MessageManager(self.bot, ctx.author, ctx.channel,
                                     ctx.prefix, [ctx.message])
            event_role = get_event_delete_role(self.bot, ctx.guild)

            if not event_role:
                role_display = '**None** (only Manage Sever members can delete events)'
            else:
                role_display = format_role_name(event_role)

            await manager.say(
                "The current event delete role is: {}\n\n".format(
                    role_display) +
                "To change the event delete role, use '{}settings seteventdeleterole <role_name>'"
                .format(ctx.prefix))
            await manager.clear()
Beispiel #15
0
    async def setclass(self, ctx, role):
        """
        Add your Destiny 2 class to the roster

        Class must be one of Titan, Warlock, or Hunter
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, [ctx.message])

        role = role.lower().title()
        if role == "Titan" or role == "Warlock" or role == "Hunter":
            with DBase() as db:
                db.add_user(ctx.author.id)
                db.update_role(ctx.author.id, role, ctx.guild.id)
            await manager.say("Your class has been updated!")
        else:
            await manager.say("Class must be one of: Titan, Hunter, Warlock")
        await manager.clear()
Beispiel #16
0
    async def broadcast(self, ctx, *, message):
        """Send a message to the owner of every server the bot belongs to"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix, [ctx.message])

        if ctx.author.id not in constants.OWNERS:
            return

        count = 0
        for guild in self.bot.guilds:
            try:
                await guild.owner.send(message)
            except:
                pass
            else:
                count+= 1

        await manager.say("Broadcast message sent to **{}** users".format(count))
        await manager.clear()
Beispiel #17
0
    async def settimezone(self, ctx, *, time_zone):
        """
        Add your timezone to the roster

        For a full list of supported timezones, check out the bot's support server
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, [ctx.message])
        time_zone = time_zone.upper()
        time_zone = "".join(time_zone.split())

        if time_zone in constants.TIME_ZONES:
            with DBase() as db:
                db.add_user(ctx.author.id)
                db.update_timezone(ctx.author.id, time_zone, ctx.guild.id)
            await manager.say("Your time zone has been updated!")
        else:
            await manager.say("Unsupported time zone. For a list of supported timezones, "
                            + "check out the bot's support server.")
        await manager.clear()
Beispiel #18
0
    async def botstats(self, ctx):
        """Displays the bot's stats"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel,
                                 [ctx.message])

        if ctx.author.id not in constants.OWNERS:
            return

        num_guilds = len(self.bot.guilds)
        users = []
        for guild in self.bot.guilds:
            if guild.id not in constants.SERVERS_NO_COUNT:
                guild_users = [user for user in guild.members if not user.bot]
                users.extend(guild_users)
        num_users = len(set(users))

        e = discord.Embed(title='{} Stats'.format(self.bot.user.name),
                          colour=constants.BLUE)
        e.description = "**Servers**: {}\n**Users**: {}".format(
            num_guilds, num_users)
        await ctx.channel.send(embed=e)
        await manager.clear()
Beispiel #19
0
    async def event(self, ctx):
        """
        Create an event in the events channel

        After invoking the event command, the bot will ask
        you to enter the event details. Once the event
        is created, it will appear in the upcoming-events
        channel. The upcoming-events channel is designed with
        the assumption that it isn't used for anything but
        displaying events; non event messages will be deleted.

        Users will be able to accept and decline the
        event by adding reactions. If a maximum number
        of attendees is set and the event is full,
        additional attendees will be placed in a standby
        section. If a spot opens up, the user at the
        top of the standby section will be automatically
        moved into the event.

        By default, everyone can make events. However, a minimum role
        requirement to create events can be defined in the settings.
        See `help settings seteventrole` for more information.

        The event creator and those with the Manage Sever permission
        can delete events by reacting to the event message with \U0001f480.
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        event_role = get_event_role(self.bot, ctx.guild)
        member_permissions = ctx.author.permissions_in(ctx.channel)

        if event_role:
            if ctx.author.top_role < event_role:
                event_role_str = format_role_name(event_role)
                await manager.say(
                    "You must be of role **{}** or higher to do that.".format(
                        event_role))
                return await manager.clear()

        await manager.say(
            'Event creation instructions have been messaged to you')

        res = await manager.say_and_wait("Enter event title:", dm=True)
        if not res:
            return await manager.clear()
        title = res.content

        description = ""
        res = await manager.say_and_wait(
            "Enter event description (type 'none' for no description):",
            dm=True)
        if not res:
            return await manager.clear()
        if res.content.upper() != 'NONE':
            description = res.content

        max_members = 0
        while not max_members:
            res = await manager.say_and_wait(
                "Enter the maximum numbers of attendees (type 'none' for no maximum):",
                dm=True)
            if not res:
                return await manager.clear()
            if res.content.upper() == 'NONE':
                break
            elif is_int(res.content) and int(res.content) in range(1, 10000):
                max_members = int(res.content)
            else:
                await manager.say(
                    "Invalid entry. Must be a number between 1 and 9999.",
                    dm=True)

        start_time = None
        while not start_time:
            res = await manager.say_and_wait(
                "Enter event time (YYYY-MM-DD HH:MM AM/PM):", dm=True)
            if not res:
                return await manager.clear()
            start_time_format = '%Y-%m-%d %I:%M %p'
            try:
                start_time = datetime.strptime(res.content, start_time_format)
            except ValueError:
                await manager.say("Invalid event time!", dm=True)

        time_zone = None
        while not time_zone:
            res = await manager.say_and_wait(
                "Enter the time zone (PST, EST, etc):", dm=True)
            if not res:
                return await manager.clear()
            user_timezone = "".join(res.content.upper().split())
            if user_timezone not in constants.TIME_ZONES:
                await manager.say("Unsupported time zone", dm=True)
            else:
                time_zone = user_timezone

        affected_rows = self.bot.db.create_event(title, start_time, time_zone,
                                                 ctx.guild.id, description,
                                                 max_members, ctx.author.id)
        if affected_rows == 0:
            await manager.say("An event with that name already exists!",
                              dm=True)
            return await manager.clear()

        event_channel = await self.get_events_channel(ctx.guild)
        await manager.say("Event created! The " + event_channel.mention +
                          " channel will be updated momentarily.",
                          dm=True)
        await self.list_events(ctx.guild)
        await manager.clear()
Beispiel #20
0
    async def pvp(self, ctx):
        """Display Crucible stats for all characters on an account"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        await ctx.channel.trigger_typing()

        # Check if user has registered their D2 account with the bot
        info = self.bot.db.get_d2_info(ctx.author.id)
        if info:
            platform = info.get('platform')
            membership_id = info.get('membership_id')
        else:
            await manager.say(
                "You must first register your Destiny 2 account with the " +
                "`{}register` command.".format(ctx.prefix))
            return await manager.clear()

        # Get display name
        try:
            res = await self.destiny.api.get_profile(platform, membership_id,
                                                     ['Profiles'])
        except:
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()
        if res['ErrorCode'] != 1:
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()
        display_name = res['Response']['profile']['data']['userInfo'][
            'displayName']

        # Get PvP stats
        try:
            res = await self.destiny.api.get_historical_stats(platform,
                                                              membership_id,
                                                              modes=[5])
        except:
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()
        if res['ErrorCode'] != 1:
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()
        pvp_stats = res['Response']['allPvP'].get('allTime')

        if not len(pvp_stats):
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()

        time_played = pvp_stats['secondsPlayed']['basic']['displayValue']
        kdr = pvp_stats['killsDeathsRatio']['basic']['displayValue']
        kda = pvp_stats['killsDeathsAssists']['basic']['displayValue']
        best_weapon = pvp_stats['weaponBestType']['basic']['displayValue']
        games_played = pvp_stats['activitiesEntered']['basic']['displayValue']
        best_kills = pvp_stats['bestSingleGameKills']['basic']['displayValue']
        best_spree = pvp_stats['longestKillSpree']['basic']['displayValue']
        combat_rating = pvp_stats['combatRating']['basic']['displayValue']
        kills = pvp_stats['kills']['basic']['displayValue']
        assists = pvp_stats['assists']['basic']['displayValue']
        deaths = pvp_stats['deaths']['basic']['displayValue']

        # Can't convert a string of '-' to a float!
        win_ratio = pvp_stats['winLossRatio']['basic']['displayValue']
        if win_ratio != '-':
            win_ratio = float(win_ratio)
            win_rate = str(round(win_ratio / (win_ratio + 1) * 100, 1)) + " %"
        else:
            win_rate = win_ratio

        e = discord.Embed(colour=constants.BLUE)
        e.set_author(name="{} | Crucible Stats".format(display_name),
                     icon_url=constants.PLATFORM_URLS.get(platform))
        e.add_field(name='Kills', value=kills, inline=True)
        e.add_field(name='Assists', value=assists, inline=True)
        e.add_field(name='Deaths', value=deaths, inline=True)
        e.add_field(name='KD Ratio', value=kdr, inline=True)
        e.add_field(name='Efficiency (KAD)', value=kda, inline=True)
        e.add_field(name='Win Rate', value=win_rate, inline=True)
        e.add_field(name='Best Spree', value=best_spree, inline=True)
        e.add_field(name='Most Kills in a Game', value=best_kills, inline=True)
        e.add_field(name='Favorite Weapon', value=best_weapon, inline=True)
        e.add_field(name='Combat Rating', value=combat_rating, inline=True)
        e.add_field(name='Games Played', value=games_played, inline=True)
        e.add_field(name='Time Played', value=time_played, inline=True)

        await manager.say(e, embed=True, delete=False)
        await manager.clear()
Beispiel #21
0
    async def pve(self, ctx):
        """Display PvE stats for all characters on an account"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        await ctx.channel.trigger_typing()

        # Check if user has registered their D2 account with the bot
        info = self.bot.db.get_d2_info(ctx.author.id)
        if info:
            platform = info.get('platform')
            membership_id = info.get('membership_id')
        else:
            await manager.say(
                "You must first register your Destiny 2 account with the " +
                "`{}register` command.".format(ctx.prefix))
            return await manager.clear()

        # Get display name
        try:
            res = await self.destiny.api.get_profile(platform, membership_id,
                                                     ['Profiles'])
        except pydest.PydestException as e:
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()
        if res['ErrorCode'] != 1:
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()
        display_name = res['Response']['profile']['data']['userInfo'][
            'displayName']

        # Get PvE stats
        try:
            res = await self.destiny.api.get_historical_stats(
                platform, membership_id, modes=[7, 4, 16, 18])
        except pydest.PydestException as e:
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()
        if res['ErrorCode'] != 1:
            await manager.say(
                "Sorry, I can't seem to retrieve your stats right now")
            return await manager.clear()
        pve_stats = res['Response']

        time_played = pve_stats['allPvE']['allTime'][
            'totalActivityDurationSeconds']['basic']['displayValue'] if len(
                pve_stats['allPvE']) else 0
        best_weapon = pve_stats['allPvE']['allTime']['weaponBestType'][
            'basic']['displayValue'] if len(pve_stats['allPvE']) else 0
        num_heroic_events = pve_stats['allPvE']['allTime'][
            'heroicPublicEventsCompleted']['basic']['displayValue'] if len(
                pve_stats['allPvE']) else 0
        num_events = pve_stats['allPvE']['allTime']['publicEventsCompleted'][
            'basic']['displayValue'] if len(pve_stats['allPvE']) else 0
        num_raids = pve_stats['raid']['allTime']['activitiesCleared']['basic'][
            'displayValue'] if len(pve_stats['raid']) else 0
        raid_time = pve_stats['raid']['allTime'][
            'totalActivityDurationSeconds']['basic']['displayValue'] if len(
                pve_stats['raid']) else 0
        num_nightfall = pve_stats['nightfall']['allTime']['activitiesCleared'][
            'basic']['displayValue'] if len(pve_stats['nightfall']) else 0
        num_strikes = pve_stats['allStrikes']['allTime']['activitiesCleared'][
            'basic']['displayValue'] if len(pve_stats['allStrikes']) else 0
        fastest_nightfall = pve_stats['nightfall']['allTime'][
            'fastestCompletionMs']['basic']['displayValue'] if len(
                pve_stats['nightfall']) else 0
        kills = pve_stats['allPvE']['allTime']['kills']['basic'][
            'displayValue'] if len(pve_stats['allPvE']) else 0
        assists = pve_stats['allPvE']['allTime']['assists']['basic'][
            'displayValue'] if len(pve_stats['allPvE']) else 0
        deaths = pve_stats['allPvE']['allTime']['deaths']['basic'][
            'displayValue'] if len(pve_stats['allPvE']) else 0

        e = discord.Embed(colour=constants.BLUE)
        e.set_author(name="{} | PvE Stats".format(display_name),
                     icon_url=constants.PLATFORM_URLS.get(platform))
        e.add_field(name='Kills', value=kills, inline=True)
        e.add_field(name='Assists', value=assists, inline=True)
        e.add_field(name='Deaths', value=deaths, inline=True)
        e.add_field(name='Strikes', value=num_strikes, inline=True)
        e.add_field(name='Nightfalls', value=num_nightfall, inline=True)
        e.add_field(name='Fastest Nightfall',
                    value=fastest_nightfall,
                    inline=True)
        e.add_field(name='Public Events', value=num_events, inline=True)
        e.add_field(name='Heroic Public Events',
                    value=num_heroic_events,
                    inline=True)
        e.add_field(name='Favorite Weapon', value=best_weapon, inline=True)
        e.add_field(name='Total Raid Time', value=raid_time, inline=True)
        e.add_field(name='Raids', value=num_raids, inline=True)
        e.add_field(name='Time Played', value=time_played, inline=True)

        await manager.say(e, embed=True, delete=False)
        await manager.clear()
Beispiel #22
0
    async def register(self, ctx):
        """Register your Destiny 2 account with the bot

        This command will let the bot know which Destiny 2 profile to associate with your Discord
        profile. Registering is a prerequisite to using any commands that require knowledge of your
        Destiny 2 profile.
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        template = "https://www.bungie.net/en/OAuth/Authorize?client_id={}&response_type=code&state={}"
        auth_url = template.format(self.bot.bungie_client_id, ctx.author.id)
        bliz_name, xbox_name, psn_name, bliz_id, xbox_id, psn_id = (None, ) * 6

        if not isinstance(ctx.channel, discord.abc.PrivateChannel):
            await manager.say(
                "Registration instructions have been messaged to you.")

        # Prompt user with link to Bungie.net OAuth authentication
        e = discord.Embed(colour=constants.BLUE)
        e.title = "Click Here to Register"
        e.url = auth_url
        e.description = (
            "Click the above link to register your Bungie.net account with Spirit. "
            +
            "Registering will allow Spirit to access your connected Destiny " +
            "2 accounts.")
        registration_msg = await manager.say(e, embed=True, dm=True)

        # Wait for user info from the web server via Redis
        res = await self.redis.subscribe(ctx.author.id)
        tsk = asyncio.ensure_future(self.wait_for_msg(res[0]))
        try:
            user_info = await asyncio.wait_for(tsk, timeout=90)
        except asyncio.TimeoutError:
            await manager.say(
                "I'm not sure where you went. We can try this again later.",
                dm=True)
            await registration_msg.delete()
            return await manager.clear()
        await ctx.channel.trigger_typing()

        # Save OAuth credentials and bungie ID
        bungie_id = user_info.get('membership_id')
        access_token = user_info.get('access_token')
        refresh_token = user_info.get('refresh_token')
        self.bot.db.update_registration(bungie_id, access_token, refresh_token,
                                        ctx.author.id)

        # Fetch platform specific display names and membership IDs
        try:
            res = await self.bot.destiny.api.get_membership_data_by_id(
                bungie_id)
        except:
            await manager.say(
                "I can't seem to connect to Bungie right now. Try again later.",
                dm=True)
            await registration_msg.delete()
            return await manager.clear()

        if res['ErrorCode'] != 1:
            await manager.say(
                "Oops, something went wrong during registration. Please try again.",
                dm=True)
            await registration_msg.delete()
            return await manager.clear()

        for entry in res['Response']['destinyMemberships']:
            if entry['membershipType'] == 4:
                bliz_name = entry['displayName']
                bliz_id = entry['membershipId']
            elif entry['membershipType'] == 1:
                xbox_name = entry['displayName']
                xbox_id = entry['membershipId']
            elif entry['membershipType'] == 2:
                psn_name = entry['displayName']
                psn_id = entry['membershipId']

        bungie_name = res['Response']['bungieNetUser']['displayName']
        self.bot.db.update_display_names(ctx.author.id, bungie_name, bliz_name,
                                         xbox_name, psn_name)
        self.bot.db.update_membership_ids(ctx.author.id, bliz_id, xbox_id,
                                          psn_id)

        # Get references to platform emojis from Spirit Support server
        platform_reactions = []
        if bliz_name:
            platform_reactions.append(self.bot.get_emoji(constants.BNET_ICON))
        if xbox_name:
            platform_reactions.append(self.bot.get_emoji(constants.XBOX_ICON))
        if psn_name:
            platform_reactions.append(self.bot.get_emoji(constants.PS_ICON))

        # Display message with prompts to select a preferred platform
        e = self.registered_embed(bungie_name, bliz_name, xbox_name, psn_name)
        platform_msg = await manager.say(e, embed=True, dm=True)
        await registration_msg.delete()

        # If only one account is connected, set it as preferred (don't display reactions)
        platform_names = (bliz_name, xbox_name, psn_name)
        if self.num_non_null_entries(platform_names) == 1:

            if bliz_name:
                platform_id = 4
            elif xbox_name:
                platform_id = 1
            else:
                platform_id = 2

            self.bot.db.update_platform(ctx.author.id, platform_id)
            return await manager.clear()

        func = self.add_reactions(platform_msg, platform_reactions)
        self.bot.loop.create_task(func)

        def check_reaction(reaction, user):
            if reaction.message.id == platform_msg.id and user == ctx.author:
                for emoji in platform_reactions:
                    if reaction.emoji == emoji:
                        return True

        # Wait for platform reaction from user
        try:
            reaction, user = await self.bot.wait_for('reaction_add',
                                                     timeout=60.0,
                                                     check=check_reaction)
        except asyncio.TimeoutError:
            await manager.say(
                "I'm not sure where you went. We can try this again later.",
                dm=True)
            return await manager.clear()

        # Save preferred platform
        platform = constants.PLATFORMS.get(reaction.emoji.name)
        self.bot.db.update_platform(ctx.author.id, platform)

        # Update message with preferred platform
        e = self.registered_embed(bungie_name,
                                  bliz_name,
                                  xbox_name,
                                  psn_name,
                                  footer=True,
                                  platform=platform)
        await platform_msg.edit(embed=e)

        return await manager.clear()
Beispiel #23
0
 async def feedback_error(self, ctx, error):
     if isinstance(error, commands.MissingRequiredArgument):
         manager = MessageManager(self.bot, ctx.author, ctx.channel,
                                  ctx.prefix, [ctx.message])
         await manager.say("You forgot to include your feedback!")
         await manager.clear()
Beispiel #24
0
    async def register(self, ctx):
        """Register your Destiny 2 account with the bot

        This command will let the bot know which Destiny 2 profile to associate with your Discord
        profile. Registering is a prerequisite to using any commands that require knowledge of your
        public Destiny 2 profile.
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])

        if not isinstance(ctx.channel, discord.abc.PrivateChannel):
            await manager.say(
                "Registration instructions have been messaged to you")

        platform = None
        platform_msg = await manager.say(
            "Registering your Destiny 2 account with me will allow " +
            "you to invoke commands that use information from your " +
            "public Destiny 2 profile. Note that you can only be " +
            "registered with one platform at a time; registering again " +
            "will overwrite your current registration.\n\n" +
            "Select a platform:",
            dm=True)

        platform_reactions = (self.bot.get_emoji(constants.XBOX_ICON),
                              self.bot.get_emoji(constants.PS_ICON),
                              self.bot.get_emoji(constants.BNET_ICON))

        func = self.add_reactions(platform_msg, platform_reactions)
        self.bot.loop.create_task(func)

        def check_reaction(reaction, user):
            if reaction.message.id == platform_msg.id and user == ctx.author:
                for emoji in platform_reactions:
                    if reaction.emoji == emoji:
                        return True

        try:
            reaction, user = await self.bot.wait_for('reaction_add',
                                                     timeout=60.0,
                                                     check=check_reaction)
        except asyncio.TimeoutError:
            await manager.say(
                "I'm not sure where you went. We can try this again later.",
                dm=True)
            return await manager.clear()
        platform = constants.PLATFORMS.get(reaction.emoji.name)

        act = await manager.say_and_wait("Enter your exact **account name**:",
                                         dm=True)
        if not act:
            return await manager.clear()

        # Number sign won't work, need to replace it
        if platform == 4:
            act_name = act.content.replace('#', '%23')
        else:
            act_name = act.content

        try:
            res = await self.destiny.api.search_destiny_player(
                platform, act_name)
        except ValueError as e:
            await manager.say(
                "Invalid account name. If this seems wrong, please contact the developer.",
                dm=True)
            return await manager.clear()
        except pydest.PydestException as e:
            await manager.say(
                "I can't seem to connect to Bungie right now. Try again later.",
                dm=True)
            return await manager.clear()

        act_exists = False
        if res['ErrorCode'] == 1 and len(res['Response']) == 1:
            act_exists = True
            membership_id = res['Response'][0]['membershipId']
        elif res['ErrorCode'] == 1 and len(res['Response']) > 1:
            for entry in res['Response']:
                if act.content == entry['displayName']:
                    act_exists = True
                    membership_id = entry['membershipId']
                    break

        if not act_exists:
            await manager.say(
                "An account with that name doesn't seem to exist.", dm=True)
        else:
            await manager.say("Account successfully registered!", dm=True)
            self.bot.db.add_user(ctx.author.id)
            self.bot.db.update_registration(platform, membership_id,
                                            ctx.author.id)

        return await manager.clear()
Beispiel #25
0
 async def item_error(self, ctx, error):
     if isinstance(error, commands.MissingRequiredArgument):
         manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix, [ctx.message])
         await manager.say("Oops! You didn't specify a search term.")
         await manager.clear()
Beispiel #26
0
    async def help(self, ctx, str_cmd=None, str_subcmd=None):
        """Display command information"""
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])

        # Determine which prefix to display in the help message
        if isinstance(ctx.channel, discord.abc.PrivateChannel):
            prefix = '!'
        else:
            # Don't want to display @botname as the prefix in the help message
            # It's way too long!
            if ctx.prefix != '<@{}> '.format(self.bot.user.id):
                prefix = ctx.prefix
            else:
                custom_prefix = self.bot.db.get_prefix(ctx.guild.id)
                if len(custom_prefix):
                    prefix = custom_prefix.get('prefix')
                else:
                    raise AttributeError("Could not retrieve command prefix")

        # User passed a command and a subcommand
        if str_cmd and str_subcmd:
            cmd = self.bot.get_command(str_cmd)
            if cmd is None:
                await manager.say(
                    "There are no commands called '{}'".format(str_cmd))
                return await manager.clear()

            # Check for subcommand
            if hasattr(cmd, 'commands'):
                for sub_cmd in cmd.commands:
                    if sub_cmd.name == str_subcmd:
                        help = self.help_embed_single(prefix, sub_cmd)
                        await manager.say(help, embed=True, delete=False)
                        break
                else:
                    await manager.say(
                        "'{}' doesn't have a subcommand called '{}'".format(
                            str_cmd, str_subcmd))
            else:
                await manager.say(
                    "'{}' does not have any subcommands".format(str_cmd))

        # User passed in a single command
        elif str_cmd:
            cmd = self.bot.get_command(str_cmd)
            if cmd is None:
                await manager.say(
                    "There are no commands called '{}'".format(str_cmd))
                return await manager.clear()

            # Check if command has subcommands
            if hasattr(cmd, 'commands'):
                sub_cmds = []
                for sub_cmd in cmd.commands:
                    sub_cmds.append(sub_cmd)
                help = self.help_embed_group(prefix, cmd, sub_cmds)
            else:
                help = self.help_embed_single(prefix, cmd)
            await manager.say(help, embed=True, delete=False)

        # No command passed, print help for all commands
        else:
            help = self.help_embed_all(prefix, self.bot.commands)
            await manager.say(help, embed=True, delete=False)

        await manager.clear()
Beispiel #27
0
 async def setprefix_error(self, ctx, error):
     if isinstance(error, commands.MissingRequiredArgument):
         manager = MessageManager(self.bot, ctx.author, ctx.channel,
                                  [ctx.message])
         await manager.say("Oops! You didn't provide a new prefix.")
         await manager.clear()
Beispiel #28
0
    async def item(self, ctx, *, search_term):
        """Search for a Destiny 2 item

        This command searches for and displays Destiny 2 items. The results are
        limited to weapons and armour. If multiple results are found, they will
        be displayed in a paginated format. The user who invoked the command
        will be able to page through the results.

        Note: The search term must contain a minimum of three characters.
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix, [ctx.message])
        paginator = Paginator(self.bot, ctx)
        await ctx.channel.trigger_typing()

        try:
            res = await self.bot.destiny.api.search_destiny_entities('DestinyInventoryItemDefinition', search_term)
        except pydest.PydestException as e:
            await manager.say("Sorry, I can't seem to search for items right now.")
            return await manager.clear()
        except ValueError as f:
            await manager.say("Your search term contains unsupported characters.")
            return await manager.clear()

        if res['ErrorCode'] != 1:
            await manager.say("Sorry, I can't seem to search for items right now")
            return await manager.clear()

        # Check how many results were found - we need at least one
        num_results = res['Response']['results']['totalResults']
        if num_results == 0:
            await manager.say("I didn't find any items that match your search.")
            return await manager.clear()

        # Iterate through each result, and add them to the paginator if valid type
        for i, entry in enumerate(res['Response']['results']['results']):

            item_hash = entry['hash']
            item = await self.bot.destiny.decode_hash(item_hash, 'DestinyInventoryItemDefinition')

            # If item isn't a weapon or armor piece, skip to the next one
            if item['itemType'] not in (2, 3):
                continue

            e = discord.Embed()
            e.set_author(name=item['displayProperties']['name'])
            e.description = "*{}*".format(item['displayProperties']['description'])
            e.set_thumbnail(url=BASE_URL + item['displayProperties']['icon'])

            # Set embed color based on item rarity
            item_rarity = int(item['inventory']['tierType'])
            if item_rarity == 2:
                e.color = discord.Color.light_grey()
            elif item_rarity == 3:
                e.color = discord.Color.dark_green()
            elif item_rarity == 4:
                e.color = discord.Color.blue()
            elif item_rarity == 5:
                e.color = discord.Color.dark_purple()
            elif item_rarity == 6:
                e.color = discord.Color.gold()
            else:
                e.color = constants.BLUE

            # Add armor/weapon specific information
            if item['itemType'] == 3:
                e = self.embed_weapon(e, item)
                e = await self.embed_perks(e, item, 4241085061)
            else:
                e = self.embed_armor(e, item)
                e = await self.embed_perks(e, item, 2518356196)

            paginator.add_embed(e)

        if not paginator.length:
            await manager.say("I didn't find any items that match your search.")
            return await manager.clear()

        func = manager.clear()
        self.bot.loop.create_task(func)
        await paginator.paginate()
Beispiel #29
0
 async def broadcast_error(self, ctx, error):
     manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix, [ctx.message])
     await manager.say("You didn't include a broadcast message")
     return await manager.clear()
Beispiel #30
0
    async def loadout(self, ctx):
        """Display your last played character's loadout

        In order to use this command, you must first register your Destiny 2 account with the bot
        via the register command.
        """
        manager = MessageManager(self.bot, ctx.author, ctx.channel, ctx.prefix,
                                 [ctx.message])
        await ctx.channel.trigger_typing()

        # Check if user has registered their D2 account with the bot
        info = self.bot.db.get_d2_info(ctx.author.id)
        if info:
            platform = info.get('platform')
            membership_id = info.get('membership_id')
        else:
            await manager.say(
                "You must first register your Destiny 2 account with the " +
                "`{}register` command.".format(ctx.prefix))
            return await manager.clear()

        try:
            res = await self.destiny.api.get_profile(
                platform, membership_id,
                ['characters', 'characterEquipment', 'profiles'])
        except pydest.PydestException as e:
            await manager.say(
                "Sorry, I can't seem to retrieve your Guardian right now.")
            return await manager.clear()

        if res['ErrorCode'] != 1:
            await manager.say(
                "Sorry, I can't seem to retrieve your Guardian right now.")
            return await manager.clear()

        # Determine which character was last played
        chars_last_played = []
        for character_id in res['Response']['characters']['data']:
            last_played_str = res['Response']['characters']['data'][
                character_id]['dateLastPlayed']
            date_format = '%Y-%m-%dT%H:%M:%SZ'
            last_played = datetime.strptime(last_played_str, date_format)
            chars_last_played.append((character_id, last_played))
        last_played_char_id = max(chars_last_played, key=lambda t: t[1])[0]
        last_played_char = res['Response']['characters']['data'].get(
            last_played_char_id)

        #######################################
        # ------ Decode Character Info ------ #
        #######################################

        role_dict = await self.destiny.decode_hash(
            last_played_char['classHash'], 'DestinyClassDefinition')
        role = role_dict['displayProperties']['name']

        gender_dict = await self.destiny.decode_hash(
            last_played_char['genderHash'], 'DestinyGenderDefinition')
        gender = gender_dict['displayProperties']['name']

        race_dict = await self.destiny.decode_hash(
            last_played_char['raceHash'], 'DestinyRaceDefinition')
        race = race_dict['displayProperties']['name']

        char_name = res['Response']['profile']['data']['userInfo'][
            'displayName']
        level = last_played_char['levelProgression']['level']
        light = last_played_char['light']
        emblem_url = 'https://www.bungie.net' + last_played_char['emblemPath']

        stats = []
        for stat_hash in ('2996146975', '392767087', '1943323491'):
            stat_dict = await self.destiny.decode_hash(
                stat_hash, 'DestinyStatDefinition')
            stat_name = stat_dict['displayProperties']['name']
            if stat_hash in last_played_char['stats'].keys():
                stats.append(
                    (stat_name, last_played_char['stats'].get(stat_hash)))
            else:
                stats.append((stat_name, 0))

        #######################################
        # ------ Decode Equipment Info ------ #
        #######################################

        weapons = [['Kinetic', '-'], ['Energy', '-'], ['Power', '-']]
        weapons_index = 0

        armor = [['Helmet', '-'], ['Gauntlets', '-'], ['Chest', '-'],
                 ['Legs', '-'], ['Class Item', '-']]
        armor_index = 0

        equipped_items = res['Response']['characterEquipment']['data'][
            last_played_char_id]['items']
        for item in equipped_items:

            item_dict = await self.destiny.decode_hash(
                item['itemHash'], 'DestinyInventoryItemDefinition')
            item_name = "{}".format(item_dict['displayProperties']['name'])

            if weapons_index < 3:
                weapons[weapons_index][1] = item_name
                weapons_index += 1

            elif armor_index < 5:
                armor[armor_index][1] = item_name
                armor_index += 1

        #################################
        # ------ Formulate Embed ------ #
        #################################

        char_info = "Level {} {} {} {}  |\N{SMALL BLUE DIAMOND}{}\n".format(
            level, race, gender, role, light)
        char_info += "{} {}  • ".format(stats[0][1], stats[0][0])
        char_info += "{} {}  • ".format(stats[1][1], stats[1][0])
        char_info += "{} {}".format(stats[2][1], stats[2][0])

        weapons_info = ""
        for weapon in weapons:
            weapons_info += '**{}:** {}  \n'.format(weapon[0], weapon[1])

        armor_info = ""
        for item in armor:
            armor_info += '**{}:** {}\n'.format(item[0], item[1])

        e = discord.Embed(colour=constants.BLUE)
        e.set_author(name=char_name,
                     icon_url=constants.PLATFORM_URLS.get(platform))
        e.description = char_info
        e.set_thumbnail(url=emblem_url)
        e.add_field(name='Weapons', value=weapons_info, inline=True)
        e.add_field(name='Armor', value=armor_info, inline=True)

        await manager.say(e, embed=True, delete=False)
        await manager.clear()