Beispiel #1
0
 async def economyset(self, ctx: commands.Context):
     """Manage Economy settings."""
     guild = ctx.guild
     if ctx.invoked_subcommand is None:
         if await bank.is_global():
             conf = self.config
         else:
             conf = self.config.guild(ctx.guild)
         await ctx.send(
             box(
                 _(
                     "----Economy Settings---\n"
                     "Minimum slot bid: {slot_min}\n"
                     "Maximum slot bid: {slot_max}\n"
                     "Slot cooldown: {slot_time}\n"
                     "Payday amount: {payday_amount}\n"
                     "Payday cooldown: {payday_time}\n"
                     "Amount given at account registration: {register_amount}"
                 ).format(
                     slot_min=await conf.SLOT_MIN(),
                     slot_max=await conf.SLOT_MAX(),
                     slot_time=await conf.SLOT_TIME(),
                     payday_time=await conf.PAYDAY_TIME(),
                     payday_amount=await conf.PAYDAY_CREDITS(),
                     register_amount=await bank.get_default_balance(guild),
                 )
             )
         )
Beispiel #2
0
    async def set_cases(self, ctx: commands.Context, action: str = None):
        """Enable or disable case creation for a mod action."""
        guild = ctx.guild

        if action is None:  # No args given
            casetypes = await modlog.get_all_casetypes(guild)
            await ctx.send_help()
            lines = []
            for ct in casetypes:
                enabled = "enabled" if await ct.is_enabled() else "disabled"
                lines.append(f"{ct.name} : {enabled}")

            await ctx.send(_("Current settings:\n") + box("\n".join(lines)))
            return

        casetype = await modlog.get_casetype(action, guild)
        if not casetype:
            await ctx.send(_("That action is not registered"))
        else:
            enabled = await casetype.is_enabled()
            await casetype.set_enabled(not enabled)
            await ctx.send(
                _("Case creation for {action_name} actions is now {enabled}.").format(
                    action_name=action, enabled="enabled" if not enabled else "disabled"
                )
            )
Beispiel #3
0
    async def discover_guild(
        self,
        author: discord.User,
        *,
        mod: bool = False,
        permissions: Union[discord.Permissions, dict] = None,
        prompt: str = "",
    ):
        """
        discovers which of shared guilds between the bot
        and provided user based on conditions (mod or permissions is an or)

        prompt is for providing a user prompt for selection
        """
        shared_guilds = []
        if permissions is None:
            perms = discord.Permissions()
        elif isinstance(permissions, discord.Permissions):
            perms = permissions
        else:
            perms = discord.Permissions(**permissions)

        for guild in self.bot.guilds:
            x = guild.get_member(author.id)
            if x is not None:
                if await self.internal_filter(x, mod, perms):
                    shared_guilds.append(guild)
        if len(shared_guilds) == 0:
            raise ValueError("No Qualifying Shared Guilds")
        if len(shared_guilds) == 1:
            return shared_guilds[0]
        output = ""
        guilds = sorted(shared_guilds, key=lambda g: g.name)
        for i, guild in enumerate(guilds, 1):
            output += "{}: {}\n".format(i, guild.name)
        output += "\n{}".format(prompt)

        for page in pagify(output, delims=["\n"]):
            await author.send(box(page))

        try:
            message = await self.bot.wait_for(
                "message",
                check=MessagePredicate.same_context(channel=author.dm_channel, user=author),
                timeout=45,
            )
        except asyncio.TimeoutError:
            await author.send(_("You took too long to select. Try again later."))
            return None

        try:
            message = int(message.content.strip())
            guild = guilds[message - 1]
        except (ValueError, IndexError):
            await author.send(_("That wasn't a valid choice."))
            return None
        else:
            return guild
Beispiel #4
0
 async def _list_global_alias(self, ctx: commands.Context):
     """List the available global aliases on this bot."""
     names = [_("Aliases:")] + sorted(
         ["+ " + a.name for a in await self.unloaded_global_aliases()]
     )
     if len(names) == 0:
         await ctx.send(_("There are no aliases on this server."))
     else:
         await ctx.send(box("\n".join(names), "diff"))
Beispiel #5
0
    async def selfrole_list(self, ctx: commands.Context):
        """
        Lists all available selfroles.
        """
        selfroles = await self._valid_selfroles(ctx.guild)
        fmt_selfroles = "\n".join(["+ " + r.name for r in selfroles])

        msg = _("Available Selfroles:\n{selfroles}").format(selfroles=fmt_selfroles)
        await ctx.send(box(msg, "diff"))
Beispiel #6
0
    async def _repo_info(self, ctx, repo: Repo):
        """Show information about a repo."""
        if repo is None:
            await ctx.send(_("Repo `{repo.name}` not found.").format(repo=repo))
            return

        msg = _("Information on {repo.name}:\n{description}").format(
            repo=repo, description=repo.description or ""
        )
        await ctx.send(box(msg))
Beispiel #7
0
    async def _repo_list(self, ctx):
        """List all installed repos."""
        repos = self._repo_manager.get_all_repo_names()
        repos = sorted(repos, key=str.lower)
        joined = _("Installed Repos:\n\n")
        for repo_name in repos:
            repo = self._repo_manager.get_repo(repo_name)
            joined += "+ {}: {}\n".format(repo.name, repo.short or "")

        for page in pagify(joined, ["\n"], shorten_by=16):
            await ctx.send(box(page.lstrip(" "), lang="diff"))
Beispiel #8
0
    async def __msg_list(self, ctx: commands.Context, event: str):
        """Handler for listing message formats."""

        guild = ctx.guild

        msg = "{} message formats:\n".format(event.capitalize())
        async with self.config.guild(guild).get_attr(event).messages() as messages:
            for n, m in enumerate(messages, start=1):
                msg += "  {}. {}\n".format(n, m)

        for page in pagify(msg, ["\n", " "], shorten_by=20):
            await ctx.send(box(page))
Beispiel #9
0
    async def build_menu(self, groups, page=1):
        footer = "You are viewing page {} of {}.".format(page if page > 0 else 1, len(groups))
        if self.shop is None and self.mode == 0:
            output = ["{} - {}".format(idx, ele) for idx, ele in enumerate(groups[page], 1)]
        elif self.mode == 0:
            header = (
                f"{'#':<3} {'Name':<29} {'Qty':<7} {'Cost':<8}\n"
                f"{'--':<3} {'-'*29:<29} {'-'*4:<7} {'-'*8:<8}"
            )
            fmt = [header]
            for idx, x in enumerate(self.sorter(groups[page]), 1):
                line_one = (
                    f"{f'{idx}.': <{3}} {x[0]: <{29}s} {x[1]['Qty']:<{8}}" f"{x[1]['Cost']: < {7}}"
                )
                fmt.append(line_one)
                fmt.append(
                    f'< {x[1]["Info"][:50]} >'
                    if len(x[1]["Info"]) < 50
                    else f'< {x[1]["Info"][:47]}... >'
                )
                fmt.append("")
            output = box("\n".join(fmt), "md")
        elif self.mode == 1 and self.user is None:
            headers = ("#", "User", "Pending Items")
            fmt = [
                (idx, discord.utils.get(self.ctx.bot.users, id=int(x[0])).name, len(x[1]))
                for idx, x in enumerate(groups[page], 1)
            ]
            output = box(tabulate(fmt, headers=headers, numalign="left"), lang="md")
        elif self.mode == 1:
            headers = ("#", "Item", "Order ID", "Timestamp")
            fmt = [
                (idx, x[1]["Item"], x[0], x[1]["Timestamp"])
                for idx, x in enumerate(groups[page], 1)
            ]

            output = box(tabulate(fmt, headers=headers, numalign="left"), lang="md")
        else:
            output = None
        return self.build_embed(output, footer)
Beispiel #10
0
    async def dataconversioncommand(self, ctx: commands.Context, v2path: str):
        """Interactive prompt for importing data from Red V2.

        Takes the path where the V2 install is, and overwrites
        values which have entries in both V2 and v3; use with caution.
        """
        resolver = SpecResolver(Path(v2path.strip()))

        if not resolver.available:
            return await ctx.send(
                _(
                    "There don't seem to be any data files I know how to "
                    "handle here. Are you sure you gave me the base "
                    "installation path?"
                )
            )
        while resolver.available:
            menu = _("Please select a set of data to import by number, or 'exit' to exit")
            for index, entry in enumerate(resolver.available, 1):
                menu += "\n{}. {}".format(index, entry)

            menu_message = await ctx.send(box(menu))

            try:
                message = await self.bot.wait_for(
                    "message", check=MessagePredicate.same_context(ctx), timeout=60
                )
            except asyncio.TimeoutError:
                return await ctx.send(_("Try this again when you are ready."))
            else:
                if message.content.strip().lower() in ["quit", "exit", "-1", "q", "cancel"]:
                    return await ctx.tick()
                try:
                    message = int(message.content.strip())
                    to_conv = resolver.available[message - 1]
                except (ValueError, IndexError):
                    await ctx.send(_("That wasn't a valid choice."))
                    continue
                else:
                    async with ctx.typing():
                        await resolver.convert(self.bot, to_conv)
                    await ctx.send(_("{} converted.").format(to_conv))
            await menu_message.delete()
        else:
            return await ctx.send(
                _(
                    "There isn't anything else I know how to convert here.\n"
                    "There might be more things I can convert in the future."
                )
            )
Beispiel #11
0
    async def ccrole_list(self, ctx):
        """Shows custom commands list"""
        guild = ctx.guild
        cmd_list = await self.config.guild(guild).cmdlist()
        cmd_list = {k: v for k, v in cmd_list.items() if v}
        if not cmd_list:
            await ctx.send(
                "There are no custom commands in this server. Use `{}ccrole add` to start adding some.".format(
                    ctx.prefix
                )
            )
            return

        cmd_list = ", ".join([ctx.prefix + c for c in sorted(cmd_list.keys())])
        cmd_list = "Custom commands:\n\n" + cmd_list

        if (
            len(cmd_list) < 1500
        ):  # I'm allowed to have arbitrary numbers for when it's too much to dm dammit
            await ctx.send(box(cmd_list))
        else:
            for page in pagify(cmd_list, delims=[" ", "\n"]):
                await ctx.author.send(box(page))
            await ctx.send("Command list DM'd")
Beispiel #12
0
 def update(self, groups, page=0):
     header = (
         f"{'#':<3} {'Items':<29} {'Qty':<7} {'Type':<8}\n"
         f"{'--':<3} {'-'*29:<29} {'-'*4:<7} {'-'*8:<8}"
     )
     fmt = [header]
     for idx, x in enumerate(groups[page], 1):
         line_one = (
             f"{f'{idx}.': <{3}} {x[0]: <{28}s} {x[1]['Qty']: < {9}}" f"{x[1]['Type']: <{7}s}"
         )
         fmt.append(line_one)
         fmt.append(
             f'< {x[1]["Info"][:50]} >'
             if len(x[1]["Info"]) < 50
             else f'< {x[1]["Info"][:47]}... >'
         )
         fmt.append("")
     return box("\n".join(fmt), lang="md")
