Пример #1
0
    async def paginate(self):
        """Actually paginate the entries and run the interactive loop if necessary."""
        await self.show_page(1, first=True)

        while self.paginating:
            try:
                react = await self.bot.wait_for("reaction_add",
                                                check=self.react_check,
                                                timeout=120.0)
                try:
                    # Can't remove other users reactions in DMs
                    if not is_private(self.message.channel):
                        await self.message.remove_reaction(
                            react[0].emoji, react[1])
                except Exception as e:
                    pass
            except asyncio.TimeoutError:
                await self.first_page()
                self.paginating = False
                try:
                    # Can't remove other users reactions in DMs
                    if not is_private(self.message.channel):
                        await self.message.clear_reactions()
                except:
                    pass
                finally:
                    break

            await self.match()
Пример #2
0
    async def monster(self, ctx, *, name: str = None):
        """Shows a monster's information

        Shows the monster's image, attributes and loot"""
        permissions = ctx.channel.permissions_for(ctx.me)
        if not permissions.embed_links:
            await ctx.send(
                "Sorry, I need `Embed Links` permission for this command.")
            return

        if name is None:
            await ctx.send(
                "Tell me the name of the monster you want to search.")
            return
        if is_private(ctx.channel):
            bot_member = self.bot.user
        else:
            bot_member = self.bot.get_member(self.bot.user.id, ctx.guild)
        if name.lower() == bot_member.display_name.lower():
            await ctx.send(
                random.choice([
                    "**" + bot_member.display_name +
                    "** is too strong for you to hunt!",
                    "Sure, you kill *one* child and suddenly you're a monster!",
                    "I'M NOT A MONSTER",
                    "I'm a monster, huh? I'll remember that, human..." +
                    EMOJI[":flame:"],
                    "You misspelled *future ruler of the world*.",
                    "You're not a good person. You know that, right?",
                    "I guess we both know that isn't going to happen.",
                    "You can't hunt me.",
                    "That's funny... If only I was programmed to laugh."
                ]))
            return
        monster = get_monster(name)
        if monster is None:
            await ctx.send("I couldn't find a monster with that name.")
            return

        if type(monster) is list:
            embed = discord.Embed(title="Suggestions",
                                  description="\n".join(monster))
            await ctx.send(
                "I couldn't find that creature, maybe you meant one of these?",
                embed=embed)
            return

        long = is_private(
            ctx.channel) or ctx.channel.name == config.ask_channel_name
        embed = self.get_monster_embed(ctx, monster, long)

        # Attach monster's image only if the bot has permissions
        if permissions.attach_files and monster["image"] != 0:
            filename = re.sub(r"[^A-Za-z0-9]", "", monster["name"]) + ".gif"
            embed.set_thumbnail(url=f"attachment://{filename}")
            await ctx.send(file=discord.File(monster["image"], f"{filename}"),
                           embed=embed)
        else:
            await ctx.send(embed=embed)
Пример #3
0
    async def wait_for_confirmation_reaction(self, ctx: Context,
                                             message: Message,
                                             deny_message: str) -> bool:
        """Waits for the command author (ctx.author) to reply with a Y or N reaction

        Returns true if the user reacted with Y, false if the user reacted with N or didn't react at all"""
        await message.add_reaction('\U0001f1fe')
        await message.add_reaction('\U0001f1f3')

        def check_react(reaction: Reaction, user: User):
            if reaction.message.id != message.id:
                return False
            if user.id != ctx.author.id:
                return False
            if reaction.emoji not in ['\U0001f1f3', '\U0001f1fe']:
                return False
            return True

        try:
            react = await self.wait_for("reaction_add",
                                        timeout=120,
                                        check=check_react)
            if react[0].emoji == '\U0001f1f3':
                await ctx.send(deny_message)
                return False
        except asyncio.TimeoutError:
            await ctx.send("You took too long!")
            return False
        finally:
            if not is_private(ctx.channel):
                try:
                    await message.clear_reactions()
                except:
                    pass
        return True
