Esempio n. 1
0
    async def on_member_join(self, member: discord.Member):
        """ Called when a member joins a guild (server) the bot is in."""
        log.info("{0.display_name} (ID: {0.id}) joined {0.guild.name}".format(
            member))
        # Updating member list
        if member.id in self.members:
            self.members[member.id].append(member.guild.id)
        else:
            self.members[member.id] = [member.guild.id]

        # No welcome message for lite servers and servers not tracking worlds
        if member.guild.id in config.lite_servers or tracked_worlds.get(
                member.guild.id) is None:
            return

        server_welcome = get_server_property("welcome", member.guild.id, "")
        pm = (config.welcome_pm + "\n" + server_welcome).format(
            user=member,
            server=member.guild,
            bot=self.user,
            owner=member.guild.owner)

        embed = discord.Embed(description="{0.mention} joined.".format(member))
        icon_url = get_user_avatar(member)
        embed.colour = discord.Colour.green()
        embed.set_author(name="{0.name}#{0.discriminator}".format(member),
                         icon_url=icon_url)
        embed.timestamp = dt.datetime.utcnow()

        # Check if user already has characters registered and announce them on log_channel
        # This could be because he rejoined the server or is in another server tracking the same worlds
        world = tracked_worlds.get(member.guild.id)
        if world is not None:
            c = userDatabase.cursor()
            try:
                c.execute(
                    "SELECT name, vocation, ABS(level) as level, guild "
                    "FROM chars WHERE user_id = ? and world = ?", (
                        member.id,
                        world,
                    ))
                results = c.fetchall()
                if len(results) > 0:
                    pm += "\nYou already have these characters in {0} registered to you: {1}"\
                        .format(world, join_list([r["name"] for r in results], ", ", " and "))
                    characters = [
                        "\u2023 {name} - Level {level} {voc} - **{guild}**".
                        format(**c, voc=get_voc_abb_and_emoji(c["vocation"]))
                        for c in results
                    ]
                    embed.add_field(name="Registered characters",
                                    value="\n".join(characters))
            finally:
                c.close()

        await self.send_log_message(member.guild, embed=embed)
        await member.send(pm)
Esempio n. 2
0
    async def on_member_join(self, member: discord.Member):
        """ Called when a member joins a guild (server) the bot is in."""
        log.info("{0.display_name} (ID: {0.id}) joined {0.guild.name}".format(
            member))
        # Updating member list
        if member.id in self.members:
            self.members[member.id].append(member.guild.id)
        else:
            self.members[member.id] = [member.guild.id]

        embed = discord.Embed(description="{0.mention} joined.".format(member),
                              color=discord.Color.green())
        embed.set_author(
            name="{0.name}#{0.discriminator} (ID: {0.id})".format(member),
            icon_url=get_user_avatar(member))

        previously_registered = ""
        # If server is not tracking worlds, we don't check the database
        if member.guild.id in config.lite_servers or self.tracked_worlds.get(
                member.guild.id) is None:
            await self.send_log_message(member.guild, embed=embed)
        else:
            # Check if user already has characters registered and announce them on log_channel
            # This could be because he rejoined the server or is in another server tracking the same worlds
            world = self.tracked_worlds.get(member.guild.id)
            previously_registered = ""
            if world is not None:
                c = userDatabase.cursor()
                try:
                    c.execute(
                        "SELECT name, vocation, ABS(level) as level, guild "
                        "FROM chars WHERE user_id = ? and world = ?", (
                            member.id,
                            world,
                        ))
                    results = c.fetchall()
                    if len(results) > 0:
                        previously_registered = "\n\nYou already have these characters in {0} registered to you: *{1}*"\
                            .format(world, join_list([r["name"] for r in results], ", ", " and "))
                        characters = [
                            "\u2023 {name} - Level {level} {voc} - **{guild}**"
                            .format(**c,
                                    voc=get_voc_abb_and_emoji(c["vocation"]))
                            for c in results
                        ]
                        embed.add_field(name="Registered characters",
                                        value="\n".join(characters))
                finally:
                    c.close()
            self.dispatch("character_change", member.id)
            await self.send_log_message(member.guild, embed=embed)

        welcome_message = get_server_property(member.guild.id, "welcome")
        welcome_channel_id = get_server_property(member.guild.id,
                                                 "welcome_channel",
                                                 is_int=True)
        if welcome_message is None:
            return
        message = welcome_message.format(user=member,
                                         server=member.guild,
                                         bot=self,
                                         owner=member.guild.owner)
        message += previously_registered
        channel = member.guild.get_channel(welcome_channel_id)
        # If channel is not found, send via pm as fallback
        if channel is None:
            channel = member
        try:
            await channel.send(message)
        except discord.Forbidden:
            try:
                # If bot has no permissions to send the message on that channel, send on private message
                # If the channel was already a private message, don't try it again
                if welcome_channel_id is None:
                    return
                await member.send(message)
            except discord.Forbidden:
                pass