Beispiel #13
0
    async def cc_show(self, ctx, command_name: str):
        """Shows a custom command's reponses and its settings."""

        try:
            cmd = await self.commandobj.get_full(ctx.message, command_name)
        except NotFound:
            ctx.send(_("I could not not find that custom command."))
            return

        responses = cmd["response"]

        if isinstance(responses, str):
            responses = [responses]

        author = ctx.guild.get_member(cmd["author"]["id"])
        # If the author is still in the server, show their current name
        if author:
            author = "{} ({})".format(author, cmd["author"]["id"])
        else:
            author = "{} ({})".format(cmd["author"]["name"], cmd["author"]["id"])

        _type = _("Random") if len(responses) > 1 else _("Normal")

        text = _(
            "Command: {}\n"
            "Author: {}\n"
            "Created: {}\n"
            "Type: {}\n".format(command_name, author, cmd["created_at"], _type)
        )

        cooldowns = cmd["cooldowns"]

        if cooldowns:
            cooldown_text = _("Cooldowns:\n")
            for rate, per in cooldowns.items():
                cooldown_text += _("{} seconds per {}\n".format(per, rate))
            text += cooldown_text

        text += _("Responses:\n")
        responses = ["- " + r for r in responses]
        text += "\n".join(responses)

        for p in pagify(text):
            await ctx.send(box(p, lang="yaml"))
Beispiel #14
0
    async def _cog_info(self, ctx, repo: Repo, cog_name: str):
        """List information about a single cog."""
        cog = discord.utils.get(repo.available_cogs, name=cog_name)
        if cog is None:
            await ctx.send(
                _("There is no cog `{cog_name}` in the repo `{repo.name}`").format(
                    cog_name=cog_name, repo=repo
                )
            )
            return

        msg = _(
            "Information on {cog_name}:\n{description}\n\nRequirements: {requirements}"
        ).format(
            cog_name=cog.name,
            description=cog.description or "",
            requirements=", ".join(cog.requirements) or "None",
        )
        await ctx.send(box(msg))
Beispiel #15
0
    async def findcog(self, ctx: commands.Context, command_name: str):
        """Find which cog a command comes from.

        This will only work with loaded cogs.
        """
        command = ctx.bot.all_commands.get(command_name)

        if command is None:
            await ctx.send(_("That command doesn't seem to exist."))
            return

        # Check if in installed cogs
        cog_name = self.cog_name_from_instance(command.instance)
        installed, cog_installable = await self.is_installed(cog_name)
        if installed:
            msg = self.format_findcog_info(command_name, cog_installable)
        else:
            # Assume it's in a base cog
            msg = self.format_findcog_info(command_name, command.instance)

        await ctx.send(box(msg))
Beispiel #16
0
    async def bankset(self, ctx: commands.Context):
        """Base command for bank settings."""
        if ctx.invoked_subcommand is None:
            if await bank.is_global():
                bank_name = await bank._conf.bank_name()
                currency_name = await bank._conf.currency()
                default_balance = await bank._conf.default_balance()
            else:
                if not ctx.guild:
                    return
                bank_name = await bank._conf.guild(ctx.guild).bank_name()
                currency_name = await bank._conf.guild(ctx.guild).currency()
                default_balance = await bank._conf.guild(ctx.guild).default_balance()

            settings = _(
                "Bank settings:\n\nBank name: {bank_name}\nCurrency: {currency_name}\n"
                "Default balance: {default_balance}"
            ).format(
                bank_name=bank_name, currency_name=currency_name, default_balance=default_balance
            )
            await ctx.send(box(settings))
Beispiel #17
0
 async def permissions_acl(self, ctx: commands.Context):
     """Manage permissions with YAML files."""
     if ctx.invoked_subcommand is None or ctx.invoked_subcommand == self.permissions_acl:
         # Send a little guide on YAML formatting
         await ctx.send(
             _("Example YAML for setting rules:\n")
             + box(
                 textwrap.dedent(
                     """\
                     COMMAND:
                         ping:
                             12345678901234567: true
                             56789012345671234: false
                     COG:
                         General:
                             56789012345671234: true
                             12345678901234567: false
                             default: false
                     """
                 ),
                 lang="yaml",
             )
         )
Beispiel #18
0
 async def _cog_list(self, ctx, repo: Repo):
     """List all available cogs from a single repo."""
     installed = await self.installed_cogs()
     installed_str = ""
     if installed:
         installed_str = _("Installed Cogs:\n") + "\n".join(
             [
                 "- {}{}".format(i.name, ": {}".format(i.short) if i.short else "")
                 for i in installed
                 if i.repo_name == repo.name
             ]
         )
     cogs = repo.available_cogs
     cogs = _("Available Cogs:\n") + "\n".join(
         [
             "+ {}: {}".format(c.name, c.short or "")
             for c in cogs
             if not (c.hidden or c in installed)
         ]
     )
     cogs = cogs + "\n\n" + installed_str
     for page in pagify(cogs, ["\n"], shorten_by=16):
         await ctx.send(box(page.lstrip(" "), lang="diff"))
Beispiel #19
0
    async def uptime(self, ctx: commands.Context):
        """Shows [botname]'s uptime."""
        def format_timedelta(delta: timedelta, unit: str):
            mapper = {
                "seconds": 1,
                "minutes": 60,
                "hours": 3600,
                "days": 86400
            }
            return humanize_number(
                math.floor(delta.total_seconds() / mapper[unit]))

        delta = datetime.utcnow() - self.bot.uptime
        description = f"{self.bot.user} has been up for {bold(humanize_timedelta(timedelta=delta) or 'less than one second')}.\n\n"

        embed = discord.Embed(
            title="\N{LARGE GREEN CIRCLE} Uptime Information",
            description=description,
            color=await ctx.embed_colour(),
            timestamp=datetime.now(),
        )

        data = {}
        units = ("seconds", "minutes", "hours", "days")
        for unit in units:
            data[unit] = str(format_timedelta(delta, unit))

        plural_unit = lambda x: f"{data[x]} {x[:-1]}" if data[
            x] == 1 else f"{data[x]} {x}"

        unit_details = "\n".join(f"+ {plural_unit(x)}" for x in units)
        embed.add_field(name="Unit Details",
                        value=box(unit_details, lang="diff"),
                        inline=False)

        app_info = await self.bot.application_info()
        bot_stats = {
            "users":
            humanize_number(len(self.bot.users)),
            "servers":
            humanize_number(len(self.bot.guilds)),
            "commands_available":
            humanize_number(len(set(self.bot.walk_commands()))),
            "owner":
            app_info.team.name if app_info.team else app_info.owner,
        }

        format_key = lambda x: x.replace("_", " ").capitalize()
        sorted_bot_stats = sorted(bot_stats.items(), key=lambda x: len(x[0]))

        embed.add_field(
            name="Bot Stats",
            value=box("\n".join(f"{format_key(k)}: {v}"
                                for k, v in sorted_bot_stats),
                      lang="yaml"),
            inline=False,
        )

        if self.commands_run:
            most_run_command = sorted(self.commands_run.items(),
                                      key=lambda x: x[1],
                                      reverse=True)
            format_time = lambda x: "once" if x == 1 else f"{x} times"
            command_usage = f"The most used command whilst the bot has been online is `{most_run_command[0][0]}`, which has been used {format_time(most_run_command[0][1])}."
            if len(self.commands_run) != 1:
                command_usage += f"\n\nThe least used command is `{most_run_command[-1][0]}`, which has been used {format_time(most_run_command[-1][1])}."

            embed.add_field(
                name="Command usage since this cog has been loaded",
                value=command_usage,
                inline=False,
            )

        embed.set_author(name=self.bot.user, icon_url=self.bot.user.avatar_url)
        await ctx.send(embed=embed)
Beispiel #20
0
    async def report_cookie(self, ctx):
        """Signaler le contenu du dernier cookie obtenu"""
        author, guild = ctx.author, ctx.guild
        last_cookie = await self.config.member(author).last_cookie()
        config = await self.config.guild(guild).all()
        confirm, cancel = self.bot.get_emoji(
            812451214037221439), self.bot.get_emoji(812451214179434551)

        if not last_cookie:
            return await ctx.send(
                "**Aucun cookie acheté** › Vous n'avez aucun cookie dans votre historique d'achats."
            )

        cookies = await self.config.guild(guild).Cookies()
        try:
            cookie_id = last_cookie['cookie_id']
            _c = cookies[cookie_id]
        except:
            return await ctx.send(
                "**Cookie inexistant** › Le cookie en question n'existe déjà plus dans la base de données, il a peut-être expiré ou a déjà été supprimé."
            )

        em = discord.Embed(title=f"Signaler le cookie *{cookie_id}*",
                           color=author.color)
        em.add_field(name="Texte du cookie", value=box(last_cookie['text']))
        em.set_footer(text=f"Voulez-vous signaler ce cookie aux modérateurs ?")
        msg = await ctx.reply(embed=em, mention_author=False)

        start_adding_reactions(msg, [confirm, cancel])
        try:
            react, _ = await self.bot.wait_for(
                "reaction_add",
                check=lambda m, u: u == ctx.author and m.message.id == msg.id,
                timeout=30)
        except asyncio.TimeoutError:
            return await msg.delete()

        if react.emoji == confirm:
            await msg.clear_reactions()
            if config['report_channel']:
                chan = self.bot.get_channel(config['report_channel'])
                if chan:
                    r = discord.Embed(title="Signalement d'un cookie",
                                      description=f"**ID :** `{cookie_id}`",
                                      color=discord.Color.red())
                    r.add_field(name="Texte du cookie signalé",
                                value=box(last_cookie['text']))
                    r.set_footer(
                        text=
                        f"Supprimer : \";cookieset delete {cookie_id}\"\nVoir tous les signalements : \";reports\""
                    )
                    await chan.send(embed=r)

            async with self.config.guild(guild).reports() as reports:
                if cookie_id not in reports:
                    reports.append(cookie_id)

            em.set_footer(text=f"Votre signalement a bien été enregistré")
            await msg.edit(embed=em, mention_author=False)
            await msg.delete(delay=20)
        else:
            return await msg.delete()
