async def search(self, ctx: commands.Context, **flags): """Search pokémon from the marketplace.""" if flags["page"] < 1: return await ctx.send("Page must be positive!") aggregations = await self.bot.get_cog("Pokemon").create_filter( flags, ctx, order_by=flags["order"]) if aggregations is None: return # Filter pokemon def padn(p, idx, n): return " " * (len(str(n)) - len(str(idx))) + str(idx) num = await self.bot.mongo.fetch_market_count(aggregations=aggregations ) if num == 0: return await ctx.send("Found no pokémon matching this search.") async def get_page(pidx, clear): pgstart = pidx * 20 pokemon = await self.bot.mongo.fetch_market_list( pgstart, 20, aggregations=aggregations) pokemon = [( self.bot.mongo.EmbeddedPokemon.build_from_mongo(x["pokemon"]), x["_id"], x["price"], ) for x in pokemon] if len(pokemon) == 0: return await clear("There are no pokémon on this page!") maxn = max(idx for x, idx, price in pokemon) page = [ f"`{padn(p, idx, maxn)}` **{p:li}** • {p.iv_percentage * 100:.2f}% • {price:,} pc" for p, idx, price in pokemon ] # Send embed embed = self.bot.Embed(color=0xF44336) embed.title = f"Pokétwo Marketplace" embed.description = "\n".join(page)[:2048] embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 20, num)} out of {num}. (Page {pidx+1} of {math.ceil(num / 20)})" ) return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags["page"] - 1)
async def send_bot_help(self, mapping): ctx = self.context ctx.invoked_with = "help" bot = ctx.bot def get_category(command): cog = command.cog return cog.qualified_name if cog is not None else "\u200bNo Category" pages = [] total = 0 filtered = await self.filter_commands(bot.commands, sort=True, key=get_category) for cog_name, commands in itertools.groupby(filtered, key=get_category): commands = sorted(commands, key=lambda c: c.name) if len(commands) == 0: continue total += len(commands) cog = bot.get_cog(cog_name) description = ((cog and cog.description) if (cog and cog.description) is not None else discord.Embed.Empty) pages.append((cog, description, commands)) async def get_page(pidx, clear): cogs = pages[min(len(pages) - 1, pidx * 6):min(len(pages) - 1, pidx * 6 + 6)] embed = self.make_default_embed( cogs, title= f"Pokétwo Command Categories (Page {pidx+1}/{len(pages)//6+1})", description= (f"Use `{self.clean_prefix}help <command>` for more info on a command.\n" f"Use `{self.clean_prefix}help <category>` for more info on a category." ), ) # embed.set_author(name=f"Page {pidx + 1}/{len(pages)} ({total} commands)") return embed paginator = pagination.Paginator(get_page, len(pages) // 6 + 1) await paginator.send(bot, ctx, 0)
async def moveset(self, ctx: commands.Context, *, search: str): """View all moves for your pokémon and how to get them.""" search = search.strip() if len(search) > 0 and search[0] in "Nn#" and search[1:].isdigit(): species = self.bot.data.species_by_number(int(search[1:])) else: species = self.bot.data.species_by_name(search) if species is None: converter = converters.Pokemon(raise_errors=False) pokemon = await converter.convert(ctx, search) if pokemon is not None: species = pokemon.species if species is None: raise converters.PokemonConversionError( f"Please either enter the name of a pokémon species, nothing for your selected pokémon, a number for " f"a specific pokémon, `latest` for your latest pokémon. ", original=ValueError(), ) async def get_page(pidx, clear): pgstart = (pidx) * 20 pgend = min(pgstart + 20, len(species.moves)) # Send embed embed = discord.Embed(color=0xE67D23) embed.title = f"{species} — Moveset" embed.set_footer( text= f"Showing {pgstart + 1}–{pgend} out of {len(species.moves)}.") for move in species.moves[pgstart:pgend]: embed.add_field(name=move.move.name, value=move.text) for i in range(-pgend % 3): embed.add_field(name="", value="") return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil( len(species.moves) / 20)) await paginator.send(self.bot, ctx, 0)
async def req(self, ctx: commands.Context, *args): if args[-1].isdigit(): page = int(args[-1]) - 1 args = args[:-1] else: page = 0 try: badge = next( x for x in self.data if " ".join(args).lower() in x["name"].lower() ) except StopIteration: await ctx.send("Couldn't find anything matching that query.") return image_name = badge["name"].replace(" ", "").lower() groups = [] for x in badge["requirements"]: if x["depth"] == 0: groups.append([]) groups[-1].append(x) async def get_page(idx): title = badge["name"] if badge.get("isEagle", False): title += " 🦅" lines = [f"**Requirement {idx + 1}**"] lines += [ ("" if x["index"] == "" else f"{x['index']}. ") + x["text"] for x in groups[idx] ] embed = discord.Embed( title=title, description="\n\n".join(lines), color=0xF44336, ) embed.set_thumbnail( url=f"http://t452.oliverni.com/merit-badges/{image_name}.png" ) embed.set_footer( text=f"Displaying requirement {idx+1} out of {len(groups)}." ) return embed paginator = pagination.Paginator(get_page, len(groups)) await paginator.send(self.bot, ctx, page=page)
async def collection(self, ctx: commands.Context, **flags): """Show users collection Queries: **id|amount|name|rarity|type|supertype|subtype|artist|set|series|evolvesfrom|hp** subtype = Item, Stage 1, Supporter, TAG TEAM, etc. supertype = Pokemon, Energy, Trainer series = Sword & Shield, POP, E-Card, Gym, NEO, etc. set = Darkness Ablaze, Rebel Clash, Unified Minds, etc. Examples: `<prefix>collection 3 --type Psychic --rarity rare, common` -> this will show page 3 the user's collection of psychic rares/commons `<prefix>collection --artist Ken Sugimori --rarity rare` -> show cards with artist ken sugimori with rare rarity `<prefix>collection --rarity rare --amount > 2 --hp > 50` -> rare cards with at least 2 amount and hp greater than 50 **jp cards dont have hp information** """ if flags['page'] < 1: return await ctx.send('Invalid page number') sort = await self.bot.db.get_user_sort(ctx.author) aggregations = await self.create_filter(flags, ctx) # dictionary with filters in em -- key, value = filter, values to filter num = await self.bot.db.get_user_cards_count(str(ctx.author.id), queries = aggregations) if num == 0: return await ctx.send('No cards matching this query') async def get_page(pidx, clear): pgstart = pidx * 20 cards = await self.bot.db.get_user_cardsV2(str(ctx.author.id), pgstart, 20, queries = aggregations, sort = sort) if len(cards) == 0: return await ctx.send('No cards in this page') page = [ f"{self.get_rarity_emoji(c['rarity'])}{''.join(self.get_energy_types_emoji(c['types']))} | **{c['id']}** | {c['name']} | **{c['amount']}**" for c in cards ] embed = self.bot.Embed(color = discord.Color.dark_teal()) embed.title = "Your cards" embed.description = '\n'.join(page)[:2048] # limit in embed embed.set_footer(text = f"Page {pidx+1} of {math.ceil(num/20)}") return embed paginator = pagination.Paginator(get_page, num_pages = math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags['page'] - 1)
async def send_bot_help(self, mapping): ctx = self.context bot = ctx.bot def get_category(command): cog = command.cog return cog.qualified_name if cog is not None else "\u200bNo Category" pages = [] total = 0 filtered = await self.filter_commands(bot.commands, sort=True, key=get_category) for cog_name, commands in itertools.groupby(filtered, key=get_category): commands = sorted(commands, key=lambda c: c.name) if len(commands) == 0: continue total += len(commands) cog = bot.get_cog(cog_name) description = (cog and cog.description) or discord.Embed.Empty pages.append((cog, description, commands)) async def get_page(pidx, clear): cog, description, commands = pages[pidx] embed = self.make_page_embed( commands, title=(cog and cog.qualified_name or "Other") + " Commands", description=discord.Embed.Empty if cog is None else cog.description, ) embed.set_author( name=f"Page {pidx + 1}/{len(pages)} ({total} commands)") return embed paginator = pagination.Paginator(get_page, len(pages)) await paginator.send(bot, ctx, 0)
async def send_trade(self, ctx: commands.Context, user: discord.Member): # TODO this code is pretty shit. although it does work trade = self.bot.trades[user.id] a, b = trade["items"].keys() done = False if trade[a] and trade[b] and not trade["executing"]: done = True trade["executing"] = True a = ctx.guild.get_member(a) or await ctx.guild.fetch_member(a) b = ctx.guild.get_member(b) or await ctx.guild.fetch_member(b) num_pages = max( math.ceil(len(x) / 20) for x in trade["items"].values()) if done: execmsg = await ctx.send("Executing trade...") async def get_page(pidx, clear): embed = self.bot.Embed(color=0xE67D23) embed.title = f"Trade between {a.display_name} and {b.display_name}." if done: embed.title = ( f"✅ Completed trade between {a.display_name} and {b.display_name}." ) embed.set_footer( text= f"Type `{ctx.prefix}trade add <number>` to add a pokémon, `{ctx.prefix}trade add <number> pc` to add Pokécoins, `{ctx.prefix}trade confirm` to confirm, or `{ctx.prefix}trade cancel` to cancel." ) for i, fullside in trade["items"].items(): mem = ctx.guild.get_member(i) or await ctx.guild.fetch_member(i ) side = fullside[pidx * 20:(pidx + 1) * 20] if mem is None: return await ctx.send("The trade has been canceled.") try: maxn = max(x.idx for x in side if type(x) != int) except ValueError: maxn = 0 def padn(idx, n): return " " * (len(str(n)) - len(str(idx))) + str(idx) def txt(p): val = f"`{padn(p.idx, maxn)}` **{p.species}**" if p.shiny: val += " ✨" val += f" • Lvl. {p.level} • {p.iv_percentage:.2%}" return val val = "\n".join( f"{x:,} Pokécoins" if type(x) == int else txt(x) for x in side) if val == "": if len(fullside) == 0: val = "None" else: val = "None on this page" sign = "🟢" if trade[i] else "🔴" embed.add_field(name=f"{sign} {mem.display_name}", value=val) embed.set_footer( text=f"Showing page {pidx + 1} out of {num_pages}.") return embed # Check if done embeds = [] if done: try: bothsides = list(enumerate(trade["items"].items())) for idx, tup in bothsides: i, side = tup mem = ctx.guild.get_member( i) or await ctx.guild.fetch_member(i) member = await self.db.fetch_member_info(mem) if member.balance < sum(x for x in side if type(x) == int): await ctx.send( "The trade could not be executed as one user does not have enough Pokécoins." ) del self.bot.trades[a.id] del self.bot.trades[b.id] return for idx, tup in bothsides: i, side = tup oidx, otup = bothsides[(idx + 1) % 2] oi, oside = otup mem = ctx.guild.get_member( i) or await ctx.guild.fetch_member(i) omem = ctx.guild.get_member( oi) or await ctx.guild.fetch_member(oi) member = await self.db.fetch_member_info(mem) omember = await self.db.fetch_member_info(omem) idxs = set() num_pokes = len(list(x for x in side if type(x) != int)) idx = await self.db.fetch_next_idx(omem, num_pokes) for x in side: if type(x) == int: await self.db.update_member( mem, {"$inc": { "balance": -x }}) await self.db.update_member( omem, {"$inc": { "balance": x }}) else: pokemon = x if pokemon.idx in idxs: continue idxs.add(pokemon.idx) update = { "$set": { "owner_id": omem.id, "idx": idx, } } idx += 1 if (pokemon.species.trade_evolution ) and pokemon.held_item != 13001: evo = pokemon.species.trade_evolution if (evo.trigger.item is None or evo.trigger.item.id == pokemon.held_item): evo_embed = self.bot.Embed(color=0xE67D23) evo_embed.title = ( f"Congratulations {omem.display_name}!" ) name = str(pokemon.species) if pokemon.nickname is not None: name += f' "{pokemon.nickname}"' evo_embed.add_field( name=f"The {name} is evolving!", value= f"The {name} has turned into a {evo.target}!", ) update["$set"][ "species_id"] = evo.target.id embeds.append(evo_embed) await self.db.update_pokemon( pokemon, update, ) except: del self.bot.trades[a.id] del self.bot.trades[b.id] raise try: await execmsg.delete() except: pass try: await self.bot.mongo.db.logs.insert_one({ "event": "trade", "users": [a.id, b.id], "items": { str(a.id): [ x if type(x) == int else x.id for x in trade["items"][a.id] ], str(b.id): [ x if type(x) == int else x.id for x in trade["items"][b.id] ], }, }) except: print("Error saving trading logs.") pass del self.bot.trades[a.id] del self.bot.trades[b.id] # Send msg paginator = pagination.Paginator(get_page, num_pages=num_pages) self.bot.loop.create_task(paginator.send(self.bot, ctx, 0)) for evo_embed in embeds: await ctx.send(embed=evo_embed)
async def search(self, ctx, **flags): """Search pokémon from auctions.""" if flags["page"] < 1: return await ctx.send("Page must be positive!") aggregations = await self.bot.get_cog("Pokemon").create_filter( flags, ctx, order_by=flags["order"]) if aggregations is None: return # Filter pokemon def padn(p, idx, n): return " " * (len(str(n)) - len(str(idx))) + str(idx) num = await self.bot.mongo.fetch_auction_count( ctx.guild, aggregations=aggregations) if num == 0: return await ctx.send("Found no pokémon matching this search.") async def get_page(pidx, clear): pgstart = pidx * 15 pokemon = await self.bot.mongo.fetch_auction_list( ctx.guild, pgstart, 15, aggregations=aggregations) pokemon = [( self.bot.mongo.EmbeddedPokemon.build_from_mongo(x["pokemon"]), x["_id"], x["current_bid"], x["bid_increment"], x.get("bidder_id", None), x["ends"], ) for x in pokemon] if len(pokemon) == 0: return await clear("There are no pokémon on this page!") now = datetime.utcnow() maxn = max(x[1] for x in pokemon) page = [ f"`{padn(p, idx, maxn)}` **{p:Li}** • {p.iv_percentage * 100:.2f}% • CB: {current_bid:,} • BI: {bid_interval:,} pc • {converters.strfdelta(ends - now, max_len=1)}" if bidder_id is not None else f"`{padn(p, idx, maxn)}` **{p:Li}** • {p.iv_percentage * 100:.2f}% • SB: {current_bid + bid_interval:,} pc • {converters.strfdelta(ends - now, max_len=1)}" for p, idx, current_bid, bid_interval, bidder_id, ends in pokemon ] # Send embed embed = self.bot.Embed(color=0x9CCFFF) embed.title = f"Auctions in {ctx.guild.name}" embed.description = "\n".join(page)[:2048] embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 15, num)} out of {num}. (Page {pidx+1} of {math.ceil(num / 15)})" ) return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 15)) await paginator.send(self.bot, ctx, flags["page"] - 1)
async def pokedex(self, ctx: commands.Context, **flags): """View your pokédex, or search for a pokémon species.""" search_or_page = " ".join(flags["page"]) if flags["orderd"] and flags["ordera"]: return await ctx.send( "You can use either --orderd or --ordera, but not both.") if flags["caught"] and flags["uncaught"]: return await ctx.send( "You can use either --caught or --uncaught, but not both.") if flags["mythical"] + flags["legendary"] + flags["ub"] > 1: return await ctx.send("You can't use more than one rarity flag!") if search_or_page is None: search_or_page = "1" if search_or_page.isdigit(): pgstart = (int(search_or_page) - 1) * 20 if pgstart >= 809 or pgstart < 0: return await ctx.send("There are no pokémon on this page.") num = await self.bot.mongo.fetch_pokedex_count(ctx.author) do_emojis = (ctx.guild is None or ctx.guild.me.permissions_in( ctx.channel).external_emojis) member = await self.bot.mongo.fetch_pokedex(ctx.author, 0, 810) pokedex = member.pokedex if not flags["uncaught"] and not flags["caught"]: for i in range(1, 810): if str(i) not in pokedex: pokedex[str(i)] = 0 elif flags["uncaught"]: for i in range(1, 810): if str(i) not in pokedex: pokedex[str(i)] = 0 else: del pokedex[str(i)] def include(key): if flags[ "legendary"] and key not in self.bot.data.list_legendary: return False if flags["mythical"] and key not in self.bot.data.list_mythical: return False if flags["ub"] and key not in self.bot.data.list_ub: return False if flags["type"] and key not in self.bot.data.list_type( flags["type"]): return False return True pokedex = { int(k): v for k, v in pokedex.items() if include(int(k)) } if flags["ordera"]: pokedex = sorted(pokedex.items(), key=itemgetter(1)) elif flags["orderd"]: pokedex = sorted(pokedex.items(), key=itemgetter(1), reverse=True) else: pokedex = sorted(pokedex.items(), key=itemgetter(0)) async def get_page(pidx, clear): pgstart = (pidx) * 20 pgend = min(pgstart + 20, len(pokedex)) # Send embed embed = self.bot.Embed(color=0xF44336) embed.title = f"Your pokédex" embed.description = f"You've caught {num} out of 809 pokémon!" embed.set_footer( text=f"Showing {pgstart + 1}–{pgend} out of {len(pokedex)}." ) # embed.description = ( # f"You've caught {len(member.pokedex)} out of 809 pokémon!" # ) for k, v in pokedex[pgstart:pgend]: species = self.bot.data.species_by_number(k) if do_emojis: text = f"{self.bot.sprites.cross} Not caught yet!" else: text = "Not caught yet!" if v > 0: if do_emojis: text = f"{self.bot.sprites.check} {v} caught!" else: text = f"{v} caught!" if do_emojis: emoji = self.bot.sprites.get(k) + " " else: emoji = "" embed.add_field( name=f"{emoji}{species.name} #{species.id}", value=text) if pgend != 809: embed.add_field(name="", value="") return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil( len(pokedex) / 20)) await paginator.send(self.bot, ctx, int(search_or_page) - 1) else: shiny = False if search_or_page[0] in "Nn#" and search_or_page[1:].isdigit(): species = self.bot.data.species_by_number( int(search_or_page[1:])) else: search = search_or_page if search_or_page.lower().startswith("shiny "): shiny = True search = search_or_page[6:] species = self.bot.data.species_by_name(search) if species is None: return await ctx.send( f"Could not find a pokemon matching `{search_or_page}`." ) member = await self.bot.mongo.fetch_pokedex( ctx.author, species.dex_number, species.dex_number + 1) embed = self.bot.Embed(color=0xF44336) embed.title = f"#{species.dex_number} — {species}" if species.description: embed.description = species.description.replace("\n", " ") if species.evolution_text: embed.add_field(name="Evolution", value=species.evolution_text, inline=False) if shiny: embed.title = f"#{species.dex_number} — ✨ {species}" embed.set_image(url=species.shiny_image_url) else: embed.set_image(url=species.image_url) base_stats = ( f"**HP:** {species.base_stats.hp}", f"**Attack:** {species.base_stats.atk}", f"**Defense:** {species.base_stats.defn}", f"**Sp. Atk:** {species.base_stats.satk}", f"**Sp. Def:** {species.base_stats.sdef}", f"**Speed:** {species.base_stats.spd}", ) embed.add_field( name="Names", value="\n".join(f"{x} {y}" for x, y in species.names), inline=False, ) embed.add_field(name="Base Stats", value="\n".join(base_stats)) embed.add_field( name="Appearance", value= f"Height: {species.height} m\nWeight: {species.weight} kg", ) embed.add_field(name="Types", value="\n".join(species.types)) text = "You haven't caught this pokémon yet!" if str(species.dex_number) in member.pokedex: text = f"You've caught {member.pokedex[str(species.dex_number)]} of this pokémon!" embed.set_footer(text=text) await ctx.send(embed=embed)
async def pokemon(self, ctx: commands.Context, **flags): """View or filter the pokémon in your collection.""" if flags["page"] < 1: return await ctx.send("Page must be positive!") member = await self.db.fetch_member_info(ctx.author) aggregations = await self.create_filter(flags, ctx, order_by=member.order_by) if aggregations is None: return # Filter pokemon do_emojis = ctx.guild.me.permissions_in(ctx.channel).external_emojis fixed_pokemon = False async def fix_pokemon(): # TODO This is janky way of removing bad database entries, I should fix this nonlocal fixed_pokemon if fixed_pokemon: return await self.db.update_member( ctx.author, {"$pull": { f"pokemon": { "species_id": { "$exists": False } } }}, ) await self.db.update_member(ctx.author, {"$pull": { f"pokemon": None }}) fixed_pokemon = True def nick(p): if p.species is None: asyncio.create_task(fix_pokemon()) return None name = str(p.species) if do_emojis: name = ( self.bot.sprites.get(p.species.dex_number, shiny=p.shiny) + " " + name) if p.shiny: name += " ✨" if p.nickname is not None: name += ' "' + p.nickname + '"' if p.favorite: name += " ❤️" return name def padn(p, idx, n): return " " * (len(str(n)) - len(str(idx))) + str(idx) num = await self.db.fetch_pokemon_count(ctx.author, aggregations=aggregations) if num == 0: return await ctx.send("Found no pokémon matching this search.") async def get_page(pidx, clear): pgstart = pidx * 20 pokemon = await self.db.fetch_pokemon_list( ctx.author, pgstart, 20, aggregations=aggregations) pokemon = [(self.bot.mongo.Pokemon.build_from_mongo(x["pokemon"]), x["idx"] + 1) for x in pokemon] if len(pokemon) == 0: return await clear("There are no pokémon on this page!") maxn = max(idx for x, idx in pokemon) page = [ f"`{padn(p, idx, maxn)}` **{txt}** • Lvl. {p.level} • {p.iv_percentage * 100:.2f}%" for p, idx in pokemon if (txt := nick(p)) is not None ] # Send embed embed = self.bot.Embed() embed.title = f"Your pokémon" embed.description = "\n".join(page)[:2048] embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 20, num)} out of {num}. (Page {pidx+1} of {math.ceil(num / 20)})" ) return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags["page"] - 1)
async def search(self, ctx: commands.Context, **flags): """Search pokémon from the marketplace.""" if flags["page"] < 1: return await ctx.send("Page must be positive!") member = await self.db.fetch_member_info(ctx.author) aggregations = await self.bot.get_cog("Pokemon").create_filter( flags, ctx, order_by=flags["order"]) if aggregations is None: return # Filter pokemon do_emojis = ctx.guild.me.permissions_in(ctx.channel).external_emojis def nick(p): name = f"L{p.level} {p.species}" if do_emojis: name = ( self.bot.sprites.get(p.species.dex_number, shiny=p.shiny) + " " + name) if p.shiny: name += " ✨" return name def padn(p, idx, n): return " " * (len(str(n)) - len(str(idx))) + str(idx) num = await self.db.fetch_market_count(aggregations=aggregations) if num == 0: return await ctx.send("Found no pokémon matching this search.") async def get_page(pidx, clear): pgstart = pidx * 20 pokemon = await self.db.fetch_market_list( pgstart, 20, aggregations=aggregations) pokemon = [( self.bot.mongo.EmbeddedPokemon.build_from_mongo(x["pokemon"]), x["_id"], x["price"], ) for x in pokemon] if len(pokemon) == 0: return await clear("There are no pokémon on this page!") maxn = max(idx for x, idx, price in pokemon) page = [ f"`{padn(p, idx, maxn)}` **{nick(p)}** • {p.iv_percentage * 100:.2f}% • {price:,} pc" for p, idx, price in pokemon ] # Send embed embed = self.bot.Embed() embed.title = f"Pokétwo Marketplace" embed.description = "\n".join(page)[:2048] embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 20, num)} out of {num}. (Page {pidx+1} of {math.ceil(num / 20)})" ) return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags["page"] - 1)
async def market(self, ctx: commands.Context, **flags): """Market functions `market 3 --rarity rare --hp > 100 --sort` -> page 3 of rare cards with 100+ hp sorted by cost `market --mine` -> first page of user's market listings `market --remove <market_id>` -> remove the listing by market_id if it is by the user `market --show <market_id>` -> show card art of the listing `market --buy <market_id>` -> buy the market listing `market --rarity rare --cost < 100` -> show rare listings with cost less than 100 """ # Buy a market listing if flags['buy']: market_id = flags['buy'] response, output = await self.bot.db.buy_from_market( ctx.author, market_id) if response: return await ctx.send(embed=await self.bot.embeds.get( { 'type': 'GENERAL', 'title': 'Bought from Market', 'color': discord.Color.blue(), 'body': output, 'footer': f'Rich boi {str(ctx.author)}' })) else: return await ctx.send(embed=await self.bot.embeds.get( { 'type': 'GENERAL', 'title': 'Unable to buy from Market', 'color': discord.Color.red(), 'body': output, 'footer': f'Requested by {str(ctx.author)}' })) # Remove user's market listing if flags['remove']: market_id = flags['remove'] response, card = await self.bot.db.remove_from_market( ctx.author, market_id) if response: return await ctx.send(embed=await self.bot.embeds.get( { 'type': 'GENERAL', 'title': 'Removed from Market', 'color': discord.Color.blue(), 'body': f'Removed {market_id} | {card} from market', 'footer': f'Requested by {str(ctx.author)}' })) else: return await ctx.send(embed=await self.bot.embeds.get( { 'type': 'GENERAL', 'title': 'Unable to remove from Market', 'color': discord.Color.blue(), 'body': 'Not valid, or not your market listing', 'footer': f'Requested by {str(ctx.author)}' })) # Show card in listing if flags['show']: market_id = flags['show'] listing = await self.bot.db.get_market_listing(market_id) if listing: picture_file = discord.File('data/images/{}.webp'.format( listing['card_id']), filename='show.webp') embed = { 'type': 'GENERAL-ATTACHMENT-IMAGE', 'body': f"{listing['card_name']} | {listing['rarity']} | {listing['card_id']}\n${listing['cost']} | {listing['amount']} cards", 'title': 'Showing Market Listing - {}'.format(listing['id']), 'color': discord.Color.green(), 'footer': 'Requested by {}'.format(str(ctx.author)), 'attachment': 'show.webp' } return await ctx.send(embed=await self.bot.embeds.get(embed), file=picture_file) else: # market listing not found return await ctx.send(embed=await self.bot.embeds.get({ 'type': 'GENERAL', 'title': 'Unable to show Market listing', 'color': discord.Color.blue(), 'body': 'Not a valid market listing, make sure market id is correct', 'footer': f'Requested by {str(ctx.author)}' })) if flags['page'] < 1: return await ctx.send('Invalid page number') aggregations = await self.create_filter(flags, ctx) num = await self.bot.db.get_market_count(queries=aggregations) if num == 0: return await ctx.send('No listings matching this query') async def get_page(pidx, clear): pgstart = pidx * 20 listings = await self.bot.db.get_marketV2(pgstart, 20, queries=aggregations, sort=flags['sort']) if len(listings) == 0: return await ctx.send('No listings in this page') page = [ f"`{l['market_id']}` | **${l['cost']}** | {l['rarity']} | {l['card_name']} | {l['card_id']} | {l['amount']}" for l in listings ] embed = self.bot.Embed(color=discord.Color.dark_teal()) embed.title = "Market Listings" embed.description = '\n'.join(page)[:2048] # limit in embed embed.set_footer(text=f"Page {pidx+1} of {math.ceil(num/20)}") return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags['page'] - 1)
async def info(self, ctx: commands.Context, *, pokemon: converters.Pokemon): """View a specific pokémon from your collection.""" pokemon, pidx = pokemon num = await self.db.fetch_pokemon_count(ctx.author) async def get_page(pidx, clear): pokemon = await self.db.fetch_pokemon(ctx.author, pidx) if pokemon is None: return await clear("Couldn't find that pokémon!") embed = discord.Embed() embed.color = 0xF44336 embed.title = f"Level {pokemon.level} {pokemon.species}" if pokemon.nickname is not None: embed.title += f' "{pokemon.nickname}"' extrafooter = "" if pokemon.shiny: embed.title += " ✨" embed.set_image(url=pokemon.species.shiny_image_url) extrafooter = " Note that we don't have artwork for all shiny pokémon yet! We're working hard to make all the shiny pokémon look shiny." else: embed.set_image(url=pokemon.species.image_url) embed.set_thumbnail(url=ctx.author.avatar_url) info = ( f"**XP:** {pokemon.xp}/{pokemon.max_xp}", f"**Nature:** {pokemon.nature}", ) embed.add_field(name="Details", value="\n".join(info), inline=False) stats = ( f"**HP:** {pokemon.hp} – IV: {pokemon.iv_hp}/31", f"**Attack:** {pokemon.atk} – IV: {pokemon.iv_atk}/31", f"**Defense:** {pokemon.defn} – IV: {pokemon.iv_defn}/31", f"**Sp. Atk:** {pokemon.satk} – IV: {pokemon.iv_satk}/31", f"**Sp. Def:** {pokemon.sdef} – IV: {pokemon.iv_sdef}/31", f"**Speed:** {pokemon.spd} – IV: {pokemon.iv_spd}/31", f"**Total IV:** {pokemon.iv_percentage * 100:.2f}%", ) embed.add_field(name="Stats", value="\n".join(stats), inline=False) if pokemon.held_item: item = models.GameData.item_by_number(pokemon.held_item) gguild = self.bot.get_guild(725819081835544596) emote = "" if item.emote is not None: try: e = next( filter(lambda x: x.name == item.emote, gguild.emojis)) emote = f"{e} " except StopIteration: pass embed.add_field(name="Held Item", value=f"{emote}{item.name}", inline=False) embed.set_footer( text=f"Displaying pokémon {pidx + 1} out of {num}." + extrafooter) return embed paginator = pagination.Paginator(get_page, num_pages=num) await paginator.send(self.bot, ctx, pidx)
async def pokemon(self, ctx: commands.Context, **flags): """View or filter the pokémon in your collection.""" if flags["page"] < 1: return await ctx.send("Page must be positive!") aggregations = await self.create_filter(flags, ctx) if aggregations is None: return # # Filter pokemon # Pagination member = await self.db.fetch_member_info(ctx.author) aggregations.extend([ { "$addFields": { "sorting": constants.SORTING_FUNCTIONS[member.order_by] } }, { "$sort": { "sorting": 1 } }, ]) do_emojis = ctx.channel.permissions_for( ctx.guild.get_member(self.bot.user.id)).external_emojis fixed_pokemon = False async def fix_pokemon(): # TODO This is janky way of removing bad database entries, I should fix this nonlocal fixed_pokemon if fixed_pokemon: return await self.db.update_member( ctx.author, {"$pull": { f"pokemon": { "species_id": { "$exists": False } } }}, ) await self.db.update_member(ctx.author, {"$pull": { f"pokemon": None }}) fixed_pokemon = True def nick(p): if p.species is None: asyncio.create_task(fix_pokemon()) return None if do_emojis: name = (str( constants.EMOJIS.get( p.species.dex_number, shiny=p.shiny)).replace( "pokemon_sprite_", "").replace("_shiny", "") + " ") else: name = "" name += str(p.species) if p.shiny: name += " ✨" if p.nickname is not None: name += ' "' + p.nickname + '"' if p.favorite: name += " ❤️" return name def padn(p, idx, n): return " " * (len(str(n)) - len(str(idx))) + str(idx) num = await self.db.fetch_pokemon_count(ctx.author, aggregations=aggregations) if num == 0: return await ctx.send("Found no pokémon matching this search.") async def get_page(pidx, clear): pgstart = pidx * 20 pokemon = await self.db.fetch_pokemon_list( ctx.author, pgstart, 20, aggregations=aggregations) pokemon = [(mongo.Pokemon.build_from_mongo(x["pokemon"]), x["idx"] + 1) for x in pokemon] if len(pokemon) == 0: return await clear("There are no pokémon on this page!") maxn = max(idx for x, idx in pokemon) page = [ f"`{padn(p, idx, maxn)}`⠀**{txt}**⠀•⠀Lvl. {p.level}⠀•⠀{p.iv_percentage * 100:.2f}%" for p, idx in pokemon if (txt := nick(p)) is not None ] # Send embed embed = discord.Embed() embed.color = 0xF44336 embed.title = f"Your pokémon" embed.description = "\n".join(page)[:2048] if do_emojis: embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 20, num)} out of {num}." ) else: embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 20, num)} out of {num}. Please give me permission to Use External Emojis! It'll make this menu look a lot better." ) return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags["page"] - 1)
async def search(self, ctx: commands.Context, **flags): """Search pokémon from the marketplace.""" if flags["page"] < 1: return await ctx.send("Page must be positive!") member = await self.bot.mongo.fetch_member_info(ctx.author) aggregations = await self.bot.get_cog("Pokemon").create_filter( flags, ctx, order_by=flags["order"]) if aggregations is None: return # Filter pokemon do_emojis = (ctx.guild is None or ctx.guild.me.permissions_in( ctx.channel).external_emojis) def padn(p, idx, n): return " " * (len(str(n)) - len(str(idx))) + str(idx) num = await self.bot.mongo.fetch_auction_count( ctx.guild, aggregations=aggregations) if num == 0: return await ctx.send("Found no pokémon matching this search.") async def get_page(pidx, clear): pgstart = pidx * 20 pokemon = await self.bot.mongo.fetch_auction_list( ctx.guild, pgstart, 20, aggregations=aggregations) pokemon = [( self.bot.mongo.EmbeddedPokemon.build_from_mongo(x["pokemon"]), x["_id"], x["current_bid"], x["bid_increment"], x.get("bidder_id", None), ) for x in pokemon] if len(pokemon) == 0: return await clear("There are no pokémon on this page!") maxn = max(idx for x, idx, price, _, bidder_id in pokemon) page = [ f"`{padn(p, idx, maxn)}` **{p:li}** • {p.iv_percentage * 100:.2f}% • CB: {current_bid:,} pc • BI: {bid_interval:,} pc" if bidder_id is not None else f"`{padn(p, idx, maxn)}` **{p:li}** • {p.iv_percentage * 100:.2f}% • SB: {current_bid + bid_interval:,} pc" for p, idx, current_bid, bid_interval, bidder_id in pokemon ] # Send embed embed = self.bot.Embed(color=0xE67D23) embed.title = f"Auctions in {ctx.guild.name}" embed.description = "\n".join(page)[:2048] embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 20, num)} out of {num}. (Page {pidx+1} of {math.ceil(num / 20)})" ) return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags["page"] - 1)
async def info(self, ctx: commands.Context, *, pokemon: converters.Pokemon): """View a specific pokémon from your collection.""" num = await self.bot.mongo.fetch_pokemon_count(ctx.author) if pokemon is None: return await ctx.send("Couldn't find that pokémon!") shift = 0 async def get_page(pidx, clear, dir=0): nonlocal shift pokemon = await self.bot.mongo.fetch_pokemon( ctx.author, pidx + shift) while pokemon is None: shift += 1 pokemon = await self.bot.mongo.fetch_pokemon( ctx.author, pidx + shift) embed = self.bot.Embed(color=pokemon.color or 0xF44336) embed.title = f"{pokemon:lnf}" if pokemon.shiny: embed.set_image(url=pokemon.species.shiny_image_url) else: embed.set_image(url=pokemon.species.image_url) embed.set_thumbnail(url=ctx.author.avatar_url) info = ( f"**XP:** {pokemon.xp}/{pokemon.max_xp}", f"**Nature:** {pokemon.nature}", ) embed.add_field(name="Details", value="\n".join(info), inline=False) stats = ( f"**HP:** {pokemon.hp} – IV: {pokemon.iv_hp}/31", f"**Attack:** {pokemon.atk} – IV: {pokemon.iv_atk}/31", f"**Defense:** {pokemon.defn} – IV: {pokemon.iv_defn}/31", f"**Sp. Atk:** {pokemon.satk} – IV: {pokemon.iv_satk}/31", f"**Sp. Def:** {pokemon.sdef} – IV: {pokemon.iv_sdef}/31", f"**Speed:** {pokemon.spd} – IV: {pokemon.iv_spd}/31", f"**Total IV:** {pokemon.iv_percentage * 100:.2f}%", ) embed.add_field(name="Stats", value="\n".join(stats), inline=False) if pokemon.held_item: item = self.bot.data.item_by_number(pokemon.held_item) emote = "" if item.emote is not None: emote = getattr(self.bot.sprites, item.emote) + " " embed.add_field(name="Held Item", value=f"{emote}{item.name}", inline=False) embed.set_footer(text=f"Displaying pokémon {pokemon.idx}.") return embed paginator = pagination.Paginator(get_page, num_pages=num) await paginator.send(self.bot, ctx, pokemon.idx)
async def pokemon(self, ctx: commands.Context, **flags): """View or filter the pokémon in your collection.""" if flags["page"] < 1: return await ctx.send("Page must be positive!") member = await self.bot.mongo.fetch_member_info(ctx.author) aggregations = await self.create_filter(flags, ctx, order_by=member.order_by) if aggregations is None: return # Filter pokemon do_emojis = (ctx.guild is None or ctx.guild.me.permissions_in( ctx.channel).external_emojis) fixed_pokemon = False def padn(p, n): return " " * (len(str(n)) - len(str(p.idx))) + str(p.idx) num = await self.bot.mongo.fetch_pokemon_count( ctx.author, aggregations=aggregations) if num == 0: return await ctx.send("Found no pokémon matching this search.") async def get_page(pidx, clear): pgstart = pidx * 20 pokemon = await self.bot.mongo.fetch_pokemon_list( ctx.author, pgstart, 20, aggregations=aggregations) pokemon = [ self.bot.mongo.Pokemon.build_from_mongo(x["pokemon"]) for x in pokemon ] if len(pokemon) == 0: return await clear("There are no pokémon on this page!") maxn = max(x.idx for x in pokemon) page = [ f"`{padn(p, maxn)}` **{p:nif}** • Lvl. {p.level} • {p.iv_percentage * 100:.2f}%" for p in pokemon ] # Send embed embed = self.bot.Embed(color=0xF44336) embed.title = f"Your pokémon" embed.description = "\n".join(page)[:2048] embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 20, num)} out of {num}. (Page {pidx+1} of {math.ceil(num / 20)})" ) return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags["page"] - 1)
async def support(self, ctx: commands.Context, **flags): """Support Tickets Functions""" #print(flags) if 'answer' in flags and flags['answer'] and flags['close']: return await ctx.send("Can only do one at a time. `--answer` `--close`") elif 'answer' in flags and flags['answer']: # bot sends answer to user who sent the support ticket and closes it if 'id' not in flags and not flags['id']: return await ctx.send("Please indicate the id with the answer. `--id <id> --answer <message>`") answer = ' '.join(flags['answer']) cursor = self.bot.db.connection.cursor() cursor.execute("SELECT id, user_id, flags, message FROM support WHERE id = %s", flags['id']) out = cursor.fetchone() cursor.execute("DELETE FROM support where id = %s", flags['id']) self.bot.db.connection.commit() cursor.close() if out: embed = self.bot.Embed(color = 0x6CFF00) embed.title = f"Support Ticket Closed" embed.description = '\n'.join([ f"**ID:** {out[0]}", f"**From user:** {'<@' + str(out[1]) + '>'}", f"**Type:** {out[2]}", f"**Message:** {out[3]}", f"**Response:** {answer}" ]) await ctx.send(embed = embed) # send dm member = self.bot.get_user(int(out[1])) if member: return await member.send(embed = embed) else: return await ctx.send("Closed ticket however user was not found. Bot is not in any server with the user!") else: return await ctx.send(f"No support ticket found with ID: {flags['id']}") elif 'id' in flags and flags['id'] and not flags['close']: cursor = self.bot.db.connection.cursor() cursor.execute("SELECT id, user_id, flags, message FROM support WHERE id = %s", flags['id']) out = cursor.fetchone() cursor.close() if out: embed = self.bot.Embed(color = 0x6CFF00) embed.title = f"Support Ticket" embed.description = f"**ID:** {out[0]}\n**Type:** {out[2]}\n**Message:** {out[3]}" return await ctx.send(embed = embed) else: return await ctx.send(f"No support ticket found with ID: {flags['id']}") elif flags['close'] and 'id' in flags and flags['id']: cursor = self.bot.db.connection.cursor() cursor.execute("DELETE FROM support where id = %s", flags['id']) self.bot.db.connection.commit() cursor.close() return await ctx.send(f"Support ID {flags['id']} closed") # list support tickets num = await self.bot.db.get_support_tickets(flags, count = True) if num == 0: return await ctx.send("No support tickets found") async def get_page(pidx, clear): pgstart = pidx * 20 s_tickets = await self.bot.db.get_support_tickets(flags, pgstart, 20) if len(s_tickets) == 0: return await ctx.send('No tickets on this page') page = [ f"`{s['id']}` | {s['flags']} | **{s['message'][:30]}**" for s in s_tickets ] embed = self.bot.Embed(color = discord.Color.dark_teal()) embed.title = "Support Tickets" embed.description = '\n'.join(page)[:2048] # limit in embed embed.set_footer(text = f"Page {pidx+1} of {math.ceil(num/20)}") return embed paginator = pagination.Paginator(get_page, num_pages = math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags['page'] - 1)
class Trading(commands.Cog): """For trading.""" def __init__(self, bot: commands.Bot): self.bot = bot if not hasattr(self.bot, "trades"): self.bot.trades = {} @property def db(self) -> Database: return self.bot.get_cog("Database") async def send_trade(self, ctx: commands.Context, user: discord.Member): # TODO this code is pretty shit. although it does work trade = self.bot.trades[user.id] a, b = trade["items"].keys() done = False if trade[a] and trade[b]: done = True del self.bot.trades[a] del self.bot.trades[b] a = ctx.guild.get_member(a) b = ctx.guild.get_member(b) num_pages = max(math.ceil(len(x) / 20) for x in trade["items"].values()) if done: execmsg = await ctx.send("Executing trade...") async def get_page(pidx, clear): embed = discord.Embed() embed.color = 0xF44336 embed.title = f"Trade between {a.display_name} and {b.display_name}." if done: embed.title = ( f"✅ Completed trade between {a.display_name} and {b.display_name}." ) embed.set_footer( text=f"Type `{ctx.prefix}trade add <number>` to add a pokémon, `{ctx.prefix}trade add <number> pc` to add Pokécoins, `{ctx.prefix}trade confirm` to confirm, or `{ctx.prefix}trade cancel` to cancel." ) for i, fullside in trade["items"].items(): mem = ctx.guild.get_member(i) side = fullside[pidx * 20 : (pidx + 1) * 20] if mem is None: return await ctx.send("The trade has been canceled.") try: maxn = max(x[1] + 1 for x in side if type(x) != int) except ValueError: maxn = 0 def padn(idx, n): return " " * (len(str(n)) - len(str(idx))) + str(idx) def txt(x): val = f"`{padn(x[1] + 1, maxn)}`⠀**{x[0].species}**" if x[0].shiny: val += " ✨" val += f"⠀•⠀Lvl. {x[0].level}⠀•⠀{x[0].iv_percentage:.2%}" return val val = "\n".join( f"{x} Pokécoins" if type(x) == int else txt(x) for x in side ) if val == "": if len(fullside) == 0: val = "None" else: val = "None on this page" sign = "🟢" if trade[i] else "🔴" embed.add_field(name=f"{sign} {mem.display_name}", value=val) embed.set_footer(text=f"Showing page {pidx + 1} out of {num_pages}.") return embed # Check if done embeds = [] if done: bothsides = list(enumerate(trade["items"].items())) for idx, tup in bothsides: i, side = tup oidx, otup = bothsides[(idx + 1) % 2] oi, oside = otup mem = ctx.guild.get_member(i) omem = ctx.guild.get_member(oi) dec = 0 member = await self.db.fetch_member_info(mem) omember = await self.db.fetch_member_info(omem) for x in side: if type(x) == int: await self.db.update_member(mem, {"$inc": {"balance": -x}}) await self.db.update_member(omem, {"$inc": {"balance": x}}) else: pokemon, idx = x if idx < member.selected: dec += 1 if ( evo := pokemon.species.trade_evolution ) and pokemon.held_item != 13001: if ( evo.trigger.item is None or evo.trigger.item.id == pokemon.held_item ): evo_embed = discord.Embed() evo_embed.color = 0xF44336 evo_embed.title = f"Congratulations {omem.name}!" name = str(pokemon.species) if pokemon.nickname is not None: name += f' "{pokemon.nickname}"' evo_embed.add_field( name=f"The {name} is evolving!", value=f"The {name} has turned into a {evo.target}!", ) pokemon.species_id = evo.target.id embeds.append(evo_embed) await self.db.update_member( mem, {"$unset": {f"pokemon.{idx}": 1}} ) await self.db.update_member( omem, { "$push": { "pokemon": { "species_id": pokemon.species.id, "level": pokemon.level, "xp": pokemon.xp, "nature": pokemon.nature, "iv_hp": pokemon.iv_hp, "iv_atk": pokemon.iv_atk, "iv_defn": pokemon.iv_defn, "iv_satk": pokemon.iv_satk, "iv_sdef": pokemon.iv_sdef, "iv_spd": pokemon.iv_spd, "shiny": pokemon.shiny, "held_item": pokemon.held_item, } }, }, ) await self.db.update_member( mem, {"$inc": {f"selected": -dec}, "$pull": {"pokemon": None}}, ) await execmsg.delete() # Send msg paginator = pagination.Paginator(get_page, num_pages=num_pages) asyncio.create_task(paginator.send(self.bot, ctx, 0)) for evo_embed in embeds: await ctx.send(embed=evo_embed)
async def market(self, ctx: commands.Context, **flags): """View or filter the pokémon in your collection.""" if flags["page"] < 1: return await ctx.send("Page must be positive!") member = await self.db.fetch_member_info(ctx.author) aggregations = await self.bot.get_cog("Pokemon").create_filter( flags, ctx) if aggregations is None: return # Filter pokemon fixed_pokemon = False async def fix_pokemon(): # TODO This is janky way of removing bad database entries, I should fix this nonlocal fixed_pokemon if fixed_pokemon: return await self.db.update_member( ctx.author, {"$pull": { f"pokemon": { "species_id": { "$exists": False } } }}, ) await self.db.update_member(ctx.author, {"$pull": { f"pokemon": None }}) fixed_pokemon = True def nick(p): name = str(p.species) if p.shiny: name += " ✨" return name num = await self.db.fetch_market_count(aggregations=aggregations) if num == 0: return await ctx.send("Found no pokémon matching this search.") async def get_page(pidx, clear): pgstart = pidx * 20 pokemon = await self.db.fetch_market_list( pgstart, 20, aggregations=aggregations) pokemon = [(mongo.Pokemon.build_from_mongo(x["pokemon"]), x["_id"], x["price"]) for x in pokemon] if len(pokemon) == 0: return await clear("There are no pokémon on this page!") page = [ f"`{id}` **L{p.level} {nick(p)}** • {p.iv_percentage:.2%} • **{price:,} pc**" for p, id, price in pokemon ] # Send embed embed = discord.Embed() embed.color = 0xF44336 embed.title = f"Market" embed.description = "\n".join(page)[:2048] embed.set_footer( text= f"Showing {pgstart + 1}–{min(pgstart + 20, num)} out of {num}." ) return embed paginator = pagination.Paginator(get_page, num_pages=math.ceil(num / 20)) await paginator.send(self.bot, ctx, flags["page"] - 1)