Esempio n. 3
0
    def get_spell_embed(ctx, spell, long):
        """Gets the embed to show in /spell command"""
        short_limit = 5
        too_long = False

        if type(spell) is not dict:
            return
        embed = discord.Embed(title="{name} ({words})".format(**spell),
                              url=get_article_url(spell["name"]))
        embed.set_author(name="TibiaWiki",
                         icon_url=WIKI_ICON,
                         url=get_article_url(spell["name"]))

        spell["premium"] = "**premium** " if spell["premium"] else ""
        if spell["mana"] < 0:
            spell["mana"] = "variable"
        if "exani hur" in spell["words"]:
            spell["words"] = "exani hur up/down"
        vocs = list()
        if spell['knight']: vocs.append("knights")
        if spell['paladin']: vocs.append("paladins")
        if spell['druid']: vocs.append("druids")
        if spell['sorcerer']: vocs.append("sorcerers")
        spell["vocs"] = join_list(vocs, ", ", " and ")

        description = "A {premium}spell for level **{level}** and up. " \
                      "It uses **{mana}** mana. It can be used by {vocs}".format(**spell)

        if spell["price"] == 0:
            description += "\nIt can be obtained for free."
        else:
            description += "\nIt can be bought for {0:,} gold coins.".format(
                spell["price"])

        for voc in vocs:
            value = ""
            if len(vocs) == 1:
                name = "Sold by"
            else:
                name = "Sold by ({0})".format(voc.title())
            count = 0
            for npc in spell["npcs"]:
                if not npc[voc[:-1]]:
                    continue
                count += 1
                value += "\n{name} ({city})".format(**npc)
                if count >= short_limit and not long:
                    value += "\n*...And more*"
                    too_long = True
                    break
            if value:
                embed.add_field(name=name, value=value)
        # Set embed color based on element:
        if spell["element"] == "Fire":
            embed.colour = Colour(0xFF9900)
        if spell["element"] == "Ice":
            embed.colour = Colour(0x99FFFF)
        if spell["element"] == "Energy":
            embed.colour = Colour(0xCC33FF)
        if spell["element"] == "Earth":
            embed.colour = Colour(0x00FF00)
        if spell["element"] == "Holy":
            embed.colour = Colour(0xFFFF00)
        if spell["element"] == "Death":
            embed.colour = Colour(0x990000)
        if spell["element"] == "Physical" or spell["element"] == "Bleed":
            embed.colour = Colour(0xF70000)

        embed.description = description

        if too_long:
            ask_channel = ctx.bot.get_channel_by_name(config.ask_channel_name,
                                                      ctx.message.guild)
            if ask_channel:
                askchannel_string = " or use #" + ask_channel.name
            else:
                askchannel_string = ""
            embed.set_footer(
                text="To see more, PM me{0}.".format(askchannel_string))

        return embed