Beispiel #21
0
    async def test_cookie_formating(self, ctx, *, text: str):
        """Permet de tester le formattage d'un cookie (balises et fonctions)
        
        __Balises__
        Vous pouvez mettre les balises suivantes dans vos cookies pour exploiter les objets renvoyés directement dans le texte
        /!\\ Mettre plusieurs fois la même balise renvoie le même objet !
        
        *{buyer}* = Acheteur du cookie
        *{guild}* / *{server}* = Serveur où vous êtes
        *{cookie_author}* = Créateur du cookie (vous-même)
        *{random_member}* = Membre aléatoire du serveur
        *{date}* = Date au moment de l'ouverture du cookie au format dd/mm/aaaa
        *{hour}* = Heure au moment de l'ouverture du cookie au format hh:mm
        *{random_ten}* / *{random_hundred}* = Nombre aléatoire entre 0 et 10 / entre 0 et 100
        *{random_bool}* = Booléen au hasard (Vrai ou Faux)
        
        __Fonctions__
        n = ID de la fonction si vous comptez en mettre plusieures identiques
        <number|X_Y|n> = Génère un nombre aléatoire entre X et Y
        <member|n> = Génère une mention de membre aléatoire
        <bool|n> = Génère un emoji booléen au hasard
        <random|A_B_C...> = Choisir une réponse aléatoire parmi les options (délim. par _)
        
        Il est possible d'utiliser `:` à la place de `|`"""
        guild, author = ctx.guild, ctx.author
        original = copy(text)

        def special_formatter(string: str):
            scan = re.compile(r"<([\w\s:'\-|]*)>",
                              re.DOTALL | re.IGNORECASE).findall(string)
            for b in scan:
                chunk = f'<{b}>'
                if len(chunk) > 200:
                    continue
                b, *p = re.split(':|\|', b)
                b = b.lower()

                if b == 'number':
                    seuils = [int(i)
                              for i in p[0].split('_')] if p else (0, 10)
                    try:
                        string = string.replace(chunk,
                                                str(random.randint(*seuils)))
                    except:
                        pass

                if b == 'member':
                    mem = random.choice(guild.members)
                    string = string.replace(chunk, mem.mention)

                if b == 'bool':
                    string = string.replace(chunk, random.choice(('✅', '❎')))

                if b == 'random' and p:
                    c = random.choice(list(p[0].split('_')))
                    string = string.replace(chunk, c)

            return string

        cookie_author = '`Auteur du cookie`'
        random_member = random.choice(guild.members)
        date, hour = datetime.now().strftime(
            '%d/%m/%Y'), datetime.now().strftime('%H:%M')
        rdm_ten = random.randint(0, 10)
        rdm_hundred = random.randint(0, 100)
        rdm_bool = random.choice(("Vrai", "Faux"))

        text = special_formatter(text).format(buyer=author,
                                              guild=guild,
                                              server=guild,
                                              cookie_author=cookie_author,
                                              random_member=random_member,
                                              date=date,
                                              hour=hour,
                                              random_ten=rdm_ten,
                                              random_hundred=rdm_hundred,
                                              random_bool=rdm_bool)

        em = discord.Embed(description=box(original), color=author.color)

        if 'http' in text:
            scan = re.compile(r'(https?://\S*\.\S*)',
                              re.DOTALL | re.IGNORECASE).findall(text)
            if scan:
                em.set_image(url=scan[0])
                name = scan[0].split('/')[-1]
                if "?" in name:
                    name = name.split('?')[0]
                if not name:
                    name = "URL"
                txt = text.replace(scan[0], f"[[{name}]]({scan[0]})")
                em.description = txt

        em.add_field(name="Résultat", value=text, inline=False)

        em.set_footer(
            text=
            "Ceci est une démonstration de ce que donnerait votre texte s'il était obtenu par quelqu'un"
        )
        await ctx.reply(embed=em, mention_author=False)
 async def server(self, ctx, server_ip: str):
     """Get info about server"""
     try:
         server: MinecraftServer = await self.bot.loop.run_in_executor(
             None, MinecraftServer.lookup, server_ip)
     except Exception as e:
         await ctx.send(chat.error(_("Unable to resolve IP: {}").format(e)))
         return
     async with ctx.channel.typing():
         try:
             status = await server.async_status()
         except OSError as e:
             await ctx.send(
                 chat.error(
                     _("Unable to get server's status: {}").format(e)))
             return
         except AsyncTimeoutError:
             await ctx.send(
                 chat.error(_("Unable to get server's status: Timed out")))
             return
         # TODO: Reimplement on async query in mcstatus
         # NOTE: Possibly, make query optional
         # try:
         #     query = await server.async_query()
         # except (ConnectionResetError, OSError):
         #     query = None
     icon_file = None
     icon = (discord.File(
         icon_file := BytesIO(
             base64.b64decode(status.favicon.split(",", 1)[1])),
         filename="icon.png",
     ) if status.favicon else None)
     embed = discord.Embed(
         title=f"{server.host}:{server.port}",
         description=chat.box(await
                              self.clear_mcformatting(status.description)),
         color=await ctx.embed_color(),
     )
     if icon:
         embed.set_thumbnail(url="attachment://icon.png")
     embed.add_field(name=_("Latency"), value=f"{status.latency} ms")
     embed.add_field(
         name=_("Players"),
         value="{0.players.online}/{0.players.max}\n{1}".format(
             status,
             chat.box(
                 list(
                     chat.pagify(
                         await self.clear_mcformatting("\n".join(
                             [p.name for p in status.players.sample])),
                         page_length=992,
                     ))[0]) if status.players.sample else "",
         ),
     )
     embed.add_field(
         name=_("Version"),
         value=_("{}\nProtocol: {}").format(status.version.name,
                                            status.version.protocol),
     )
     # if query:
     #     embed.add_field(name=_("World"), value=f"{query.map}")
     #     embed.add_field(
     #         name=_("Software"),
     #         value=_("{}\nVersion: {}").format(query.software.brand, query.software.version)
     #         # f"Plugins: {query.software.plugins}"
     #     )
     await ctx.send(file=icon, embed=embed)
     if icon_file:
         icon_file.close()
Beispiel #23
0
 def _multiply(self, mul):
     return box(self * mul)
Beispiel #24
0
 def _shuffle(self):
     data = self.split()
     random.shuffle(data)
     return box(" ".join(data))
Beispiel #25
0
    async def invite_filter(self, message):
        author = message.author
        guild = author.guild
        EMBED_TITLE = "🔥📧 • Invite filter"
        EMBED_FIELDS = [{
            "name": "Username",
            "value": f"`{author}`"
        }, {
            "name": "ID",
            "value": f"`{author.id}`"
        }, {
            "name": "Channel",
            "value": message.channel.mention
        }]

        result = INVITE_URL_RE.findall(message.content)

        if not result:
            return

        exclude_own_invites = await self.config.guild(
            guild).invite_filter_exclude_own_invites()

        if exclude_own_invites:
            external_invite = await get_external_invite(guild, result)
            if external_invite is None:
                return False
        else:
            external_invite = result[0][1]

        if len(message.content) > 1000:
            content = box(f"{message.content[:1000]}(...)")
        else:
            content = box(message.content)

        action = Action(await self.config.guild(guild).invite_filter_action())

        if action == Action.Ban:
            reason = "Posting an invite link (Defender autoban)"
            await guild.ban(author, reason=reason, delete_message_days=0)
            self.dispatch_event("member_remove", author, Action.Ban.value,
                                reason)
        elif action == Action.Kick:
            reason = "Posting an invite link (Defender autokick)"
            await guild.kick(author, reason=reason)
            self.dispatch_event("member_remove", author, Action.Kick.value,
                                reason)
        elif action == Action.Softban:
            reason = "Posting an invite link (Defender autokick)"
            await guild.ban(author, reason=reason, delete_message_days=1)
            await guild.unban(author)
            self.dispatch_event("member_remove", author, Action.Softban.value,
                                reason)
        elif action == Action.Punish:
            punish_role = guild.get_role(
                await self.config.guild(guild).punish_role())
            punish_message = await self.format_punish_message(author)
            if punish_role and not self.is_role_privileged(punish_role):
                await author.add_roles(
                    punish_role, reason="Defender: punish role assignation")
                if punish_message:
                    await message.channel.send(punish_message)
            else:
                self.send_to_monitor(
                    guild,
                    "[InviteFilter] Failed to punish user. Is the punish role "
                    "still present and with *no* privileges?")
                return

        try:
            await message.delete()
        except discord.Forbidden:
            self.send_to_monitor(
                guild, "[InviteFilter] Failed to delete message: "
                f"no permissions in #{message.channel}")
        except discord.NotFound:
            pass
        except Exception as e:
            log.error("Unexpected error in invite filter's message deletion",
                      exc_info=e)

        invite_data = f"**About [discord.gg/{external_invite}](https://discord.gg/{external_invite})**\n"

        try:
            invite = await self.bot.fetch_invite(external_invite)
        except (discord.NotFound, discord.HTTPException):
            invite_data += f"I could not gather more information about the invite."
        else:
            if invite.guild:
                invite_data += f"This invite leads to the server `{invite.guild.name}` (`{invite.guild.id}`)\n"
                if invite.approximate_presence_count is not None and invite.approximate_member_count is not None:
                    invite_data += (
                        f"It has **{invite.approximate_member_count}** members "
                        f"({invite.approximate_presence_count} online)\n")
                icon_url = invite.guild.icon_url_as()
                banner_url = invite.guild.banner_url_as()
                is_partner = "PARTNERED" in invite.guild.features
                is_verified = "VERIFIED" in invite.guild.features
                chars = []
                chars.append(
                    f"It was created {timestamp(invite.guild.created_at, relative=True)}"
                )
                if is_partner:
                    chars.append("it is a **partner** server")
                if is_verified:
                    chars.append("it is **verified**")
                if icon_url:
                    chars.append(f"it has an [icon set]({icon_url})")
                if banner_url:
                    chars.append(f"it has a [banner set]({banner_url})")
                if invite.guild.description:
                    chars.append(
                        f"the following is its description:\n{box(invite.guild.description)}"
                    )
                invite_data += f"{humanize_list(chars)}"
            else:
                invite_data += f"I have failed to retrieve the server's data. Possibly a group DM invite?\n"

        if action == Action.NoAction:
            notif_text = f"I have deleted a message with this content:\n{content}\n{invite_data}"
        else:
            notif_text = f"I have {ACTIONS_VERBS[action]} a user for posting this message:\n{content}\n{invite_data}"

        quick_action = QuickAction(author.id, "Posting an invite link")
        heat_key = f"core-if-{author.id}-{message.channel.id}"
        await self.send_notification(guild,
                                     notif_text,
                                     title=EMBED_TITLE,
                                     fields=EMBED_FIELDS,
                                     jump_to=message,
                                     no_repeat_for=timedelta(minutes=1),
                                     heat_key=heat_key,
                                     quick_action=quick_action)

        await self.create_modlog_case(
            self.bot,
            guild,
            message.created_at,
            action.value,
            author,
            guild.me,
            "Posting an invite link",
            until=None,
            channel=None,
        )

        return True