Пример #4
0
 async def stop_pages(self):
     """stops the interactive pagination session"""
     # await self.bot.delete_message(self.message)
     try:
         # Can't remove reactions in DMs, so don't even try
         if not is_private(self.message.channel):
             await self.message.clear_reactions()
     except:
         pass
     await self.show_page(1)
     self.paginating = False
Пример #5
0
    async def npc(self, ctx, *, name: str = None):
        """Shows information about an NPC

        Shows an NPC's picture, trade offers and location."""
        permissions = ctx.channel.permissions_for(ctx.me)
        if not permissions.embed_links:
            await ctx.send(
                "Sorry, I need `Embed Links` permission for this command.")
            return

        if name is None:
            await ctx.send("Tell me the name of an NPC.")
            return

        npc = get_npc(name)

        if npc is None:
            await ctx.send("I don't know any NPC with that name.")
            return

        if type(npc) is list:
            embed = discord.Embed(title="Suggestions",
                                  description="\n".join(npc))
            await ctx.send(
                "I couldn't find that NPC, maybe you meant one of these?",
                embed=embed)
            return

        long = is_private(
            ctx.channel) or ctx.channel.name == config.ask_channel_name
        embed = self.get_npc_embed(ctx, npc, long)
        # Attach spell's image only if the bot has permissions
        if permissions.attach_files:
            files = []
            if npc["image"] != 0:
                filename = re.sub(r"[^A-Za-z0-9]", "", npc["name"]) + ".png"
                embed.set_thumbnail(url=f"attachment://{filename}")
                files.append(discord.File(npc["image"], filename))
            if None not in [npc["x"], npc["y"], npc["z"]]:
                map_filename = re.sub(r"[^A-Za-z0-9]", "",
                                      npc["name"]) + "-map.png"
                map_image = get_map_area(npc["x"], npc["y"], npc["z"])
                embed.set_image(url=f"attachment://{map_filename}")
                embed.add_field(
                    name="Location",
                    value=
                    f"[Mapper link]({get_mapper_link(npc['x'],npc['y'],npc['z'])})",
                    inline=False)
                files.append(discord.File(map_image, map_filename))
            await ctx.send(files=files, embed=embed)
        else:
            await ctx.send(embed=embed)
Пример #6
0
    def react_check(self, reaction: Reaction, user: User):
        if reaction.message.id != self.message.id:
            return False

        if (not is_private(self.message.channel)
                and user.id != self.author.id) or user.id == self.bot.user.id:
            return False

        for (emoji, func) in self.reaction_emojis:
            if reaction.emoji == emoji:
                self.match = func
                return True
        return False
Пример #7
0
    async def wait_for_confirmation_reaction(
            self,
            ctx: Context,
            message: Message,
            timeout: float = 120) -> Optional[bool]:
        """Waits for the command author (ctx.author) to reply with a Y or N reaction

        Returns True if the user reacted with Y
        Returns False if the user reacted with N
        Returns None if the user didn't react at all"""
        YES_REACTION = '\U0001f1fe'
        NO_REACTION = '\U0001f1f3'
        try:
            await message.add_reaction(YES_REACTION)
            await message.add_reaction(NO_REACTION)
        except discord.Forbidden:
            log.error(
                "wait_for_confirmation_reaction: No permission to add reactions."
            )
            return None

        def check_react(reaction: Reaction, user: User):
            if reaction.message.id != message.id:
                return False
            if user.id != ctx.author.id:
                return False
            if reaction.emoji not in [NO_REACTION, YES_REACTION]:
                return False
            return True

        try:
            react = await self.wait_for("reaction_add",
                                        timeout=timeout,
                                        check=check_react)
            if react[0].emoji == NO_REACTION:
                return False
        except asyncio.TimeoutError:
            return None
        finally:
            if not is_private(ctx.channel):
                try:
                    await message.clear_reactions()
                except:
                    pass
        return True
