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 now = datetime.utcnow() def padn(p, n): return " " * (len(str(n)) - len(str(p.id))) + str(p.id) def prepare_page(menu, items): menu.maxn = max(x.id for x in items) def format_item(menu, x): if x.bidder_id is not None: return ( f"`{padn(x, menu.maxn)}` **{x.pokemon:Li}** • " f"{x.pokemon.iv_total / 186:.2%} • CB: {x.current_bid:,} • " f"BI: {x.bid_increment:,} pc • {converters.strfdelta(x.ends - now, max_len=1)}" ) else: return ( f"`{padn(x, menu.maxn)}` **{x.pokemon:Li}** • " f"{x.pokemon.iv_total / 186:.2%} • SB: {x.current_bid + x.bid_increment:,} pc • " f"{converters.strfdelta(x.ends - now, max_len=1)}" ) count = await self.bot.mongo.fetch_auction_count(ctx.guild, aggregations) pokemon = self.bot.mongo.fetch_auction_list(ctx.guild, aggregations) pages = pagination.ContinuablePages( pagination.AsyncListPageSource( pokemon, title=f"Auctions in {ctx.guild.name}", prepare_page=prepare_page, format_item=format_item, per_page=15, count=count, ) ) pages.current_page = flags["page"] - 1 self.bot.menus[ctx.author.id] = pages try: await pages.start(ctx) except IndexError: await ctx.send("No auctions found.")
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" embed_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) embed_pages.append((cog, description, commands)) async def get_page(source, menu, pidx): cogs = embed_pages[min(len(embed_pages) - 1, pidx * 6):min(len(embed_pages) - 1, pidx * 6 + 6)] embed = self.make_default_embed( cogs, title= f"Pokétwo Command Categories (Page {pidx+1}/{len(embed_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." ), ) return embed pages = pagination.ContinuablePages( pagination.FunctionPageSource(math.ceil(len(embed_pages) / 6), get_page)) ctx.bot.menus[ctx.author.id] = pages await pages.start(ctx)
async def moveset(self, ctx, *, 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.PokemonConverter(raise_errors=False) pokemon = await converter.convert(ctx, search) if pokemon is not None: species = pokemon.species if species is None: raise commands.BadArgument( "Please either enter the name of a pokémon species, nothing for your selected pokémon, a number for " "a specific pokémon, `latest` for your latest pokémon. ", ) async def get_page(source, menu, pidx): pgstart = pidx * 20 pgend = min(pgstart + 20, len(species.moves)) # Send embed embed = discord.Embed(color=0x9CCFFF) 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 pages = pagination.ContinuablePages( pagination.FunctionPageSource(math.ceil(len(species.moves) / 20), get_page)) self.bot.menus[ctx.author.id] = pages await pages.start(ctx)
async def pokemon(self, ctx, **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 def padn(p, n): return " " * (len(str(n)) - len(str(p.idx))) + str(p.idx) def prepare_page(menu, items): menu.maxn = max(x.idx for x in items) def format_item(menu, p): return f"`{padn(p, menu.maxn)}` **{p:nif}** • Lvl. {p.level} • {p.iv_total / 186:.2%}" count = await self.bot.mongo.fetch_pokemon_count( ctx.author, aggregations) pokemon = self.bot.mongo.fetch_pokemon_list(ctx.author, aggregations) pages = pagination.ContinuablePages( pagination.AsyncListPageSource( pokemon, title="Your pokémon", prepare_page=prepare_page, format_item=format_item, per_page=20, count=count, )) pages.current_page = flags["page"] - 1 self.bot.menus[ctx.author.id] = pages try: await pages.start(ctx) except IndexError: await ctx.send("No pokémon found.")
async def search(self, ctx, **flags): """Search pokémon from the marketplace.""" def map_field(field): if field == "_id": return f"market_data._id" return field aggregations = await self.bot.get_cog("Pokemon").create_filter( flags, ctx, order_by=flags["order"], map_field=map_field) if aggregations is None: return # Filter pokemon def padn(p, n): return " " * (len(str(n)) - len(str(p))) + str(p) def prepare_page(menu, items): menu.maxn = max(x["market_data"]["_id"] for x in items) def format_item(menu, x): pokemon = self.bot.mongo.Pokemon.build_from_mongo(x) return f"`{padn(x['market_data']['_id'], menu.maxn)}` **{pokemon:li}** • {pokemon.iv_total / 186:.2%} • {x['market_data']['price']:,} pc" pokemon = self.bot.mongo.fetch_market_list(aggregations) pages = pagination.ContinuablePages( pagination.AsyncListPageSource( pokemon, title=f"Pokétwo Marketplace", prepare_page=prepare_page, format_item=format_item, per_page=20, ), allow_last=False, allow_go=False, ) self.bot.menus[ctx.author.id] = pages try: await pages.start(ctx) except IndexError: await ctx.send("No listings found.")
async def search(self, ctx, **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, n): return " " * (len(str(n)) - len(str(p.id))) + str(p.id) def prepare_page(menu, items): menu.maxn = max(x.id for x in items) def format_item(menu, x): return f"`{padn(x, menu.maxn)}` **{x.pokemon:li}** • {x.pokemon.iv_total / 186:.2%} • {x.price:,} pc" pokemon = self.bot.mongo.fetch_market_list(aggregations) pages = pagination.ContinuablePages( pagination.AsyncListPageSource( pokemon, title=f"Pokétwo Marketplace", prepare_page=prepare_page, format_item=format_item, per_page=20, ), allow_last=False, allow_go=False, ) pages.current_page = flags["page"] - 1 self.bot.menus[ctx.author.id] = pages try: await pages.start(ctx) except IndexError: await ctx.send("No listings found.")
async def info(self, ctx, *, pokemon: converters.PokemonConverter): """View a specific pokémon from your collection.""" if pokemon is None: return await ctx.send("Couldn't find that pokémon!") ## Hacky way using 0=first, 1=prev, 2=curr, 3=next, 4=last page LOL async def get_page(source, menu, pidx): nonlocal pokemon menu.current_page = 2 agg = None if pidx == 4: agg = [{"$sort": {"idx": -1}}] elif pidx == 3: agg = [{"$match": {"idx": {"$gt": pokemon.idx}}}] elif pidx == 1: agg = [ { "$match": { "idx": { "$lt": pokemon.idx } } }, { "$sort": { "idx": -1 } }, ] elif pidx == 0: agg = [] if agg is not None: it = self.bot.mongo.fetch_pokemon_list(ctx.author, agg) async for x in it: pokemon = x break embed = self.bot.Embed(color=pokemon.color or 0x9CCFFF) 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}.\nID: {pokemon.id}") return embed pages = pagination.ContinuablePages(pagination.FunctionPageSource( 5, get_page), allow_go=False) pages.current_page = 2 ctx.bot.menus[ctx.author.id] = pages await pages.start(ctx)
async def pokedex(self, ctx, **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(source, menu, pidx): pgstart = pidx * 20 pgend = min(pgstart + 20, len(pokedex)) # Send embed embed = self.bot.Embed(color=0x9CCFFF) 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 pages = pagination.ContinuablePages( pagination.FunctionPageSource(math.ceil(809 / 20), get_page)) pages.current_page = int(search_or_page) - 1 self.bot.menus[ctx.author.id] = pages await pages.start(ctx) 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=0x9CCFFF) 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 send_trade(self, ctx, 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(source, menu, pidx): embed = self.bot.Embed(color=0x9CCFFF) 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}." ) 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 = f"`{padn(p.idx, maxn)}` **✨ {p.species}**" 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.bot.mongo.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." ) await self.end_trade(a.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.bot.mongo.fetch_member_info(mem) omember = await self.bot.mongo.fetch_member_info(omem) idxs = set() num_pokes = len(list(x for x in side if type(x) != int)) idx = await self.bot.mongo.fetch_next_idx(omem, num_pokes) for x in side: if type(x) == int: await self.bot.mongo.update_member( mem, {"$inc": { "balance": -x }}) await self.bot.mongo.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.held_item != 13001: evos = [ evo for evo in pokemon.species.trade_evolutions if (evo.trigger.item is None or evo. trigger.item.id == pokemon.held_item) ] if len(evos) > 0: evo = random.choice(evos) evo_embed = self.bot.Embed(color=0x9CCFFF) evo_embed.title = ( f"Congratulations {mem.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}!", ) self.bot.dispatch("evolve", mem, pokemon, evo.target) self.bot.dispatch("evolve", omem, pokemon, evo.target) update["$set"][ "species_id"] = evo.target.id embeds.append(evo_embed) await self.bot.mongo.update_pokemon( pokemon, update, ) except: await self.end_trade(a.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 await self.end_trade(a.id) # Send msg pages = pagination.ContinuablePages( pagination.FunctionPageSource(num_pages, get_page)) self.bot.menus[a.id] = pages self.bot.menus[b.id] = pages await pages.start(ctx) for evo_embed in embeds: await ctx.send(embed=evo_embed)
async def send_trade(self, ctx, user: discord.Member): # TODO this code is pretty shit. although it does work trade = self.bot.trades[user.id] a, b = trade["users"] done = False if trade[a.id] and trade[b.id] and not trade["executing"]: done = True trade["executing"] = True num_pages = max(math.ceil(len(x) / 20) for x in trade["pokemon"].values()) if done: execmsg = await ctx.send("Executing trade...") users = {k: [("p", x) for x in v] for k, v in trade["pokemon"].items()} for x in users: if trade["redeems"][x] > 0: users[x].insert(0, ("r", trade["redeems"][x])) if trade["pokecoins"][x] > 0: users[x].insert(0, ("c", trade["pokecoins"][x])) embed_pages = list(zip_longest(*[list(chunks(x, 20)) for x in users.values()])) if len(embed_pages) == 0: embed_pages = [[[], []]] async def get_page(source, menu, pidx): embed = self.bot.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}." for mem, page in zip((a, b), embed_pages[pidx]): try: maxn = max(x.idx for t, x in page or [] if t == "p") 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 = f"`{padn(p.idx, maxn)}` **✨ {p.species}**" val += f" • Lvl. {p.level} • {p.iv_percentage:.2%}" return val val = "\n".join( f"{x:,} Pokécoins" if t == "c" else f"{x:,} redeems" if t == "r" else txt(x) for t, x in page or [] ) if val == "": if len(users[mem.id]) == 0: val = "None" else: val = "None on this page" sign = "🟢" if trade[mem.id] 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}.\nReminder: Trading Pokécoins or Pokémon for real-life currencies or items in other bots is prohibited and will result in the suspension of your Pokétwo account!" ) return embed # Check if done embeds = [] if done: try: bothsides = list(enumerate(trade["pokemon"].items())) for u in trade["users"]: member = await self.bot.mongo.fetch_member_info(u) if member.balance < trade["pokecoins"][u.id]: await ctx.send("The trade could not be executed as one user does not have enough Pokécoins.") await self.end_trade(a.id) return if member.redeems < trade["redeems"][u.id]: await ctx.send("The trade could not be executed as one user does not have enough redeems.") await self.end_trade(a.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.bot.mongo.fetch_member_info(mem) omember = await self.bot.mongo.fetch_member_info(omem) idxs = set() num_pokes = len(list(x for x in side if type(x) != int)) idx = await self.bot.mongo.fetch_next_idx(omem, num_pokes) if trade["pokecoins"][i] > 0: await self.bot.mongo.update_member(mem, {"$inc": {"balance": -trade["pokecoins"][i]}}) await self.bot.mongo.update_member(omem, {"$inc": {"balance": trade["pokecoins"][i]}}) if trade["redeems"][i] > 0: await self.bot.mongo.update_member(mem, {"$inc": {"redeems": -trade["redeems"][i]}}) await self.bot.mongo.update_member(omem, {"$inc": {"redeems": trade["redeems"][i]}}) for x in side: pokemon = x if pokemon.idx in idxs: continue idxs.add(pokemon.idx) update = { "$set": { "owner_id": omem.id, "idx": idx, } } idx += 1 if pokemon.held_item != 13001: evos = [ evo for evo in pokemon.species.trade_evolutions if (evo.trigger.item is None or evo.trigger.item.id == pokemon.held_item) ] if len(evos) > 0: evo = random.choice(evos) evo_embed = self.bot.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}!", ) self.bot.dispatch("evolve", mem, pokemon, evo.target) self.bot.dispatch("evolve", omem, pokemon, evo.target) update["$set"]["species_id"] = evo.target.id embeds.append(evo_embed) await self.bot.mongo.update_pokemon( pokemon, update, ) except: await self.end_trade(a.id) raise try: await execmsg.delete() except: pass try: await self.bot.mongo.db.logs.insert_one( { "event": "trade", "users": [a.id, b.id], "pokemon": { str(a.id): [x.id for x in trade["pokemon"][a.id]], str(b.id): [x.id for x in trade["pokemon"][b.id]], }, "pokecoins": { str(a.id): trade["pokecoins"][a.id], str(b.id): trade["pokecoins"][b.id], }, "redeems": { str(a.id): trade["redeems"][a.id], str(b.id): trade["redeems"][b.id], }, } ) except: pass await self.end_trade(a.id) # Send msg pages = pagination.ContinuablePages(pagination.FunctionPageSource(num_pages, get_page)) self.bot.menus[a.id] = pages self.bot.menus[b.id] = pages if menu := trade.get("menu"): menu.stop() await menu.message.delete()