Beispiel #26
0
    async def message_leaderboard(self, ctx):
        """
        Message Tracker Leaderboard, displays all the members.

        [Credit to Core Economy](https://github.com/Cog-Creators/Red-DiscordBot/blob/dc68bc5d373c69aa1307ecef8118da14379ac67a/redbot/cogs/economy/economy.py#L545-L663)
        """
        try:
            self.counted_message[ctx.guild.id]
            update_config = await self.update_guild_config_from_cache(
                ctx.guild)  # updates from cache
            await self.remove_non_members_from_config()  # clears non_members

            if update_config is False:
                return await ctx.send(
                    "Something happened with updating. Please try again.")
        except KeyError:  # If it fails to have anything, we may assume that no messages have been sent.
            pass
        config_info = await self.config.all_members(ctx.guild)

        if not config_info:
            return await ctx.send(
                "There is no tracked messages for this server.")

        if await self.config.guild(ctx.guild).enabled_system() is False:
            await ctx.send(
                "This server does not have this system enabled. We won't be tracking any new messages."
            )
            # Even if it's turned off, we should still allow it to be shown.

        async with ctx.typing():

            sorting_list = sorted(config_info.items(),
                                  key=lambda x: x[1]["counter"],
                                  reverse=True)

            pound_len = len(str(len(sorting_list)))
            top_message_len = len(str(sorting_list[0][1]["counter"]))

            embed_message = ""
            embed_header = "{pound:{pound_len}}{score:{bal_len}}{name:2}\n".format(
                pound="#",
                name="Name",
                score="Messages",
                bal_len=top_message_len + 8,
                pound_len=pound_len + 2,
            )
            footer_message = "Page {page_num}/{page_len}."  # Work this in somehow.

            base = discord.Embed(
                title="{guild}'s leaderboard".format(guild=ctx.guild.name),
                description="")
            embed_list = []
            pos = 1
            new_embed = base.copy()
            embed_message = embed_header

            for user_id, counter in sorting_list:
                user = ctx.guild.get_member(user_id).display_name
                if user is None:
                    user = user_id

                if user_id != ctx.author.id:
                    embed_message += (
                        f"{f'{pos}.': <{pound_len+2}} "
                        f"{humanize_number(counter['counter']): <{top_message_len + 6}} {user}\n"
                    )
                else:
                    embed_message += (
                        f"{f'{pos}.': <{pound_len+2}} "
                        f"{humanize_number(counter['counter']): <{top_message_len + 6}} <<{ctx.author.display_name}>>\n"
                    )

                if pos % 10 == 0:
                    new_embed = base.copy()
                    new_embed.description = box(embed_message, lang="md")
                    new_embed.set_footer(text=footer_message.format(
                        page_num=ceil(len(embed_list) + 1),
                        page_len=ceil(len(sorting_list) / 10),
                    ))
                    embed_list.append(new_embed)
                    embed_message = embed_header

                pos += 1

            if embed_message != embed_header:
                new_embed = base.copy()
                new_embed.description = box(embed_message, lang="md")
                new_embed.set_footer(text=footer_message.format(
                    page_num=ceil(len(embed_list) + 1),
                    page_len=ceil(len(sorting_list) / 10)))
                embed_list.append(new_embed)

        if not embed_list:
            return await ctx.send("Sorry, no leaderboard to display.")

        await menu(
            ctx,
            embed_list,
            DEFAULT_CONTROLS
            if len(embed_list) > 1 else {"\N{CROSS MARK}": close_menu},
        )
Beispiel #27
0
    async def advusagecount(self, ctx):
        avatar = self.bot.user.avatar_url_as(static_format="png")
        uptime = str(self.get_bot_uptime())
        errors_count = "{:,}".format(self.counter["command_error"])
        messages_read = "{:,}".format(self.counter["messages_read"])
        messages_sent = "{:,}".format(self.counter["msg_sent"])
        dms_received = "{:,}".format(self.counter["dms_received"])
        guild_join = "{:,}".format(self.counter["guild_join"])
        guild_leave = "{:,}".format(self.counter["guild_remove"])
        resumed_sessions = "{:,}".format(self.counter["sessions_resumed"])
        commands_count = "{:,}".format(self.counter["processed_commands"])
        new_mem = "{:,}".format(self.counter["new_members"])
        left_mem = "{:,}".format(self.counter["members_left"])
        msg_deleted = "{:,}".format(self.counter["messages_deleted"])
        msg_edited = "{:,}".format(self.counter["messages_edited"])
        react_added = "{:,}".format(self.counter["reactions_added"])
        react_removed = "{:,}".format(self.counter["reactions_removed"])
        roles_add = "{:,}".format(self.counter["roles_added"])
        roles_rem = "{:,}".format(self.counter["roles_removed"])
        roles_up = "{:,}".format(self.counter["roles_updated"])
        mem_ban = "{:,}".format(self.counter["members_banned"])
        mem_unban = "{:,}".format(self.counter["members_unbanned"])
        emoji_add = "{:,}".format(self.counter["emojis_added"])
        emoji_rem = "{:,}".format(self.counter["emojis_removed"])
        emoji_up = "{:,}".format(self.counter["emojis_updated"])
        vc_joins = "{:,}".format(self.counter["users_joined_bot_music_room"])
        tracks_played = "{:,}".format(self.counter["tracks_played"])
        #streams_played = "{:,}".format(self.counter["streams_played"])
        #yt_streams = "{:,}".format(self.counter["yt_streams_played"])
        #mixer_streams = "{:,}".format(self.counter["mixer_streams_played"])
        #ttv_streams = "{:,}".format(self.counter["ttv_streams_played"])
        #other_streams = "{:,}".format(self.counter["other_streams_played"])
        #youtube_tracks = "{:,}".format(self.counter["youtube_tracks"])
        #soundcloud_tracks = "{:,}".format(self.counter["soundcloud_tracks"])
        #bandcamp_tracks = "{:,}".format(self.counter["bandcamp_tracks"])
        #vimeo_tracks = "{:,}".format(self.counter["vimeo_tracks"])
        #mixer_tracks = "{:,}".format(self.counter["mixer_tracks"])
        #twitch_tracks = "{:,}".format(self.counter["twitch_tracks"])
        #other_tracks = "{:,}".format(self.counter["other_tracks"])
        try:
            total_num = "{:,}/{:,}".format(len(lavalink.active_players()),
                                           len(lavalink.all_players()))
        except AttributeError:
            total_num = "{:,}/{:,}".format(
                len([p for p in lavalink.players if p.current is not None]),
                len([p for p in lavalink.players]),
            )

        em = discord.Embed(
            title=_("Usage count of {} since last restart:").format(
                ctx.bot.user.name),
            color=await ctx.embed_colour())
        em.add_field(name=_("Message Stats"),
                     value=box(_("""
Messages Read:       {}
Messages Sent:       {}
Messages Deleted:    {}
Messages Edited      {}
DMs Recieved:        {}""").format(messages_read, messages_sent, msg_deleted,
                                   msg_edited, dms_received),
                               lang="prolog"),
                     inline=False)
        em.add_field(name=_("Commands Stats"),
                     value=box(_("""
Commands Processed:  {}
Errors Occured:      {}
Sessions Resumed:    {}""").format(commands_count, errors_count,
                                   resumed_sessions),
                               lang="prolog"),
                     inline=False)
        em.add_field(name=_("Guild Stats"),
                     value=box(_("""
Guilds Joined:       {}
Guilds Left:         {}""").format(guild_join, guild_leave),
                               lang="prolog"),
                     inline=False)
        em.add_field(name=_("User Stats"),
                     value=box(_("""
New Users:           {}
Left Users:          {}
Banned Users:        {}
Unbanned Users:      {}""").format(new_mem, left_mem, mem_ban, mem_unban),
                               lang="prolog"),
                     inline=False)
        em.add_field(name=_("Role Stats"),
                     value=box(_("""
Roles Added:         {}
Roles Removed:       {}
Roles Updated:       {}""").format(roles_add, roles_rem, roles_up),
                               lang="prolog"),
                     inline=False)
        em.add_field(name=_("Emoji Stats"),
                     value=box(_("""
Reacts Added:        {}
Reacts Removed:      {}
Emoji Added:         {}
Emoji Removed:       {}
Emoji Updated:       {}""").format(react_added, react_removed, emoji_add,
                                   emoji_rem, emoji_up),
                               lang="prolog"),
                     inline=False)
        em.add_field(name=_("Audio Stats"),
                     value=box(_("""
Users Who Joined VC: {}
Tracks Played:       {}
Number Of Players:   {}""").format(vc_joins, tracks_played, total_num),
                               lang="prolog"),
                     inline=False)
        em.set_thumbnail(url=avatar)
        em.set_footer(text=_("Since {}").format(uptime))
        await ctx.send(embed=em)
Beispiel #28
0
    async def repoinfo(self, ctx, repo_name):
        DLCOG = self.bot.get_cog("Downloader")
        if DLCOG is None:
            await ctx.send(inline("Downloader cog not loaded."))
            return
        repo = DLCOG._repo_manager.get_repo(repo_name)
        if repo is None:
            await ctx.send(box("Repo not found.\n\nAvaliable Repos:\n" +
                               "\n".join(
                                   DLCOG._repo_manager.get_all_repo_names())))
            return
        extensions = [i.name for i in repo.available_cogs]
        cogs = filter(lambda x: x.__module__.split(".")[0] in extensions,
                      self.bot.cogs.values())

        hs = await commands.help.HelpSettings.from_context(ctx)
        rhf = commands.help.RedHelpFormatter()
        coms = [(
            cog.__cog_name__,
            await commands.help.RedHelpFormatter().get_cog_help_mapping(ctx,
                                                                        cog, hs)
        ) for cog in cogs]

        if not coms:
            await ctx.send(inline("There are no loaded cogs on the repo!"))
            return

        if await ctx.embed_requested():

            emb = {"embed": {"title": "", "description": ""},
                   "footer": {"text": ""}, "fields": []}

            for cog_name, data in coms:

                if cog_name:
                    title = f"**__{cog_name}:__**"
                else:
                    title = "**__No Category:__**"

                def shorten_line(a_line: str) -> str:
                    if len(a_line) < 70:
                        return a_line
                    return a_line[:67] + "..."

                cog_text = "\n".join(
                    shorten_line(
                        f"**{name}** {command.format_shortdoc_for_context(ctx)}")
                    for name, command in sorted(data.items())
                )

                for i, page in enumerate(
                        pagify(cog_text, page_length=1000, shorten_by=0)):
                    title = title if i < 1 else f"{title} (continued)"
                    field = EmbedField(title, page, False)
                    emb["fields"].append(field)

            await rhf.make_and_send_embeds(ctx, emb, help_settings=hs)

        else:
            to_join = ["Commands for {}:\n".format(repo_name)]

            names = []
            for k, v in coms:
                names.extend(list(v.name for v in v.values()))

            max_width = max(
                discord.utils._string_width(name or "No Category:") for name in
                names)

            def width_maker(cmds):
                doc_max_width = 80 - max_width
                for nm, com in cmds:
                    width_gap = discord.utils._string_width(nm) - len(nm)
                    doc = com.format_shortdoc_for_context(ctx)
                    if len(doc) > doc_max_width:
                        doc = doc[: doc_max_width - 3] + "..."
                    yield nm, doc, max_width - width_gap

            for cog_name, data in coms:

                title = f"{cog_name}:" if cog_name else "No Category:"
                to_join.append(title)

                for name, doc, width in width_maker(sorted(data.items())):
                    to_join.append(f"  {name:<{width}} {doc}")

            to_page = "\n".join(to_join)
            pages = [box(p) for p in pagify(to_page)]
            await rhf.send_pages(ctx, pages, embed=False, help_settings=hs)
