async def _twoslot_pob(self, equip, item_type): embed = Embed(color=self.bot.user_color) ##print(equip) try: if f'{item_type} 1' in equip and f'{item_type} 2' in equip: rwp1 = utils.ItemRender( equip[f'{item_type} 1']['object'].rarity) wp1 = rwp1.render(equip[f'{item_type} 1']['object']) rwp2 = utils.ItemRender( equip[f'{item_type} 2']['object'].rarity) wp2 = rwp2.render(equip[f'{item_type} 2']['object']) box = list(wp1.size) if wp2.size[1] > box[1]: box[1] = wp2.size[1] box[0] = box[0] + wp2.size[0] + 2 img = Image.new('RGBA', box, color='black') img.paste(wp1.convert('RGBA'), box=(0, 0)) img.paste(wp2.convert('RGBA'), box=(wp1.size[0] + 2, 0)) else: wp_n = f'{item_type} 1' if f'{item_type} 1' in equip else f'{item_type} 2' rwp = utils.ItemRender(equip[wp_n]['object'].rarity) img = rwp.render(equip[wp_n]['object']) image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) file = File(image_fp, filename=f'{item_type.lower()}.png') slot_list = [] if f'{item_type} 1' in equip and 'gems' in equip[f'{item_type} 1']: slot_list.append(f'{item_type} 1') if f'{item_type} 2' in equip and 'gems' in equip[f'{item_type} 2']: slot_list.append(f'{item_type} 2') for slot in slot_list: val_list = [] for gem in equip[slot]['gems']: val_list.append( f" ㆍ {gem['level']}/{gem['quality']} {gem['name']}") embed.add_field(name=f"{slot} Gems", value='\n'.join(val_list), inline=True) return {'file': file, 'embed': embed} except KeyError: return None
async def _oneslot_pob(self, equip, itemtype): embed = Embed(color=self.bot.user_color) if itemtype in equip: wp_n = itemtype rwp = utils.ItemRender(equip[wp_n]['object'].rarity) img = rwp.render(equip[wp_n]['object']) image_fp = BytesIO() img.save(image_fp, 'png') #print(image_fp.tell()) image_fp.seek(0) file = File(image_fp, filename=f"{itemtype.lower().replace(' ','')}.png") # upload = await self.bot.dump_channel.send(file=file) # embed.set_image(url=upload.attachments[0].url) #print(equip[wp_n]) if 'gems' in equip[wp_n] and equip[wp_n]['gems']: val_list = [] for gem in equip[wp_n]['gems']: val_list.append( f" - {gem['level']}/{gem['quality']} {gem['name']}") value = '\n'.join(val_list) embed.add_field(name=f"{wp_n} Gems", value=value, inline=True) return {'file': file, 'embed': embed} else: return None
async def _twoslot_pob(self, equip, itemtype): embed = Embed(color=self.bot.user_color) if f'{itemtype} 1' in equip or f'{itemtype} 2' in equip: if f'{itemtype} 1' in equip and f'{itemtype} 2' in equip: rwp1 = utils.ItemRender( equip[f'{itemtype} 1']['object'].rarity) wp1 = rwp1.render(equip[f'{itemtype} 1']['object']) rwp2 = utils.ItemRender( equip[f'{itemtype} 2']['object'].rarity) wp2 = rwp2.render(equip[f'{itemtype} 2']['object']) box = list(wp1.size) if wp2.size[1] > box[1]: box[1] = wp2.size[1] box[0] = box[0] + wp2.size[0] + 2 img = Image.new('RGBA', box, color='black') img.paste(wp1.convert('RGBA'), box=(0, 0)) img.paste(wp2.convert('RGBA'), box=(wp1.size[0] + 2, 0)) else: wp_n = f'{itemtype} 1' if f'{itemtype} 1' in equip else f'{itemtype} 2' rwp = utils.ItemRender(equip[wp_n]['object'].rarity) img = rwp.render(equip[wp_n]['object']) image_fp = BytesIO() img.save(image_fp, 'png') #img.show() #print(image_fp.tell()) image_fp.seek(0) file = File(image_fp, filename=f'{itemtype.lower()}.png') # upload = await self.bot.dump_channel.send(file=file) # embed.set_image(url=upload.attachments[0].url) slot_list = [] if f'{itemtype} 1' in equip and 'gems' in equip[f'{itemtype} 1']: slot_list.append(f'{itemtype} 1') if f'{itemtype} 2' in equip and 'gems' in equip[f'{itemtype} 2']: slot_list.append(f'{itemtype} 2') for slot in slot_list: val_list = [] for gem in equip[slot]['gems']: val_list.append( f" - {gem['level']}/{gem['quality']} {gem['name']}") value = '\n'.join(val_list) embed.add_field(name=f"{slot} Gems", value=value, inline=True) return {'file': file, 'embed': embed} else: return None
async def link(self, ctx): """ Link items decorated with [[]] in chat """ item_matches = self.re.findall(ctx.message.content) if not item_matches: return tasks = [] print(item_matches) for item in item_matches[:5]: tasks.append(self.bot.loop.run_in_executor(None, find_one, item.strip('[[').strip(']]'), self.client, self.bot.loop)) results = await asyncio.gather(*tasks) results = [x for x in results if x] images = [] for result in results: if result.base == "Prophecy": flavor = 'prophecy' elif 'gem' in result.tags: flavor = 'gem' print(result.vendors) else: flavor = result.rarity r = utils.ItemRender(flavor) images.append(r.render(result)) if len(images) > 1: box = [0, 0] for image in images: box[0] = box[0] + image.size[0] if image.size[1] > box[1]: box[1] = image.size[1] box[0] = box[0] + (2*len(images)) img = Image.new('RGBA', box, color='black') #img.show() paste_coords = [0, 0] for image in images: #image.show() img.paste(image.convert('RGBA'), box=paste_coords[:]) paste_coords[0] = paste_coords[0] + image.size[0] + 2 else: img = images[0] image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) print("Image ready") await ctx.channel.send(file=File(image_fp, filename='image.png'))
async def convert(self, ctx): """ Convert an item copied from PoB or PoETradeMacro to the Zana version """ # Put my PoB item parser to good use try: pob_item = utils.parse_pob_item(ctx.message.content) except: print(ctx.message.content) return d = {} print(pob_item) await self.bot.loop.run_in_executor(None, utils._get_wiki_base, pob_item, d, self.client, "Chat Item") #print(d) #print(d['Chat Item'].energy_shield) #utils.modify_base_stats(d['Chat Item']) #print(d['Chat Item'].energy_shield) renderer = utils.ItemRender(d['Chat Item'].rarity) img = renderer.render(d['Chat Item']) image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) file = File(image_fp, filename=f"converted.png") upload = await self.bot.dump_channel.send(file=file) em = Embed() em.set_author(name=f"{ctx.author.name}#{ctx.author.discriminator}", icon_url=ctx.author.avatar_url) em.set_image(url=upload.attachments[0].url) try: await ctx.send(embed=em) except: try: await ctx.send( f"**{ctx.author.name}#{ctx.author.discriminator}**:\n", file=file) except: await ctx.error("`Attach Files` permission required", delete_after=2)
async def _oneslot_pob(self, equip, item_type): embed = Embed(color=self.bot.user_color) try: wp_n = item_type ##print(equip[wp_n], wp_n) rwp = utils.ItemRender(equip[wp_n]['object'].rarity) img = rwp.render(equip[wp_n]['object']) image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) file = File(image_fp, filename=f"{item_type.lower().replace(' ', '')}.png") if 'gems' in equip[wp_n] and equip[wp_n]['gems']: val_list = [] for gem in equip[wp_n]['gems']: val_list.append( f" ㆍ {gem['level']}/{gem['quality']} {gem['name']}") value = '\n'.join(val_list) embed.add_field(name=f"{wp_n} Gems", value=value, inline=True) return {'file': file, 'embed': embed} except KeyError: return None
async def poe(self, ctx, *, item: str): """Search for and post a POE <item> image""" item = Client().find_items({'_pageName': f'%{item}%'}, limit=1) if not item: return result = item[0] if result.base == "Prophecy": flavor = 'prophecy' elif 'gem' in result.tags: flavor = 'gem' # do some meta stufff here maybe? elif 'divination_card' in result.tags: flavor = 'unique' # possibly needs more here else: flavor = result.rarity r = poeutils.ItemRender(flavor) image = r.render(result) image_fp = BytesIO() image.save(image_fp, 'png') image_fp.seek(0) await ctx.send(file=discord.File(image_fp, result.name + ".png"))
async def roll(self, ctx, *, item: str = None): """ 'Divine' any Unique item and test your luck! """ if not item: return await ctx.error( "The correct format to use `roll` is\n`@Zana roll <itemname>`") unique = await self.bot.loop.run_in_executor(None, find_one, item, self.client) unique = copy.copy(unique) if not unique: return await ctx.error(f"Couldn't find {item} on the wiki!") if unique.rarity.lower() != 'unique': return await ctx.error("You can only roll unique items!") base = await self.bot.loop.run_in_executor(None, find_one, unique.base, self.client) base = copy.copy(base) implicits = utils.unescape_to_list(unique.implicits) explicits = utils.unescape_to_list(unique.explicits) decided_implicits = [] decided_explicits = [] for implicit in implicits: if '(' in implicit and ')' in implicit and 'hidden' not in implicit.lower( ): matches = self.pr_re.findall(implicit) match_dict = {} for match in matches: stat = match[1:-1] separator = stat.find('-', 1) range_start = stat[:separator] range_end = stat[separator + 1:] if '.' in range_start or '.' in range_end: randomized_stat = random.uniform( float(range_start), float(range_end)) else: randomized_stat = random.randint( int(range_start), int(range_end)) if randomized_stat == 0: continue match_dict[match] = randomized_stat new_impl = implicit for rep in match_dict: new_impl = new_impl.replace(rep, str(match_dict[rep])) if match_dict[rep] < 0: new_impl = new_impl.replace('+', '') new_impl = new_impl.replace('increased', 'reduced') if match_dict: decided_implicits.append(new_impl) else: decided_implicits.append(implicit) for explicit in explicits: if '(' in explicit and ')' in explicit and 'hidden' not in explicit.lower( ): matches = self.pr_re.findall(explicit) match_dict = {} for match in matches: stat = match[1:-1] separator = stat.find('-', 1) range_start = stat[:separator] range_end = stat[separator + 1:] if '.' in range_start or '.' in range_end: randomized_stat = random.uniform( float(range_start), float(range_end)) else: randomized_stat = random.randint( int(range_start), int(range_end)) if randomized_stat == 0: continue match_dict[match] = randomized_stat new_expl = explicit for rep in match_dict: new_expl = new_expl.replace(rep, str(match_dict[rep])) if match_dict[rep] < 0: new_expl = new_expl.replace('+', '') new_expl = new_expl.replace('increased', 'reduced') if match_dict: decided_explicits.append(new_expl) else: decided_explicits.append(explicit) escaped_implicits = '<br>'.join(decided_implicits) escaped_explicits = '<br>'.join(decided_explicits) base.implicits = escaped_implicits unique.implicits = escaped_implicits base.explicits = escaped_explicits unique.explicits = escaped_explicits try: utils.modify_base_stats(base) if 'weapon' in unique.tags: unique.attack_speed = base.attack_speed unique.critical_chance = base.critical_chance unique.range = base.range unique.fire_min = base.fire_min unique.fire_max = base.fire_max unique.cold_min = base.cold_min unique.cold_max = base.cold_max unique.lightning_min = base.lightning_min unique.lightning_max = base.lightning_max unique.chaos_min = base.chaos_min unique.chaos_max = base.chaos_max unique.physical_min = base.physical_min unique.physical_max = base.physical_max else: unique.armour = base.armour unique.evasion = base.evasion unique.energy_shield = base.energy_shield except Exception: pass renderer = utils.ItemRender('unique') img = renderer.render(unique) image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) try: f = File(image_fp, filename=f'image{round(time.time())}.png') await ctx.channel.send(file=f) except Exception: await ctx.error("`Attach Files` permission required")
async def convert(self, ctx): """ Convert an item copied from PoB or PoETradeMacro to the Zana version. """ # Put my PoB item parser to good use try: pob_item = utils.parse_pob_item(ctx.message.content) except: return d = {} await self.bot.loop.run_in_executor(None, utils._get_wiki_base, pob_item, d, self.client, "Chat Item") renderer = utils.ItemRender(d['Chat Item'].rarity) img = renderer.render(d['Chat Item']) image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) file = File(image_fp, filename=f"converted.png") upload = await self.bot.dump_channel.send(file=file) embed = Embed( description="*Click the reaction below for raw item text.*") embed.set_author(name=f"{ctx.author.name}#{ctx.author.discriminator}", icon_url=ctx.author.avatar_url) embed.set_image(url=upload.attachments[0].url) embed.set_footer( text= "Don't want your items converted? An admin can disable it using @Zana disable_conversion." ) try: embed_msg = await ctx.send(embed=embed) embed_id = embed_msg.id try: await ctx.message.delete() except Exception: #Funny thing is, error is an embed, if someone removes that perm, #the error doesn't go through as well await ctx.error("`Manage Messages` required to delete", delete_after=2) env_emoji = '📩' try: await embed_msg.add_reaction(env_emoji) except Exception: return def check(_payload): try: check_one = _payload.emoji == env_emoji check_two = _payload.message_id == embed_id check_thr = _payload.user_id != self.bot.user.id return all([check_one, check_two, check_thr]) except Exception: return False while True: payload = await self.bot.wait_for('raw_reaction_add', check=check) try: await embed_msg.remove_reaction(payload) except Exception: pass try: await user.send(f"```\n{ctx.message.content}\n```") except Exception: pass except Exception: try: await ctx.send( f"**{ctx.author.name}#{ctx.author.discriminator}**:\n", file=file) except Exception: await ctx.error("`Attach Files` permission required", delete_after=2) else: try: await ctx.message.delete() except Exception: await ctx.error("`Manage Messages` required to delete", delete_after=2)
async def link(self, ctx): """ Link items decorated with [[]] in chat. """ item_matches = self.br_re.findall(ctx.message.content) if not item_matches: return tasks = [] # Because my poe lib is actually completely blocking, i wrote a find_once func and # I just run instances of find_one in executor + gather ##print(item_matches) for item in item_matches[:5]: tasks.append( self.bot.loop.run_in_executor(None, find_one, item.strip('[[]]'), self.client)) results = await self._item_search(ctx, item_matches[:5]) print(results) images = [] meta = [] ##print(results) for result in results: if isinstance(result, dict): matches = result.get('matches') if matches and len(matches) < 2: ctx.message.content = f"[[{matches[0][0]}]]" self.bot.loop.create_task(self.link.invoke(ctx)) else: continue # TODO: clarify this statement if not isinstance(result, PassiveSkill): if result.base == "Prophecy": flavor = 'prophecy' elif 'gem' in result.tags: flavor = 'gem' dt = {'name': f"{result.name} vendors"} ven_str = "" for vendor in result.vendors: classes = "Available to all classes" if vendor[ 'classes'] == '' else vendor['classes'] siosa = True if vendor['act'] == '3' and vendor[ 'classes'] == '' else False ven_info = self.vendor_info[vendor[ 'act']] if not siosa else self.vendor_info['Siosa'] ven_str += f"**Act {vendor['act']}** ㆍ {classes} ㆍ {ven_info}\n" dt['value'] = ven_str meta.append(dt) elif 'divination_card' in result.tags: # Lib has a different render function for div cards as they don't fit the standard stats and sorting # method, might change in the future but would be extremely unneat code-wise. r = utils.ItemRender('unique') images.append(r.render_divcard(result)) try: reward = await self.bot.loop.run_in_executor( None, find_one, result.reward, self.client) if reward.base == "Prophecy": i_render = utils.ItemRender('prophecy') images.append(i_render.render(reward)) elif 'gem' in reward.tags: i_render = utils.ItemRender('gem') images.append(i_render.render(reward)) elif 'divination_card' in reward.tags: i_render = utils.ItemRender('unique') images.append(i_render.render_divcard(reward)) else: i_render = utils.ItemRender(reward.rarity) images.append(i_render.render(reward)) except Exception: pass if result.drop.areas: txt = '\n'.join([ f'\u2022 {x}' for x in result.drop.areas.split(',') ]) if len(txt) <= 1024: meta.append({ 'name': f"{result.name} Drop Locations", 'value': txt }) else: loc_list = result.drop.areas.split(',') txt = '\n'.join([ f'\u2022 {x}' for x in loc_list[:(len(loc_list) // 2) - 1] ]) txt += f"\n[...More](http://poewiki.net/wiki/{quote_plus(result.name).replace('+', '%20')})" meta.append({ 'name': f"{result.name} Drop Locations", 'value': txt }) continue else: flavor = result.rarity else: flavor = 'normal' if 'divination_card' not in result.tags: r = utils.ItemRender(flavor) images.append(r.render(result)) results = [x for x in results if not isinstance(x, dict)] ##print(results[0].implicits) ##print(results[0].explicits) # Stitch images together, traditionally 5 images tops, but as div cards can feature their reward as an image # Possible max images can be 10 # R.I.P that one time where we stitched headhunters for image width of 69700 if len(results) < 2 and isinstance(results[0], dict): return if len(images) > 1: box = [0, 0] for image in images: box[0] = box[0] + image.size[0] if image.size[1] > box[1]: box[1] = image.size[1] box[0] = box[0] + (2 * len(images)) img = Image.new('RGBA', box, color='black') paste_coords = [0, 0] for image in images: img.paste(image.convert('RGBA'), box=paste_coords[:]) paste_coords[0] = paste_coords[0] + image.size[0] + 2 else: img = images[0] image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) embed = Embed(color=self.bot.user_color) links = [] for item in results: links.append( f"\u2022 [{item.name}](http://poewiki.net/wiki/{quote_plus(item.name).replace('+', '%20')})" ) embed.add_field(name="Wiki Links", value='\n'.join(links)) embed.set_image(url="attachment://image.png") # Meta is basically only used for gems to show vendor info, might add more stuff later, good base to build on if meta: for m in meta: embed.add_field(name=m['name'], value=m['value'] or "None", inline=True) try: await ctx.channel.send(file=File(image_fp, filename='image.png'), embed=embed) except Exception: await ctx.error("`Attach Files` permission required", delete_after=2)
async def buy(self, ctx, *, item_plus_league: str = None): """ List the 3 lowest priced items with whisper and price info. """ verified_item, league = await self._search_api(ctx, item_plus_league) if isinstance(verified_item, dict): price = utils.item_price(verified_item['matches'][0][0], league) iname = verified_item['matches'][0][0] else: price = utils.item_price(verified_item.name, league) iname = verified_item.name lowest = price.lowest() tasks = [] for item in lowest: tasks.append( self.bot.loop.run_in_executor(None, utils.parse_poe_char_api, {'items': [item['item']]}, self.client, True)) results = await asyncio.gather(*tasks) files = {'files': [], 'indexes': []} sockets = {'sockets': [], 'indexes': []} for ind, item in enumerate(results): if not item['equipped']['items_objects']: continue if 'sockets' in lowest[ind]['item'] and lowest[ind]['item'][ 'sockets']: socks = {} for sock in lowest[ind]['item']['sockets']: if not sock['group'] in socks: socks[sock['group']] = [] socks[sock['group']].append(sock['sColour']) sock_strs = [] for val in socks.values(): sock_strs.append('-'.join(val)) sockets['sockets'].append('\n'.join(sock_strs)) sockets['indexes'].append(ind) result = item['equipped']['items_objects'] if not isinstance(result, PassiveSkill): if result.base == "Prophecy": flavor = 'prophecy' elif 'gem' in result.tags: flavor = 'gem' elif 'divination_card' in result.tags: # Lib has a different render function for div cards as they don't fit the standard stats and sorting # method, might change in the future but would be extremely unneat code-wise. r = utils.ItemRender('unique') img = r.render_divcard(result) else: flavor = result.rarity else: flavor = 'normal' if 'divination_card' not in result.tags: r = utils.ItemRender(flavor) img = r.render(result) image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) files['files'].append( File( image_fp, filename=f"{result.name.lower().replace(' ', '')}{ind}.png" )) files['indexes'].append(ind) if files: upload = await self.bot.dump_channel.send(files=files['files']) upload.attachments.reverse() else: upload = None embed_dict = dict.fromkeys(self.reaction_emojis[:-1]) price = ', '.join([ f"*{entry['listing']['price']['amount']} " f"{entry['listing']['price']['currency']}*" for entry in lowest ]) sockets['sockets'].reverse() for ind, react in enumerate(embed_dict): embed = Embed(title=f"Lowest 3 Listings for {iname}", description=f"Prices: {price}", color=self.bot.user_color) try: if ind in files['indexes']: embed.set_image(url=upload.attachments.pop().url) except (IndexError, AttributeError): pass embed.add_field( name="Price", value=f"{lowest[ind]['listing']['price']['amount']} " f"{lowest[ind]['listing']['price']['currency']}") if ind in sockets['indexes']: embed.add_field(name="Sockets", value=sockets['sockets'].pop()) embed.add_field(name="Whisper", value=f"`{lowest[ind]['listing']['whisper']}`") embed_dict[react] = embed await responsive_embed(self.bot, embed_dict, ctx, timeout=60 * 5, use_dict_emojis=True)
async def link(self, ctx): """ Link items decorated with [[]] in chat """ item_matches = self.re.findall(ctx.message.content) if not item_matches: return tasks = [] print(item_matches) # Because my poe lib is actually completely blocking, i wrote a find_once func and # I just run instances of find_ones in executor + gather for item in item_matches[:5]: tasks.append( self.bot.loop.run_in_executor( None, find_one, f"{item.strip('[[').strip(']]')}", self.client, self.bot.loop)) results = await asyncio.gather(*tasks) # Results are returned as None for invalid items from find_one, so remove None-s results = [x for x in results if x] new_selections = [] for result in results: if isinstance(result, dict): if len(result['matches']) and len(result['matches']) > 2: em = Embed( title="Item not found", description= f"""Couldn't find anything for *"{result['name']}"*, did you mean:\n """ + "\n".join(f'\u2022 *{x[0]}*' for x in result['matches'])) msg = await ctx.channel.send(embed=em) def check(reaction, user): try: return reaction.emoji in self.reaction_emojis \ and reaction.message.id == msg.id \ and user.id != self.bot.user.id except: return False for emoji in self.reaction_emojis: await msg.add_reaction(emoji) try: reaction, user = await self.bot.wait_for( 'reaction_add', check=check, timeout=20) except asyncio.TimeoutError: return await msg.delete() if reaction.emoji == self.reaction_emojis[-1]: return await msg.delete() new_selections.append( result['matches'][self.reaction_emojis.index( reaction.emoji)][0]) await msg.delete() tasks = [] print(new_selections) for new in new_selections: tasks.append( self.bot.loop.run_in_executor(None, find_one, new, self.client, self.bot.loop)) new_results = await asyncio.gather(*tasks) results.extend(new_results) images = [] meta = [] print(results) for result in results: if isinstance(result, dict): if len(result['matches']) and len(result['matches']) < 2: ctx.message.content = f"[[{result['matches'][0][0]}]]" self.bot.loop.create_task(self.link.invoke(ctx)) else: continue if not isinstance(result, PassiveSkill): if result.base == "Prophecy": flavor = 'prophecy' elif 'gem' in result.tags: flavor = 'gem' print(result.vendors) dt = {'name': f"{result.name} vendors"} venstr = "" for vendor in result.vendors: classes = "Available to all classes" if vendor[ 'classes'] == '' else vendor['classes'] siosa = True if vendor['act'] == '3' and vendor[ 'classes'] == '' else False venstr += f"**Act {vendor['act']}** - {classes} - " \ f"{self.vendor_info[vendor['act']] if not siosa else self.vendor_info['Siosa']}\n" dt['value'] = venstr meta.append(dt) elif 'divination_card' in result.tags: # Lib has a different render function for div cards as they don't fit the standard stats and sorting # method, might change in the future but would be extremely unneat code-wise. r = utils.ItemRender('unique') images.append(r.render_divcard(result)) try: reward = await self.bot.loop.run_in_executor( None, find_one, result.reward, self.client, self.bot.loop) if reward.base == "Prophecy": i_render = utils.ItemRender('prophecy') images.append(i_render.render(reward)) elif 'gem' in reward.tags: i_render = utils.ItemRender('gem') images.append(i_render.render(reward)) elif 'divination_card' in reward.tags: i_render = utils.ItemRender('unique') images.append(i_render.render_divcard(reward)) else: i_render = utils.ItemRender(reward.rarity) images.append(i_render.render(reward)) except: pass if result.drop.areas: meta.append({ 'name': f"{result.name} Drop Locations", 'value': '\n'.join([ f'\u2022 {x}' for x in result.drop.areas.split(',') ]) }) continue else: flavor = result.rarity else: flavor = 'normal' if 'divination_card' not in result.tags: r = utils.ItemRender(flavor) images.append(r.render(result)) results = [x for x in results if not isinstance(x, dict)] # Stitch images together, traditionally 5 images tops, but as div cards can feature their reward as an image # Possible max images can be 10 # R.I.P that one time where we stitched headhunters for image width of 69700 if len(results) < 2 and isinstance(results[0], dict): return if len(images) > 1: box = [0, 0] for image in images: box[0] = box[0] + image.size[0] if image.size[1] > box[1]: box[1] = image.size[1] box[0] = box[0] + (2 * len(images)) img = Image.new('RGBA', box, color='black') #img.show() paste_coords = [0, 0] for image in images: #image.show() img.paste(image.convert('RGBA'), box=paste_coords[:]) paste_coords[0] = paste_coords[0] + image.size[0] + 2 else: img = images[0] image_fp = BytesIO() img.save(image_fp, 'png') image_fp.seek(0) print("Image ready") em = Embed(color=self.bot.user_color) links = [] for item in results: links.append( f"\u2022 [{item.name}](http://pathofexile.gamepedia.com/{quote_plus(item.name).replace('+','%20')})" ) em.add_field(name="Wiki Links", value='\n'.join(links)) em.set_image(url="attachment://image.png") # Meta basically only used for gems to show vendor info, might add more stuff later, good base to build on if meta: for m in meta: em.add_field(name=m['name'], value=m['value'] or "None", inline=True) try: await ctx.channel.send(file=File(image_fp, filename='image.png'), embed=em) except: await ctx.error("`Attach Files` permission required", delete_after=2)