Skip to content

Commit

Permalink
Document changes and Dex
Browse files Browse the repository at this point in the history
With Dex now having basic documentation, all our API documentation is
now inter-linked.
  • Loading branch information
Zarel committed Jun 9, 2021
1 parent f47e38c commit a813a55
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 157 deletions.
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ PS has other useful command-line invocations, which you can investigate with `./

Unit tests can be run with `npm test`. You can run specific unit tests with `npx mocha -g "text"`, which will run all unit tests whose name contains "text", or you can just edit the unit test from `it` to `it.only`.

Packaging for npm is done by running `./build decl && npm publish`. Only Zarel has the NPM credentials to do this, but feel free to request a new NPM package if you need something.


Contributing
------------------------------------------------------------------------
Expand Down Expand Up @@ -293,6 +295,8 @@ In general, we prefer modern ways of writing things as long as they're supported
- `.forEach`: Don't use; we always prefer `for`...`of` for readability as well as perf (others like `map`/`filter` are fine, though)
- `.reduce`: we usually prefer `for`...`of` for readability, but you can use it in code that you code-own if you really want to
- Multiline template strings: A frequent source of bugs, so we prefer to explicitly use `\n` and concatenate over multiple lines.
- `async`/`await`: We prefer it for readability, but in certain cases we use raw Promises or even callbacks for performance. Don't worry about it too much; we usually won't nitpick code that uses any async implementation (although we might insist on `async`/`await` if the reability difference is huge).
Expand Down
107 changes: 107 additions & 0 deletions sim/DEX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
Dex
===

`Dex` is a library for getting information about Pokémon, moves, items, abilities, natures, stats, etc.

By default, `Dex` gets information about the latest games (currently Pokémon Sword and Shield), but `Dex.mod` can be used to get information about other games.

```js
const {Dex} = require('pokemon-showdown');

const tackle = Dex.moves.get('Tackle');

console.log(tackle.basePower); // prints 40
```


Nonstandard information
-----------------------

The Dex API gives access to a lot of nonstandard data (from other games, from CAP, unreleased things, etc). You often want to filter it out before using it.

See NONSTANDARD.md for details: https://github.com/smogon/pokemon-showdown/blob/master/sim/NONSTANDARD.md

Nonstandard things will still have `exists: true`, but things we don't have information for at all (for instance, if you typo) will have `exists: false`.

`isNonstandard` will be `null` for normal things.

```js
const {Dex} = require('pokemon-showdown');

const frobnicate = Dex.moves.get('frobnicate');
console.log(frobnicate.exists); // prints false
console.log(missingno.isNonstandard); // prints 'Custom'

const tomohawk = Dex.species.get('tomohawk');
console.log(tomohawk.exists); // prints true
console.log(tomohawk.isNonstandard); // prints 'CAP'

const pikachu = Dex.species.get('pikachu');
console.log(pikachu.exists); // prints true
console.log(pikachu.isNonstandard); // prints null
```


`Dex.mod`
---------

`Dex.mod(modName: string): ModdedDex`

* `Dex` by itself is an object for getting latest-generation information. To get information about another generation, replace `Dex` with `Dex.mod(modName)`. For instance, to get information about Pokémon Yellow, replace `Dex` with `Dex.mod('gen1')`.

In the rest of this page, `dex` will refer to any instance of `ModdedDex`, either `Dex` or the return value of `Dex.mod`.

```js
const {Dex} = require('pokemon-showdown');

const tackle = Dex.mod('gen1').moves.get('Tackle');