Beispiel #29
0
    async def debugid(self, ctx, *, query):
        padinfo_cog = self.bot.get_cog('PadInfo')
        # m is a named monster
        m, err, debug_info = lookup_named_monster(query)

        if m is None:
            await ctx.send(box('No match: ' + err))
            return

        msg = "{}. {}".format(m.monster_no_na, m.name_na)
        msg += "\nLookup type: {}".format(debug_info)

        def list_or_none(l):
            if len(l) == 1:
                return '\n\t{}'.format(''.join(l))
            elif len(l):
                return '\n\t' + '\n\t'.join(sorted(l))
            else:
                return 'NONE'

        msg += "\n\nNickname original components:"
        msg += "\n monster_basename: {}".format(m.monster_basename)
        msg += "\n group_computed_basename: {}".format(
            m.group_computed_basename)
        msg += "\n extra_nicknames: {}".format(list_or_none(m.extra_nicknames))

        msg += "\n\nNickname final components:"
        msg += "\n basenames: {}".format(list_or_none(m.group_basenames))
        msg += "\n prefixes: {}".format(list_or_none(m.prefixes))

        msg += "\n\nAccepted nickname entries:"
        accepted_nn = list(
            filter(
                lambda nn: m.monster_id == padinfo_cog.index_all.all_entries[
                    nn].monster_id, m.final_nicknames))
        accepted_twnn = list(
            filter(
                lambda nn: m.monster_id == padinfo_cog.index_all.
                two_word_entries[nn].monster_id, m.final_two_word_nicknames))

        msg += "\n nicknames: {}".format(list_or_none(accepted_nn))
        msg += "\n two_word_nicknames: {}".format(list_or_none(accepted_twnn))

        msg += "\n\nOverwritten nickname entries:"
        replaced_nn = list(
            filter(lambda nn: nn not in accepted_nn, m.final_nicknames))

        replaced_twnn = list(
            filter(lambda nn: nn not in accepted_twnn,
                   m.final_two_word_nicknames))

        replaced_nn_info = map(
            lambda nn: (nn, padinfo_cog.index_all.all_entries[nn]),
            replaced_nn)
        replaced_twnn_info = map(
            lambda nn: (nn, padinfo_cog.index_all.two_word_entries[nn]),
            replaced_twnn)

        replaced_nn_text = list(
            map(
                lambda nn_info: '{} : {}. {}'.format(nn_info[0], nn_info[
                    1].monster_no_na, nn_info[1].name_na), replaced_nn_info))

        replaced_twnn_text = list(
            map(
                lambda nn_info: '{} : {}. {}'.format(nn_info[0], nn_info[
                    1].monster_no_na, nn_info[1].name_na), replaced_twnn_info))

        msg += "\n nicknames: {}".format(list_or_none(replaced_nn_text))
        msg += "\n two_word_nicknames: {}".format(
            list_or_none(replaced_twnn_text))

        msg += "\n\nNickname entry sort parts:"
        msg += "\n (is_low_priority, group_size, monster_no_na) : ({}, {}, {})".format(
            m.is_low_priority, m.group_size, m.monster_no_na)

        msg += "\n\nMatch selection sort parts:"
        msg += "\n (is_low_priority, rarity, monster_no_na) : ({}, {}, {})".format(
            m.is_low_priority, m.rarity, m.monster_no_na)

        sent_messages = []
        for page in pagify(msg):
            sent_messages.append(await ctx.send(box(page)))
        await rpadutils.await_and_remove(self.bot,
                                         sent_messages[-1],
                                         ctx.author,
                                         delete_msgs=sent_messages,
                                         timeout=30)
Beispiel #30
0
    async def game(self, channel):
        """Runs a quiz game on a channel."""
        channelinfo = self.playing_channels[channel.id]
        category = channelinfo["CategoryID"]
        category_name = channelinfo["Category"]

        try:
            response = await self.get_questions(
                channel.guild, category=channelinfo["CategoryID"])
        except RuntimeError:
            await channel.send(
                "An error occurred in retrieving questions. Please try again.")
            self.playing_channels.pop(channel.id)
            raise

        # Introduction
        intro = (
            f"Welcome to the quiz game! Your category is `{category_name}`.\n"
            "Remember to answer correctly as quickly as you can for more points.\n"
            "You have 10 seconds per question: the timer is shown in reactions on each question.\n"
            "The game will begin shortly.")
        await channel.send(intro)
        await asyncio.sleep(4)

        # Question and Answer
        afk_questions = 0
        for index, dictionary in enumerate(response["results"]):
            answers = [dictionary["correct_answer"]
                       ] + dictionary["incorrect_answers"]

            # Display question and countdown
            if len(answers) == 2:  # true/false question
                answers = ["True", "False", "", ""]
            else:
                answers = [html.unescape(answer) for answer in answers]
                random.shuffle(answers)

            message = ""
            message += html.unescape(dictionary["question"]) + "\n"
            message += f"A. {answers[0]}\n"
            message += f"B. {answers[1]}\n"
            message += f"C. {answers[2]}\n"
            message += f"D. {answers[3]}\n"

            message_obj = await channel.send(box(message))
            await message_obj.add_reaction("0⃣")
            channelinfo["Answers"].clear(
            )  # clear the previous question's answers
            start_time = time.perf_counter()

            numbers = [
                "1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣",
                "9⃣", "🔟"
            ]
            for i in range(10):
                if len(channelinfo["Answers"]) == len(channelinfo["Players"]):
                    break
                await asyncio.sleep(1)
                await message_obj.add_reaction(numbers[i])

            # Organize answers
            user_answers = channelinfo["Answers"]
            # snapshot channelinfo["Answers"] at this point in time
            # to ignore new answers that are added to it
            answerdict = {["a", "b", "c", "d"][num]: answers[num]
                          for num in range(4)}

            # Check for AFK
            if len(user_answers) < 2:
                afk_questions += 1
                afk_count = await self.config.guild(channel.guild).afk()
                if afk_questions == int(afk_count):
                    await channel.send(
                        "The game has been cancelled due to lack of participation."
                    )
                    self.playing_channels.pop(channel.id)
                    return
            else:
                afk_questions = 0

            # Find and display correct answer
            correct_letter = ""
            for letter, answer in answerdict.items():
                if answer == html.unescape(dictionary["correct_answer"]):
                    correct_letter = letter
                    break
            assert answerdict[correct_letter] == html.unescape(
                dictionary["correct_answer"])

            if await self.config.guild(channel.guild).show_answer():
                message = f"Correct answer:```{correct_letter.upper()}. {answerdict[correct_letter]}```"
                await channel.send(message)

            # Assign scores
            for playerid in user_answers:
                if user_answers[playerid]["Choice"] == correct_letter:
                    time_taken = user_answers[playerid]["Time"] - start_time
                    assert time_taken > 0
                    if time_taken < 1:
                        channelinfo["Players"][playerid] += 1000
                    else:
                        # the 20 in the formula below is 2 * 10s (max answer time)
                        channelinfo["Players"][playerid] += round(
                            1000 * (1 - (time_taken / 20)))

            # Display top 5 players and their points
            message = self.scoreboard(channel)
            await channel.send("Scoreboard:\n" + message)
            await asyncio.sleep(4)

            questions = await self.config.guild(channel.guild).questions()
            if index < (int(questions) - 1):
                await channel.send("Next question...")
                await asyncio.sleep(1)

        await self.end_game(channel)
Beispiel #31
0
 async def helpsearch(self, ctx):
     """Help info for the search command."""
     await ctx.author.send(box(HELP_MSG.format(ctx)))
Beispiel #32
0
 def _trim(self, trimmer):
     return box(self.strip(trimmer).strip())
Beispiel #33
0
    async def godvillegame(self, ctx, *, godname: str):
        """Get data about godville's god by name"""
        async with self.session.get("{}/{}".format(BASE_API_GLOBAL,
                                                   godname.casefold())) as sg:
            if sg.status == 404:
                await ctx.send(
                    chat.error(
                        "404 — Sorry, but there is nothing here\nCheck god name and try again"
                    ))
                return
            elif sg.status != 200:
                await ctx.send(
                    chat.error(
                        "Something went wrong. Server returned {}.".format(
                            sg.status)))
                return
            profile = await sg.json()
        profile = GodvilleUser(profile)
        text_header = "{} and his {}\n{}\n" \
            .format(chat.bold(profile.god),
                    chat.bold(profile.name),
                    chat.italics(chat.escape(profile.motto.strip(), formatting=True))
                    if profile.motto else chat.inline("Nothing here"))
        if profile.arena_is_in_fight:
            text_header += "In fight: {}\n".format(profile.fight_type_rus)
        if profile.town:
            text_header += "In city: {}\n".format(profile.town)
        if profile.need_update:
            text_header += chat.bold("! INFO OUTDATED !") + "\n"
        text = ""
        pet = ""
        times = ""
        if profile.gold_approximately:
            text += "Gold: {}\n".format(profile.gold_approximately)
        if profile.distance:
            text += "Milestone: {}\n".format(profile.distance)
        if profile.quest_progress:
            text += "Quest: {} ({}%)\n".format(profile.quest,
                                               profile.quest_progress)
        if profile.experience:
            text += "Exp for next level: {}%\n".format(profile.experience)
        text += "Level: {}\n".format(profile.level)
        if profile.godpower:
            text += "Godpower: {}/{}\n".format(
                profile.godpower, 200 if profile.savings_date else 100)
        text += "Personality: {}\n".format(profile.alignment)
        text += "Gender: {}\n".format(profile.gender)
        text += "Wins / Losses: {}/{}\n".format(profile.arena_won,
                                                profile.arena_lost)
        text += "Guild: {} ({})\n".format(profile.clan, profile.clan_position) if profile.clan \
            else "Guild: Not in guild\n"
        text += "Bricks: {} ({}%)\n".format(profile.bricks,
                                            profile.bricks / 10)
        if profile.inventory:
            text += "Inventory: {}/{} ({}%)\n".format(
                profile.inventory, profile.inventory_max,
                int(profile.inventory / profile.inventory_max * 100))
        else:
            text += "Inventory max: {}\n".format(profile.inventory_max)
        if profile.health:
            text += "Health: {}/{} ({}%)\n".format(
                profile.health, profile.health_max,
                int(profile.health / profile.health_max * 100))
        else:
            text += "Health maximum: {}\n".format(profile.health_max)
        if profile.ark_male:
            text += "Manimals: {} ({}%)\n".format(profile.ark_male,
                                                  profile.ark_male / 10)
        if profile.ark_female:
            text += "Fenimals: {} ({}%)\n".format(profile.ark_female,
                                                  profile.ark_female / 10)
        if profile.savings:
            text += "Savings: {}\n".format(profile.savings)
        if profile.trading_level:
            text += "Trading Level: {}\n".format(profile.trading_level)
        if profile.wood:
            text += "Wood: {} ({}%)\n".format(profile.wood, profile.wood / 10)

        # private (api only)
        if profile.diary_last:
            text += "Diary: {}\n".format(profile.diary_last)
        if profile.activatables:
            text += "Activatables in inv: {}\n".format(", ".join(
                profile.activatables))
        if profile.aura:
            text += "Aura: {}\n".format(profile.aura)

        # pet
        if profile.pet.name:
            pet += "Name: {}\n".format(profile.pet.name)
            pet += "Level: {}\n".format(profile.pet.level or "No level")
            if profile.pet.type:
                pet += "Type: {}\n".format(profile.pet.type)
            if profile.pet.wounded:
                pet += "❌ — Knocked out"

        # times
        if profile.temple_date:
            times += "Temple completed: {}\n".format(
                profile.date_string("temple"))
        if profile.ark_date:
            times += "Ark completed: {}\n".format(profile.date_string("ark"))
        if profile.savings_date:
            times += "Pension collected: {}\n".format(
                profile.date_string("savings"))  # ?

        finaltext = ""
        finaltext += text_header
        finaltext += chat.box(text)
        if pet:
            finaltext += "Pet:\n"
            finaltext += chat.box(pet)
        if times:
            finaltext += chat.box(times)
        await ctx.send(finaltext)