Пример #8
0
    async def spell(self, ctx, *, name: str = None):
        """Shows information about a spell

        Shows a spell's icon, general information, price, npcs that teach it."""
        permissions = ctx.channel.permissions_for(ctx.me)
        if not permissions.embed_links:
            await ctx.send(
                "Sorry, I need `Embed Links` permission for this command.")
            return

        if name is None:
            await ctx.send("Tell me the name or words of a spell.")
            return

        spell = get_spell(name)

        if spell is None:
            await ctx.send("I don't know any spell with that name or words.")
            return

        if type(spell) is list:
            embed = discord.Embed(title="Suggestions",
                                  description="\n".join(spell))
            await ctx.send(
                "I couldn't find that spell, maybe you meant one of these?",
                embed=embed)
            return

        long = is_private(
            ctx.channel) or ctx.channel.name == config.ask_channel_name
        embed = self.get_spell_embed(ctx, spell, long)

        # Attach spell's image only if the bot has permissions
        if permissions.attach_files and spell["image"] != 0:
            filename = re.sub(r"[^A-Za-z0-9]", "", spell["name"]) + ".gif"
            embed.set_thumbnail(url=f"attachment://{filename}")
            await ctx.send(file=discord.File(spell["image"], f"{filename}"),
                           embed=embed)
        else:
            await ctx.send(embed=embed)
Пример #9
0
    async def show_page(self, page, *, first=False):
        self.current_page = page
        entries = self.get_page(page)
        p = []
        if self.numerate:
            for t in enumerate(entries, 1 + ((page - 1) * self.per_page)):
                p.append('%s. %s' % t)
        else:
            for t in entries:
                p.append(t)
        self.embed.set_footer(text='Page %s/%s (%s entries)' %
                              (page, self.maximum_pages, len(self.entries)))
        if self.title:
            self.embed.title = self.title

        self.embed.description = self.description + "\n" + '\n'.join(p)
        if not self.paginating:
            return await self.message.channel.send(embed=self.embed)

        if not first:
            return await self.message.edit(embed=self.embed)

        # verify we can actually use the pagination session
        if not self.permissions.add_reactions:
            raise CannotPaginate('Bot does not have add reactions permission.')
        if not self.permissions.read_message_history:
            raise CannotPaginate(
                "Bot does not have read message history permission.")

        self.message = await self.message.channel.send(embed=self.embed)
        for (reaction, _) in self.reaction_emojis:
            if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'):
                # no |<< or >>| buttons if we only have two pages
                # we can't forbid it if someone ends up using it but remove
                # it from the default set
                continue
            # Stop reaction doesn't work on PMs so do not add it
            if is_private(self.message.channel) and reaction == '\U000023F9':
                continue
            await self.message.add_reaction(reaction)
Пример #10
0
    async def item(self, ctx, *, name: str = None):
        """Shows an item's information

        Shows the item's sprite, attributes, buy and sell offers and creature drops."""
        permissions = ctx.channel.permissions_for(ctx.me)
        if not permissions.embed_links:
            await ctx.send(
                "Sorry, I need `Embed Links` permission for this command.")
            return

        if name is None:
            await ctx.send("Tell me the name of the item you want to search.")
            return
        item = get_item(name)
        if item is None:
            await ctx.send("I couldn't find an item with that name.")
            return

        if type(item) is list:
            embed = discord.Embed(title="Suggestions",
                                  description="\n".join(item))
            await ctx.send(
                "I couldn't find that item, maybe you meant one of these?",
                embed=embed)
            return

        long = is_private(
            ctx.channel) or ctx.channel.name == config.ask_channel_name
        embed = self.get_item_embed(ctx, item, long)

        # Attach item's image only if the bot has permissions
        permissions = ctx.channel.permissions_for(ctx.me)
        if permissions.attach_files or item["image"] != 0:
            filename = re.sub(r"[^A-Za-z0-9]", "", item["name"]) + ".gif"
            embed.set_thumbnail(url=f"attachment://{filename}")
            await ctx.send(file=discord.File(item["image"], f"{filename}"),
                           embed=embed)
        else:
            await ctx.send(embed=embed)