Esempio n. 4
0
    async def add_account(self, ctx: NabCtx, *, params):
        """Register a character and all other visible characters to a discord user.

        If a character is hidden, only that character will be added. Characters in other worlds are skipped."""
        params = params.split(",")
        if len(params) != 2:
            raise commands.BadArgument()
        target_name, char_name = params

        user = ctx.author
        world = ctx.world

        target = self.bot.get_member(target_name, ctx.guild)
        if target is None:
            return await ctx.send(
                f"{ctx.tick(False)} I couldn't find any users named @{target_name}"
            )
        if target.bot:
            return await ctx.send(
                f"{ctx.tick(False)} You can't register characters to discord bots!"
            )

        # Get list of the user's shared servers with the bot
        target_guilds = self.bot.get_user_guilds(target.id)
        # Filter only the servers that follow the same as the current context
        target_guilds = list(
            filter(lambda x: self.bot.tracked_worlds.get(x.id) == world,
                   target_guilds))

        msg = await ctx.send(f"{config.loading_emoji} Fetching characters...")
        try:
            char = await get_character(char_name)
            if char is None:
                return await msg.edit(content="That character doesn't exist.")
        except NetworkError:
            return await msg.edit(
                content="I couldn't fetch the character, please try again.")
        chars = char.other_characters
        # If the char is hidden,we still add the searched character, if we have just one, we replace it with the
        # searched char, so we don't have to look him up again
        if len(chars) == 0 or len(chars) == 1:
            chars = [char]
        skipped = []
        updated = []
        added: List[Character] = []
        existent = []
        for char in chars:
            # Skip chars in non-tracked worlds
            if char.world != world:
                skipped.append(char)
                continue
            with closing(userDatabase.cursor()) as c:
                c.execute(
                    "SELECT name, guild, user_id as owner, abs(level) as level "
                    "FROM chars "
                    "WHERE name LIKE ?", (char.name, ))
                db_char = c.fetchone()
            if db_char is not None:
                owner = self.bot.get_member(db_char["owner"])
                # Previous owner doesn't exist anymore
                if owner is None:
                    updated.append({
                        'name': char.name,
                        'world': char.world,
                        'prevowner': db_char["owner"],
                        'vocation': db_char["vocation"],
                        'level': db_char['level'],
                        'guild': db_char['guild']
                    })
                    continue
                # Char already registered to this user
                elif owner.id == target.id:
                    existent.append("{0.name} ({0.world})".format(char))
                    continue
                # Character is registered to another user, we stop the whole process
                else:
                    reply = "A character in that account ({0}) is already registered to **{1.display_name}**"
                    await ctx.send(reply.format(db_char["name"], owner))
                    return
            # If we only have one char, it already contains full data
            if len(chars) > 1:
                try:
                    await ctx.channel.trigger_typing()
                    char = await get_character(char.name)
                except NetworkError:
                    await ctx.send(
                        "I'm having network troubles, please try again.")
                    return
            if char.deleted is not None:
                skipped.append(char)
                continue
            added.append(char)

        if len(skipped) == len(chars):
            await ctx.send(
                f"Sorry, I couldn't find any characters in **{world}**.")
            return

        reply = ""
        log_reply = dict().fromkeys([server.id for server in target_guilds],
                                    "")
        if len(existent) > 0:
            reply += "\nThe following characters were already registered to @{1}: {0}" \
                .format(join_list(existent, ", ", " and "), target.display_name)

        if len(added) > 0:
            reply += "\nThe following characters were added to @{1.display_name}: {0}" \
                .format(join_list(["{0.name} ({0.world})".format(c) for c in added], ", ", " and "), target)
            for char in added:
                log.info(
                    "{2.display_name} registered character {0} was assigned to {1.display_name} (ID: {1.id})"
                    .format(char.name, target, user))
                # Announce on server log of each server
                for guild in target_guilds:
                    _guild = "No guild" if char.guild is None else char.guild_name
                    voc = get_voc_abb_and_emoji(char.vocation)
                    log_reply[guild.id] += "\n\u2023 {1.name} - Level {1.level} {2} - **{0}**" \
                        .format(_guild, char, voc)

        if len(updated) > 0:
            reply += "\nThe following characters were reassigned to @{1.display_name}: {0}" \
                .format(join_list(["{name} ({world})".format(**c) for c in updated], ", ", " and "), target)
            for char in updated:
                log.info(
                    "{2.display_name} reassigned character {0} to {1.display_name} (ID: {1.id})"
                    .format(char['name'], target, user))
                # Announce on server log of each server
                for guild in target_guilds:
                    char["voc"] = get_voc_abb_and_emoji(char["vocation"])
                    if char["guild"] is None:
                        char["guild"] = "No guild"
                    log_reply[guild.id] += "\n\u2023 {name} - Level {level} {voc} - **{guild}** (Reassigned)". \
                        format(**char)

        for char in updated:
            with userDatabase as conn:
                conn.execute("UPDATE chars SET user_id = ? WHERE name LIKE ?",
                             (target.id, char['name']))
        for char in added:
            with userDatabase as conn:
                conn.execute(
                    "INSERT INTO chars (name,level,vocation,user_id, world, guild) VALUES (?,?,?,?,?,?)",
                    (char.name, char.level * -1, char.vocation, target.id,
                     char.world, char.guild_name))

        with userDatabase as conn:
            conn.execute(
                "INSERT OR IGNORE INTO users (id, name) VALUES (?, ?)", (
                    target.id,
                    target.display_name,
                ))
            conn.execute("UPDATE users SET name = ? WHERE id = ?", (
                target.display_name,
                target.id,
            ))

        await ctx.send(reply)
        for server_id, message in log_reply.items():
            if message:
                message = f"{target.mention} registered:" + message
                embed = discord.Embed(description=message)
                embed.set_author(name=f"{target.name}#{target.discriminator}",
                                 icon_url=get_user_avatar(target))
                embed.colour = discord.Colour.dark_teal()
                icon_url = get_user_avatar(user)
                embed.set_footer(
                    text="{0.name}#{0.discriminator}".format(user),
                    icon_url=icon_url)
                await self.bot.send_log_message(self.bot.get_guild(server_id),
                                                embed=embed)
