@pkmn/engine 0.1.0-dev.b9fb6eab → 0.1.0-dev.bb8e286d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +101 -62
  2. package/build/pkg/addon.d.ts +7 -0
  3. package/build/pkg/addon.js +112 -0
  4. package/build/pkg/addon.js.map +1 -0
  5. package/build/pkg/data/ids.json +12 -12
  6. package/build/pkg/data/layout.json +27 -5
  7. package/build/pkg/data/protocol.json +69 -12
  8. package/build/pkg/data.d.ts +4 -4
  9. package/build/pkg/data.js +3 -5
  10. package/build/pkg/data.js.map +1 -1
  11. package/build/pkg/gen1.d.ts +5 -4
  12. package/build/pkg/gen1.js +49 -33
  13. package/build/pkg/gen1.js.map +1 -1
  14. package/build/pkg/index.d.ts +17 -13
  15. package/build/pkg/index.js.map +1 -1
  16. package/build/pkg/protocol.d.ts +4 -2
  17. package/build/pkg/protocol.js +61 -40
  18. package/build/pkg/protocol.js.map +1 -1
  19. package/build/test/display.js +400 -0
  20. package/build/test/display.js.map +1 -0
  21. package/build/tools/debug.js +135 -0
  22. package/build/tools/debug.js.map +1 -0
  23. package/build.zig +130 -94
  24. package/package.json +75 -42
  25. package/src/bin/install-pkmn-engine +11 -6
  26. package/src/bin/pkmn-debug +62 -0
  27. package/src/lib/binding/node.zig +47 -146
  28. package/src/lib/binding/wasm.zig +6 -4
  29. package/src/lib/common/battle.zig +17 -0
  30. package/src/lib/common/data.zig +19 -31
  31. package/src/lib/common/debug.zig +21 -11
  32. package/src/lib/common/js.zig +118 -0
  33. package/src/lib/common/optional.zig +67 -0
  34. package/src/lib/common/options.zig +12 -3
  35. package/src/lib/common/protocol.zig +931 -387
  36. package/src/lib/common/rational.zig +357 -0
  37. package/src/lib/common/rng.zig +24 -15
  38. package/src/lib/common/util.zig +12 -0
  39. package/src/lib/gen1/README.md +295 -181
  40. package/src/lib/gen1/calc.zig +426 -0
  41. package/src/lib/gen1/chance.zig +1060 -0
  42. package/src/lib/gen1/data/moves.zig +202 -190
  43. package/src/lib/gen1/data/species.zig +4 -4
  44. package/src/lib/gen1/data/types.zig +10 -10
  45. package/src/lib/gen1/data.zig +90 -76
  46. package/src/lib/gen1/helpers.zig +577 -32
  47. package/src/lib/gen1/mechanics.zig +1143 -828
  48. package/src/lib/gen2/README.md +105 -85
  49. package/src/lib/gen2/calc.zig +143 -0
  50. package/src/lib/gen2/chance.zig +1314 -0
  51. package/src/lib/gen2/data/items.zig +14 -20
  52. package/src/lib/gen2/data/moves.zig +664 -570
  53. package/src/lib/gen2/data/species.zig +2 -2
  54. package/src/lib/gen2/data/types.zig +137 -34
  55. package/src/lib/gen2/data.zig +128 -90
  56. package/src/lib/gen2/generated.zig +806 -0
  57. package/src/lib/gen2/helpers.zig +16 -22
  58. package/src/lib/gen2/mechanics.zig +3506 -12
  59. package/src/lib/pkmn.zig +68 -9
  60. package/src/test/display/pkmn.html.tmpl +368 -0
@@ -6,11 +6,13 @@ document](../../../docs/DESIGN.md). The Generation I engine is implemented and t
6
6
  following files:
7
7
 
8
8
  - [`data.zig`](data.zig) ([`data`](data)): contains definitions of all of the data structures used
