Ruby-Cogs/pokecord/general.py

348 lines
14 KiB
Python

import asyncio
import copy
import json
from typing import Union
import discord
import tabulate
from redbot.core import commands
from redbot.core.i18n import Translator
from redbot.core.utils.chat_formatting import *
from redbot.core.utils.predicates import MessagePredicate
from .abc import MixinMeta
from .converters import Args
from .functions import chunks, poke_embed
from .menus import GenericMenu, PokedexFormat, PokeList, PokeListMenu, SearchFormat
from .statements import *
poke = MixinMeta.poke
_ = Translator("Pokecord", __file__)
class GeneralMixin(MixinMeta):
"""Ava's Pokemon General commands"""
@commands.max_concurrency(1, commands.BucketType.user)
@commands.command(name="list", aliases=["pokemon"])
async def _list(self, ctx, user: discord.Member = None):
"""List a trainers or your own pokémon!"""
conf = await self.user_is_global(ctx.author)
if not await conf.has_starter():
return await ctx.send(
_(
"You haven't picked a starter pokemon yet! Check out {prefix}starter before trying to list your pokemon."
).format(prefix=ctx.clean_prefix)
)
user = user or ctx.author
async with ctx.typing():
result = await self.cursor.fetch_all(query=SELECT_POKEMON, values={"user_id": user.id})
pokemons = []
for i, data in enumerate(result, start=1):
poke = json.loads(data[0])
poke["sid"] = i
pokemons.append(poke)
if not pokemons:
return await ctx.send(_("You don't have any pokémon, go get catching trainer!"))
_id = await conf.pokeid()
await ctx.send(
_("{user}'s selected Pokémon ID is {id}").format(user=user, id=_id),
delete_after=5,
)
await PokeListMenu(
source=PokeList(pokemons),
cog=self,
ctx=ctx,
user=user,
delete_message_after=False,
).start(ctx=ctx, wait=False)
@commands.max_concurrency(1, commands.BucketType.user)
@poke.command()
async def nick(self, ctx, id: int, *, nickname: str):
"""Set a pokémons nickname.
ID refers to the position within your pokémon listing.
This is found at the bottom of the pokemon on `[p]list`"""
conf = await self.user_is_global(ctx.author)
if not await conf.has_starter():
return await ctx.send(
_(
"You haven't picked a starter pokemon yet! Check out {prefix}starter before trying to nickname a pokemon."
).format(prefix=ctx.clean_prefix)
)
if id <= 0:
return await ctx.send(_("The ID must be greater than 0!"))
if len(nickname) > 40:
await ctx.send(
"The nickname you have specified is too big. It must be under 40 characters."
)
return
async with ctx.typing():
result = await self.cursor.fetch_all(
query=SELECT_POKEMON, values={"user_id": ctx.author.id}
)
pokemons = [None]
for data in result:
pokemons.append([json.loads(data[0]), data[1]])
if not pokemons:
return await ctx.send(_("You don't have any pokémon, trainer!"))
if id > len(pokemons):
return await ctx.send(
_(
"You don't have a pokemon at that slot.\nID refers to the position within your pokémon listing.\nThis is found at the bottom of the pokemon on `[p]list`"
)
)
pokemon = pokemons[id]
pokemon[0]["nickname"] = nickname
await self.cursor.execute(
query=UPDATE_POKEMON,
values={
"user_id": ctx.author.id,
"message_id": pokemon[1],
"pokemon": json.dumps(pokemon[0]),
},
)
await ctx.send(
_("Your {pokemon} has been nicknamed `{nickname}`").format(
pokemon=self.get_name(pokemon[0]["name"], ctx.author), nickname=nickname
)
)
@commands.max_concurrency(1, commands.BucketType.user)
@poke.command(aliases=["free"])
async def release(self, ctx, id: int):
"""Release a pokémon."""
conf = await self.user_is_global(ctx.author)
if not await conf.has_starter():
return await ctx.send(
_(
"You haven't picked a starter pokemon yet! Check out {prefix}starter before trying to release a pokemon."
).format(prefix=ctx.clean_prefix)
)
if id <= 0:
return await ctx.send(_("The ID must be greater than 0!"))
async with ctx.typing():
result = await self.cursor.fetch_all(
query=SELECT_POKEMON,
values={"user_id": ctx.author.id},
)
pokemons = [None]
for data in result:
pokemons.append([json.loads(data[0]), data[1]])
if not pokemons:
return await ctx.send(_("You don't have any pokémon, trainer!"))
if id >= len(pokemons):
return await ctx.send(
_(
"You don't have a pokemon at that slot.\nID refers to the position within your pokémon listing.\nThis is found at the bottom of the pokemon on `[p]list`"
)
)
pokemon = pokemons[id]
name = self.get_name(pokemon[0]["name"], ctx.author)
if len(pokemons) == 2:
return await ctx.send(
_(
f"**{name}** is the last pokemon you've got. You cannot release it to the wilds."
)
)
await ctx.send(
_(
"You are about to free {name}, if you wish to continue type `yes`, otherwise type `no`."
).format(name=name)
)
try:
pred = MessagePredicate.yes_or_no(ctx, user=ctx.author)
await ctx.bot.wait_for("message", check=pred, timeout=20)
except asyncio.TimeoutError:
await ctx.send("Exiting operation.")
return
if pred.result:
msg = ""
userconf = await self.user_is_global(ctx.author)
pokeid = await userconf.pokeid()
if id < pokeid:
msg += _(
"\nYour default pokemon may have changed. I have tried to account for this change."
)
await userconf.pokeid.set(pokeid - 1)
elif id == pokeid:
msg += _(
"\nYou have released your selected pokemon. I have reset your selected pokemon to your first pokemon."
)
await userconf.pokeid.set(1)
await self.cursor.execute(
query="DELETE FROM users where message_id = :message_id",
values={"message_id": pokemon[1]},
)
await ctx.send(_("Your {name} has been freed.{msg}").format(name=name, msg=msg))
else:
await ctx.send(_("Operation cancelled."))
@commands.max_concurrency(1, commands.BucketType.user)
@commands.command(usage="id_or_latest")
@commands.guild_only()
async def select(self, ctx, _id: Union[int, str]):
"""Select your default pokémon."""
conf = await self.user_is_global(ctx.author)
if not await conf.has_starter():
return await ctx.send(
_(
"You haven't chosen a starter pokemon yet, check out {prefix}starter for more information."
).format(prefix=ctx.clean_prefix)
)
async with ctx.typing():
result = await self.cursor.fetch_all(
query="""SELECT pokemon, message_id from users where user_id = :user_id""",
values={"user_id": ctx.author.id},
)
pokemons = [None]
for data in result:
pokemons.append([json.loads(data[0]), data[1]])
if not pokemons:
return await ctx.send(_("You don't have any pokemon to select."))
if isinstance(_id, str):
if _id == "latest":
_id = len(pokemons) - 1
else:
await ctx.send(
_("Unidentified keyword, the only supported action is `latest` as of now.")
)
return
if _id < 1 or _id > len(pokemons) - 1:
return await ctx.send(
_(
"You've specified an invalid ID.\nID refers to the position within your pokémon listing.\nThis is found at the bottom of the pokemon on `[p]list`"
)
)
await ctx.send(
_("You have selected {pokemon} as your default pokémon.").format(
pokemon=self.get_name(pokemons[_id][0]["name"], ctx.author)
)
)
conf = await self.user_is_global(ctx.author)
await conf.pokeid.set(_id)
await self.update_user_cache()
@commands.command()
@commands.max_concurrency(1, commands.BucketType.user)
async def pokedex(self, ctx):
"""Check your caught pokémon!"""
async with ctx.typing():
pokemons = await self.config.user(ctx.author).pokeids()
pokemonlist = copy.deepcopy(self.pokemonlist)
for i, pokemon in enumerate(pokemonlist, start=1):
if str(pokemon) in pokemons:
pokemonlist[i]["amount"] = pokemons[str(pokemon)]
a = [value for value in pokemonlist.items()]
chunked = [item for item in chunks(a, 20)]
await GenericMenu(
source=PokedexFormat(chunked),
delete_message_after=False,
cog=self,
len_poke=len(pokemonlist),
).start(
ctx=ctx,
wait=False,
)
@commands.command()
async def psearch(self, ctx, *, args: Args):
"""Search your pokemon.
Arguements must have `--` before them.
`--name` | `--n` - Search pokemon by name.
`--level`| `--l` - Search pokemon by level.
`--id` | `--i` - Search pokemon by ID.
`--variant` | `--v` - Search pokemon by variant.
`--type` | `--t` - Search pokemon by type.
`--gender` | `--g` - Search by gender.
`--iv` | - Search by total IV.
"""
async with ctx.typing():
result = await self.cursor.fetch_all(
query="""SELECT pokemon, message_id from users where user_id = :user_id""",
values={"user_id": ctx.author.id},
)
if not result:
await ctx.send(_("You don't have any pokémon trainer!"))
pokemons = [None]
for data in result:
pokemons.append([json.loads(data[0]), data[1]])
correct = ""
for i, poke in enumerate(pokemons[1:], 1):
name = self.get_name(poke[0]["name"], ctx.author)
poke_str = _(
"{pokemon} **|** Level: {level} **|** ID: {id} **|** Index: {index}\n"
).format(pokemon=name, level=poke[0]["level"], id=poke[0]["id"], index=i)
if args["names"]:
if name.lower() == args["names"].lower():
correct += poke_str
elif args["level"]:
if poke[0]["level"] == args["level"][0]:
correct += poke_str
elif args["id"]:
if poke[0]["id"] == args["id"][0]:
correct += poke_str
elif args["variant"]:
if poke[0].get("variant", "None").lower() == args["variant"].lower():
correct += poke_str
elif args["iv"]:
if sum(poke[0]["ivs"].values()) == args["iv"][0]:
correct += poke_str
elif args["gender"]:
if (
args["gender"].lower()
== poke[0].get("gender", "No Gender").lower().split()[0]
):
correct += poke_str
elif args["type"]:
if args["type"].lower() in [x.lower() for x in poke[0]["type"]]:
correct += poke_str
if not correct:
await ctx.send("No pokémon returned for that search.")
return
content = list(pagify(correct, page_length=1024))
await GenericMenu(
source=SearchFormat(content),
delete_message_after=False,
).start(ctx=ctx, wait=False)
@commands.command()
@commands.max_concurrency(1, commands.BucketType.user)
async def current(self, ctx):
"""Show your current selected pokemon"""
conf = await self.user_is_global(ctx.author)
if not await conf.has_starter():
return await ctx.send(
_(
"You haven't picked a starter pokemon yet! Check out {prefix}starter before trying to list your pokemon."
).format(prefix=ctx.clean_prefix)
)
user = ctx.author
async with ctx.typing():
result = await self.cursor.fetch_all(query=SELECT_POKEMON, values={"user_id": user.id})
pokemons = []
for i, data in enumerate(result, start=1):
poke = json.loads(data[0])
poke["sid"] = i
pokemons.append(poke)
if not pokemons:
return await ctx.send(_("You don't have any pokémon, go get catching trainer!"))
_id = await conf.pokeid()
try:
pokemon = pokemons[_id - 1]
except IndexError:
await ctx.send(
_(
"An error occured trying to find your pokemon at slot {slotnum}\nAs a result I have set your default pokemon to 1."
).format(slotnum=_id)
)
await conf.pokeid.set(1)
return
else:
embed, _file = await poke_embed(self, ctx, pokemon, file=True)
await ctx.send(embed=embed, file=_file)