console.log(tackle.basePower); // returns 35
```


Return values
-------------

Return values have not been stabilized yet. Use the TypeScript definitions if you'd like, but you should probably pin a specific dependency version.


`dex: ModdedDex`
----------------

`dex.moves.get(moveName: string): Move`

* Gets information about a move. `moveName` can have any capitalization or whitespace.

[This includes nonstandard information.](#Nonstandard-information).

`dex.moves.all(): Move[]`

* Lists all moves we have information for. [This includes nonstandard information.](#Nonstandard-information).

`dex.species.get(speciesName: string): Species`

* Gets information about a Pokémon species or forme. `speciesName` can have any capitalization or whitespace. [This includes nonstandard information.](#Nonstandard-information).

Forme information is documented here: https://github.com/smogon/pokemon-showdown/blob/master/data/FORMES.md

`dex.species.all(): Species[]`

* Lists all Pokémon species we have information for. [This includes nonstandard information.](#Nonstandard-information).

`dex.abilities.get(abilitysName: string): Ability`

* Gets information about an ability. `abilitysName` can have any capitalization or whitespace. [This includes nonstandard information.](#Nonstandard-information).

`dex.abilities.all(): Ability[]`

* Lists all abilities we have information for. [This includes nonstandard information.](#Nonstandard-information).

`dex.items.get(itemName: string): Item`

* Gets information about an item. `itemName` can have any capitalization or whitespace. [This includes nonstandard information.](#Nonstandard-information).

`dex.items.all(): Item[]`

* Lists all items we have information for. [This includes nonstandard information.](#Nonstandard-information).

12 changes: 6 additions & 6 deletions sim/NONSTANDARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ Unobtainable Hidden Abilities

In Gen 5, the game data contained a lot of Hidden Abilities, such as Volt Absorb Zapdos, which ended up never getting released, and were later retconned.

Pokémon Showdown does not contain this data. Pokémon with never-released Gen 5 Hidden Abilities are recorded as simply not having Hidden Abilities in Gen 5.
Pokémon with never-released Gen 5 Hidden Abilities have `species.unreleasedHidden` set to `true` in Gen 5.


Typed Hidden Powers
-------------------

The data contains information for moves named "Hidden Power Fire", "Hidden Power Ice", etc. These are provided for convenience when building teams – selecting them simultaneously sets the move to "Hidden Power" and the Pokémon's IVs as appropriate – and when running damage calculations.
The data contains information for moves named "Hidden Power Fire", "Hidden Power Ice", etc. These are provided for convenience: when building teams (to set the move to "Hidden Power" and change IVs), when running damage calculations, and when exporting or sending movesets.

These are matched with `move.realMove === "Hidden Power"`. Since no other move has this feature, you can also check `move.realMove` for existence.

Expand All @@ -83,7 +83,7 @@ Max moves

Max moves cannot be learned normally, and behave weirdly if hacked into a Pokémon's moveset.

They are matched with `move.isMax`.
They are matched with `move.isMax`. `move.isNonstandard === null` for Max moves.


G-Max moves
Expand All @@ -99,7 +99,7 @@ Z-moves

Z-moves cannot be learned normally, and behave weirdly if hacked onto a Pokémon's moveset.

Damaging and Pokémon-specific Z moves are matched with `move.isZ`.
Damaging and Pokémon-specific Z moves are matched with `move.isZ`. `move.isNonstandard === null` for Z moves.


Z-status moves
Expand Down Expand Up @@ -135,12 +135,12 @@ There is an Ability named "-" in Gen 8, and "No Ability" in some older games, wh

Pokémon Showdown always calls it "No Ability".

No Ability has `ability.isNonstandard === 'Past'` in Gen 3+.
No Ability has `ability.isNonstandard === 'Past'` in Gen 3+. In Gen 1-2, No Ability is considered the only legal ability, and will have `ability.isNonstandard === null`.


Items with no competitive effect
--------------------------------

We do not carry information about all holdable items. Players wishing to hold an item with no competitive effect can simply hold a "Poke Ball".

`Dex.items.all()` only contains information about items that are competitively relevant.
`Dex.items.all()` only contains information about items that are competitively relevant. Do not rely on this not to have any given item; "competitively relevant" is not an objective metric and may change (especially since Fling does have an effect for most items we currently consider irrelevant).
163 changes: 17 additions & 146 deletions sim/README.md
Original file line number Diff line number Diff line change
@@ -1,160 +1,31 @@
Simulator
=========
Node.js package
===============

Pokémon Showdown's simulator API is implemented as a `ReadWriteStream`. You write player choices to it, and you read protocol messages from it.
Simulating battles
------------------

`npm install pokemon-showdown`
See: https://github.com/smogon/pokemon-showdown/blob/master/sim/SIMULATOR.md

```js
const Sim = require('pokemon-showdown');
stream = new Sim.BattleStream();
Also available as a command-line API!

(async () => {
for await (const output of stream) {
console.log(output);
}
})();