Esempio n. 5
0
    async def add_account(self, ctx, *, params):
        """Register a character and all other visible characters to a discord user.

        If a character is hidden, only that character will be added. Characters in other worlds are skipped.

        The syntax is the following:
        /addacc user,char"""
        params = params.split(",")
        if len(params) != 2:
            await ctx.send(
                "The correct syntax is: ``/addacc username,character``")
            return
        target_name, char_name = params

        # This is equivalent to someone using /stalk addacc on themselves.
        user = ctx.author
        world = tracked_worlds.get(ctx.guild.id)

        if world is None:
            await ctx.send("This server is not tracking any tibia worlds.")
            return

        target = self.bot.get_member(target_name, ctx.guild)
        if target is None:
            await ctx.send(f"I couldn't find any users named @{target_name}")
            return
        target_guilds = self.bot.get_user_guilds(target.id)
        target_guilds = list(filter(lambda x: x == world, target_guilds))

        await ctx.trigger_typing()
        try:
            char = await get_character(char_name)
            if char is None:
                await ctx.send("That character doesn't exists.")
                return
        except NetworkError:
            await ctx.send("I couldn't fetch the character, please try again.")
            return
        chars = char.other_characters
        # If the char is hidden,we still add the searched character, if we have just one, we replace it with the
        # searched char, so we don't have to look him up again
        if len(chars) == 0 or len(chars) == 1:
            chars = [char]
        skipped = []
        updated = []
        added = []  # type: List[Character]
        existent = []
        for char in chars:
            # Skip chars in non-tracked worlds
            if char.world != world:
                skipped.append(char)
                continue
            with closing(userDatabase.cursor()) as c:
                c.execute(
                    "SELECT name, guild, user_id as owner FROM chars WHERE name LIKE ?",
                    (char.name, ))
                db_char = c.fetchone()
            if db_char is not None:
                owner = self.bot.get_member(db_char["owner"])
                # Previous owner doesn't exist anymore
                if owner is None:
                    updated.append({
                        'name': char.name,
                        'world': char.world,
                        'prevowner': db_char["owner"]
                    })
                    continue
                # Char already registered to this user
                elif owner.id == user.id:
                    existent.append("{0.name} ({0.world})".format(char))
                    continue
                # Character is registered to another user, we stop the whole process
                else:
                    reply = "A character in that account ({0}) is already registered to **{1.display_name}**"
                    await ctx.send(reply.format(db_char["name"], owner))
                    return
            # If we only have one char, it already contains full data
            if len(chars) > 1:
                try:
                    await ctx.message.channel.trigger_typing()
                    char = await get_character(char.name)
                except NetworkError:
                    await ctx.send(
                        "I'm having network troubles, please try again.")
                    return
            if char.deleted is not None:
                skipped.append(char)
                continue
            added.append(char)

        if len(skipped) == len(chars):
            await ctx.send(
                f"Sorry, I couldn't find any characters in **{world}**.")
            return

        reply = ""
        log_reply = dict().fromkeys([server.id for server in target_guilds],
                                    "")
        if len(existent) > 0:
            reply += "\nThe following characters were already registered to @{1}: {0}" \
                .format(join_list(existent, ", ", " and "), target.display_name)

        if len(added) > 0:
            reply += "\nThe following characters were added to @{1.display_name}: {0}" \
                .format(join_list(["{0.name} ({0.world})".format(c) for c in added], ", ", " and "), target)
            for char in added:
                log.info(
                    "{2.display_name} registered character {0} was assigned to {1.display_name} (ID: {1.id})"
                    .format(char.name, target, user))
                # Announce on server log of each server
                for guild in target_guilds:
                    _guild = "No guild" if char.guild is None else char.guild_name
                    log_reply[
                        guild.
                        id] += "\n\t{1.name} - {1.level} {1.vocation} - **{0}**".format(
                            _guild, char)

        if len(updated) > 0:
            reply += "\nThe following characters were reassigned to @{1.display_name}: {0}" \
                .format(join_list(["{name} ({world})".format(**c) for c in updated], ", ", " and "), target)
            for char in updated:
                log.info(
                    "{2.display_name} reassigned character {0} to {1.display_name} (ID: {1.id})"
                    .format(char['name'], target, user))
                # Announce on server log of each server
                for guild in target_guilds:
                    log_reply[guild.id] += "\n\t{name} (Reassigned)".format(
                        **char)

        for char in updated:
            with userDatabase as conn:
                conn.execute("UPDATE chars SET user_id = ? WHERE name LIKE ?",
                             (user.id, char['name']))
        for char in added:
            with userDatabase as conn:
                conn.execute(
                    "INSERT INTO chars (name,level,vocation,user_id, world, guild) VALUES (?,?,?,?,?,?)",
                    (char.name, char.level * -1, char.vocation, user.id,
                     char.world, char.guild_name))

        with userDatabase as conn:
            conn.execute(
                "INSERT OR IGNORE INTO users (id, name) VALUES (?, ?)", (
                    user.id,
                    user.display_name,
                ))
            conn.execute("UPDATE users SET name = ? WHERE id = ?", (
                user.display_name,
                user.id,
            ))

        await ctx.send(reply)
        for server_id, message in log_reply.items():
            if message:
                message = f"{user.mention} registered the following characters to {target.mention}" + message
                await self.bot.send_log_message(self.bot.get_guild(server_id),
                                                message)