Beispiel #34
0
 def _reverse(self):
     return box(self[::-1])
Beispiel #35
0
async def boxPagifySay(say_fn, msg):
    for page in pagify(msg, delims=["\n"]):
        await say_fn(box(page))
Beispiel #36
0
 async def _version_msg(self, ctx, version=None):
     msg = box(_("Nsfw cog version: ") + version, lang="py")
     return await ctx.send(msg)
Beispiel #37
0
        cooldowns = cmd.get("cooldowns", {})

        if cooldowns:
            cooldown_text = _("Cooldowns:\n")
            for rate, per in cooldowns.items():
                cooldown_text += _("{num} seconds per {period}\n").format(
                    num=per, period=rate)
            text += cooldown_text

        text += _("Responses:\n")
        responses = ["- " + r for r in responses]
        text += "\n".join(responses)

        for p in pagify(text):
            await ctx.send(box(p, lang="yaml"))

    @commands.Cog.listener()
    async def on_message_without_command(self, message):
        is_private = isinstance(message.channel, discord.abc.PrivateChannel)

        # user_allowed check, will be replaced with self.bot.user_allowed or
        # something similar once it's added
        user_allowed = True

        if len(message.content
               ) < 2 or is_private or not user_allowed or message.author.bot:
            return

        if await self.bot.cog_disabled_in_guild(self, message.guild):
            return
Beispiel #38
0
    async def staff(self, ctx: commands.Context, *, reason: str = None):
        """
        Alert for the staff.
        """

        channel = await self.config.guild(ctx.guild).channel()
        role = await self.config.guild(ctx.guild).role()

        if not channel:
            return await ctx.send(
                error("The staff have not yet setup a staff channel."))

        channel = self.bot.get_channel(channel)
        role = ctx.guild.get_role(role)

        now = datetime.now()
        date = now.strftime("%d/%m/%y")

        message_list = []
        backslash = '\n'

        async for message in ctx.channel.history(limit=6):
            author, msg = message.author, message.content.replace('`', '')
            if len(msg) > 30:
                msg = msg[:30].strip(' ') + '...'
            elif not len(msg):
                msg = "[Embed, Attachment or File]"
            message_list.append(
                f"{str(author.display_name)}: {msg.replace(backslash, ' ')}")

        context = box('\n'.join(message_list), lang='yaml')
        reason = reason or "No reason was provided."

        embed = discord.Embed(
            title=warning("Staff Attention Pending | Conspicuous Activity"),
            description="[Click here for context]({})".format(
                ctx.message.jump_url),
            color=await ctx.embed_colour(),
        )

        embed.add_field(name="Member", value=ctx.author.mention, inline=True)
        embed.add_field(name="Channel", value=ctx.channel.mention, inline=True)
        embed.add_field(name="Date", value=date, inline=True)
        embed.add_field(name="Reason", value=reason, inline=False)
        embed.add_field(name="Context", value=context, inline=False)

        if await ctx.embed_requested():
            try:
                await channel.send(
                    allowed_mentions=discord.AllowedMentions(roles=True),
                    content=role.mention if role else None,
                    embed=embed,
                )
                await ctx.send(
                    "I have alerted the authorities, please remain calm.")
            except discord.Forbidden:
                return await ctx.send(
                    "I do not have permissions to alert the staff.")
        else:
            return await ctx.send(
                "I do not have permissions to send embeds in the staff's channel."
            )
Beispiel #39
0
 def _snake(self):
     return box(self.replace(" ", "_"))
Beispiel #40
0
    async def tip_cookie_author(self, ctx, somme: int = None):
        """Permet de donner un tip à l'auteur du dernier cookie acheté
        
        Par défaut le tip prendra la valeur définie comme récompense lors des like de cookie"""
        author, guild = ctx.author, ctx.guild
        if not somme:
            somme = await self.config.guild(guild).reward(
            ) if await self.config.guild(guild).reward() > 0 else 1

        last_cookie = await self.config.member(author).last_cookie()
        eco = self.bot.get_cog('XPay')
        currency = await eco.get_currency(guild)
        confirm, cancel = self.bot.get_emoji(
            812451214037221439), self.bot.get_emoji(812451214179434551)

        if not last_cookie:
            return await ctx.send(
                "**Aucun cookie acheté** › Vous n'avez aucun cookie dans votre historique d'achats."
            )

        cookie_price = await self.config.guild(guild).price()
        if somme <= 0 or somme > cookie_price:
            return await ctx.send(
                f"**Valeur invalide** › Le tip doit être compris entre 1 et la valeur d'achat ({cookie_price}{currency})."
            )

        if not await eco.check_balance(author, somme):
            return await ctx.send(
                "**Solde insuffisant** › Vous n'avez pas les moyens de tipper cette somme."
            )

        if last_cookie['tipped']:
            return await ctx.send(
                "**Déjà tippé** › Vous ne pouvez pas donner plus d'un seul tip par cookie."
            )

        if last_cookie['author']:
            lc_author = guild.get_member(last_cookie['author'])
            em = discord.Embed(title=f"Envoyer un tip à **{lc_author.name}**",
                               color=author.color)
            em.add_field(name="Texte du cookie",
                         value=box(last_cookie['text']))
            em.set_footer(
                text=
                f"Voulez-vous envoyer {somme}{currency} à l'auteur de ce cookie pour le récompenser ?"
            )
            msg = await ctx.reply(embed=em, mention_author=False)

            start_adding_reactions(msg, [confirm, cancel])
            try:
                react, _ = await self.bot.wait_for(
                    "reaction_add",
                    check=lambda m, u: u == ctx.author and m.message.id == msg.
                    id,
                    timeout=30)
            except asyncio.TimeoutError:
                return await msg.delete()

            if react.emoji == confirm:
                await msg.clear_reactions()
                await self.config.member(author).last_cookie.set_raw(
                    'tipped', value=True)
                try:
                    await eco.withdraw_credits(author,
                                               somme,
                                               reason="Tip de fortune cookie")
                except:
                    em.set_footer(text=f"Erreur dans l'envoi du tips")
                    return await msg.edit(embed=em)
                else:
                    await eco.deposit_credits(
                        lc_author,
                        somme,
                        reason="Tip reçu pour un fortune cookie")
                em.set_footer(
                    text=
                    f"Vous avez envoyé {somme}{currency} à {lc_author.name}")
                return await msg.edit(embed=em, mention_author=False)
            else:
                return await msg.delete()
        else:
            await ctx.send(
                "**Auteur inconnu** › L'auteur de votre dernier cookie acheté ne semble plus être sur ce serveur et ne peut donc recevoir de tips."
            )
Beispiel #41
0
 def _alternating(self):
     text = list(self)
     text[0::2] = map(str.upper, text[0::2])
     text[1::2] = map(str.lower, text[1::2])
     return box(text)