Пример #11
0
    async def diagnose(self,
                       ctx: discord.ext.commands.Context,
                       *,
                       server_name=None):
        """Diagnose the bots permissions and channels"""
        # This will always have at least one server, otherwise this command wouldn't pass the is_admin check.
        admin_guilds = self.bot.get_user_admin_guilds(ctx.message.author.id)

        if server_name is None:
            if not is_private(ctx.message.channel):
                if ctx.message.guild not in admin_guilds:
                    await ctx.send(
                        "You don't have permissions to diagnose this server.")
                    return
                guild = ctx.message.guild
            else:
                if len(admin_guilds) == 1:
                    guild = admin_guilds[0]
                else:
                    guild_list = [
                        str(i + 1) + ": " + admin_guilds[i].name
                        for i in range(len(admin_guilds))
                    ]
                    await ctx.send(
                        "Which server do you want to check?\n\t0: *Cancel*\n\t"
                        + "\n\t".join(guild_list))

                    def check(m):
                        return m.author == ctx.author and m.channel == ctx.channel

                    try:
                        answer = await self.bot.wait_for("message",
                                                         timeout=60.0,
                                                         check=check)
                        answer = int(answer.content)
                        if answer == 0:
                            await ctx.send("Changed your mind? Typical human.")
                            return
                        guild = admin_guilds[answer - 1]
                    except IndexError:
                        await ctx.send(
                            "That wasn't in the choices, you ruined it. Start from the beginning."
                        )
                        return
                    except ValueError:
                        await ctx.send("That's not a number!")
                        return
                    except asyncio.TimeoutError:
                        await ctx.send("I guess you changed your mind.")
                        return
        else:
            guild = self.bot.get_guild_by_name(server_name)
            if guild is None:
                await ctx.send("I couldn't find a server with that name.")
                return
            if guild not in admin_guilds:
                await ctx.send(
                    "You don't have permissions to diagnose **{0}**.".format(
                        guild.name))
                return

        if guild is None:
            return
        member = self.bot.get_member(self.bot.user.id, guild)
        server_perms = member.guild_permissions

        channels = guild.text_channels
        not_read_messages = []
        not_send_messages = []
        not_add_reactions = []
        not_read_history = []
        not_manage_messages = []
        not_embed_links = []
        not_attach_files = []
        not_mention_everyone = []
        count = 0
        for channel in channels:
            count += 1
            channel_permissions = channel.permissions_for(member)
            if not channel_permissions.read_messages:
                not_read_messages.append(channel)
            if not channel_permissions.send_messages:
                not_send_messages.append(channel)
            if not channel_permissions.manage_messages:
                not_manage_messages.append(channel)
            if not channel_permissions.embed_links:
                not_embed_links.append(channel)
            if not channel_permissions.attach_files:
                not_attach_files.append(channel)
            if not channel_permissions.mention_everyone:
                not_mention_everyone.append(channel)
            if not channel_permissions.add_reactions:
                not_add_reactions.append(channel)
            if not channel_permissions.read_message_history:
                not_read_history.append(channel)

        channel_lists_list = [
            not_read_messages, not_send_messages, not_manage_messages,
            not_embed_links, not_attach_files, not_mention_everyone,
            not_add_reactions, not_read_history
        ]
        permission_names_list = [
            "Read Messages", "Send Messages", "Manage Messages", "Embed Links",
            "Attach Files", "Mention Everyone", "Add reactions",
            "Read Message History"
        ]
        server_wide_list = [
            server_perms.read_messages, server_perms.send_messages,
            server_perms.manage_messages, server_perms.embed_links,
            server_perms.attach_files, server_perms.mention_everyone,
            server_perms.add_reactions, server_perms.read_message_history
        ]

        answer = "Permissions for {0.name}:\n".format(guild)
        i = 0
        while i < len(channel_lists_list):
            answer += "**{0}**\n\t{1} Server wide".format(
                permission_names_list[i], get_check_emoji(server_wide_list[i]))
            if len(channel_lists_list[i]) == 0:
                answer += "\n\t{0} All channels\n".format(
                    get_check_emoji(True))
            elif len(channel_lists_list[i]) == count:
                answer += "\n\t All channels\n".format(get_check_emoji(False))
            else:
                channel_list = ["#" + x.name for x in channel_lists_list[i]]
                answer += "\n\t{0} Not in: {1}\n".format(
                    get_check_emoji(False), ",".join(channel_list))
            i += 1

        ask_channel = self.bot.get_channel_by_name(config.ask_channel_name,
                                                   guild)
        answer += "\nAsk channel:\n\t"
        if ask_channel is not None:
            answer += "{0} Enabled: {1.mention}".format(
                get_check_emoji(True), ask_channel)
        else:
            answer += "{0} Not enabled".format(get_check_emoji(False))

        log_channel = self.bot.get_channel_by_name(config.log_channel_name,
                                                   guild)
        answer += "\nLog channel:\n\t"
        if log_channel is not None:
            answer += "{0} Enabled: {1.mention}".format(
                get_check_emoji(True), log_channel)
        else:
            answer += "{0} Not enabled".format(get_check_emoji(False))
        await ctx.send(answer)
        return
