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)
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
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
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)
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)