Beispiel #42
0
    async def _negaverse(
        self, ctx: commands.Context, offering: int = None, roll: Optional[int] = -1, nega: discord.Member = None
    ):
        """This will send you to fight a nega-member!"""
        if self.in_adventure(ctx):
            ctx.command.reset_cooldown(ctx)
            return await smart_embed(
                ctx,
                _("You tried to teleport to another dimension but the monster ahead did not give you a chance."),
            )

        bal = await bank.get_balance(ctx.author)
        currency_name = await bank.get_currency_name(
            ctx.guild,
        )
        if offering is None:
            ctx.command.reset_cooldown(ctx)
            return await smart_embed(
                ctx,
                _(
                    "**{author}**, you need to specify how many "
                    "{currency_name} you are willing to offer to the gods for your success."
                ).format(author=escape(ctx.author.display_name), currency_name=currency_name),
            )
        if offering <= 500 or bal <= 500:
            ctx.command.reset_cooldown(ctx)
            return await smart_embed(ctx, _("The gods refuse your pitiful offering."))
        if offering > bal:
            offering = int(bal)
        admin_roll = -1
        nega_set = False
        if (roll >= 0 or nega) and await self.bot.is_owner(ctx.author):
            if not is_dev(ctx.author):
                if not await self.no_dev_prompt(ctx):
                    ctx.command.reset_cooldown(ctx)
                    return
            nega_set = True
            admin_roll = roll
        offering_value = 0
        winning_state = False
        loss_state = False
        xp_won_final = 0
        lock = self.get_lock(ctx.author)
        await lock.acquire()
        try:
            nv_msg = await ctx.send(
                _(
                    "**{author}**, this will cost you at least {offer} {currency_name}.\n"
                    "You currently have {bal}. Do you want to proceed?"
                ).format(
                    author=escape(ctx.author.display_name),
                    offer=humanize_number(offering),
                    currency_name=currency_name,
                    bal=humanize_number(bal),
                )
            )
            start_adding_reactions(nv_msg, ReactionPredicate.YES_OR_NO_EMOJIS)
            pred = ReactionPredicate.yes_or_no(nv_msg, ctx.author)
            try:
                await ctx.bot.wait_for("reaction_add", check=pred, timeout=60)
            except asyncio.TimeoutError:
                ctx.command.reset_cooldown(ctx)
                await self._clear_react(nv_msg)
                lock.release()
                return
            if not pred.result:
                with contextlib.suppress(discord.HTTPException):
                    ctx.command.reset_cooldown(ctx)
                    await nv_msg.edit(
                        content=_("**{}** decides against visiting the negaverse... for now.").format(
                            escape(ctx.author.display_name)
                        )
                    )
                    lock.release()
                    return await self._clear_react(nv_msg)

            percentage_offered = (offering / bal) * 100
            min_roll = int(percentage_offered / 10)
            entry_roll = max(random.randint(max(1, min_roll), 20), 0) if admin_roll == -1 else admin_roll
            if entry_roll == 1:
                tax_mod = random.randint(4, 8)
                tax = round(bal / tax_mod)
                if tax > offering:
                    loss = tax
                else:
                    loss = offering
                offering_value += loss
                loss_state = True
                await bank.withdraw_credits(ctx.author, loss)
                entry_msg = _(
                    "A swirling void slowly grows and you watch in horror as it rushes to "
                    "wash over you, leaving you cold... and your coin pouch significantly lighter. "
                    "The portal to the negaverse remains closed."
                )
                lock.release()
                return await nv_msg.edit(content=entry_msg)
            else:
                entry_msg = _(
                    "Shadowy hands reach out to take your offering from you and a swirling "
                    "black void slowly grows and engulfs you, transporting you to the negaverse."
                )
                await nv_msg.edit(content=entry_msg)
                await self._clear_react(nv_msg)
                await bank.withdraw_credits(ctx.author, offering)
            if nega_set:
                nega_member = nega
                negachar = _("The Almighty Nega-{c}").format(c=escape(nega_member.display_name))
            else:
                nega_member = random.choice(ctx.message.guild.members)
                negachar = _("Nega-{c}").format(c=escape(nega_member.display_name))

            nega_msg = await ctx.send(
                _("**{author}** enters the negaverse and meets **{negachar}**.").format(
                    author=escape(ctx.author.display_name), negachar=negachar
                )
            )

            try:
                character = await Character.from_json(ctx, self.config, ctx.author, self._daily_bonus)
            except Exception as exc:
                log.exception("Error with the new character sheet", exc_info=exc)
                lock.release()
                ctx.command.reset_cooldown(ctx)
                return
            roll = random.randint(max(1, min_roll * 2), 50) if admin_roll == -1 else admin_roll
            if is_dev(nega_member):
                roll = -2
            versus = random.randint(10, 60)
            xp_mod = random.randint(1, 10)
            daymult = self._daily_bonus.get(str(datetime.today().isoweekday()), 0)
            xp_won = int((offering / xp_mod))
            xp_to_max = int((character.maxlevel + 1) ** 3.5)
            ten_percent = xp_to_max * 0.1
            xp_won = ten_percent if xp_won > ten_percent else xp_won
            xp_won = int(xp_won * (min(max(random.randint(0, character.rebirths), 1), 50) / 100 + 1))
            xp_won = int(xp_won * (character.gear_set_bonus.get("xpmult", 1) + daymult))
            if roll == -2:
                looted = ""
                curr_balance = character.bal
                await bank.set_balance(ctx.author, 0)
                offering_value += curr_balance
                loss_string = _("all of their")
                loss_state = True
                items = await character.looted(how_many=max(int(10 - roll) // 2, 1))
                if items:
                    item_string = "\n".join([f"{v} x{i}" for v, i in items])
                    looted = box(f"{item_string}", lang="css")
                    await self.config.user(ctx.author).set(await character.to_json(ctx, self.config))
                loss_msg = _(
                    ", losing {loss} {currency_name} as **{negachar}** rifled through their belongings."
                ).format(loss=loss_string, currency_name=currency_name, negachar=negachar)
                if looted:
                    loss_msg += _(" **{negachar}** also stole the following items:\n\n{items}").format(
                        items=looted, negachar=negachar
                    )
                await nega_msg.edit(
                    content=_("{content}\n**{author}** fumbled and died to **{negachar}'s** savagery{loss_msg}").format(
                        content=nega_msg.content,
                        author=escape(ctx.author.display_name),
                        negachar=negachar,
                        loss_msg=loss_msg,
                    )
                )
                ctx.command.reset_cooldown(ctx)
            elif roll < 10:
                loss = round(bal // 3)
                looted = ""
                curr_balance = character.bal
                try:
                    await bank.withdraw_credits(ctx.author, loss)
                    offering_value += loss
                    loss_string = humanize_number(loss)
                except ValueError:
                    await bank.set_balance(ctx.author, 0)
                    offering_value += curr_balance
                    loss_string = _("all of their")
                loss_state = True
                if character.bal < loss:
                    items = await character.looted(how_many=max(int(10 - roll) // 2, 1))
                    if items:
                        item_string = "\n".join([f"{v} {i}" for v, i in items])
                        looted = box(f"{item_string}", lang="css")
                        await self.config.user(ctx.author).set(await character.to_json(ctx, self.config))
                loss_msg = _(
                    ", losing {loss} {currency_name} as **{negachar}** rifled through their belongings."
                ).format(loss=loss_string, currency_name=currency_name, negachar=negachar)
                if looted:
                    loss_msg += _(" **{negachar}** also stole the following items:\n\n{items}").format(
                        items=looted, negachar=negachar
                    )
                await nega_msg.edit(
                    content=_("{content}\n**{author}** fumbled and died to **{negachar}'s** savagery{loss_msg}").format(
                        content=nega_msg.content,
                        author=escape(ctx.author.display_name),
                        negachar=negachar,
                        loss_msg=loss_msg,
                    )
                )
                ctx.command.reset_cooldown(ctx)
            elif roll == 50 and versus < 50:
                await nega_msg.edit(
                    content=_(
                        "{content}\n**{author}** decapitated **{negachar}**. "
                        "You gain {xp_gain} xp and take "
                        "{offering} {currency_name} back from the shadowy corpse."
                    ).format(
                        content=nega_msg.content,
                        author=escape(ctx.author.display_name),
                        negachar=negachar,
                        xp_gain=humanize_number(xp_won),
                        offering=humanize_number(offering),
                        currency_name=currency_name,
                    )
                )
                with contextlib.suppress(Exception):
                    lock.release()
                msg = await self._add_rewards(ctx, ctx.author, xp_won, offering, False)
                xp_won_final += xp_won
                offering_value += offering
                winning_state = True
                if msg:
                    await smart_embed(ctx, msg, success=True)
            elif roll > versus:
                await nega_msg.edit(
                    content=_(
                        "{content}\n**{author}** "
                        "{dice}({roll}) bravely defeated **{negachar}** {dice}({versus}). "
                        "You gain {xp_gain} xp."
                    ).format(
                        dice=self.emojis.dice,
                        content=nega_msg.content,
                        author=escape(ctx.author.display_name),
                        roll=roll,
                        negachar=negachar,
                        versus=versus,
                        xp_gain=humanize_number(xp_won),
                    )
                )
                with contextlib.suppress(Exception):
                    lock.release()
                msg = await self._add_rewards(ctx, ctx.author, xp_won, 0, False)
                xp_won_final += xp_won
                offering_value += offering
                winning_state = True
                if msg:
                    await smart_embed(ctx, msg, success=True)
            elif roll == versus:
                ctx.command.reset_cooldown(ctx)
                await nega_msg.edit(
                    content=_(
                        "{content}\n**{author}** {dice}({roll}) almost killed **{negachar}** {dice}({versus})."
                    ).format(
                        dice=self.emojis.dice,
                        content=nega_msg.content,
                        author=escape(ctx.author.display_name),
                        roll=roll,
                        negachar=negachar,
                        versus=versus,
                    )
                )
            else:
                loss = round(bal / (random.randint(10, 25)))
                curr_balance = character.bal
                looted = ""
                try:
                    await bank.withdraw_credits(ctx.author, loss)
                    offering_value += loss
                    loss_string = humanize_number(loss)
                except ValueError:
                    await bank.set_balance(ctx.author, 0)
                    loss_string = _("all of their")
                    offering_value += curr_balance
                loss_state = True
                if character.bal < loss:
                    items = await character.looted(how_many=max(int(10 - roll) // 2, 1))
                    if items:
                        item_string = "\n".join([f"{i}  - {v}" for v, i in items])
                        looted = box(f"{item_string}", lang="css")
                        await self.config.user(ctx.author).set(await character.to_json(ctx, self.config))
                loss_msg = _(", losing {loss} {currency_name} as **{negachar}** looted their backpack.").format(
                    loss=loss_string,
                    currency_name=currency_name,
                    negachar=negachar,
                )
                if looted:
                    loss_msg += _(" **{negachar}** also stole the following items:\n\n{items}").format(
                        items=looted, negachar=negachar
                    )
                await nega_msg.edit(
                    content=_(
                        "**{author}** {dice}({roll}) was killed by **{negachar}** {dice}({versus}){loss_msg}"
                    ).format(
                        dice=self.emojis.dice,
                        author=escape(ctx.author.display_name),
                        roll=roll,
                        negachar=negachar,
                        versus=versus,
                        loss_msg=loss_msg,
                    )
                )
                ctx.command.reset_cooldown(ctx)
        finally:
            lock = self.get_lock(ctx.author)
            with contextlib.suppress(Exception):
                lock.release()
            try:
                character = await Character.from_json(ctx, self.config, ctx.author, self._daily_bonus)
            except Exception as exc:
                log.exception("Error with the new character sheet", exc_info=exc)
            else:
                changed = False
                if character.last_currency_check + 600 < time.time() or character.bal > character.last_known_currency:
                    character.last_known_currency = await bank.get_balance(ctx.author)
                    character.last_currency_check = time.time()
                    changed = True
                if offering_value > 0:
                    current_gold__losses_value = character.nega.get("gold__losses", 0)
                    character.nega.update({"gold__losses": int(current_gold__losses_value + offering_value)})
                    changed = True
                if xp_won_final > 0:
                    current_xp__earnings_value = character.nega.get("xp__earnings", 0)
                    character.nega.update({"xp__earnings": current_xp__earnings_value + xp_won_final})
                    changed = True
                if winning_state is not False:
                    current_wins_value = character.nega.get("wins", 0)
                    character.nega.update({"wins": current_wins_value + 1})
                    changed = True
                if loss_state is not False:
                    current_loses_value = character.nega.get("loses", 0)
                    character.nega.update({"loses": current_loses_value + 1})
                    changed = True

                if changed:
                    await self.config.user(ctx.author).set(await character.to_json(ctx, self.config))
Beispiel #43
0
 def _replace(self, text_to_replace, replacement):
     replace = lambda x: x.replace(text_to_replace, replacement)
     return box(replace(self))
Beispiel #44
0
    async def dblinfo(self,
                      ctx,
                      *,
                      bot: Union[int, discord.Member, discord.User,
                                 None] = None):
        """
            Show information of a chosen bot on discordbots.org.

            `[bot]`: Can be a mention or ID of a bot.
        """
        key = await ctx.bot.db.api_tokens.get_raw("dbl", default=None)
        if key is None:
            return await ctx.send(
                _("Owner of this bot needs to set an API key first !"))
        if bot is None:
            return await ctx.send_help()
        if isinstance(bot, int):
            try:
                bot = await self.bot.fetch_user(bot)
            except discord.NotFound:
                return await ctx.send(str(bot) + _(" is not a Discord user."))
        if not bot.bot:
            return await ctx.send(
                _("This is not a bot user, please try again with a bot."))

        try:
            async with ctx.typing():
                try:
                    info = await self._get_data(ctx, bot=bot.id)
                    if info is None:
                        return
                    stats = await self._get_data(ctx,
                                                 endpoint="/stats",
                                                 bot=bot.id)
                except TypeError:
                    return

                emoji = (discord.utils.get(self.bot.emojis,
                                           id=392249976639455232)
                         if self.bot.get_guild(264445053596991498) is not None
                         else "`\N{WHITE HEAVY CHECK MARK}`")
                format_kwargs = {
                    "description": (bold(_("Description:")) +
                                    box("\n{}\n").format(info["shortdesc"])
                                    if info["tags"] else ""),
                    "tags": (bold(_("Tags:")) +
                             box("\n{}\n\n").format(", ".join(info["tags"]))
                             if info["tags"] else ""),
                    "if_cert":
                    (bold(_("\nCertified !")) +
                     f" {emoji}\n" if info["certifiedBot"] else "\n"),
                    "prefix":
                    (bold(_("Prefix:")) + " {}\n".format(info["prefix"])
                     if info.get("prefix", "") else ""),
                    "lib": (bold(_("Library:")) + " {}\n".format(info["lib"])
                            if info.get("lib", "") else ""),
                    "servs": (bold(_("Server count:")) +
                              " {:,}\n".format(stats["server_count"])
                              if stats.get("server_count", "") else ""),
                    "shards": (bold(_("Shard count:")) +
                               " {:,}\n".format(stats["shard_count"])
                               if stats.get("shard_count", "") else ""),
                    "m_votes": (bold(_("Monthly votes:")) +
                                (" {:,}\n".format(info["monthlyPoints"])
                                 if info.get("monthlyPoints", "") else "0\n")),
                    "t_votes": (bold(_("Total votes:")) + (" {:,}\n".format(
                        info["points"]) if info.get("points", "") else "0\n")),
                    "owners": (
                        bold(
                            _("Owner{}: ").format(
                                "s" if len(info["owners"]) > 1 else "")) +
                        ", ".join([
                            str((await self.bot.fetch_user(i)))
                            for i in info["owners"]
                        ]) + "\n"  # Thanks Slime :ablobcatsipsweats:
                    ),
                    "approval_date":
                    (bold(_("Approval date:")) +
                     " {}\n\n".format(info["date"].replace("T", " ")[:-5])),
                    "dbl_page": (_("[DBL Page]({})").format(
                        f"https://discordbots.org/bot/{bot.id}")),
                    "if_inv": (_(" • [Invitation link]({})").format(
                        info["invite"]) if info["invite"] else ""),
                    "if_supp":
                    (_(" • [Support](https://discord.gg/{})").format(
                        info["support"]) if info["support"] else ""),
                    "if_gh": (_(" • [GitHub]({})").format(info["github"])
                              if info["github"] else ""),
                    "if_wsite": (_(" • [Website]({})").format(info["website"])
                                 if info["website"] else ""),
                }
                description = (
                    "{description}"
                    "{tags}"
                    "{if_cert}"
                    "{prefix}"
                    "{lib}"
                    "{servs}{shards}"
                    "{m_votes}"
                    "{t_votes}"
                    "{owners}"
                    "{approval_date}"
                    "{dbl_page}{if_inv}{if_supp}{if_gh}{if_wsite}").format(
                        **format_kwargs)
                em = discord.Embed(color=(await ctx.embed_colour()),
                                   description=description)
                em.set_author(
                    name=_("DBL Info about {}:").format(info["username"]),
                    icon_url=
                    "https://cdn.discordapp.com/emojis/393548388664082444.gif",
                )
                em.set_thumbnail(url=bot.avatar_url_as(static_format="png"))
                return await ctx.send(embed=em)
        except Exception as error:
            return await ctx.send(
                _("Something went wrong when trying to get bot information.\n")
                + inline(str(error)))
Beispiel #45
0
 def _squash(self):
     return box(self.replace(" ", ""))
Beispiel #46
0
    async def print_cmdlist(self, ctx, cmdlist, inline=False):
        #TODO: Write a docstring once I figure out what this does
        if not cmdlist:
            await ctx.send("There are no padglobal commands yet")
            return

        prefix = ctx.prefix
        prefixes = defaultdict(int)

        for c in cmdlist:
            m = re.match(r'^([a-zA-Z]+)\d+$', c)
            if m:
                grp = m.group(1)
                prefixes[grp] = prefixes[grp] + 1

        good_prefixes = [cmd for cmd, cnt in prefixes.items() if cnt > 1]
        prefix_to_suffix = defaultdict(list)
        prefix_to_other = defaultdict(list)

        i = 0
        msg = PAD_CMD_HEADER.format(ctx.prefix) + "\n"

        if inline:
            for cmd in sorted([cmd for cmd in cmdlist.keys()]):
                msg += " {} : {}\n".format(cmd, cmdlist[cmd])
            for page in pagify(msg):
                await ctx.author.send(box(page))
            return

        for cmd in sorted([cmd for cmd in cmdlist.keys()]):
            m = re.match(r'^([a-zA-Z]+)(\d+)$', cmd)
            if m:
                prefix = m.group(1)
                if prefix in good_prefixes:
                    suffix = m.group(2)
                    prefix_to_suffix[prefix].append(suffix)
                    continue

            should_skip = False
            for good_prefix in good_prefixes:
                if cmd.startswith(good_prefix):
                    prefix_to_other[prefix].append(cmd)
                    should_skip = True
                    break
            if should_skip:
                continue

            msg += " {}{}\n".format(ctx.prefix, cmd)

        if prefix_to_suffix:
            msg += "\nThe following commands are indexed:\n"
            for prefix in sorted(prefix_to_suffix.keys()):
                msg += " {}{}[n]:\n  ".format(ctx.prefix, prefix)

                for suffix in sorted(map(int, prefix_to_suffix[prefix])):
                    msg += " {}{}".format(prefix, suffix)

                if len(prefix_to_other[prefix]):
                    msg += "\n"
                    for cmd in sorted(prefix_to_other[prefix]):
                        msg += " {}{}".format(ctx.prefix, cmd)
                msg += "\n\n"

        for page in pagify(msg):
            await ctx.author.send(box(page))
Beispiel #47
0
 def _remove(self, remove):
     return box(self.replace(remove, ""))
Beispiel #48
0
    async def godville(self, ctx, *, godname: str):
        """Get data about godville's god by name"""
        async with self.session.get("{}/{}/{}".format(
                BASE_API, godname.casefold(),
                await self.api_by_god(godname.casefold(), "godville")
                or "")) as sg:
            if sg.status == 404:
                await ctx.send(
                    chat.error(
                        "404 — Sorry, but there is nothing here\nCheck god name and try again"
                    ))
                return
            elif sg.status != 200:
                await ctx.send(
                    chat.error(
                        "Something went wrong. Server returned {}.".format(
                            sg.status)))
                return
            profile = await sg.json()
        profile = GodvilleUser(profile)
        text_header = "{} и его {}\n{}\n" \
            .format(chat.bold(profile.god),
                    chat.bold(profile.name),
                    chat.italics(chat.escape(profile.motto.strip(), formatting=True))
                    if profile.motto else chat.inline("Здесь ничего нет"))
        if profile.arena_is_in_fight:
            text_header += "В сражении: {}\n".format(profile.fight_type_rus)
        if profile.town:
            text_header += "В городе: {}\n".format(profile.town)
        if profile.need_update:
            text_header += chat.bold("! УСТАРЕВШАЯ ИНФОРМАЦИЯ !") + "\n"
        text = ""
        pet = ""
        times = ""
        if profile.gold_approximately:
            text += "Золота: {}\n".format(profile.gold_approximately)
        if profile.distance:
            text += "Столбов от столицы: {}\n".format(profile.distance)
        if profile.quest_progress:
            text += "Задание: {} ({}%)\n".format(profile.quest,
                                                 profile.quest_progress)
        if profile.experience:
            text += "Опыта до следующего уровня: {}%\n".format(
                profile.experience)
        text += "Уровень: {}\n".format(profile.level)
        if profile.godpower:
            text += "Праны: {}/{}\n".format(
                profile.godpower, 200 if profile.savings_date else 100)
        text += "Характер: {}\n".format(profile.alignment)
        text += "Пол: {}\n".format(profile.gender)
        text += "Побед/Поражений: {}/{}\n".format(profile.arena_won,
                                                  profile.arena_lost)
        text += "Гильдия: {} ({})\n".format(profile.clan, profile.clan_position) if profile.clan \
            else "Гильдия: Не состоит\n"
        text += "Кирпичей: {} ({}%)\n".format(profile.bricks,
                                              profile.bricks / 10)
        if profile.inventory:
            text += "Инвентарь: {}/{} ({}%)\n".format(
                profile.inventory, profile.inventory_max,
                int(profile.inventory / profile.inventory_max * 100))
        else:
            text += "Вместимость инвентаря: {}\n".format(profile.inventory_max)
        if profile.health:
            text += "Здоровье: {}/{} ({}%)\n".format(
                profile.health, profile.health_max,
                int(profile.health / profile.health_max * 100))
        else:
            text += "Максимум здоровья: {}\n".format(profile.health_max)
        if profile.ark_male:
            text += "Тварей ♂: {} ({}%)\n".format(profile.ark_male,
                                                  profile.ark_male / 10)
        if profile.ark_female:
            text += "Тварей ♀: {} ({}%)\n".format(profile.ark_female,
                                                  profile.ark_female / 10)
        if profile.savings:
            text += "Сбережений: {}\n".format(profile.savings)
        if profile.trading_level:
            text += "Уровень торговли: {}\n".format(profile.trading_level)
        if profile.wood:
            text += "Поленьев: {} ({}%)\n".format(profile.wood,
                                                  profile.wood / 10)

        # private (api only)
        if profile.diary_last:
            text += "Дневник: {}\n".format(profile.diary_last)
        if profile.activatables:
            text += "Активируемое в инвентаре: {}\n".format(", ".join(
                profile.activatables))
        if profile.aura:
            text += "Аура: {}\n".format(profile.aura)

        # pet
        if profile.pet.name:
            pet += "Имя: {}\n".format(profile.pet.name)
            pet += "Уровень: {}\n".format(profile.pet.level or "Без уровня")
            if profile.pet.type:
                pet += "Тип: {}\n".format(profile.pet.type)
            if profile.pet.wounded:
                pet += "❌ — Контужен"

        # times
        if profile.temple_date:
            times += "Храм достроен: {}\n".format(
                profile.date_string("temple"))
        if profile.ark_date:
            times += "Ковчег достроен: {}\n".format(profile.date_string("ark"))
        if profile.savings_date:
            times += "Пенсия собрана: {}\n".format(
                profile.date_string("savings"))

        finaltext = ""
        finaltext += text_header
        finaltext += chat.box(text)
        if pet:
            finaltext += "Питомец:\n"
            finaltext += chat.box(pet)
        if times:
            finaltext += chat.box(times)
        await ctx.send(finaltext)
Beispiel #49
0
    async def welcomeset(self, ctx: commands.Context):
        """Change Welcome settings."""

        await ctx.trigger_typing()

        if ctx.invoked_subcommand is None:
            guild = ctx.guild
            c = await self.config.guild(guild).all()

            channel = await self.__get_channel(ctx.guild)

            j = c["join"]
            jw = j["whisper"]
            v = c["leave"]
            b = c["ban"]
            u = c["unban"]

            msg = box(
                (
                    "  Enabled: {}\n"
                    "  Channel: {}\n"
                    "  Join:\n"
                    "    Enabled: {}\n"
                    "    Delete previous: {}\n"
                    "    Whisper:\n"
                    "      State: {}\n"
                    "      Message: {}\n"
                    "    Messages: {}; do '{prefix}welcomeset join msg list' for a list\n"
                    "    Bot message: {}\n"
                    "  Leave:\n"
                    "    Enabled: {}\n"
                    "    Delete previous: {}\n"
                    "    Messages: {}; do '{prefix}welcomeset leave msg list' for a list\n"
                    "  Ban:\n"
                    "    Enabled: {}\n"
                    "    Delete previous: {}\n"
                    "    Messages: {}; do '{prefix}welcomeset ban msg list' for a list\n"
                    "  Unban:\n"
                    "    Enabled: {}\n"
                    "    Delete previous: {}\n"
                    "    Messages: {}; do '{prefix}welcomeset unban msg list' for a list\n"
                    ""
                ).format(
                    c["enabled"],
                    channel,
                    j["enabled"],
                    j["delete"],
                    jw["state"],
                    jw["message"],
                    len(j["messages"]),
                    j["bot"],
                    v["enabled"],
                    v["delete"],
                    len(v["messages"]),
                    b["enabled"],
                    b["delete"],
                    len(b["messages"]),
                    u["enabled"],
                    u["delete"],
                    len(u["messages"]),
                    prefix=ctx.prefix,
                ),
                "Current Welcome settings:",
            )

            await ctx.send(msg)