Code Monkey home page Code Monkey logo

discord-pokemon-battles's Introduction

Brock

Unit Tests Integration Tests

A Discord bot that allows you to have Pokemon battles on Discord with your friends.

It uses pokemonbattlelib served over HTTP to simulate the battles using generation 4 rules.

Setup

Required:

Put your discord bot's token in the token file.

You can optionally set up a virtual environment,

conda env create -f environment.yml
conda env update -f environment.yml --prune # update an existing environment
conda activate pkmn-discord

and then install the development dependencies.

pip install -r requirements-dev.txt
pre-commit install

Developing

docker-compose up

To force a rebuild:

docker-compose up --build

The battle API is served over port 4000, and the flask server is served over port 5000.

Linting

You can run these scripts to check your code. (Requires the packages in requirements-dev.txt to be installed.)

./scripts/lint-style.sh
./scripts/lint-check-types.sh

Commands

Commands are subject to change since we are in the development stage at the moment. This will be an evolving list of commands!

Prefix: p!

  • help
  • ping will return pong
  • challenge OPPONENT

Testing

Unit Tests

docker-compose run bot ./scripts/test.sh

Integration Tests

Setup

  1. Create another bot. This will be the "tester".
  2. Make sure these settings are enabled under the Bot section.

Both Privileged Gateway Intents enabled

  1. Run docker-compose run bot ./scripts/integration-test.sh to create the config file at tests/config
  2. Fill out the fields in the newly generated tests/config

Running the Integration Tests

  1. Make sure Brock is running
docker-compose up -d
  1. Run the tests
docker-compose run bot ./scripts/integration-test.sh

If tests/config is not present, it will be created for you when you run the script. It requires another bot (the tester) to send messages and interact with Brock (the testee).

  1. You can now stop Brock
docker-compose down

discord-pokemon-battles's People

Contributors

a-very-cunning-ham avatar dyc3 avatar elenirotsides avatar jlora23 avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

kennethskelton

discord-pokemon-battles's Issues

BattleContext Class

Background

A battle context describes the POV of a given Pokemon on the battlefield. It provides enough information for a user to make an informed decision about what turn to make next.

Fields

  • Battle: The state of the battlefield
  • Pokemon: The pokemon that this context belongs to.
  • Team: The team ID of the Pokemon
  • Targets: All pokemon on the battlefield
  • Allies: Ally targets in relation to the Pokemon
  • Opponents: Enemy targets in relation to the Pokemon

Objectives

  • Create a class called BattleContext in pkmntypes.py
  • Create a function/constructor to parse the json into an instance of BattleContext
    • In Python, when JSON is parsed, it gets turned into a dict. So the function should take a dict as input, not a string.
    • Parsing the pokemon objects is not necessary for this issue, as that should be taken care of by #16 .