Пример #12
0
    async def makesay(self, ctx: discord.ext.commands.Context, *,
                      message: str):
        """Makes the bot say a message
        If it's used directly on a text channel, the bot will delete the command's message and repeat it itself

        If it's used on a private message, the bot will ask on which channel he should say the message."""
        if is_private(ctx.message.channel):
            description_list = []
            channel_list = []
            prev_server = None
            num = 1
            for server in self.bot.guilds:
                author = self.bot.get_member(ctx.message.author.id, server)
                bot_member = self.bot.get_member(self.bot.user.id, server)
                # Skip servers where the command user is not in
                if author is None:
                    continue
                # Check for every channel
                for channel in server.text_channels:
                    author_permissions = author.permissions_in(
                        channel)  # type: discord.Permissions
                    bot_permissions = bot_member.permissions_in(
                        channel)  # type: discord.Permissions
                    # Check if both the author and the bot have permissions to send messages and add channel to list
                    if (author_permissions.send_messages and bot_permissions.send_messages) and \
                            (ctx.message.author.id in config.owner_ids or author_permissions.administrator):
                        separator = ""
                        if prev_server is not server:
                            separator = "---------------\n\t"
                        description_list.append(
                            "{2}{3}: **#{0}** in **{1}**".format(
                                channel.name, server.name, separator, num))
                        channel_list.append(channel)
                        prev_server = server
                        num += 1
            if len(description_list) < 1:
                await ctx.send(
                    "We don't have channels in common with permissions.")
                return
            await ctx.send(
                "Choose a channel for me to send your message (number only): \n\t0: *Cancel*\n\t"
                + "\n\t".join(["{0}".format(i) for i in description_list]))

            def check(m):
                return m.author == ctx.message.author and m.channel == ctx.message.channel

            try:
                answer = await self.bot.wait_for("message",
                                                 timeout=60.0,
                                                 check=check)
                answer = int(answer.content)
                if answer == 0:
                    await ctx.send("Changed your mind? Typical human.")
                    return
                await channel_list[answer - 1].send(message)
                await ctx.send("Message sent on {0} ({1})".format(
                    channel_list[answer - 1].mention,
                    channel_list[answer - 1].guild))
            except IndexError:
                await ctx.send(
                    "That wasn't in the choices, you ruined it. Start from the beginning."
                )
            except ValueError:
                await ctx.send("That's not a valid answer!")
            except asyncio.TimeoutError:
                await ctx.send("... are you there? Fine, nevermind!")
        else:
            await ctx.message.delete()
            await ctx.message.channel.send(message)
Пример #13
0
 def __global_check(self, ctx):
     return is_private(ctx.channel) or \
            ctx.channel.id not in self.ignored.get(ctx.guild.id, []) or checks.is_owner_check(ctx) \
            or checks.check_guild_permissions(ctx, {'manage_channels': True})