async def achievement(self, ctx: NabCtx, *, name: str): """Displays an achievement's information. Shows the achievement's grade, points, description, and instructions on how to unlock.""" permissions = ctx.bot_permissions if not permissions.embed_links: await ctx.send( "Sorry, I need `Embed Links` permission for this command.") return achievement = get_achievement(name) if achievement is None: await ctx.send("I couldn't find an achievement with that name.") return if type(achievement) is list: name = await ctx.choose(achievement) if name is None: return achievement = get_achievement(name) embed = discord.Embed(title=achievement["name"], description=achievement["description"], url=get_article_url(achievement["name"])) embed.set_author(name="TibiaWiki", icon_url=WIKI_ICON, url=get_article_url(achievement["name"])) embed.add_field(name="Grade", value="⭐" * int(achievement["grade"])) embed.add_field(name="Points", value=achievement["points"]) embed.add_field(name="Spoiler", value=achievement["spoiler"], inline=True) await ctx.send(embed=embed)
def get_key_embed(key): if key is None: return None embed = discord.Embed(title=f"Key {key['number']:04}", url=get_article_url(f"Key {key['number']:04}")) embed.set_author(name="TibiaWiki", icon_url=WIKI_ICON, url=get_article_url(f"Key {key['number']:04}")) if key.get("name") is not None: embed.description = f"**Also known as:** {key['name']}" if key.get("location") is not None: embed.add_field(name="Location", value=key["location"]) if key.get("origin") is not None: embed.add_field(name="Origin", value=key["origin"]) if key.get("notes") is not None: embed.add_field(name="Notes/Use", value=key["notes"]) return embed
async def achievement(self, ctx, *, name: str = None): """Shows an achievement's information Shows the achievement's grade, points, description, and instructions on how to unlock.""" permissions = ctx.channel.permissions_for(ctx.me) if not permissions.embed_links: await ctx.send( "Sorry, I need `Embed Links` permission for this command.") return if name is None: await ctx.send( "Tell me the name of the achievement you want to check.") return achievement = get_achievement(name) if achievement is None: await ctx.send("I couldn't find an achievement with that name.") return if type(achievement) is list: embed = discord.Embed(title="Suggestions", description="\n".join(achievement)) await ctx.send( "I couldn't find that achievement, maybe you meant one of these?", embed=embed) return embed = discord.Embed(title=achievement["name"], description=achievement["description"], url=get_article_url(achievement["name"])) embed.set_author(name="TibiaWiki", icon_url=WIKI_ICON, url=get_article_url(achievement["name"])) embed.add_field(name="Grade", value=EMOJI[":star:"] * int(achievement["grade"])) embed.add_field(name="Points", value=achievement["points"]) embed.add_field(name="Spoiler", value=achievement["spoiler"], inline=True) await ctx.send(embed=embed)
def get_npc_embed(ctx, npc, long): """Gets the embed to show in /npc command""" short_limit = 5 long_limit = 100 too_long = False if type(npc) is not dict: return embed = discord.Embed(title=npc["name"], url=get_article_url(npc["title"])) embed.set_author(name="TibiaWiki", icon_url=WIKI_ICON, url=get_article_url(npc["title"])) embed.add_field(name="Job", value=npc["job"]) if npc["name"] == "Rashid": rashid = get_rashid_info() npc["city"] = rashid["city"] npc["x"] = rashid["x"] npc["y"] = rashid["y"] npc["z"] = rashid["z"] if npc["name"] == "Yasir": npc["x"] = None npc["y"] = None npc["z"] = None embed.add_field(name="City", value=npc["city"]) if npc["selling"]: count = 0 value = "" for item in npc["selling"]: count += 1 item["currency"] = item["currency"].replace( "gold coin", "gold") value += "\n{name} \u2192 {value:,} {currency}".format(**item) if count > short_limit and not long: value += "\n*...And {0} others*".format( len(npc['selling']) - short_limit) too_long = True break if long and count > long_limit: value += "\n*...And {0} others*".format( len(npc['selling']) - long_limit) break split_selling = split_message(value, FIELD_VALUE_LIMIT) for value in split_selling: if value == split_selling[0]: name = "Selling" else: name = "\u200F" embed.add_field(name=name, value=value) if npc["buying"]: count = 0 value = "" for item in npc["buying"]: count += 1 item["currency"] = item["currency"].replace( "gold coin", "gold") value += "\n{name} \u2192 {value:,} {currency}".format(**item) if count > short_limit and not long: value += "\n*...And {0} others*".format( len(npc['buying']) - short_limit) too_long = True break if long and count > long_limit: value += "\n*...And {0} others*".format( len(npc['buying']) - long_limit) break split_buying = split_message(value, FIELD_VALUE_LIMIT) for value in split_buying: if value == split_buying[0]: name = "Buying" else: name = "\u200F" embed.add_field(name=name, value=value) if npc["destinations"]: count = 0 value = "" for destination in npc["destinations"]: count += 1 value += "\n{name} \u2192 {price} gold".format(**destination) embed.add_field(name="Destinations", value=value) vocs = ["knight", "sorcerer", "paladin", "druid"] if npc["spells"]: values = {} count = {} skip = {} for spell in npc["spells"]: value = "\n{name} \u2014 {price:,} gold".format(**spell) for voc in vocs: if skip.get(voc, False): continue if spell[voc] == 0: continue values[voc] = values.get(voc, "") + value count[voc] = count.get(voc, 0) + 1 if count.get(voc, 0) >= short_limit and not long: values[voc] += "\n*...And more*" too_long = True skip[voc] = True for voc, content in values.items(): fields = split_message(content, FIELD_VALUE_LIMIT) for i, split_field in enumerate(fields): name = f"Teaches ({voc.title()}s)" if i == 0 else "\u200F" embed.add_field(name=name, value=split_field, inline=not len(fields) > 1) 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
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
def get_item_embed(ctx, item, long): """Gets the item embed to show in /item command""" short_limit = 5 long_limit = 40 npcs_too_long = False drops_too_long = False quests_too_long = False def adjust_city(name, city): name = name.lower() if name == 'alesar' or name == 'yaman': return "Green Djinn's Fortress" elif name == "nah'bob" or name == "haroun": return "Blue Djinn's Fortress" elif name == 'rashid': return get_rashid_info()["city"] elif name == 'Yasir': return 'his boat' return city embed = discord.Embed(title=item["title"], description=item["flavor_text"], url=get_article_url(item["title"])) embed.set_author(name="TibiaWiki", icon_url=WIKI_ICON, url=get_article_url(item["title"])) properties = f"Weight: {item['weight']} oz" for attribute, value in item["attributes"].items(): if attribute in ["imbuements"]: continue if attribute == "vocation": value = ", ".join(value.title().split("+")) properties += f"\n{attribute.replace('_',' ').title()}: {value}" embed.add_field(name="Properties", value=properties) if "imbuements" in item["attributes"] and len( item["attributes"]["imbuements"]) > 0: embed.add_field(name="Used for", value="\n".join(item["attributes"]["imbuements"])) if item["sellers"]: item_value = 0 currency = "" count = 0 value = "" for i, npc in enumerate(item["sellers"]): if i == 0: item_value = npc["value"] currency = npc["currency"] if npc["value"] != item_value: break npc["city"] = adjust_city(npc["name"], npc["city"]) value += "\n{name} ({city})".format(**npc) count += 1 if count > short_limit and not long: value += "\n*...And {0} others*".format( len(item['sellers']) - short_limit) npcs_too_long = True break embed.add_field(name=f"Sold for {item_value:,} {currency} by", value=value) if item["buyers"]: item_price = 0 currency = "" count = 0 value = "" for i, npc in enumerate(item["buyers"]): if i == 0: item_price = npc["value"] currency = npc["currency"] if npc["value"] != item_price: break npc["city"] = adjust_city(npc["name"], npc["city"]) name = npc["name"].lower() if name == 'alesar' or name == 'yaman': embed.colour = Colour.green() elif name == "nah'bob" or name == "haroun": embed.colour = Colour.blue() elif name == 'rashid': embed.colour = Colour(0xF0E916) elif name == 'briasol': embed.colour = Colour(0xA958C4) value += "\n{name} ({city})".format(**npc) count += 1 if count > short_limit and not long: value += "\n*...And {0} others*".format( len(item['buyers']) - short_limit) npcs_too_long = True break embed.add_field(name=f"Bought for {item_price:,} {currency} by", value=value) if item["quests_reward"]: value = "" count = 0 name = "Awarded in" for quest in item["quests_reward"]: count += 1 value += "\n" + quest["name"] if count >= short_limit and not long: value += "\n*...And {0} others*".format( len(item["quests_reward"]) - short_limit) quests_too_long = True break embed.add_field(name=name, value=value) if item["loot_from"]: name = "Dropped by" count = 0 value = "" for creature in item["loot_from"]: count += 1 if creature["chance"] is None: creature["chance"] = "??.??%" elif creature["chance"] >= 100: creature["chance"] = "Always" else: creature["chance"] = f"{creature['chance']:05.2f}%" value += "\n`{chance} {name}`".format(**creature) if count >= short_limit and not long: value += "\n*...And {0} others*".format( len(item["loot_from"]) - short_limit) drops_too_long = True break if long and count >= long_limit: value += "\n*...And {0} others*".format( len(item["loot_from"]) - long_limit) break embed.add_field(name=name, value=value, inline=not long) if npcs_too_long or drops_too_long or quests_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
def get_monster_embed(ctx, monster, long): """Gets the monster embeds to show in /mob command The message is split in two embeds, the second contains loot only and is only shown if long is True""" embed = discord.Embed(title=monster["title"], url=get_article_url(monster["title"])) embed.set_author(name="TibiaWiki", icon_url=WIKI_ICON, url=get_article_url(monster["title"])) hp = "?" if monster["hitpoints"] is None else "{0:,}".format( monster["hitpoints"]) experience = "?" if monster["experience"] is None else "{0:,}".format( monster["experience"]) if not (monster["experience"] is None or monster["hitpoints"] is None or monster["hitpoints"] < 0): ratio = "{0:.2f}".format(monster['experience'] / monster['hitpoints']) else: ratio = "?" embed.add_field(name="HP", value=hp) embed.add_field(name="Experience", value=experience) embed.add_field(name="HP/Exp Ratio", value=ratio) weak = [] resist = [] immune = [] elements = [ "physical", "holy", "death", "fire", "ice", "energy", "earth", "drown", "lifedrain" ] # Iterate through elemental types for index, value in monster.items(): if index in elements: if monster[index] is None: continue if monster[index] == 0: immune.append(index.title()) elif monster[index] > 100: weak.append([index.title(), monster[index] - 100]) elif monster[index] < 100: resist.append([index.title(), monster[index] - 100]) # Add paralysis to immunities if monster["paralysable"] == 0: immune.append("Paralysis") if monster["see_invisible"] == 1: immune.append("Invisibility") if immune: embed.add_field(name="Immune to", value="\n".join(immune)) else: embed.add_field(name="Immune to", value="Nothing") if resist: embed.add_field(name="Resistant to", value="\n".join( ["{1}% {0}".format(*i) for i in resist])) else: embed.add_field(name="Resistant to", value="Nothing") if weak: embed.add_field(name="Weak to", value="\n".join( ["+{1}% {0}".format(*i) for i in weak])) else: embed.add_field(name="Weak to", value="Nothing") # If monster drops no loot, we might as well show everything if long or not monster["loot"]: embed.add_field( name="Max damage", value="{max_damage:,}".format( **monster) if monster["max_damage"] is not None else "???") embed.add_field(name="Abilities", value=monster["abilities"], inline=False) if monster["loot"] and long: loot_string = "" for item in monster["loot"]: if item["chance"] is None: item["chance"] = "??.??%" elif item["chance"] >= 100: item["chance"] = "Always" else: item["chance"] = "{0:05.2f}%".format(item['chance']) if item["max"] > 1: item["count"] = "({min}-{max})".format(**item) else: item["count"] = "" loot_string += "{chance} {item} {count}\n".format(**item) split_loot = split_message(loot_string, FIELD_VALUE_LIMIT) for loot in split_loot: if loot == split_loot[0]: name = "Loot" else: name = "\u200F" embed.add_field(name=name, value="`" + loot + "`") if monster["loot"] and not 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
def get_imbuement_embed(ctx: NabCtx, imbuement, long, prices): """Gets the item embed to show in /item command""" embed = discord.Embed(title=imbuement["name"], url=get_article_url(imbuement["name"])) embed.set_author(name="TibiaWiki", icon_url=WIKI_ICON, url=get_article_url(imbuement["name"])) embed.add_field(name="Effect", value=imbuement["effect"]) materials = "" if not prices: embed.set_footer( text=f"Provide material prices to calculate costs." f" More info: {ctx.clean_prefix}help {ctx.invoked_with}") elif len(prices) < len(imbuement["materials"]): embed.set_footer( text="Not enough material prices provided for this tier.") prices = [] for i, material in enumerate(imbuement["materials"]): price = "" if prices: price = f" ({prices[i]:,} gold each)" materials += "\nx{amount} {name}{price}".format(**material, price=price) if prices: fees = [5000, 25000, 100000] # Gold fees for each tier fees_100 = [15000, 55000, 150000] # Gold fees for each tier with 100% chance tiers = {"Basic": 0, "Intricate": 1, "Powerful": 2} # Tiers order tokens = [2, 4, 6] # Token cost for materials of each tier tier = tiers[imbuement["tier"]] # Current tier token_imbuements = [ "Vampirism", "Void", "Strike" ] # Imbuements that can be bought with gold tokens tier_prices = [] # The total materials cost for each tier materials_cost = 0 # The cost of all materials for the current tier for m, p in zip(imbuement["materials"], prices): materials_cost += m["amount"] * p tier_prices.append(materials_cost) def parse_prices(_tier: int, _materials: int): return f"**Materials:** {_materials:,} gold.\n" \ f"**Total:** {_materials+fees[_tier]:,} gold | " \ f"{(_materials+fees[_tier])/20:,.0f} gold/hour\n" \ f"**Total (100% chance):** {_materials+fees_100[_tier]:,} gold | " \ f"{(_materials+fees_100[_tier])/20:,.0f} gold/hour" # If no gold token price was provided or the imbuement type is not applicable, just show material cost if len(prices) - 1 <= tier or imbuement[ "type"] not in token_imbuements: embed.add_field(name="Materials", value=materials) embed.add_field(name="Cost", value=parse_prices(tier, materials_cost), inline=False) if imbuement["type"] in token_imbuements: embed.set_footer( text= "Add gold token price at the end to find the cheapest option." ) return embed token_price = prices[tier + 1] # Gold token's price possible_tokens = "2" if tokens[tier] == 2 else f"2-{tokens[tier]}" embed.add_field( name="Materials", value=f"{materials}\n――――――\n" f"{possible_tokens} Gold Tokens ({token_price:,} gold each)") token_cost = 0 # The total cost of the part that will be bought with tokens cheapeast_tier = -1 # The tier which materials are more expensive than gold tokens. for i in range(tier + 1): _token_cost = token_price * tokens[i] if _token_cost < tier_prices[i]: token_cost = _token_cost cheapeast_tier = i # Using gold tokens is never cheaper. if cheapeast_tier == -1: embed.add_field(name="Cost", value=f"Getting the materials is cheaper.\n\n" f"{parse_prices(tier, materials_cost)}", inline=False) # Buying everything with gold tokens is cheaper elif cheapeast_tier == tier: embed.add_field( name="Cost", value= f"Getting all materials with gold tokens is cheaper.\n\n" f"{parse_prices(tier, token_cost)}", inline=False) else: total_cost = token_cost + tier_prices[ cheapeast_tier + 1] - tier_prices[cheapeast_tier] embed.add_field( name="Cost", value= f"Getting the materials for **{list(tiers.keys())[cheapeast_tier]} " f"{imbuement['type']}** with gold tokens and buying the rest is " f"cheaper.\n\n{parse_prices(tier, total_cost)}", inline=False) else: embed.add_field(name="Materials", value=materials) return embed
def get_monster_embed(ctx: NabCtx, monster, long): """Gets the monster embeds to show in /mob command The message is split in two embeds, the second contains loot only and is only shown if long is True""" embed = discord.Embed(title=monster["title"], url=get_article_url(monster["title"])) embed.set_author(name="TibiaWiki", icon_url=WIKI_ICON, url=get_article_url(monster["title"])) hp = "?" if monster["hitpoints"] is None else "{0:,}".format( monster["hitpoints"]) experience = "?" if monster["experience"] is None else "{0:,}".format( monster["experience"]) speed = "?" if monster["speed"] is None else "{0:,}".format( monster["speed"]) embed.description = f"**HP** {hp} | **Exp** {experience} | **Speed** {speed}" attributes = { "summon": "Summonable", "convince": "Convinceable", "illusionable": "Illusionable", "pushable": "Pushable", "paralysable": "Paralysable", "see_invisible": "Sees Invisible" } attributes = "\n".join([ f"{ctx.tick(monster[x])} {repl}" for x, repl in attributes.items() if monster[x] is not None ]) embed.add_field(name="Attributes", value="Unknown" if not attributes else attributes) elements = [ "physical", "holy", "death", "fire", "ice", "energy", "earth" ] # Iterate through elemental types elemental_modifiers = {} for element in elements: if monster[element] is None or monster[element] == 100: continue elemental_modifiers[element] = monster[element] - 100 elemental_modifiers = dict( sorted(elemental_modifiers.items(), key=lambda x: x[1])) if elemental_modifiers: content = "" for element, value in elemental_modifiers.items(): if config.use_elemental_emojis: content += f"\n{config.elemental_emojis[element]} {value:+}%" else: content += f"\n{value:+}% {element.title()}" embed.add_field(name="Elemental modifiers", value=content) if monster["bestiary_class"] is not None: difficulties = { "Harmless": config.difficulty_off_emoji * 4, "Trivial": config.difficulty_on_emoji + config.difficulty_off_emoji * 3, "Easy": config.difficulty_on_emoji * 2 + config.difficulty_off_emoji * 2, "Medium": config.difficulty_on_emoji * 3 + config.difficulty_off_emoji, "Hard": config.difficulty_on_emoji * 4 } occurrences = { "Common": config.occurrence_on_emoji * 1 + config.occurrence_off_emoji * 3, "Uncommon": config.occurrence_on_emoji * 2 + config.occurrence_off_emoji * 2, "Rare": config.occurrence_on_emoji * 3 + config.occurrence_off_emoji * 1, "Very Rare": config.occurrence_on_emoji * 4, } kills = { "Harmless": 25, "Trivial": 250, "Easy": 500, "Medium": 1000, "Hard": 2500 } points = { "Harmless": 1, "Trivial": 5, "Easy": 15, "Medium": 25, "Hard": 50 } bestiary_info = monster['bestiary_class'] if monster["bestiary_level"] is not None: difficulty = difficulties.get( monster["bestiary_level"], f"({monster['bestiary_level']})") required_kills = kills[monster['bestiary_level']] given_points = points[monster['bestiary_level']] bestiary_info += f"\n{difficulty}" if monster["occurrence"] is not None: occurrence = occurrences.get(monster["occurrence"], f"") if monster['occurrence'] == 'Very Rare': required_kills = 5 given_points = max(points[monster['bestiary_level']] * 2, 5) bestiary_info += f"\n{occurrence}" if monster["bestiary_level"] is not None: bestiary_info += f"\n{required_kills:,} kills | {given_points}{config.charms_emoji}️" embed.add_field(name="Bestiary Class", value=bestiary_info) # If monster drops no loot, we might as well show everything if long or not monster["loot"]: embed.add_field( name="Max damage", value="{max_damage:,}".format( **monster) if monster["max_damage"] is not None else "???") embed.add_field(name="Abilities", value=monster["abilities"], inline=False) if monster["loot"] and long: loot_string = "" for item in monster["loot"]: if item["chance"] is None: item["chance"] = "??.??%" elif item["chance"] >= 100: item["chance"] = "Always" else: item["chance"] = "{0:05.2f}%".format(item['chance']) if item["max"] > 1: item["count"] = "({min}-{max})".format(**item) else: item["count"] = "" loot_string += "{chance} {item} {count}\n".format(**item) split_loot = split_message(loot_string, FIELD_VALUE_LIMIT - 20) for loot in split_loot: if loot == split_loot[0]: name = "Loot" else: name = "\u200F" embed.add_field(name=name, value="`" + loot + "`") if monster["loot"] and not long: ask_channel = ctx.ask_channel_name if ask_channel: askchannel_string = " or use #" + ask_channel else: askchannel_string = "" embed.set_footer( text="To see more, PM me{0}.".format(askchannel_string)) return embed