stream.write(`>start {"formatid":"gen7randombattle"}`);
stream.write(`>player p1 {"name":"Alice"}`);
stream.write(`>player p2 {"name":"Bob"}`);
```
Validating and converting teams
-------------------------------

The stream can also be accessed from other programming languages using standard IO.
See: https://github.com/smogon/pokemon-showdown/blob/master/sim/TEAMS.md

In this case, you would clone the repository, and then run:
Also available as a command-line API!

```bash
echo '>start {"formatid":"gen7randombattle"}
>player p1 {"name":"Alice"}
>player p2 {"name":"Bob"}
' | ./pokemon-showdown simulate-battle
```

Getting Pokédex information
---------------------------

Writing to the simulator
------------------------
See: https://github.com/smogon/pokemon-showdown/blob/master/sim/DEX.md

In a standard battle, what you write to the simulator looks something like this:

```
>start {"formatid":"gen7ou"}
>player p1 {"name":"Alice","team":"insert packed team here"}
>player p2 {"name":"Bob","team":"insert packed team here"}
>p1 team 123456
>p2 team 123456
>p1 move 1
>p2 switch 3
>p1 move 3
>p2 move 2
```
Undocumented APIs
-----------------

(In a data stream, messages should be delimited by `\n`; in an object stream, `\n` will be implicitly added after every message.)

Notice that every line starts with `>`. Lines not starting with `>` are comments, so that input logs can be mixed with output logs and/or normal text easily.

Note that the text after `>p1`, `>p2`, `>p3`, or `>p4` can be untrusted input directly from the player, and should be treated accordingly.

Possible message types include:

```
>start OPTIONS
```

Starts a battle:

`OPTIONS` is a JSON object containing the following properties (optional, except `formatid`):

- `formatid` - a string representing the format ID

- `seed` - an array of four numbers representing a seed for the random number generator (defaults to a random seed)

- `p1` - `PLAYEROPTIONS` for player 1 (defaults to no player; player options must then be passed with `>player p1`)

- `p2` - `PLAYEROPTIONS` for player 2 (defaults to no player; player options must then be passed with `>player p2`)

- `p3` - `PLAYEROPTIONS` for player 3 (defaults to no player; player options must then be passed with `>player p3`)

- `p4` - `PLAYEROPTIONS` for player 4 (defaults to no player; player options must then be passed with `>player p4`)

If `p1` and `p2` (and `p3` and `p4` for 4 player battles) are specified, the battle will begin immediately. Otherwise, they must be specified with `>player` before the battle will begin.

See documentation of `>player` (below) for `PLAYEROPTIONS`.

```
>player PLAYERID PLAYEROPTIONS
```

Sets player information:

`PLAYERID` is `p1`, `p2`, `p3`, or `p4`

`PLAYEROPTIONS` is a JSON object containing the following properties (all optional):

- `name` is a string for the player name (defaults to "Player 1" or "Player 2")

- `avatar` is a string for the player avatar (defaults to "")

- `team` is a team (either in JSON or a string in [packed format][https://github.com/smogon/pokemon-showdown/blob/master/sim/TEAMS.md])

`team` will not be validated! [Use the team validator first][https://github.com/smogon/pokemon-showdown/blob/master/sim/TEAMS.md]. In random formats, `team` can be left out or set to `null` to have the team generator generate a random team for you.

```
>p1 CHOICE
>p2 CHOICE
>p3 CHOICE
>p4 CHOICE
```

Makes a choice for a player. [Possible choices are documented in `SIM-PROTOCOL.md`][possible-choices].

[possible-choices]: https://github.com/smogon/pokemon-showdown/blob/master/sim/SIM-PROTOCOL.md#possible-choices


Reading from the simulator
--------------------------

The simulator will send back messages. In a data stream, they're delimited by `\n\n`. In an object stream, they will just be sent as separate strings.

Messages start with a message type followed by `\n`. A message will never have two `\n` in a row, so that `\n\n` unambiguously separates messages.

A message looks like:

update
MESSAGES

An update which should be sent to all players and spectators.

[The messages the simulator sends back are documented in `SIM-PROTOCOL.md`][sim-protocol]. You can also look at a replay log for examples.

[sim-protocol]: https://github.com/smogon/pokemon-showdown/blob/master/sim/SIM-PROTOCOL.md

One message type that only appears here is `|split|PLAYERID`:

|split|PLAYERID
SECRET
PUBLIC

- `PLAYERID` - one of `p1`, `p2`, `p3`, or `p4`.
- `SECRET` - messages for the specific player or an omniscient observer (details which may contain information about exact details of the player's set, like exact HP)
- `PUBLIC` - message with public details suitable for display to opponents / teammates / spectators. Note that this may be empty.

sideupdate
PLAYERID
MESSAGES

Send messages to only one player. `|split` will never appear here.

`PLAYERID` will be `p1`, `p2`, `p3`, or `p4`.

Note that choice requests (updates telling the player what choices they have for using moves or switching pokemon) are sent this way.

[Choice requests are documented in "Choice requests" in `SIM-PROTOCOL.md`][choice-requests].

[choice-requests]: https://github.com/smogon/pokemon-showdown/blob/master/sim/SIM-PROTOCOL.md#choice-requests

end
LOGDATA

Sent at the end of a battle. `LOGDATA` is a JSON object that has various information you might find useful but are too lazy to extract from the update messages, such as turn count and winner name.
Pokémon Showdown's Node.js package has TypeScript definitions for everything it exports, including a lot of undocumented APIs.

Please be aware that any undocumented API is unstable and should not be relied upon not to change. We do not follow semver for undocumented APIs. If you _really_ want to use an undocumented API, remember to pin the exact PS version in your dependencies. You probably also want to follow the API update channel in the Discord server: https://psim.us/devdiscord

0 comments on commit a813a55

Please sign in to comment.