Example JSON
{
    "Battle": {
        "Weather": 0,
        "ShiftSet": false,
        "State": 1
    },
    "Pokemon": {
        "Name": "Pichu",
        "NatDex": 172,
        "Level": 79,
        "Ability": 98,
        "TotalExperience": 493039,
        "Gender": 0,
        "IVs": [
            1,
            2,
            4,
            0,
            2,
            1
        ],
        "EVs": [
            18,
            17,
            22,
            32,
            21,
            41
        ],
        "Nature": 8,
        "Stats": [
            124,
            72,
            35,
            66,
            65,
            108
        ],
        "StatModifiers": [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        "StatusEffects": 0,
        "CurrentHP": 124,
        "HeldItem": {
            "Id": 0,
            "Name": "",
            "Category": 0,
            "FlingPower": 0,
            "FlingEffect": 0,
            "Flags": 0
        },
        "Moves": [
            {
                "Id": 433,
                "CurrentPP": 0,
                "MaxPP": 0,
                "Name": "Trick Room",
                "Type": 8192,
                "Category": 0,
                "Targets": 12,
                "Priority": -7,
                "Power": 0,
                "Accuracy": 0,
                "InitialMaxPP": 0
            },
            {
                "Id": 225,
                "CurrentPP": 0,
                "MaxPP": 0,
                "Name": "Dragon Breath",
                "Type": 32768,
                "Category": 2,
                "Targets": 10,
                "Priority": 0,
                "Power": 60,
                "Accuracy": 100,
                "InitialMaxPP": 0
            },
            {
                "Id": 232,
                "CurrentPP": 0,
                "MaxPP": 0,
                "Name": "Metal Claw",
                "Type": 256,
                "Category": 1,
                "Targets": 10,
                "Priority": 0,
                "Power": 50,
                "Accuracy": 95,
                "InitialMaxPP": 0
            },
            {
                "Id": 59,
                "CurrentPP": 0,
                "MaxPP": 0,
                "Name": "Blizzard",
                "Type": 16384,
                "Category": 2,
                "Targets": 11,
                "Priority": 0,
                "Power": 110,
                "Accuracy": 70,
                "InitialMaxPP": 0
            }
        ],
        "Friendship": 0,
        "OriginalTrainerID": 0,
        "Type": 4096
    },
    "Team": 0,
    "Allies": [
        {
            "Party": 0,
            "Slot": 0,
            "Team": 0,
            "Pokemon": {
                "Name": "Pichu",
                "NatDex": 172,
                "Level": 79,
                "Ability": 98,
                "TotalExperience": 493039,
                "Gender": 0,
                "IVs": [
                    1,
                    2,
                    4,
                    0,
                    2,
                    1
                ],
                "EVs": [
                    18,
                    17,
                    22,
                    32,
                    21,
                    41
                ],
                "Nature": 8,
                "Stats": [
                    124,
                    72,
                    35,
                    66,
                    65,
                    108
                ],
                "StatModifiers": [
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0
                ],
                "StatusEffects": 0,
                "CurrentHP": 124,
                "HeldItem": {
                    "Id": 0,
                    "Name": "",
                    "Category": 0,
                    "FlingPower": 0,
                    "FlingEffect": 0,
                    "Flags": 0
                },
                "Moves": [
                    {
                        "Id": 433,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Trick Room",
                        "Type": 8192,
                        "Category": 0,
                        "Targets": 12,
                        "Priority": -7,
                        "Power": 0,
                        "Accuracy": 0,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 225,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Dragon Breath",
                        "Type": 32768,
                        "Category": 2,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 60,
                        "Accuracy": 100,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 232,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Metal Claw",
                        "Type": 256,
                        "Category": 1,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 50,
                        "Accuracy": 95,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 59,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Blizzard",
                        "Type": 16384,
                        "Category": 2,
                        "Targets": 11,
                        "Priority": 0,
                        "Power": 110,
                        "Accuracy": 70,
                        "InitialMaxPP": 0
                    }
                ],
                "Friendship": 0,
                "OriginalTrainerID": 0,
                "Type": 4096
            }
        }
    ],
    "Opponents": [
        {
            "Party": 0,
            "Slot": 0,
            "Team": 1,
            "Pokemon": {
                "Name": "Mew",
                "NatDex": 151,
                "Level": 6,
                "Ability": 108,
                "TotalExperience": 179,
                "Gender": 0,
                "IVs": [
                    3,
                    1,
                    1,
                    4,
                    0,
                    3
                ],
                "EVs": [
                    7,
                    24,
                    41,
                    11,
                    3,
                    20
                ],
                "Nature": 8,
                "Stats": [
                    28,
                    17,
                    17,
                    17,
                    17,
                    17
                ],
                "StatModifiers": [
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0
                ],
                "StatusEffects": 0,
                "CurrentHP": 28,
                "HeldItem": {
                    "Id": 0,
                    "Name": "",
                    "Category": 0,
                    "FlingPower": 0,
                    "FlingEffect": 0,
                    "Flags": 0
                },
                "Moves": [
                    {
                        "Id": 61,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Bubble Beam",
                        "Type": 1024,
                        "Category": 2,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 65,
                        "Accuracy": 100,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 457,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Head Smash",
                        "Type": 32,
                        "Category": 1,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 150,
                        "Accuracy": 80,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 434,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Draco Meteor",
                        "Type": 32768,
                        "Category": 2,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 130,
                        "Accuracy": 90,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 359,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Hammer Arm",
                        "Type": 2,
                        "Category": 1,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 100,
                        "Accuracy": 90,
                        "InitialMaxPP": 0
                    }
                ],
                "Friendship": 0,
                "OriginalTrainerID": 0,
                "Type": 8192
            }
        }
    ],
    "Targets": [
        {
            "Party": 0,
            "Slot": 0,
            "Team": 0,
            "Pokemon": {
                "Name": "Pichu",
                "NatDex": 172,
                "Level": 79,
                "Ability": 98,
                "TotalExperience": 493039,
                "Gender": 0,
                "IVs": [
                    1,
                    2,
                    4,
                    0,
                    2,
                    1
                ],
                "EVs": [
                    18,
                    17,
                    22,
                    32,
                    21,
                    41
                ],
                "Nature": 8,
                "Stats": [
                    124,
                    72,
                    35,
                    66,
                    65,
                    108
                ],
                "StatModifiers": [
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0
                ],
                "StatusEffects": 0,
                "CurrentHP": 124,
                "HeldItem": {
                    "Id": 0,
                    "Name": "",
                    "Category": 0,
                    "FlingPower": 0,
                    "FlingEffect": 0,
                    "Flags": 0
                },
                "Moves": [
                    {
                        "Id": 433,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Trick Room",
                        "Type": 8192,
                        "Category": 0,
                        "Targets": 12,
                        "Priority": -7,
                        "Power": 0,
                        "Accuracy": 0,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 225,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Dragon Breath",
                        "Type": 32768,
                        "Category": 2,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 60,
                        "Accuracy": 100,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 232,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Metal Claw",
                        "Type": 256,
                        "Category": 1,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 50,
                        "Accuracy": 95,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 59,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Blizzard",
                        "Type": 16384,
                        "Category": 2,
                        "Targets": 11,
                        "Priority": 0,
                        "Power": 110,
                        "Accuracy": 70,
                        "InitialMaxPP": 0
                    }
                ],
                "Friendship": 0,
                "OriginalTrainerID": 0,
                "Type": 4096
            }
        },
        {
            "Party": 0,
            "Slot": 0,
            "Team": 1,
            "Pokemon": {
                "Name": "Mew",
                "NatDex": 151,
                "Level": 6,
                "Ability": 108,
                "TotalExperience": 179,
                "Gender": 0,
                "IVs": [
                    3,
                    1,
                    1,
                    4,
                    0,
                    3
                ],
                "EVs": [
                    7,
                    24,
                    41,
                    11,
                    3,
                    20
                ],
                "Nature": 8,
                "Stats": [
                    28,
                    17,
                    17,
                    17,
                    17,
                    17
                ],
                "StatModifiers": [
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0
                ],
                "StatusEffects": 0,
                "CurrentHP": 28,
                "HeldItem": {
                    "Id": 0,
                    "Name": "",
                    "Category": 0,
                    "FlingPower": 0,
                    "FlingEffect": 0,
                    "Flags": 0
                },
                "Moves": [
                    {
                        "Id": 61,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Bubble Beam",
                        "Type": 1024,
                        "Category": 2,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 65,
                        "Accuracy": 100,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 457,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Head Smash",
                        "Type": 32,
                        "Category": 1,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 150,
                        "Accuracy": 80,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 434,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Draco Meteor",
                        "Type": 32768,
                        "Category": 2,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 130,
                        "Accuracy": 90,
                        "InitialMaxPP": 0
                    },
                    {
                        "Id": 359,
                        "CurrentPP": 0,
                        "MaxPP": 0,
                        "Name": "Hammer Arm",
                        "Type": 2,
                        "Category": 1,
                        "Targets": 10,
                        "Priority": 0,
                        "Power": 100,
                        "Accuracy": 90,
                        "InitialMaxPP": 0
                    }
                ],
                "Friendship": 0,
                "OriginalTrainerID": 0,
                "Type": 8192
            }
        }
    ]
}

Add Item turns to turn prompt

The turn prompt currently only prompts the user to do a fight turn. Instead, it should prompt the user if they want to fight, use an item, or switch pokemon.

Pokemon Ownership

Users need to be able to own pokemon. Ownership should be indicated by putting the pokemon's id in the user's profile.

UserProfile already contains a list of Object IDs for pokemon, so all this issue entails is adding a method to assign ownership of a pokemon to a profile.

Turn prompts are blocked by other battle participants

When there are 2 discord users in a battle, they get prompted for turns one at a time.

We want turn prompts to be sent out at the same time, so people don't have to wait on other people to finish their turn just so they can start theirs.

Update pokemon state at the end of the battle

At the end of a battle, the pokemon that participated in the battle need to have their new state stored in persistent storage so that users are able to train and level up their pokemon.

Database for persistance

When a user gets a pokemon, the pokemon should be saved in the database, and assigned an ID (probably automatically by the database). The user's profile should be updated with the pokemon's id to denote ownership.

  • Set up mongodb in docker-compose.yml
  • Write helper functions to interact with the database

Refactor code to use BattleContext class

Now that we have these helper classes, we need to actually use them.

All the functions that use battle context as dicts that need to be converted to use battle context as BattleContext

  • battleapi.get_battle_context
  • util.prompt_for_turn

Refactor code to use Pokemon class

Now that we have these helper classes, we need to actually use them.

All the functions that use pokemon as dicts that need to be converted to use pokemon as Pokemon

  • BattleContext.__init__
  • battleapi,generate_pokemon
  • util.prompt_for_turn

Unable to save user profile

running

pokemon = await battleapi.generate_pokemon()
await pokemon.save()
profile = UserProfile()
profile.user_id = message.author.id
profile.add_pokemon(pokemon)
await profile.save()

results in an error of discord.ext.commands.errors.CommandInvokeError: Command raised an exception: InvalidDocument: cannot encode object: {ObjectId('60761d525022f450ed0703c2')}, of type: <class 'set'>

the full error is:

bot_1  | Ignoring exception in command minigame:
bot_1  | Traceback (most recent call last):
bot_1  |   File "/usr/local/lib/python3.9/site-packages/discord/ext/commands/core.py", line 85, in wrapped
bot_1  |     ret = await coro(*args, **kwargs)
bot_1  |   File "/code/bot.py", line 108, in minigame
bot_1  |     await profile.save()
bot_1  |   File "/code/userprofile.py", line 36, in save
bot_1  |     await storage.save_object(self, session=session)
bot_1  |   File "/code/storage.py", line 53, in save_object
bot_1  |     result = await coll.insert_one(
bot_1  |   File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 52, in run
bot_1  |     result = self.fn(*self.args, **self.kwargs)
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/collection.py", line 698, in insert_one
bot_1  |     self._insert(document,
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/collection.py", line 613, in _insert
bot_1  |     return self._insert_one(
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/collection.py", line 602, in _insert_one
bot_1  |     self.__database.client._retryable_write(
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/mongo_client.py", line 1498, in _retryable_write
bot_1  |     return self._retry_with_session(retryable, func, s, None)
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/mongo_client.py", line 1384, in _retry_with_session
bot_1  |     return self._retry_internal(retryable, func, session, bulk)
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/mongo_client.py", line 1416, in _retry_internal
bot_1  |     return func(session, sock_info, retryable)
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/collection.py", line 590, in _insert_command
bot_1  |     result = sock_info.command(
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/pool.py", line 699, in command
bot_1  |     self._raise_connection_failure(error)
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/pool.py", line 683, in command
bot_1  |     return command(self, dbname, spec, slave_ok,
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/network.py", line 120, in command
bot_1  |     request_id, msg, size, max_doc_size = message._op_msg(
bot_1  |   File "/usr/local/lib/python3.9/site-packages/pymongo/message.py", line 714, in _op_msg
bot_1  |     return _op_msg_uncompressed(
bot_1  | bson.errors.InvalidDocument: cannot encode object: {ObjectId('60761d525022f450ed0703c2')}, of type: <class 'set'>
bot_1  |
bot_1  | The above exception was the direct cause of the following exception:
bot_1  |
bot_1  | Traceback (most recent call last):
bot_1  |   File "/usr/local/lib/python3.9/site-packages/discord/ext/commands/bot.py", line 939, in invoke
bot_1  |     await ctx.command.invoke(ctx)
bot_1  |   File "/usr/local/lib/python3.9/site-packages/discord/ext/commands/core.py", line 863, in invoke
bot_1  |     await injected(*ctx.args, **ctx.kwargs)
bot_1  |   File "/usr/local/lib/python3.9/site-packages/discord/ext/commands/core.py", line 94, in wrapped
bot_1  |     raise CommandInvokeError(exc) from exc
bot_1  | discord.ext.commands.errors.CommandInvokeError: Command raised an exception: InvalidDocument: cannot encode object: {ObjectId('60761d525022f450ed0703c2')}, of type: <class 'set'>

Add some way to use an existing message as the message for a reaction menu

Right now, prompt_menu requires you to specify the menu items that will be displayed in the message. However, this doesn't work great if we want to render (display) the menu differently, like with an image.

It would be nice to just specify the Message and the number of menu items, or a list of emojis to use as the menu items instead. Should work very similarly to prompt_menu.

This doesn't necessarily need to replace prompt_menu

Pretty printing for HealTransaction

Related code:

def pretty(self) -> str:
"""Get a human-readable representation of this transaction."""
if self.type == 0:
user = Pokemon(**self.args["User"])
target = Target(**self.args["Target"])
move = self.args["Move"]
return f"{user.Name} used {move['Name']} on {target.pokemon.Name} for {self.args['Damage']} damage."
elif self.type == 8:
target = Target(**self.args["Target"])
return f"{target.pokemon.Name} fainted."
elif self.type == 11:
return f"The battle has ended."
else:
return f"TODO: {self.name}<{self.type}> {self.args}"

Need a command to quickly set up a random battle

For testing purposes, it would be nice to have a command that would set up a random battle between 2 parties.

Currently, the challenge command does make a random battle, but it only generates 1v1 battles.

A random battle has 2 parties with a random amount (1-6) of random pokemon in each party, where each pokemon has random moves.

Need an easy way to generate pokemon

This can be done with the battle api endpoint GET /pokedex/generate. It can take the query parameters natdex, level, and moves

Example payload:

{"Name":"Pichu","NatDex":172,"Level":79,"Ability":null,"TotalExperience":493039,"Gender":0,"IVs":[1,2,4,0,2,1],"EVs":[18,17,22,32,21,41],"Nature":8,"Stats":[124,72,35,66,65,108],"StatModifiers":[0,0,0,0,0,0,0,0,0],"StatusEffects":0,"CurrentHP":124,"HeldItem":null,"Moves":[{"ID":396,"Name":"Aura Sphere","Type":2,"Category":2,"Targets":10,"CurrentPP":20,"MaxPP":20,"Priority":0,"Power":80,"Accuracy":0},{"ID":389,"Name":"Sucker Punch","Type":65536,"Category":1,"Targets":10,"CurrentPP":5,"MaxPP":5,"Priority":1,"Power":70,"Accuracy":100},{"ID":55,"Name":"Water Gun","Type":1024,"Category":2,"Targets":10,"CurrentPP":25,"MaxPP":25,"Priority":0,"Power":40,"Accuracy":100},{"ID":275,"Name":"Ingrain","Type":2048,"Category":0,"Targets":7,"CurrentPP":20,"MaxPP":20,"Priority":0,"Power":0,"Accuracy":0}],"Friendship":0,"OriginalTrainerID":0,"Type":4096}

Battle API container does not stay up to date with upstream code

The battle API container does not stay up to date with the upstream code, because the docker layers get cached, and don't get invalidated.

Solution is probably to clone the code outside of the container, and copy it in, instead of just directly cloning the repo inside the docker container.

Load pokemon from database by ID

We can save pokemon to the database, but we can't load them back up without directly interacting with storage.db

  • Should take ObjectId
  • Should return Pokemon
  • Should raise exception if not found

Reaction menu abstraction

We need some way to reuse the code for the reaction menu that we created for the turn prompt (located in util.py, prompt_for_turn).

  • Should take menu items as input
  • Should return the index of the menu item that was selected.

Starter pokemon selection

When a user interacts with the bot, and there is no user profile, the bot should tell the user to run p!begin to pick a starter pokemon.

The p!begin command should allow the user to pick any starter pokemon from any of the available generations.

blocked by #60

Pokemon Class

Objectives

  • Create a class called Pokemon in pkmntypes.py
  • Create a function/constructor to parse the json into an instance of Pokemon
    • In Python, when JSON is parsed, it gets turned into a dict. So the function should take a dict as input, not a string.
Example JSON
{
    "Name": "Charizard",
    "NatDex": 6,
    "Level": 83,
    "Ability": 9,
    "TotalExperience": 590969,
    "Gender": 0,
    "IVs": [
        3,
        3,
        0,
        4,
        0,
        4
    ],
    "EVs": [
        18,
        37,
        4,
        15,
        23,
        5
    ],
    "Nature": 8,
    "Stats": [
        228,
        154,
        135,
        191,
        150,
        175
    ],
    "StatModifiers": [
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
    ],
    "StatusEffects": 0,
    "CurrentHP": 228,
    "HeldItem": {
        "Id": 0,
        "Name": "",
        "Category": 0,
        "FlingPower": 0,
        "FlingEffect": 0,
        "Flags": 0
    },
    "Moves": [
        {
            "Id": 450,
            "CurrentPP": 0,
            "MaxPP": 0,
            "Name": "Bug Bite",
            "Type": 64,
            "Category": 1,
            "Targets": 10,
            "Priority": 0,
            "Power": 60,
            "Accuracy": 100,
            "InitialMaxPP": 0
        },
        {
            "Id": 196,
            "CurrentPP": 0,
            "MaxPP": 0,
            "Name": "Icy Wind",
            "Type": 16384,
            "Category": 2,
            "Targets": 11,
            "Priority": 0,
            "Power": 55,
            "Accuracy": 95,
            "InitialMaxPP": 0
        },
        {
            "Id": 53,
            "CurrentPP": 0,
            "MaxPP": 0,
            "Name": "Flamethrower",
            "Type": 512,
            "Category": 2,
            "Targets": 10,
            "Priority": 0,
            "Power": 90,
            "Accuracy": 100,
            "InitialMaxPP": 0
        },
        {
            "Id": 63,
            "CurrentPP": 0,
            "MaxPP": 0,
            "Name": "Hyper Beam",
            "Type": 1,
            "Category": 2,
            "Targets": 10,
            "Priority": 0,
            "Power": 150,
            "Accuracy": 90,
            "InitialMaxPP": 0
        }
    ],
    "Friendship": 0,
    "OriginalTrainerID": 0,
    "Type": 516
}

View owned pokemon

Users need to be able to view all their pokemon.

  • All pokemon in a list, each pokemon has a small summary
  • Single pokemon with extra details

Helper module to communicate with the battle api

Currently, we have a decent amount of code that communicates with the battle api. The problem is that it's kinda verbose, example:

async with aiohttp.ClientSession() as session:
	async with session.get(f"http://api:4000/battle/simulate?id={bid}") as resp:

It would be nice to be able to replace this with something like:

results = await battleapi.simulate(bid)

Display transations in original channel and in participants DMs

Transactions describe what exactly happened in the battle.

Transaction fields:

  • type - int - Denotes the type of transaction
  • name - str - The name of the transaction
  • args - dict - The transaction's parameters. Different transactions can have different parameters

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.