9
- by the engine, described in detail [below](#data-structures)
9
+ to implement the core mechanics of the engine, described in detail [below](#data-structures)
10
+ - [`chance.zig`](chance.zig): TODO
11
+ - [`calc.zig`](calc.zig): TODO
10
12
  - [`helpers.zig`](helpers.zig): helpers used to construct complex data types with
11
13
  sensible defaults (internally used by tests and tools)
12
- - [`mechanics.zig`](mechanics.zig): code which manipulates the data structures in order to implement
13
- the mechanics of the game
14
+ - [`mechanics.zig`](mechanics.zig): code which manipulates the data structures to implement the
15
+ mechanics of the game
14
16
  - [`test.zig`](test.zig): unit tests for `mechanics.zig` (the code is also tested by [integration
15
17
  tests](../../../docs/TESTING.md) at a higher level)
16
18
 
@@ -37,7 +39,8 @@ The following information is required to simulate a Generation I Pokémon battle
37
39
  | `side.team` | `PartyMons` | `side.pokemon` |
38
40
  | `side.last_used_move` | `PlayerUsedMove` | `pokemon.lastMove` |
39
41
  | `side.last_selected_move` | `PlayerSelectedMove` | `side.lastSelectedMove` |
40
- | `battle.last_selected_indexes` | `PlayerMoveListIndex` | `side.lastMove` |
42
+ | `battle.last_moves.index` | `PlayerMoveListIndex` | - |
43
+ | `battle.last_moves.counterable` | - | `side.lastMove` |
41
44
  | `side.order` | - | `pokemon.position` |
42
45
  | `{pokemon,active}.moves` | `{party,battle}_struct.{Moves,PP}` | `pokemon.{baseMoveSlots,moveSlots}` |
43
46
  | `pokemon.hp` | `{party,battle}_struct.HP` | `pokemon.hp` |
@@ -58,36 +61,37 @@ The following information is required to simulate a Generation I Pokémon battle
58
61
  | `volatiles.substitute` | `PlayerSubstituteHP` | `volatiles.substitute.hp` |
59
62
  | `volatiles.disabled_{move,duration}` | `PlayerDisabledMove{,Number}` | `volatiles.disable.{move,time}` |
60
63
 
61
- - Pokémon Showdown [does not implement the correct Generation I RNG](#rng) and as such its `seed` is
64
+ - Pokémon Showdown [doesn't implement the correct Generation I RNG](#rng) and as such its `seed` is
62
65
  different
63
- - `battle.turn` only needs to be tracked in order to be compatible with the Pokémon Showdown
64
- protocol
66
+ - `battle.turn` only needs to be tracked to be compatible with the Pokémon Showdown protocol
65
67
  - Pokémon Showdown tracks several last used move variables (`Battle.lastMove`, `Side.lastMove`, and
66
68
  `Pokemon.lastMove`), none of which accurately match the `PlayerUsedMove` variable from the
67
- cartridge (`Side.lastMove` should be what is used, but is used by Pokémon Showdown only for
68
- Counter and is not set and cleared in the correct locations. `Pokemon.lastMove` matches
69
- `PlayerUsedMove` more often so is what the engine attempts to model, despite the implications for
70
- Counter)
71
- - Pokémon Showdown does not implement the [partial-trapping move Mirror Move
69
+ cartridge (`Side.lastMove` should be what's used, but is used by Pokémon Showdown only for Counter
70
+ and isn't set and cleared in the correct locations. `Pokemon.lastMove` matches `PlayerUsedMove`
71
+ more often so is what the engine attempts to model, despite the implications for Counter)
72
+ - `battle.last_moves` doesn't map precisely to cartridge concepts because it's used to track desyncs
73
+ which instead are represented on the cartridge as discrepancies between the two separate battle
74
+ states that exist in the link battle.
75
+ - Pokémon Showdown doesn't implement the [partial-trapping move Mirror Move
72
76
  glitch](https://glitchcity.wiki/Partial_trapping_move_Mirror_Move_link_battle_glitch) and as such
73
- does not need to keep track of a player's last selected move index (`PlayerMoveListIndex`)
77
+ doesn't need to keep track of a player's last selected move index (`PlayerMoveListIndex`)
74
78
  - Battle results (win, lose, draw) and request states are communicated via the return value of
75
79
  `Battle.update`
76
- - Nicknames (`BattleMonNick`/`pokemon.name`) are not handled by the pkmn engine as they are expected
80
+ - Nicknames (`BattleMonNick`/`pokemon.name`) aren't handled by the pkmn engine as they're expected
77
81
  to be handled by driver code if required
78
82
  - Pokémon Red's `LastSwitchInEnemyMonHP`, `InHandlePlayerMonFainted`, `PlayerNumHits`,
79
83
  `PlayerMonMinimized`, and `Move{DidntMiss,Missed}` are relevant for messaging/UI only
80
84
  - Pokémon Red's `TransformedEnemyMonOriginalDVs` is only relevant for the [Transform DV manipulation
81
85
  glitch](https://pkmn.cc/bulba/Transform_glitches#Transform_DV_manipulation_glitch)
82
- - Pokémon Red's `PlayerMove*` tracks information that is stored in the `Move` class
86
+ - Pokémon Red's `PlayerMove*` tracks information that's stored in the `Move` class
83
87
  - Pokémon Red's `PlayerStatsToDouble`/`PlayerStatsToHalve` are constants which are always 0
84
- - pkmn does not store the DVs/stat experience of Pokémon as they are expected to already be
85
- accounted for in the `Pokemon` `stats` and never need to be referenced in-battle (though a `DVs`
86
- struct exists to simplify generating legal test data)
88
+ - pkmn doesn't store the DVs/stat experience of Pokémon as they're expected to already be accounted
89
+ for in the `Pokemon` `stats` and never need to be referenced in-battle (though a `DVs` struct
90
+ exists to simplify generating legal test data)
87
91
  - Instead of storing unmodified stats like Pokémon Red or Pokémon Showdown, pkmn simply tracks the
88
92
  identity of the Pokémon that has been transformed into in the `active.volatiles.transform` field
89
93
  - pkmn uses `volatiles.state` for total accumulated damage for Bide but also for implementing
90
- accuracy overwrite mechanics for certain moves (this glitch is present on the device but is not
94
+ accuracy overwrite mechanics for certain moves (this glitch is present on the device but isn't
91
95
  correctly implemented by Pokémon Showdown currently)
92
96
 
93
97
  ### `Battle` / `Side`
@@ -98,14 +102,14 @@ The following information is required to simulate a Generation I Pokémon battle
98
102
  store general information about the battle. Unlike in Pokémon Showdown there is a distinction
99
103
  between the data structure for the "active" Pokémon and its party members (see below).
100
104
 
101
- Due to layout constraints, the index of the last selected move for a side is stored in what would
102
- otherwise be the padding bytes of`Battle` (the `last_selected_indexes` field) instead of in `Side`.
105
+ Due to layout constraints, details about the last moves for a side are stored in what would
106
+ otherwise be the padding bytes of `Battle` (the `last_moves` field) instead of in `Side`.
103
107
 
104
108
  ### `Pokemon` / `ActivePokemon`
105
109
 
106
- Similar to the cartridge, in order to save space different information is stored depending on
107
- whether a [Pokémon](https://pkmn.cc/bulba/Pok%c3%a9mon_data_structure_%28Generation_I%29) is
108
- actively participating in battle vs. is switched out (pret's [`battle_struct` vs.
110
+ Similar to the cartridge, to save space different information is stored depending on whether a
111
+ [Pokémon](https://pkmn.cc/bulba/Pok%c3%a9mon_data_structure_%28Generation_I%29) is actively
112
+ participating in battle vs. is switched out (pret's [`battle_struct` vs.
109
113
  `party_struct`](https://pkmn.cc/pokered/macros/ram.asm)). In Pokémon Showdown, all the Pokémon in a
110
114
  battle are represented by the same
111
115
  [`Pokemon`](https://github.com/smogon/pokemon-showdown/blob/master/sim/pokemon.ts) class, and static
@@ -117,14 +121,14 @@ A `MoveSlot` is a data-type for a `(move, current pp)` pair. A pared down versio
117
121
  Showdown's `Pokemon.moveSlot`, it also stores data from the cartridge's `battle_struct::Move` macro
118
122
  and can be used to replace the `PlayerMove*` data. Move PP is stored as a full byte instead of how
119
123
  the cartridge (`battle_struct::PP`) stores it (6 bits for current PP and the remaining 2 bits used
120
- to store the number of applied PP Ups). PP Up bits do not actually need to be stored on move slot
124
+ to store the number of applied PP Ups). PP Up bits don't actually need to be stored on move slot
121
125
  as max PP is never relevant in Generation I.
122
126
 
123
127
  #### `Status`
124
128
 
125
129
  Bitfield representation of a Pokémon's major [status
126
- condition](https://pkmn.cc/bulba/Status_condition), mirroring how it is stored on the cartridge. A
127
- value of `0x00` means that the Pokémon is not affected by any major status, otherwise the lower 3
130
+ condition](https://pkmn.cc/bulba/Status_condition), mirroring how it's stored on the cartridge. A
131
+ value of `0x00` means that the Pokémon isn't affected by any major status, otherwise the lower 3
128
132
  bits represent the remaining duration for Sleep. Other status are denoted by the presence of
129
133
  individual bits - at most one status should be set at any given time.
130
134
 
@@ -133,10 +137,10 @@ below), so the upper most bit of `Status` is instead used to track state require
133
137
  quirks:
134
138
 
135
139
  - when combined with a valid sleep duration (or 0), it indicates that the `SLP` status was
136
- self-inflicted (required in order to implement Pokémon Showdown's "Sleep Clause Mod")
140
+ self-inflicted (required to implement Pokémon Showdown's "Sleep Clause Mod")
137
141
  - when combined with `PSN` it indicates that the Pokémon is actually badly poisoned (required in
138
142
  order to send the same incorrect protocol messages as Pokémon Showdown - the Toxic volatile
139
- alone is not sufficient in compatibility mode because it gets lost on switch)
143
+ alone isn't sufficient in compatibility mode because it gets lost on switch)
140
144
 
141
145
  #### `Volatiles`
142
146
 
@@ -172,17 +176,16 @@ boolean flags that are cleared when the Pokémon faints or switches out:
172
176
  [Toxic](https://pkmn.cc/bulba/Toxic_(move)) (counter),
173
177
  [Transform](https://pkmn.cc/bulba/Transform_(move)) (identity), and
174
178
  [Disable](https://pkmn.cc/bulba/Disable_(move)) (move and duration), and multi-hit attacks all
175
- require additional information that is also stored in the `Volatiles` structure. `MultiHit` is not
176
- strictly required to be stored as it should always be 0 after updates barring errors, however it is
179
+ require additional information that's also stored in the `Volatiles` structure. `MultiHit` isn't
180
+ strictly required to be stored as it should always be 0 after updates barring errors, however it's
177
181
  convenient to maintain as it maps neatly to the cartridge and is effectively "free" space-wise due
178
182
  to padding.
179
183
 
180
184
  The `state` field of `Volatiles` is effectively treated as a union:
181
185
 
182
186
  - if `volatiles.Bide` is set, `volatiles.data.state` reflects the total accumulated Bide damage
183
- - otherwise, `volatiles.data.state` reflects the last computed move accuracy (required in order to
184
- implement the [Rage and Thrash / Petal Dance accuracy
185
- bug](https://www.youtube.com/watch?v=NC5gbJeExbs))
187
+ - otherwise, `volatiles.data.state` reflects the last computed move accuracy (required to implement
188
+ the [Rage and Thrash / Petal Dance accuracy bug](https://www.youtube.com/watch?v=NC5gbJeExbs))
186
189
 
187
190
  #### `Stats` / `Boosts`
188
191
 
@@ -194,11 +197,11 @@ boosts should always range from `-6`...`6` instead of `1`...`13` as on the cartr
194
197
 
195
198
  `Move` serves as an identifier for a unique [Pokémon move](https://pkmn.cc/bulba/Move) that can be
196
199
  used to retrieve `Move.Data` with information regarding base power, accuracy, and type. As covered
197
- above, PP information isn't strictly necessary in Generation I so is dropped. `Move.None` exists as
198
- a special sentinel value to indicate `null`. Move PP data is only included for testing and is not
200
+ earlier, PP information isn't strictly necessary in Generation I so is dropped. `Move.None` exists
201
+ as a special sentinel value to indicate `null`. Move PP data is only included for testing and isn't
199
202
  necessary for the actual engine implementation.
200
203
 
201
- In order to workaround various [Pokémon Showdown bugs](#bugs) and to support its protocol in traces,
204
+ In order to workaround various [Pokémon Showdown bugs](#bugs) and to support its protocol in logs,
202
205
  additional information is stored in `Move.Data` (`targets`) about what Pokémon Showdown believes the
203
206
  `Move.Target` to be (despite the concept of targeting not existing until Generation III when Double
204
207
  battles were introduced). More specifically, a move's "targeting" status is required in various
@@ -217,11 +220,11 @@ places to determine which protocol messages to print.
217
220
  ### `Species` / `Species.Data`
218
221
 
219
222
  `Species` just serves as an identifier for a unique [Pokémon
220
- species](https://pkmn.cc/bulba/Pokémon_species_data_structure_(Generation_I)) as the base stats
221
- of a species are already accounted for in the computed stats in the `Pokemon` structure and nothing
222
- in battle requires these to be recomputed. Similarly, Type is unnecessary to include as it is also
223
+ species](https://pkmn.cc/bulba/Pokémon_species_data_structure_(Generation_I)) as the base stats of a
224
+ species are already accounted for in the computed stats in the `Pokemon` structure and nothing in
225
+ battle requires these to be recomputed. Similarly, Type is unnecessary to include as it's also
223
226
  already present in the `Pokemon` struct. `Species.None` exists as a special sentinel value to
224
- indicate `null`. `Species.Data` is only included for testing and is not necessary for the actual
227
+ indicate `null`. `Species.Data` is only included for testing and isn't necessary for the actual
225
228
  engine implementation, outside of `Species.CHANCES` which is required as the base speed / 2 of the
226
229
  species is necessary for computing critical hit probability.
227
230
 
@@ -234,19 +237,27 @@ effectiveness - like the cartridge, effectiveness is stored as `0`, `5`, `10`, a
234
237
  (technically only a 2-bit value is required, but as with `Types` Zig only allows a minimum of a byte
235
238
  to be stored at each address of an array).
236
239
 
237
- The 'precedence' of the various type matchups matters beyond just the [dual-type damage
240
+ The 'precedence' of the various type match-ups matters beyond just the [dual-type damage
238
241
  misinformation
239
242
  glitch](https://pkmn.cc/bulba/List_of_glitches_(Generation_I)#Dual-type_damage_misinformation) -
240
243
  type effectiveness modifiers are applied based on the (haphazard) ordering of the effectiveness
241
244
  table as opposed to first applying modifiers for a species's first type and then second type. The
242
- engine maintains a `Type.PRECEDENCE` table with just the matchups that are relevant in game (certain
243
- type combinations cannot crop up with the limited Generation I species pool and as such are pruned
244
- for efficiency) and only looks up precedence when necessary to minimize expensive searches. Pokémon
245
- Showdown does not implement type precedence.
245
+ engine maintains a `Type.PRECEDENCE` table with just the match-ups that are relevant in game
246
+ (certain type combinations can't crop up with the limited Generation I species pool and as such are
247
+ pruned for efficiency) and only looks up precedence when necessary to minimize expensive searches.
248
+ Pokémon Showdown doesn't implement type precedence.
249
+
250
+ ### `Chance` / `Actions` / `Action` / `Durations` / `Duration`
251
+
252
+ TODO
253
+
254
+ ### `Calc` / `Overrides` / `Summaries` / `Summary`
255
+
256
+ TODO
246
257
 
247
258
  ## Information
248
259
 
249
- The information of each field (in terms of [bits of
260
+ The information of each field required for mechanics (in terms of [bits of
250
261
  entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory))) is as follows:
251
262
 
252
263
  | Data | Range | Bits | | Data | Range | Bits |
@@ -268,8 +279,8 @@ entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory))) is as foll
268
279
  | **crit chance** | 7..65 | 6 | | **transform** | 0..15 | 4 |
269
280
  | **target** | 0..4 | 3 | | | | |
270
281
 
271
- From this we can determine the minimum bits[^1] required to store each data structure to determine
272
- how much overhead the representations above have after taking into consideration [alignment &
282
+ From this one can determine the minimum bits[^1] required to store each data structure to determine
283
+ how much overhead the preceding representations have after taking into consideration [alignment &
273
284
  padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
274
285
  [denormalization](https://en.wikipedia.org/wiki/Denormalization):
275
286
 
@@ -282,9 +293,9 @@ padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
282
293
  - the active Pokémon's level and current and max HP can always be referred to the `Pokemon`
283
294
  struct
284
295
  - **`Side`**: `ActivePokemon` + 6× `Pokemon` + active (`3`) + last used (`8`) + last selected
285
- (`8`)
286
- - `order` does not need to be stored as the party can always be rearranged as switches occur
287
- - **`Battle`**: 6× `Side` + seed (10× `8` + `4`) + turn (`10`) + last damage (`10`)
296
+ (`8`) + counterable (`1`) + last move index (`3`)
297
+ - `order` doesn't need to be stored as the party can always be rearranged as switches occur
298
+ - **`Battle`**: 6× `Side` + seed (9× `8` + `4`) + turn (`10`) + last damage (`10`)
288
299
  - **`Type.CHART`**: attacking types (`15`) × defending types (`15`) × effectiveness (`2`)[^2]
289
300
  - **`Type.PRECEDENCE`**: 29× attacking type (`4`) + defending type (`4`) pairs
290
301
  - **`Moves.DATA`**: 165× base power (`6`) + effect (`7`) + accuracy (`4`) + type (`4`) + target
@@ -295,8 +306,8 @@ padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
295
306
  | ----------------- | ----------- | ------------ | -------- |
296
307
  | `Pokemon` | 192 | 147 | 30.6% |
297
308
  | `ActivePokemon` | 256 | 202 | 26.7% |
298
- | `Side` | 1472 | 1056 | 33.5% |
299
- | `Battle` | 3088 | 2216 | 33.7% |
309
+ | `Side` | 1472 | 1107 | 33.0% |
310
+ | `Battle` | 3088 | 2310 | 33.7% |
300
311
  | `Type.CHART` | 1800 | 450 | 300.0% |
301
312
  | `Type.PRECEDENCE` | 232 | 232 | 0.0% |
302
313
  | `Moves.DATA` | 5280 | 3960 | 33.3% |
@@ -309,54 +320,59 @@ consideration the worst case all Pokémon types are required and 48 moves. The `
309
320
  could be eliminated and instead the `Move` data actually required by each `Pokemon` could be placed
310
321
  beside the `MoveSlot`, though this is both less general and adds unnecessary complexity.
311
322
 
312
- [^1]: For data with lower cardinality it is possible to save memory by ordinalizing the values and
323
+ [^1]: For data with lower cardinality it's possible to save memory by ordinalizing the values and
313
324
  turning them into indices into a lookup table (e.g. encode all possible move base powers in a lookup
314
325
  table and store the index into that table instead of the actual base power). While this approach may
315
326
  minimize the absolute memory used, performance is more likely to suffer as the goal is to minimize
316
- uncached memory lookups, not total memory usage.
327
+ un-cached memory lookups, not total memory usage.
317
328
 
318
329
  [^2]: Instead of storing as a sparse multi-dimensional array the type chart could instead only
319
330
  [store values which are not normal
320
331
  effectiveness](https://github.com/pret/pokered/blob/master/data/types/type_matchups.asm) in 820 bits
321
332
  as 82× attacking type (`4`) + defending type (`4`) + non-Normal effectiveness (`2`). This would
322
333
  avoid having to do two memory lookups at the cost of a longer time scanning, but the second lookup
323
- should already be fast due to locality of reference meaning it will likely already be in the cache.
334
+ should already be fast due to locality of reference meaning it's likely to already be in the cache.
324
335
  This approach would also render `Type.PRECEDENCE` unnecessary.
325
336
 
326
337
  ## Layout
327
338
 
328
339
  The precise layout of the engine's data structures is important to those implementing driver code,
329
340
  as clients must directly probe the engine's state through these structures (i.e. the pkmn engine
330
- does not produce an equivalent to Pokémon Showdown's `|request|` protocol message, this information
341
+ doesn't produce an equivalent to Pokémon Showdown's `|request|` protocol message, this information
331
342
  must be gleaned through the `Battle` state). Useful size and offset information can be found in
332
343
  the [`layout.json`](../../data/layout.json) which exists to simplify writing driver code.
333
344
 
334
- Documentation of the wire protocol used for logging traces when `-Dtrace` is enabled can be found in
335
- [PROTOCOL.md](../../../docs/PROTOCOL.md).
345
+ Documentation of the wire protocol used for protocol message logging when `-Dlog` is enabled can be
346
+ found in [PROTOCOL.md](../../../docs/PROTOCOL.md). Note that the
347
+ [`pkmn-debug`](../../../README.md#pkmn-debug) tool exists to display the binary protocol and battle
348
+ data in the browser for ease of debugging.
336
349
 
337
350
  ### `Battle`
338
351
 
339
- | Start | End | Data | Description |
340
- | ------- | ------- | ----------------------- | ------------------------------------------------------- |
341
- | 0 | 184 | [`sides[0]`](#side) | Player 1's side |
342
- | 184 | 368 | [`sides[1]`](#side) | Player 2's side |
343
- | 368 | 370 | `turn` | The current turn number |
344
- | 370 | 372 | `last_damage` | The last damage dealt by either side |
345
- | 372 | 373-376 | `last_selected_indexes` | The slot index of the last selected moves for each side |
346
- | 373-376 | 384 | `rng` | The RNG state |
352
+ | Start | End | Data | Description |
353
+ | ------- | ------- | ------------------- | ------------------------------------------------------ |
354
+ | 0 | 184 | [`sides[0]`](#side) | Player 1's side |
355
+ | 184 | 368 | [`sides[1]`](#side) | Player 2's side |
356
+ | 368 | 370 | `turn` | The current turn number |
357
+ | 370 | 372 | `last_damage` | The last damage dealt by either side |
358
+ | 372 | 374-376 | `last_moves` | Details about the last move selected/used by each side |
359
+ | 374-376 | 384 | `rng` | The RNG state |
347
360
 
348
361
  - the current `turn` is 2 bytes, written in native-endianness
349
- - `last_selected_indexes` layout depends on whether or not Pokémon Showdown compatibility mode is
350
- enabled (`-Dshowdown`). In either case it stores a move "slot", where 0 is used as an empty value and
351
- 1-4 represent actual moves:
352
- - if `showdown` is enabled bytes 372 and 373 are used to store the last selected move index of
353
- `side[0]` and bytes 374 and 375 store the last selected move index of `side[1]`
354
- - otherwise byte 372 stores the last selected move index of `side[0]` in its first 4 bits and
355
- `side[1]`'s in its second 4 bits
362
+ - `last_moves` layout depends on whether or not Pokémon Showdown compatibility mode is enabled
363
+ (`-Dshowdown`). In either case it stores the last selected move index and last executed move for
364
+ each player (required to detect desyncs). In the case of the move index, 0 is used as an empty
365
+ value and 1-4 represent actual moves:
366
+ - if `showdown` is enabled byte 372 is used to store the last selected move index of `side[0]` and
367
+ byte 373 is used to store whether or not the side's last executed move would have been considered
368
+ "counterable"; and bytes 374 and 375 store the same information for `side[1]`
369
+ - otherwise the first 4 bits of byte 372 stores the last selected move index of `side[0]` and the
370
+ next 4 bits store whether that side's last executed move would have been considered
371
+ "counterable", with the same information for `side[1]`'s being stored in the second byte
356
372
  - the `rng` depends on whether or not Pokémon Showdown compatibility mode is enabled (`-Dshowdown`):
357
373
  - if `showdown` is enabled, the RNG state begins on byte 376 and consists of a 64-bit seed,
358
374
  written in native-endianness
359
- - otherwise the RNG state begins on byte 373 and consists of the 10 bytes of the seed followed by
375
+ - otherwise the RNG state begins on byte 374 and consists of the 9 bytes of the seed followed by
360
376
  the index pointing to which byte of the seed is currently being used
361
377
 
362
378
  ### `Side`
@@ -375,9 +391,9 @@ Documentation of the wire protocol used for logging traces when `-Dtrace` is ena
375
391
  | 183 | 184 | `last_used_move` | The last move the player used |
376
392
 
377
393
  - `order` is a 6 byte array where `order[i]` represents the "slot" of `pokemon[i]`, where the slot
378
- is usually a unique value from 1-6 but can be 0 in situations where a player brings less than six
394
+ is usually a unique value from 1 to 6 but can be 0 in situations where a player brings less than six
379
395
  Pokémon to battle (note however that if `order[i]` is 0 than for all j > 0 `order[i+j]` **must**
380
- equal 0).
396
+ equal 0)
381
397
 
382
398
  ### `ActivePokemon`
383
399
 
@@ -402,7 +418,7 @@ Documentation of the wire protocol used for logging traces when `-Dtrace` is ena
402
418
  | 28 | 29 | `moves[2].id` | The active Pokémon's third move |
403
419
  | 29 | 30 | `moves[2].pp` | The PP of the active Pokémon's third move |
404
420
  | 30 | 31 | `moves[3].id` | The active Pokémon's fourth move |
405
- | 31 | 32 | `moves[3].pp` | The PP of the active Pokémon's fourth moe |
421
+ | 31 | 32 | `moves[3].pp` | The PP of the active Pokémon's fourth move |
406
422
 
407
423
  - the active Pokémon's `stats.hp` is always identical to the corresponding stored Pokémon's `stats.hp`
408
424
  - `boosts` and `types` includes bytes which store two 4-bit fields each
@@ -411,34 +427,34 @@ Documentation of the wire protocol used for logging traces when `-Dtrace` is ena
411
427
 
412
428
  > **NOTE:** The offsets in the following table represent *bits* and **not** bytes.
413
429
 
414
- | Start | End | Data | Description |
415
- | ----- | --- | ------------------- | ----------------------------------------------------------- |
416
- | 0 | 1 | `Bide` | Whether the "Bide" volatile status is present |
417
- | 1 | 2 | `Thrashing` | Whether the "Thrashing" volatile status is present |
418
- | 2 | 3 | `MultiHit` | Whether the "MultiHit" volatile status is present |
419
- | 3 | 4 | `Flinch` | Whether the "Flinch" volatile status is present |
420
- | 4 | 5 | `Charging` | Whether the "Charging" volatile status is present |
421
- | 5 | 6 | `Binding` | Whether the "Binding" volatile status is present |
422
- | 6 | 7 | `Invulnerable` | Whether the "Invulnerable" volatile status is present |
423
- | 7 | 8 | `Confusion` | Whether the "Confusion" volatile status is present |
424
- | 8 | 9 | `Mist` | Whether the "Mist" volatile status is present |
425
- | 9 | 10 | `FocusEnergy` | Whether the "FocusEnergy" volatile status is present |
426
- | 10 | 11 | `Substitute` | Whether the "Substitute" volatile status is present |
427
- | 11 | 12 | `Recharging` | Whether the "Recharging" volatile status is present |
428
- | 12 | 13 | `Rage` | Whether the "Rage" volatile status is present |
429
- | 13 | 14 | `LeechSeed` | Whether the "LeechSeed" volatile status is present |
430
- | 14 | 15 | `Toxic` | Whether the "Toxic" volatile status is present |
431
- | 15 | 16 | `LightScreen` | Whether the "LightScreen" volatile status is present |
432
- | 16 | 17 | `Reflect` | Whether the "Reflect" volatile status is present |
433
- | 17 | 18 | `Transform` | Whether the "Transform" volatile status is present |
434
- | 18 | 21 | `confusion` | The remaining turns of confusion |
435
- | 21 | 24 | `attacks` | The number of attacks remaining |
436
- | 24 | 40 | `state` | A union of either: <ul><li>the total accumulated damage from Bide</li><li>the overwritten accuracy of certain moves</li></ul> |
437
- | 40 | 48 | `substitute` | The remaining HP of the Substitute |
438
- | 48 | 52 | `transform` | The identity of whom the active Pokémon is transformed into |
439
- | 52 | 56 | `disabled_duration` | The remaining turns the move is disabled |
440
- | 56 | 59 | `disabled_move` | The move slot (1-4) that is disabled |
441
- | 59 | 64 | `toxic` | The number of turns toxic damage has been accumulating |
430
+ | Start | End | Data | Description |
431
+ | ----- | --- | -------------------| ----------------------------------------------------------- |
432
+ | 0 | 1 | `Bide` | Whether the "Bide" volatile status is present |
433
+ | 1 | 2 | `Thrashing` | Whether the "Thrashing" volatile status is present |
434
+ | 2 | 3 | `MultiHit` | Whether the "MultiHit" volatile status is present |
435
+ | 3 | 4 | `Flinch` | Whether the "Flinch" volatile status is present |
436
+ | 4 | 5 | `Charging` | Whether the "Charging" volatile status is present |
437
+ | 5 | 6 | `Binding` | Whether the "Binding" volatile status is present |
438
+ | 6 | 7 | `Invulnerable` | Whether the "Invulnerable" volatile status is present |
439
+ | 7 | 8 | `Confusion` | Whether the "Confusion" volatile status is present |
440
+ | 8 | 9 | `Mist` | Whether the "Mist" volatile status is present |
441
+ | 9 | 10 | `FocusEnergy` | Whether the "FocusEnergy" volatile status is present |
442
+ | 10 | 11 | `Substitute` | Whether the "Substitute" volatile status is present |
443
+ | 11 | 12 | `Recharging` | Whether the "Recharging" volatile status is present |
444
+ | 12 | 13 | `Rage` | Whether the "Rage" volatile status is present |
445
+ | 13 | 14 | `LeechSeed` | Whether the "LeechSeed" volatile status is present |
446
+ | 14 | 15 | `Toxic` | Whether the "Toxic" volatile status is present |
447
+ | 15 | 16 | `LightScreen` | Whether the "LightScreen" volatile status is present |
448
+ | 16 | 17 | `Reflect` | Whether the "Reflect" volatile status is present |
449
+ | 17 | 18 | `Transform` | Whether the "Transform" volatile status is present |
450
+ | 18 | 21 | `confusion` | The remaining turns of confusion |
451
+ | 21 | 24 | `attacks` | The number of attacks remaining |
452
+ | 24 | 40 | `state` | A union of either: <ul><li>the total accumulated damage from Bide</li><li>the overwritten accuracy of certain moves</li></ul> |
453
+ | 40 | 48 | `substitute` | The remaining HP of the Substitute |
454
+ | 48 | 52 | `transform` | The identity of whom the active Pokémon is transformed into |
455
+ | 52 | 56 | `disable_duration` | The remaining turns the move is disabled |
456
+ | 56 | 59 | `disable_move` | The move slot (1-4) that's disabled |
457
+ | 59 | 64 | `toxic` | The number of turns toxic damage has been accumulating |
442
458
 
443
459
  ### `Pokemon`
444
460
 
@@ -463,6 +479,76 @@ Documentation of the wire protocol used for logging traces when `-Dtrace` is ena
463
479
  | 22 | 23 | `type1`/`type2` | The Pokémon's stored types |
464
480
  | 23 | 24 | `level` | The Pokémon's level |
465
481
 
482
+
483
+ ### `Action`
484
+
485
+ `Actions` consist of an `Action` for Player 1 followed by an `Action` for Player 2.
486
+
487
+ > **NOTE:** The offsets in the following table represent *bits* and **not** bytes.
488
+
489
+ | Start | End | Data | Description |
490
+ | ----- | --- | ------------------------ | ------------------------------------------------------------------------------- |
491
+ | 0 | 8 | `damage` | The roll to be returned damage (217-255). |
492
+ | 8 | 10 | `hit` | The roll to be returned for accuracy (1 for miss, 2 for hit). |
493
+ | 10 | 12 | `critical_hit` | The roll to be returned for critical hits (1 for no, 2 for yes). |
494
+ | 12 | 14 | `secondary_chance` | The roll to be returned for secondary chance rolls (1 for no-proc, 2 for proc). |
495
+ | 14 | 16 | `speed_tie` | The player to return for speed ties (1 for Player 1, 2 for Player 2). |
496
+ | 16 | 18 | `confused` | The roll to be returned for confusion self-hits (1 for no-proc, 2 for proc). |
497
+ | 18 | 20 | `paralyzed` | The roll to be returned for full paralysis (1 for no-proc, 2 for proc). |
498
+ | 20 | 24 | `duration` | The roll to be returned for the duration (including for binding moves). |
499
+ | 24 | 40 | [`durations`](#duration) | Values of various durations. |
500
+ | 40 | 44 | `move_slot` | The roll to be returned for the move slot (1-4, invalid values ignored). |
501
+ | 44 | 48 | `move_slot` | The roll to be returned for a multi-hit move distribution (2-5). |
502
+ | 48 | 56 | `psywave` | One greater than the roll to be returned for Psywave damage. |
503
+ | 56 | 64 | `metronome` | The move to return for Metronome. |
504
+
505
+ - for any field a value of 0 is considered to be unset
506
+ - **both Player 1 and Player 2 must set the same value for `speed_tie`.**
507
+ - `duration` determines the roll for any effect which lasts over multiple turns, whereas `durations` can either be used to
508
+ track how long these effects have lasted (for the purposes of computing probablities with `-Dchance`) or can be used to
509
+ [override](#overrides) (extend or end) the duration of specfic effects with `-Dcalc`.
510
+
511
+ #### `Duration`
512
+
513
+ > **NOTE:** The offsets in the following table represent *bits* and **not** bytes.
514
+
515
+ | Start | End | Data |
516
+ | ----- | --- | ----------- |
517
+ | 0 | 3 | `sleep` |
518
+ | 3 | 6 | `confusion` |
519
+ | 4 | 10 | `disable` |
520
+ | 10 | 13 | `attacking` |
521
+ | 13 | 16 | `binding` |
522
+
523
+ - the meaning of each field depends on the context in which `Duration` appears:
524
+ - within `Chance` `actions`, the durations tracked refer to the number of turns a Pokémon has been
525
+ observed to be under an effect
526
+ - within `Overrides` `actions`, the durations refer to the value the next `Chance` `actions`
527
+ should be made to take on
528
+ - within `Overrides` `durations`, the durations serve as a mask to determine to whether or not the
529
+ durations in `Overrides` `actions` should be considered to be set or not
530
+ ◊
531
+ ### `Overrides`
532
+
533
+ | Start | End | Data | Description |
534
+ | ----- | --- | --------------------------- | ------------------------------------------------------------------------------------- |
535
+ | 0 | 8 | [`action.p1`](#action) | Rolls to force Player 1's RNG to return for specific events. |
536
+ | 8 | 16 | [`action.p2`](#action) | Rolls to force Player 2's RNG to return for specific events. |
537
+ | 16 | 18 | [`durations.p1`](#duration) | Whether or not to modify Player 1's effect durations to match `actions.p1.durations`. |
538
+ | 18 | 20 | [`durations.p2`](#duration) | Whether or not to modify Player 2's effect durations to match `actions.p1.durations`. |
539
+ | 20 | 24 | - | *Zero padding* |
540
+
541
+ ### `Summaries`
542
+
543
+ | Start | End | Data | Description |
544
+ | ----- | --- | ------------------ | ------------------------------------------------------------------------------- |
545
+ | 0 | 2 | `p1.damage.base` | Player 1's base computed damage before the damage roll is applied. |
546
+ | 2 | 4 | `p1.damage.final` | Player 1's final computed damage that gets applied to the Pokémon. |
547
+ | 4 | 6 | `p1.damage.capped` | Whether higher damage from Player 1 will saturate / result in the same outcome. |
548
+ | 6 | 8 | `p2.damage.base` | Player 2's base computed damage before the damage roll is applied. |
549
+ | 8 | 10 | `p2.damage.final` | Player 2's final computed damage that gets applied to the Pokémon. |
550
+ | 10 | 12 | `p2.damage.capped` | Whether higher damage from Player 2 will saturate / result in the same outcome. |
551
+
466
552
  ## Bugs
467
553
 
468
554
  In addition to its alternative [RNG semantics](#rng), Pokémon Showdown's implementation of the first
@@ -471,66 +557,85 @@ Smogon](https://www.smogon.com/forums/posts/5933177/show):
471
557
 
472
558
  - moves on Pokémon Showdown can do 0 damage instead of failing or causing a [division-by-zero
473
559
  freeze](https://pkmn.cc/bulba-glitch-1#Division_by_0).
474
- - Pokémon Showdown does not implement type effectiveness precedence correctly.
560
+ - Pokémon Showdown doesn't implement type effectiveness precedence correctly.
475
561
  - Pokémon Showdown checks for type and OHKO immunity before accuracy.
476
562
  - Confusion self-hits use the wrong damage formula resulting in off-by-one errors (and also fail to
477
- account for an opponent's Reflect). Furthermore, the confusion self-hit damage will erroneously be
478
- inflicted to the confused user's substitute if the confused user had been attempting to use a
479
- self-targeting move.
480
-
481
- Beyond the general bugs listed above, several move effects are implemented incorrectly by Pokémon
482
- Showdown. Some of these moves are [too fundamentally broken to be implemented](#unimplementable) by
483
- the pkmn engine, but the following moves have their broken behavior preserved in `-Dshowdown` mode:
484
-
485
- - **Bide**: If the opponent faints after Bide inflicts damage on Pokémon Showdown residual damage
486
- incorrectly still gets applied to Bide's user.
563
+ account for an opponent's Reflect). Furthermore, the confusion self-hit damage erroneously gets
564
+ inflicted on the confused user's substitute if the confused user had been attempting to use a
565
+ self-targeting move. Finally, Pokémon Showdown erroneously considers the *uncapped* self-hit
566
+ damage for the purposes of tracking the battle's last damage.
567
+
568
+ Beyond these general bugs, several move effects are implemented incorrectly by Pokémon Showdown.
569
+ Some of these moves are [too fundamentally broken to be implemented](#unimplementable) by the pkmn
570
+ engine, but the following moves have their broken behavior preserved in `-Dshowdown` mode:
571
+
572
+ - **Bide**: Bide's damage can overflow if OHKO moves are involved because OHKO moves work by setting
573
+ the damage to 65535 - Pokémon Showdown doesn't implement this overflow and instead lets Bide's
574
+ damage grow unbounded. Additionally, if the opponent faints after Bide inflicts damage on Pokémon
575
+ Showdown residual damage incorrectly still gets applied to Bide's user.
576
+ - **Counter**: On Pokémon Showdown choices made while sleeping (which shouldn't have been
577
+ registered) can erroneously cause Counter to trigger Desync Clause Mod behavior. Additionally,
578
+ because Pokémon Showdown neglects to zero the last battle damage if a move misses due to immunity
579
+ or invulnerability Counter occasionally works on Pokémon Showdown when it should fail.
487
580
  - **Leech Seed**: Leech Seed fails to heal its source side if a seeded target faints due to
488
- recoil/crash damage on Pokémon Showdown. Pokémon Showdown also updates the battle's last damage
489
- field with the uncapped Leech Seed damage which has consequences for Bide and Counter.
581
+ recoil/crash damage on Pokémon Showdown.
490
582
  - **Pay Day**: Pay Day should still scatter coins if it hits (but doesn't break) and opponent's
491
583
  Substitute but doesn't on Pokémon Showdown.
492
- - **Flinch**: Flinching does not get cleared during move selection on Pokémon Showdown and is
584
+ - **Flinch**: Flinching doesn't get cleared during move selection on Pokémon Showdown and is
493
585
  instead cleared in Pokémon Showdown's "residual" phase, meaning the flinch status gets erroneously
494
586
  preserved across fainting (as fainting triggers Pokémon Showdown's "instaswitch" behavior which
495
587
  skips end-of-turn residuals).
496
588
  - **Rage**: Rage boosts should still result in burn/paralysis [stat modification
497
589
  errors](https://pkmn.cc/bulba-glitch-1#Stat_modification_errors) but don't on Pokémon Showdown.
498
- - **Thrash** / **Petal Dance**: once a Pokémon is locked into a thrashing move they will lose all
499
- speed ties on Pokémon Showdown (due to the fact that if they win the speed tie their action will
500
- then get "changed" and inserted back into the queue after their opponent's action).
590
+ Furthermore, Pokémon Showdown only builds Rage for Disable/Explosion (hit/miss) when attacking
591
+ into a Substitute instead of all moves. Pokémon Showdown also implements the [Rage and Thrash /
592
+ Petal Dance accuracy bug]( https://www.youtube.com/watch?v=NC5gbJeExbs) incorrectly, as the
593
+ accuracy only gets written when the volatile is present which can lead to incorrect accuracy
594
+ values on turns where Rage is used on the same turn as a move which modifies accuracy or evasion.
595
+ - **Thrash** / **Petal Dance**: once a Pokémon is locked into a thrashing move they lose all speed
596
+ ties on Pokémon Showdown (due to the fact that if they win the speed tie their action then gets
597
+ "changed" and inserted back into the queue after their opponent's action). Pokémon Showdown also
598
+ implements accuracy incorrectly, as covered earlier.
501
599
  - **Freeze** / **Sleep**: Pokémon Showdown requires a move to be selected when a Pokémon is frozen
502
600
  or sleeping and uses that in the event that the status is removed while on the cartridge no
503
601
  selection is possible and no turn exists for the thawed/woken Pokémon to act except in the case of
504
602
  a Fire-type move thawing a slower Pokémon (which should result in the [Freeze top move selection
505
- glitch](https://glitchcity.wiki/Freeze_top_move_selection_glitch), which is not implemented and
603
+ glitch](https://glitchcity.wiki/Freeze_top_move_selection_glitch), which isn't implemented and
506
604
  would also likely be incorrect if it were to be implemented due to how Pokémon Showdown
507
605
  incorrectly saves arbitrary moves with its choice selection semantics). Furthermore, thrashing
508
- volatiles should not be cleared if the user misses a turn due to freeze / sleep.
606
+ volatiles shouldn't be cleared if the user misses a turn due to freeze / sleep.
509
607
  - **Hyper Beam**: due to improperly implemented selection mechanics, the [Hyper Beam
510
608
  automatic-selection glitch](https://glitchcity.wiki/Hyper_Beam_automatic_selection_glitch) does
511
609
  not exist on Pokémon Showdown. Additionally, Hyper Beam being able to cause [Freeze permanent
512
- helplessness](https://pkmn.cc/bulba-glitch-1#Hyper_Beam_.2B_Freeze_permanent_helplessness) is not
610
+ helplessness](https://pkmn.cc/bulba-glitch-1#Hyper_Beam_.2B_Freeze_permanent_helplessness) isn't
513
611
  implement by Pokémon Showdown.
514
612
  - **Roar** / **Whirlwind**: these moves can miss on Pokémon Showdown (and advance the RNG when
515
- checking) which is incorrect (these moves should always fail, but do not check accuracy or advance
613
+ checking) which is incorrect (these moves should always fail, but don't check accuracy or advance
516
614
  the RNG). More importantly, these moves should *not* cause the tracked last battle damage to be
517
- zeroed, but on Pokémon Showdown they do.
615
+ zeroed, but on Pokémon Showdown they do. These should also `|-fail|...|[still]` instead of doing
616
+ nothing.
518
617
  - **Substitute**: in addition to the [Substitute + Confusion
519
618
  glitch](https://pkmn.cc/bulba-glitch-1#Substitute_.2B_Confusion_glitch) not being implemented
520
- correctly (covered above), the [Substitute 1/4
619
+ correctly (covered earlier), the [Substitute 1/4
521
620
  glitch](https://glitchcity.wiki/Substitute_%C2%BC_HP_glitch) also fails in many cases due to
522
621
  Pokémon Showdown implementing the health check based on floating point division instead of integer
523
- divison like on the cartridge (meaning the Substitute 1/4 glitch will only occur if the Pokémon's
524
- maximum HP is evenly divisible by 4). Finally, Substitute also incorrectly blocks Dream Eater on
525
- Pokémon Showdown.
622
+ division like on the cartridge (meaning the Substitute 1/4 glitch only occurs if the Pokémon's
623
+ maximum HP is evenly divisible by 4). Substitute also incorrectly blocks Dream Eater on
624
+ Pokémon Showdown and incorrectly still heals 1 HP for any draining moves if the attack does 0
625
+ damage. Finally, Pokémon Showdown uses a `subFainted` field to track whether a Substitute was
626
+ broken to know when to nullify a move's effect, only it doesn't get cleared at the end of
627
+ the turn and can result in incorrect behavior on subsequent turns with the moves Mirror Move and
628
+ Metronome that invoke `runMove` (which is where `subFainted` gets cleared) on the user but skips
629
+ calling it for the eventual true target.
526
630
 
527
631
  In addition to numerous cases where Pokémon Showdown uses the wrong type of message (e.g. `|-fail`
528
- vs. `|-miss|` vs. `|-immune|`, e.g. in the case of Leech Seed) which are not documented here, Pokémon
529
- Showdown sometimes gets message ordering incorrect (which does not effect the outcome
530
- of the battle, only pedantic UI correctness):
632
+ vs. `|-miss|` vs. `|-immune|`, e.g. in the case of Leech Seed) which aren't documented here, Pokémon
633
+ Showdown sometimes gets message ordering incorrect (which doesn't effect the outcome of the battle,
634
+ only pedantic UI correctness):
531
635
 
532
636
  - **Rage**: Rage should report the `|-boost|` before the Disable `|-miss|`, not after.
533
637
  - **Haze**: Haze clears the status/volatiles in an incorrect order.
638
+ - **Teleport**: Teleport should `|-fail|...|[still]` instead of doing nothing.
534
639
  - **Twineedle**: the `|-hitcount|` ("Hit 2 times") should come before the `|-status|` message, not
535
640
  after.
536
641
  - **Thrash** / **Petal Dance**: confusion should silently get applied before the `|move|` message,
@@ -540,21 +645,21 @@ Pokémon Showdown also implements a number of modifications to the cartridge (us
540
645
  called out in the `|rule|` section at the beginning of a battle's log):
541
646
 
542
647
  - **Sleep Clause Mod**: players are prevented from putting more than one of their opponent's Pokémon
543
- to sleep at a time (usage of the move will fail).
648
+ to sleep at a time (usage of the move fails).
544
649
  - **Freeze Clause Mod**: players are prevented from freezing more than one of their opponent's
545
- Pokémon at a time (usage of the move will fail).
546
- - **Desync Clause Mod**: If the usage of a move would cause a desync it instead causes a
547
- failure. However, this mod does not trigger for [**division by
650
+ Pokémon at a time (usage of the move fails).
651
+ - **Desync Clause Mod**: If the usage of a move would cause a desync it instead causes a failure.
652
+ However, this mod doesn't trigger for [**division by
548
653
  zero**](https://pkmn.cc/bulba/List_of_glitches_(Generation_I)#Division_by_0) - instead of failing,
549
654
  Pokémon Showdown silently patches the damage calculation to divide by 1 instead of 0. The
550
655
  definition of the Desync Clause Mod should be extended or the code should be changed to fail
551
656
  instead of succeeding in these cases.
552
657
  - **Endless Battle Clause**: Prematurely ends the battle in a tie after 1000 turns or in certain
553
- situations where it is trivially detectable that no progress can be made.
658
+ situations where it's trivially detectable that no progress can be made.
554
659
  - **Switch Priority Clause Mod**: When both player switch out their Pokémon at the same time the
555
660
  faster Pokémon switches first. This mod is **not broadcast at the start of the battle in the
556
- `|rule|` section** in Generation I (or II) as the actual order of switches here does not have
557
- competitive implications like it does in Generation III, but it is still contrary to how the games
661
+ `|rule|` section** in Generation I (or II) as the actual order of switches here doesn't have
662
+ competitive implications like it does in Generation III, but it's still contrary to how the games
558
663
  work where the [host (Player 1)'s Pokemon would switch
559
664
  first](https://www.smogon.com/forums/posts/5989318/show).
560
665
 
@@ -592,31 +697,39 @@ the correct control flow):
592
697
  still gets a turn under the [trapping sleep
593
698
  glitch](https://glitchcity.wiki/Trapping_move_and_sleep_glitch), Wrap does 0 damage against
594
699
  Ghost-type Pokémon instead of properly respecting immunity, and binding effects are handled in the
595
- wrong order in the code.
596
- - **Counter**: On Pokémon Showdown choices made while sleeping (which should not have been
597
- registered) can erroneously cause Counter to trigger Desync Clause Mod behavior.
700
+ wrong order in the code which results in either out of order messaging or, more consequentially,
701
+ Pokémon using Rage/Bide or Thrashing/Charging moves being incorrectly forced to skip a turn when
702
+ the Pokémon using the Binding move switches.
598
703
  - **Mimic**: Pokémon Showdown checks that the user of Mimic has Mimic in one of their move slots,
599
- which means Mimic legally called via Metronome or Mirror Move will only work if the user also has
600
- Mimic (and the moved mimicked by Mimic called via Metronome / Mirror Move will erroneously
601
- override the Mimic move slot instead of the Metronome / Mirror Move move slot). Furthermore,
602
- because Pokémon Showdown deducts PP based on a move's name instead of slot, if Mimic copies a move
603
- the Pokémon already knows, PP deduction for using either the original move of the mimicked move
604
- will instead deduct PP for whichever appears at the lower move slot index and the PP will be
605
- allowed to go negative (effectively allowing for infinite PP use).
606
- - **Mirror Move**: Binding moves misbehave when used via Mirror Move (though Pokémon Showdown has
607
- its own weird behavior and does not implement the [partial trapping move Mirror Move
704
+ which means Mimic legally called via Metronome or Mirror Move only works if the user also has
705
+ Mimic (and the moved mimicked by Mimic called via Metronome / Mirror Move erroneously overrides
706
+ the Mimic move slot instead of the Metronome / Mirror Move move slot). Furthermore, because
707
+ Pokémon Showdown deducts PP based on a move's name instead of slot, if Mimic copies a move the
708
+ Pokémon already knows, PP deduction for using either the original move of the mimicked move
709
+ instead deducts PP for whichever appears at the lower move slot index and the PP is allowed to go
710
+ negative (effectively allowing for infinite PP use). Pokémon Showdown also doesn't deduct PP from
711
+ using Transform if it was copied by Mimic.
712
+ - **Mirror Move**: As covered earlier, both Substitute and Binding moves misbehave when used via
713
+ Mirror Move (though Pokémon Showdown has its own weird behavior and doesn't implement the [partial
714
+ trapping move Mirror Move
608
715
  glitch](https://glitchcity.wiki/Partial_trapping_move_Mirror_Move_link_battle_glitch) that exists
609
- on the cartridge).
610
- - **Metronome**: In addition to the issues with binding moves, Metronome and Mirror Move cannot
611
- mutually call each other more than 3 times in a row without causing the Pokémon Showdown simulator
612
- to crash due to defensive safety checks that do not exist on the cartridge.
613
- - **Transform**: Transform screws up the effect of Disable, because on Pokémon Showdown, Disable
716
+ on the cartridge). Additionally, Pokémon Showdown sets the last used move every turn a Pokémon is
717
+ Thrashing instead of just on the turn it's actually selected meaning Mirror Move sometimes
718
+ successfully mirrors a Thrashing move when it should fail. Finally, if Mirror Move copies Struggle
719
+ it shouldn't deduct PP but on Pokémon Showdown it does.
720
+ - **Metronome**: In addition to the issues with binding moves and Substitute, Metronome and Mirror
721
+ Move can't mutually call each other more than 3 times in a row without causing the Pokémon
722
+ Showdown simulator to crash due to defensive safety checks that don't exist on the cartridge.
723
+ - **Transform**: Transform screws up the effect of Disable, because on Pokémon Showdown, Disable
614
724
  prevents moves of a given *name* from being used (e.g. "Water Gun") as opposed to moves in a
615
- specific *slot* (e.g. the 2nd move slot), and a Pokémon's moves can change after Transform (this
616
- is not an issue with Disable + Mimic because Mimic happens to replace the same slot). Furthermore,
617
- transforming and then using Mirror Move / Metronome can result in [glitchy behavior and
725
+ specific *slot* (e.g. the second move slot), and a Pokémon's moves can change after Transform
726
+ (this isn't an issue with Disable + Mimic because Mimic happens to replace the same slot).
727
+ Transform also has a bad interaction with Pokémon Showdown's buggy Haze implementation, as Haze on
728
+ Pokémon Showdown doesn't copy unmodified stats, leaving the Transformed Pokémon with incorrect
729
+ stats. Furthermore, transforming and then using Mirror Move / Metronome can result in [glitchy
730
+ behavior and
618
731
  softlocks](https://pkmn.cc/bulba/Transform_glitches#Transform_.2B_Mirror_Move.2FMetronome_PP_error)
619
- which Pokémon Showdown does not implement.
732
+ which Pokémon Showdown doesn't implement.
620
733
 
621
734
  Importantly, Pokémon Showdown's **speed tie RNG mechanics are unimplementable** in the pkmn engine
622
735
  as they rely on internal implementation decisions made by Pokémon Showdown that are impossible to
@@ -627,13 +740,13 @@ below).
627
740
 
628
741
  **The pkmn engine aims to match the cartridge's RNG frame-accurately**, in that provided with the
629
742
  same initial seed and inputs it should produce the same battle playout as the Pokémon Red cartridge.
630
- **Pokémon Showdown does not correctly implement frame-accurate RNG in any generation**, and along
631
- with the [bugs](#bugs) discussed above this results in large differences in the codebase. Because
743
+ **Pokémon Showdown doesn't correctly implement frame-accurate RNG in any generation**, and along
744
+ with the [bugs](#bugs) discussed earlier this results in large differences in the codebase. Because
632
745
  the pkmn engine aims to be as compatible with Pokémon Showdown as possible when in `-Dshowdown`
633
746
  compatibility mode, the implications of these differences are outlined below:
634
747
 
635
748
  - **RNG**: Pokémon Showdown uses the RNG from Generation V & VI in every generation, despite
636
- the seeds and algorithm being different. Pokémon Red uses a simple 8-bit RNG with 10 distinct
749
+ the seeds and algorithm being different. Pokémon Red uses a simple 8-bit RNG with 9 distinct
637
750
  seeds generated when the link connection is established, whereas Pokémon Showdown uses a 64-bit
638
751
  RNG with a 32-bit output.
639
752
  - **Algorithm**: As detailed in the table below, the algorithm used by Pokémon Showdown in the
@@ -646,15 +759,15 @@ compatibility mode, the implications of these differences are outlined below:
646
759
  sampling to ensure uniformity as is done on the cartridge. This means that certain values are
647
760
  fractionally more likely to be chosen than others, though this bias is usually quite small (e.g.
648
761
  in the case of Metronome instead of selecting moves with an equal $1\over163$ chance, Pokémon
649
- Showdown will select some with a $1\over2^{32}$ greater chance than others).
762
+ Showdown selects some with a $1\over2^{32}$ greater chance than others).
650
763
  - **Order of operations**: RNG calls effectively introduce something similar to a ["memory
651
764
  barrier"](https://en.wikipedia.org/wiki/Memory_barrier) in that they must be sequenced correctly
652
765
  (though operations which occur between them may happen in any order). Pokémon Showdown violates
653
766
  this by introducing additional operations (see below) and changing up the order of existing
654
767
  operations (e.g. choosing to check for hit/miss, determine the number of hits for moves with
655
768
  multiple hits, determine if a move hit critically and then the damage instead of checking for
656
- hit/miss and determining number of hits *after* the other two). While it is often desirable to
657
- rearrange code for performance or to improve readability this can only be done if it does not
769
+ hit/miss and determining number of hits *after* the other two). While it's often desirable to
770
+ rearrange code for performance or to improve readability this can only be done if it doesn't
658
771
  affect accuracy.
659
772
  - **Speed-ties**: In addition to [breaking switch-in speed ties with an RNG
660
773
  call](https://www.smogon.com/forums/threads/adv-switch-priority.3622189/), speed ties in Pokémon
@@ -665,16 +778,16 @@ compatibility mode, the implications of these differences are outlined below:
665
778
  ties proves impossible, and thus the reference Pokémon Showdown implementation pkmn engine aims to
666
779
  match has been [patched](../../../docs/TESTING.md#patches) to change this behavior.
667
780
  - **Effects**: Pokémon Showdown occasionally incorrectly inserts RNG calls in move effect handlers
668
- when they are not relevant:
781
+ when they're not relevant:
669
782
  - Roar / Whirlwind roll to hit and can "miss" as opposed to simply failing
670
783
 
671
- Finally, the **initial 10-byte seed for link battles on Pokémon Red cannot include bytes larger than
784
+ Finally, the **initial 9-byte seed for link battles on Pokémon Red can't include bytes larger than
672
785
  the `SERIAL_PREAMBLE_BYTE`**, so must be in the range $\left[0, 252\right]$. This has implications
673
- on the first 10 random numbers generated during the battle and has [**non-trivial competitive
786
+ on the first 9 random numbers generated during the battle and has [**non-trivial competitive
674
787
  implications**](https://www.smogon.com/forums/posts/9068411/show) (at the start of the battle move
675
788
  effects become more likely, the ["1/256-miss" glitch](https://glitchcity.wiki/1/256_miss_glitch)
676
- cannot happen, Player 1 is more likely to win speed ties, etc) that Pokémon Showdown cannot
677
- replicate due to everything described above.
789
+ can't happen, Player 1 is more likely to win speed ties, etc) that Pokémon Showdown can't replicate
790
+ due to everything described earlier.
678
791
 
679
792
  All of places in the link battle code where randomness is required are outlined below:
680
793
 
@@ -694,19 +807,19 @@ All of places in the link battle code where randomness is required are outlined
694
807
  | **Paralysis** (full) | `beforeMove` | Trigger if $X < 63$ |
695
808
  | **Poison** (chance) | `Effects.poison` | Trigger if $X < 52$ ($103$ for Smog / Sludge) |
696
809
  | **Sleep** (duration) | `Effects.sleep` | <dl><dt>Pokémon Red</dt><dd>Continue generating until $X \land 7 \neq 0$</dd><dt>Pokémon Showdown</dt><dd>Generate $X \in \left[1, 8\right)$</dd></dl> |
697
- | **Bide** (duration) | `Effects.bide` | <dl><dt>Pokémon Red</dt><dd>Last for $\left(X \land 1\right) + 2$ turns</dd><dt>Pokémon Showdown</dt><dd>Last for $X \in \left[2, 4\right)$ turns</dd></dl> |
810
+ | **Bide** (duration) | `Effects.bide` | <dl><dt>Pokémon Red</dt><dd>Last for $\left(X \land 1\right) + 2$ turns</dd><dt>Pokémon Showdown</dt><dd>Last for $X \in \left[2, 4\right)$ turns</dd></dl> |
698
811
  | **Disable** (move) | `Effects.disable` | <dl><dt>Pokémon Red</dt><dd>Continue generating until $X \land 3$ is the index of a non-empty move slot</dd><dt>Pokémon Showdown</dt><dd>Generate $X \in \left[0, \|movesSlots\|\right)$</dd></dl> |
699
812
  | **Disable** (duration) | `Effects.disable` | <dl><dt>Pokémon Red</dt><dd>Last for $\left(X \land 7\right) + 1$ turns</dd><dt>Pokémon Showdown</dt><dd>Last for $X \in \left[1, 9\right)$ turns</dd></dl> |
700
- | **Metronome** (move) | `metronome` | <dl><dt>Pokémon Red</dt><dd>Continue generating until $X$ matches the index of a move which is not Struggle or Metronome</dd><dt>Pokémon Showdown</dt><dd>Generate $X \in \left[0, \|validMoves\|\right)$, where $validMoves$ is ordered set of moves with Struggle and Metronome removed <i>(indexes of moves > Metronome will be shifted down)</i></dd></dl> |
813
+ | **Metronome** (move) | `metronome` | <dl><dt>Pokémon Red</dt><dd>Continue generating until $X$ matches the index of a move which isn't Struggle or Metronome</dd><dt>Pokémon Showdown</dt><dd>Generate $X \in \left[0, \|validMoves\|\right)$, where $validMoves$ is ordered set of moves with Struggle and Metronome removed <i>(indexes of moves > Metronome are shifted down)</i></dd></dl> |
701
814
  | **Mimic** (move) | `Effects.mimic` | <dl><dt>Pokémon Red</dt><dd>Continue generating until $X \land 3$ is the index of a non-empty move slot</dd><dt>Pokémon Showdown</dt><dd>Generate $X \in \left[0, \|movesSlots\|\right)$</dd></dl> |
702
815
  | **Psywave** (power) | `specialDamage` | <dl><dt>Pokémon Red</dt><dd>Continue generating until $X < {3\over2} \cdot level$</dd><dt>Pokémon Showdown</dt><dd>Generate $X \in \left[0, {3\over2} \cdot level\right)$</dd></dl> |
703
816
  | **Thrash** (rampage) | `Effects.thrash` | <dl><dt>Pokémon Red</dt><dd>Last for $\left(X \land 1\right) + 2$ turns</dd><dt>Pokémon Showdown</dt><dd>Last for $X \in \left[2, 4\right)$ turns</dd></dl> |
704
817
  | **Thrash** (confusion) | `beforeMove` | <dl><dt>Pokémon Red</dt><dd>Last for $\left(X \land 3\right) + 2$ turns</dd><dt>Pokémon Showdown</dt><dd>Last for $X \in \left[2, 6\right)$ turns</dd></dl> |
705
- | **Binding** (duration) | `Effects.binding` | <dl><dt>Pokémon Red</dt><dd>Last for $\left(X \land 3\right) + 1$ further turns if $\left(X \land 3\right) < 2$<br /> otherwise last for $\left(Y \land 3\right) + 1$ further turns (reroll)</dd><dt>Pokémon Showdown</dt><dd>Last for $X \in \{2, 2, 3, 3, 4, 5\} - 1$ further turns</dd></dl> |
818
+ | **Binding** (duration) | `Effects.binding` | <dl><dt>Pokémon Red</dt><dd>Last for $\left(X \land 3\right) + 1$ further turns if $\left(X \land 3\right) < 2$<br /> otherwise last for $\left(Y \land 3\right) + 1$ further turns (reroll)</dd><dt>Pokémon Showdown</dt><dd>Last for $X \in \{2, 2, 2, 3, 3, 3, 4, 5\} - 1$ further turns</dd></dl> |
706
819
  | **Multi-Hit** (hits) | `Effects.multiHit` | *Ibid.* |
707
820
  | **Unboost** (chance) | `Effects.unboost` | Trigger if $X < 85$ |
708
821
 
709
- *In the table above,* $X$ *is always in the range* $\left[0, 256\right)$ *for Pokémon Red and for
822
+ *In the preceding table,* $X$ *is always in the range* $\left[0, 256\right)$ *for Pokémon Red and for
710
823
  Pokémon Showdown is always **scaled** from the 32-bit output range of the RNG to either be in that
711
824
  range or to whichever range is specified by the description.*
712
825
 
@@ -749,7 +862,8 @@ table provides a rough mapping between pkmn and Pokémon Red methods:
749
862
  | `handleResidual` | `HandlePoisonBurnLeechSeed` |
750
863
  | `endTurn` / `checkEBC` | - |
751
864
 
752
- Pokémon Red groups move effect handlers together into several groups, these have also been renamed for clarification in the pkmn engine:
865
+ Pokémon Red groups move effect handlers together into several groups, these have also been renamed
866
+ for clarification in the pkmn engine:
753
867
 
754
868
  | pkmn | Pokémon Red (pret) |
755
869
  | --------------- | ------------------------- |
@@ -765,7 +879,7 @@ The pkmn engine attempts to adhere to certain naming conventions:
765
879
  - **`p1`** & **`p2`** always correspond to the `Side` of `Player.P1` and `Player.P2` respectively
766
880
  - **`player`** is the executing turn `Player` (`hWhoseTurn`) and **`player.foe()`** is their
767
881
  opponent
768
- - if `player` (executing turn player) is present then **`side`** will always correspond to their
882
+ - if `player` (executing turn player) is present then **`side`** always corresponds to their
769
883
  `Side` and **`foe`** the opposing `Side`, however `side` can refer to an arbitrary `Side` object
770
884
  if there is no `player` in scope (e.g. in helper functions)
771
885
  - **`target_player`** is a target `Player` whose corresponding `Side` is **`target`**