@pkmn/engine 0.1.0-dev.63cef311 → 0.1.0-dev.6cc9e067

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 (63) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +135 -73
  3. package/build/pkg/addon.d.ts +7 -0
  4. package/build/pkg/addon.js +111 -0
  5. package/build/pkg/addon.js.map +1 -0
  6. package/build/pkg/data/ids.json +12 -12
  7. package/build/pkg/data/layout.json +27 -5
  8. package/build/pkg/data/protocol.json +69 -12
  9. package/build/pkg/data.d.ts +5 -6
  10. package/build/pkg/data.js +3 -5
  11. package/build/pkg/data.js.map +1 -1
  12. package/build/pkg/gen1.d.ts +5 -4
  13. package/build/pkg/gen1.js +49 -33
  14. package/build/pkg/gen1.js.map +1 -1
  15. package/build/pkg/index.d.ts +17 -13
  16. package/build/pkg/index.js.map +1 -1
  17. package/build/pkg/protocol.d.ts +4 -2
  18. package/build/pkg/protocol.js +65 -44
  19. package/build/pkg/protocol.js.map +1 -1
  20. package/build/test/display.js +400 -0
  21. package/build/test/display.js.map +1 -0
  22. package/build/tools/debug.js +134 -0
  23. package/build/tools/debug.js.map +1 -0
  24. package/build.zig +168 -140
  25. package/package.json +86 -46
  26. package/src/bin/install-pkmn-engine +79 -39
  27. package/src/bin/pkmn-debug +62 -0
  28. package/src/lib/common/battle.zig +17 -0
  29. package/src/lib/common/data.zig +19 -31
  30. package/src/lib/common/debug.zig +21 -11
  31. package/src/lib/common/js.zig +118 -0
  32. package/src/lib/common/optional.zig +67 -0
  33. package/src/lib/common/options.zig +12 -3
  34. package/src/lib/common/protocol.zig +942 -403
  35. package/src/lib/common/rational.zig +357 -0
  36. package/src/lib/common/rng.zig +35 -26
  37. package/src/lib/common/util.zig +12 -0
  38. package/src/lib/gen1/calc.zig +426 -0
  39. package/src/lib/gen1/chance.zig +1061 -0
  40. package/src/lib/gen1/data/moves.zig +202 -190
  41. package/src/lib/gen1/data/species.zig +5 -5
  42. package/src/lib/gen1/data/types.zig +10 -10
  43. package/src/lib/gen1/data.zig +106 -92
  44. package/src/lib/gen1/helpers.zig +602 -41
  45. package/src/lib/gen1/mechanics.zig +1228 -821
  46. package/src/lib/gen2/calc.zig +143 -0
  47. package/src/lib/gen2/chance.zig +1315 -0
  48. package/src/lib/gen2/data/items.zig +14 -20
  49. package/src/lib/gen2/data/moves.zig +664 -570
  50. package/src/lib/gen2/data/species.zig +2 -2
  51. package/src/lib/gen2/data/types.zig +137 -34
  52. package/src/lib/gen2/data.zig +134 -96
  53. package/src/lib/gen2/generated.zig +806 -0
  54. package/src/lib/gen2/helpers.zig +50 -26
  55. package/src/lib/gen2/mechanics.zig +3591 -12
  56. package/src/lib/node.zig +131 -0
  57. package/src/lib/pkmn.zig +86 -12
  58. package/src/lib/wasm.zig +13 -0
  59. package/src/test/display/pkmn.html.tmpl +368 -0
  60. package/src/lib/binding/node.zig +0 -229
  61. package/src/lib/binding/wasm.zig +0 -10
  62. package/src/lib/gen1/README.md +0 -778
  63. package/src/lib/gen2/README.md +0 -309
package/LICENSE CHANGED
@@ -1,6 +1,4 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2021-2023 pkmn contributors
1
+ Copyright (c) 2021-2024 pkmn contributors
4
2
 
5
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
4
  this software and associated documentation files (the "Software"), to deal in
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <br />
4
4
  <br />
5
5
  <a href="https://github.com/pkmn/engine/actions/workflows/test.yml">
6
- <img alt="Test Status" src="https://github.com/pkmn/engine/workflows/Tests/badge.svg" />
6
+ <img alt="Test Status" src="https://github.com/pkmn/engine/actions/workflows/test.yml/badge.svg" />
7
7
  </a>
8
8
  <a href="#status">
9
9
  <img alt="WIP" src="https://img.shields.io/badge/status-WIP-red.svg" />
@@ -12,13 +12,21 @@
12
12
  <img alt="License" src="https://img.shields.io/badge/License-MIT-blue.svg" />
13
13
  </a>
14
14
  </p>
15
+
16
+ > [!WARNING]
17
+ > **This project is under heavy development** and currently the `main` branch contains numerous breaking
18
+ > changes which may not work and which are not fully documented. Please **wait for the forthcoming
19
+ > initial v0.1 release** before depending on this project (code from the
20
+ > [`old`](https://github.com/pkmn/engine/releases/tag/old) tag can also be used to experiment with a
21
+ > more stable version of the codebase).
22
+
15
23
  <hr />
16
24
 
17
25
  A minimal, complete, Pokémon battle simulation engine optimized for performance and
18
26
  [designed](docs/DESIGN.md) for tooling, embedded systems, and [artificial
19
27
  intelligence](https://github.com/pkmn/0-ERROR) use cases. This engine aims to be a frame-accurate and
20
28
  [bug-for-bug compatible](http://www.catb.org/jargon/html/B/bug-for-bug-compatible.html)
21
- implementation of both Pokémon battles as defined by the original game code, and the [Pokémon
29
+ implementation of both Pokémon battles as defined by the original game code and the [Pokémon
22
30
  Showdown](https://pokemonshowdown.com/)[^1] simulator which represents Pokémon battling as practically
23
31
  interpreted online.
24
32
 
@@ -49,14 +57,14 @@ $ zig build --prefix /usr/local -Doptimize=ReleaseFast
49
57
  ```
50
58
 
51
59
  The Zig website has [installation instructions](https://ziglang.org/learn/getting-started/) which
52
- walk through how to install Zig on each platform - the engine code should work on Zig v0.11.0 dev
53
- build 2168 or greater, though tracks Zig's master branch so this may change in the future if
54
- breaking language changes are introduced:
60
+ walk through how to install Zig on each platform - the engine code should work on Zig v0.13.0,
61
+ though tracks Zig's master branch so this may change in the future if breaking language changes are
62
+ introduced.
55
63
 
56
64
  `libpkmn` can be built with `-Dshowdown` to instead produce the Pokémon Showdown compatible
57
- `libpkmn-showdown` library. Furthermore, trace logging can be enabled through `-Dtrace`. The
58
- `libpkmn` and `libpkmn-showdown` objects available in the binary release are compiled with and
59
- without the `-Dtrace` flag respectively.
65
+ `libpkmn-showdown` library. Furthermore, protocol message logging can be enabled through `-Dlog`.
66
+ The `libpkmn` and `libpkmn-showdown` objects available in the binary release are both compiled with
67
+ the `-Dlog` flag by default.
60
68
 
61
69
  ### `@pkmn/engine`
62
70
 
@@ -67,44 +75,67 @@ $ npm install @pkmn/engine
67
75
  ```
68
76
 
69
77
  The driver depends on being able to find compiled Node/WASM addons in
70
- `node_modules/@pkmn/engine/build/lib` in order to be useful. When you install the package a
71
- [`postinstall` lifecycle script](https://docs.npmjs.com/cli/v8/using-npm/scripts) will run
72
- [`install-pkmn-engine`](src/bin/install-pkmn-engine) which will check for a compatible `zig`
73
- compiler (see above regarding minimum version) and download one to
74
- `node_module/@pkmn/engine/build/bin` if it can't find one, as well as looking for (and downloading,
75
- if necessary) the required Node headers needed to successfully build the addons natively.
76
-
77
- **If you have configured NPM to `--ignore-scripts` you must either run `npx install-pkmn-engine`
78
+ `node_modules/@pkmn/engine/build/lib` to be useful. When you install the package a [`postinstall`
79
+ lifecycle script](https://docs.npmjs.com/cli/v8/using-npm/scripts) runs
80
+ [`install-pkmn-engine`](src/bin/install-pkmn-engine) which checks for a compatible `zig` compiler
81
+ (see earlier regarding minimum version) and download one to `node_module/@pkmn/engine/build/bin` if
82
+ it can't find one, as well as looking for (and downloading, if necessary) the required Node headers
83
+ needed to successfully build the addons natively.
84
+
85
+ **If you have configured `npm` to `--ignore-scripts` you must either run `npx install-pkmn-engine`
78
86
  directly or build the addons manually and place the artifacts in the expected paths.**
79
87
 
80
88
  ### `pkmn`
81
89
 
82
- Until the [Zig package manager](https://github.com/ziglang/zig/projects/4) is completed, the
83
- recommended way of using the `pkmn` package in Zig is by either copying this repository into your
84
- project or by using [git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) and then
85
- adding the following to your `build.zig`:
90
+ To include `pkmn`, add it as a dependency in your project's
91
+ [`build.zig.zon`](https://github.com/ziglang/zig/blob/master/doc/build.zig.zon.md):
92
+
93
+
94
+ ```zig
95
+ .dependencies = .{
96
+ .pkmn = .{
97
+ .url = "https://github.com/pkmn/engine/archive/RELEASE.tar.gz",
98
+ },
99
+ },
100
+ ```
101
+
102
+ Replace `RELEASE` with the tag for the [release](https://github.com/pkmn/engine/releases) you wish
103
+ to use (e.g. `0.1.0` or `nightly`) or the specific hash of any commit. Next, run `zig build` and
104
+ copy the expected hash from the error message into your `build.zig.zon` alongside the `.url`:
105
+
106
+ ```sh
107
+ $ zig build
108
+ error: dependency is missing hash field
109
+ .url = "https://github.com/pkmn/engine/archive/nightly.tar.gz",
110
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
111
+ note: expected .hash = "122056b93b403033cb7d9bed96a02c2eb8cc1275515976167726ada6eb4207e8ef8a",
112
+ ```
113
+
114
+ Note that this hash is **not** going to be the same as the commit hash. After adding the hash to
115
+ your `build.zig.zon` you will be able to import the `pkmn` package's build helpers into your
116
+ `build.zig`:
86
117
 
87
118
  ```zig
88
119
  const std = @import("std");
89
- const pkmn = @import("lib/pkmn/build.zig");
120
+ const pkmn = @import("pkmn");
90
121
 
91
- pub fn build(b: *std.build.Builder) void {
122
+ pub fn build(b: *std.Build) void {
92
123
  ...
93
- exe.addModule("pkmn", pkmn.module(b, .{ .showdown = true, .trace = true }));
124
+ exe.addModule("pkmn", pkmn.module(b, .{ .showdown = true, .log = true }));
94
125
  ...
95
126
  }
96
127
  ```
97
128
 
98
- The engine's `build.zig` exposes a `module` function that takes an options structure to allow for
99
- configuring whether or not Pokémon Showdown compatibility mode or trace logs should be enabled.
100
- Alternatively, you may set options via a `pkmn_options` [root source file
129
+ The `pkmn` package exposes a `module` function that takes an options structure to allow for
130
+ configuring whether or not Pokémon Showdown compatibility mode or protocol message logging should be
131
+ enabled. Alternatively, you may set options via a `pkmn_options` [root source file
101
132
  declaration](https://ziglang.org/documentation/master/#Root-Source-File). There are several
102
133
  undocumented internal options that can be tweaked as well via build or root options, though these
103
- options are not officially supported, affect correctness, and may change meaning or behavior without
134
+ options aren't officially supported, affect correctness, and may change meaning or behavior without
104
135
  warning. Use at your own risk.
105
136
 
106
137
  ```zig
107
- pub const pkmn_options = .{ .showdown = true, .trace = true };
138
+ pub const pkmn_options = .{ .showdown = true, .log = true };
108
139
  ```
109
140
 
110
141
  ## Usage
@@ -112,63 +143,66 @@ pub const pkmn_options = .{ .showdown = true, .trace = true };
112
143
  For each Pokémon generation, the engine provides a battle structure with two functions - a function
113
144
  to `update` the battle's state based on both players' choices and a function that defines which
114
145
  `choices` are valid at that decision point (at the beginning of a battle both player's must "pass"
115
- as their first choice in order to switch in the first member of their party). If `-Dtrace` logging
116
- is enabled each update will produce logs which can be decoded into a buffer (`LOGS_SIZE` constants
117
- are provided to make it easy to allocate a buffer of the correct size). Each `update` will return a
118
- result to indicate either that the battle has terminated or which types of choices will be available
119
- for each player.
146
+ as their first choice to switch in the first member of their party). If `-Dlog` protocol logging is
147
+ enabled each update produces logs which can be decoded into a buffer (`LOGS_SIZE` constants are
148
+ provided to make it easy to allocate a buffer of the correct size). Each `update` returns a result
149
+ to indicate either that the battle has terminated or which types of choices are available for each
150
+ player.
120
151
 
121
152
  Unlike [Pokémon Showdown's
122
153
  SIM-PROTOCOL](https://github.com/smogon/pokemon-showdown/blob/master/sim/SIM-PROTOCOL.md#choice-requests)
123
154
  which provides a rich request object at each decision point, the pkmn engine computes the possible
124
- choices on demand based on the result of the previous `update` and the battle state (`OPTIONS_SIZE`
155
+ choices on demand based on the result of the previous `update` and the battle state (`CHOICES_SIZE`
125
156
  is a good size to initialize the buffer passed to `choices`). **Attempting to update the battle with
126
157
  a choice not present in the options returned by `choices` is undefined behavior and may corrupt
127
158
  state or cause the engine to crash.**
128
159
 
129
160
  Battles may be played out from any point but to freshly initialize a battle which is yet to start
130
161
  the turn count and active Pokémon should be zeroed out (driver code should handle this for you).
131
- Most driver code should also provide helpers to make initialize a battle convenient - check the
162
+ Most driver code should also provide helpers to make initializing battle convenient - check the
132
163
  respective documentation and examples for the bindings being used. The engine's [protocol
133
164
  documentation](docs/PROTOCOL.md) goes into greater detail on the specifics of updates and the
134
165
  potential logs that may result.
135
166
 
136
167
  *The snippets below are meant to merely illustrate in broad strokes how the pkmn engine can be used
137
- \- the [`examples`](src/examples) directory contains fully commented and runnable code.*
168
+ \- the [`examples`](examples) directory contains fully commented and runnable code.*
138
169
 
139
170
  ### C
140
171
 
141
172
  [`pkmn.h`](src/include/pkmn.h) exports the C API for `libpkmn`. Symbols are all prefixed with
142
- `pkmn_` to avoid name collisions. If `-Dtrace` is enabled and logging throws an error then the error
143
- will be encoded in the `pkmn_result` and can be checked with `pkmn_error`.
173
+ `pkmn_` to avoid name collisions. If `-Dlog` is enabled and logging throws an error then the error
174
+ is encoded in the `pkmn_result` and can be checked with `pkmn_error`.
144
175
 
145
176
  ```c
146
177
  #include <pkmn.h>
147
178
 
179
+ pkmn_battle_options options;
180
+ pkmn_gen1_battle_options_set(&options, ...);
148
181
  pkmn_battle battle = ...;
149
- uint8_t buf[PKMN_LOGS_SIZE];
182
+
150
183
  pkmn_result result;
151
184
  pkmn_choice c1 = 0, c2 = 0;
152
- while (!pkmn_result_type(result = pkmn_battle_update(&battle, c1, c2, buf, PKMN_LOGS_SIZE))) {
185
+ while (!pkmn_result_type(result = pkmn_battle_update(&battle, c1, c2, &options))) {
153
186
  c1 = choose(PKMN_PLAYER_P1, pkmn_result_p1(result));
154
187
  c2 = choose(PKMN_PLAYER_P2, pkmn_result_p2(result));
188
+ pkmn_gen1_battle_options_set(&options, ...);
155
189
  }
156
190
  if (pkmn_error(result)) exit(1);
157
191
  ```
158
192
 
159
- [(full code)](src/examples/c/example.c)
193
+ [(full code)](examples/c/example.c)
160
194
 
161
- The C API does not export any helpers for creating or accessing the opaque battle objects - it is
195
+ The C API doesn't export any helpers for creating or accessing the opaque battle objects - it's
162
196
  instead intended to be used as the foundation for more ergonomic bindings in [other
163
197
  languages](#other) (the lack of namespaces and bit fields having an implementation-defined layout in
164
198
  C are the main contributing factors to the sparseness of what `libpkmn` chooses to expose).
165
199
 
166
200
  ### JavaScript / TypeScript
167
201
 
168
- `@pkmn/engine` depends on the [`@pkmn/data`](https://www.npmjs.com/package/@pkmn/data) which
202
+ `@pkmn/engine` depends on the [`@pkmn/data`](https://www.npmjs.com/package/@pkmn/data) package which
169
203
  requires a `Dex` implementation to be provided as well. The `Battle.create` function can be used to
170
204
  initialize a `Battle` from the beginning, or `Battle.restore` can be used to re-instantiate a battle
171
- which is in already progress. If logging is enabled the output can be turned into Pokémon Showdown
205
+ which is already in progress. If logging is enabled the output can be turned into Pokémon Showdown
172
206
  protocol via `Log.parse`.
173
207
 
174
208
  ```ts
@@ -191,20 +225,20 @@ while (!(result = battle.update(c1, c2)).type) {
191
225
  console.log(result);
192
226
  ```
193
227
 
194
- [(full code)](src/examples/js/example.ts)
228
+ [(full code)](examples/js/example.ts)
195
229
 
196
- By default, the `@pkmn/engine` package will compile the engine with `-Dshowdown`, though by running
230
+ By default, the `@pkmn/engine` package compiles the engine with `-Dshowdown`, though by running
197
231
  `install-pkmn-engine` directly and passing in `--options` you can override this default and build
198
232
  different configurations of the extension for the driver to use. The driver can support
199
233
  configurations both with and without Pokémon Showdown compatibility simultaneously if present. On
200
- update, the post-install script will attempt to rebuild whichever extensions it finds with the same
234
+ update, the post-install script attempts to rebuild whichever extensions it finds with the same
201
235
  configuration parameters that were originally used meaning updating to the newest version of the
202
236
  library should be seamless.
203
237
 
204
238
  Despite relying on the native engine code, the `@pkmn/engine` code is designed to also work in
205
239
  browsers which support [WebAssembly](https://webassembly.org/). Running `npm run start:web` from the
206
- [`examples`](src/examples/js) directory will start a server that can be used to demonstrate the
207
- engine running in the browser.
240
+ [`examples`](examples/js) directory starts a server that can be used to demonstrate the engine
241
+ running in the browser.
208
242
 
209
243
  ### Zig
210
244
 
@@ -215,29 +249,29 @@ be used when logging is enabled to allow for easily printing e.g. to standard ou
215
249
  const std = @import("std");
216
250
  const pkmn = @import("pkmn");
217
251
 
218
- var random = std.rand.DefaultPrng.init(seed).random();
219
- var options: [pkmn.OPTIONS_SIZE]pkmn.Choice = undefined;
252
+ var random = std.Random.DefaultPrng.init(seed).random();
253
+ var choices: [pkmn.CHOICES_SIZE]pkmn.Choice = undefined;
220
254
 
221
255
  var battle = ...
222
- var log = ...
256
+ var options = pkmn.battle.options(...);
223
257
 
224
258
  var c1 = pkmn.Choice{};
225
259
  var c2 = pkmn.Choice{};
226
260
 
227
- var result = try battle.update(c1, c2, log);
228
- while (result.type == .None) : (result = try battle.update(c1, c2, log)) {
229
- c1 = options[random.uintLessThan(u8, battle.choices(.P1, result.p1, &options))];
230
- c2 = options[random.uintLessThan(u8, battle.choices(.P2, result.p2, &options))];
261
+ var result = try battle.update(c1, c2, &options);
262
+ while (result.type == .None) : (result = try battle.update(c1, c2, &options)) {
263
+ c1 = choices[random.uintLessThan(u8, battle.choices(.P1, result.p1, &choices))];
264
+ c2 = choices[random.uintLessThan(u8, battle.choices(.P2, result.p2, &choices))];
231
265
  }
232
266
 
233
267
  std.debug.print("{}\n", .{result.type});
234
268
  ```
235
269
 
236
- [(full code)](src/examples/zig/example.zig)
270
+ [(full code)](examples/zig/example.zig)
237
271
 
238
272
  The Zig package also supports some APIs which are difficult to expose elsewhere such as the
239
273
  `FixedRNG` which allows you to fully specify the exact RNG frames (which can be useful for ensuring
240
- certain outcomes/effects always occur) for a battle, though doing so will change the size of the
274
+ certain outcomes/effects always occur) for a battle, though doing so changes the size of the
241
275
  `Battle` object.
242
276
 
243
277
  ### Other
@@ -248,12 +282,40 @@ simplify the process even further [`src/data`](src/data) contains JSON dumps of
248
282
  data, structure sizes and offsets, and protocol information used by the reference driver code. The
249
283
  following is a list of known `libpkmn` bindings written by developers outside of the [pkmn
250
284
  organization](https://github.com/pkmn) that may be helpful (though note that these projects may not
251
- necessarily be up-to-date/complete/correct - inclusion in this list does not imply endorsement):
285
+ necessarily be up-to-date/complete/correct - inclusion in this list doesn't imply endorsement):
286
+
287
+ | Language | License | URL |
288
+ | ---------- | --------- | ------------------------------------ |
289
+ | **C++** | `BSL-1.0` | https://github.com/pasyg/wrapsire |
290
+ | **Python** | `MIT` | https://github.com/AnnikaCodes/PyKMN |
252
291
 
253
- | Language | License | URL |
254
- | ---------- | --------- | --------------------------------------- |
255
- | **C++** | `BSL-1.0` | https://github.com/pasyg/engine-wrapper |
256
- | **Python** | `MIT` | https://github.com/AnnikaCodes/PyKMN |
292
+
293
+ #### `pkmn-debug`
294
+
295
+ The [`@pkmn/engine`](#pkmnengine) package ships with a `pkmn-debug` tool which exists to decode the
296
+ binary data structures and protocols used by the engine and to output a [standalone
297
+ webpage](https://pkmn.cc/debug.html) that can be used for debugging. To use this tool in a folder
298
+ that has the `@pkmn/engine` package installed locally you can use `npx pkmn-debug`, though you may
299
+ also wish to install the package globally to be able to use this tool anywhere without
300
+ [`npx`](https://docs.npmjs.com/cli/v7/commands/npx):
301
+
302
+ ```sh
303
+ $ npm install --global @pkmn/engine
304
+ ```
305
+
306
+ By default, `pkmn-debug` expects to read [binary debug protocol](docs/PROTOCOL.md#debugging) from
307
+ [standard input](https://en.wikipedia.org/wiki/Standard_streams) and output HTML to standard output:
308
+
309
+ ```sh
310
+ $ <cmd> | pkmn-debug > index.html
311
+ ```
312
+
313
+ Alternatively, if a single filename argument is passed to the `pkmn-debug` it reads from that
314
+ instead:
315
+
316
+ ```sh
317
+ $ pkmn-debug <file> > index.html
318
+ ```
257
319
 
258
320
  ## Status
259
321
 
@@ -270,14 +332,14 @@ Currently, most of the foundational work from stage 0 is done:
270
332
 
271
333
  - [benchmark and integration testing](src/test) infrastructure
272
334
  - [documentation](docs) about design, research, methodology, etc
273
- - definition and implementation of the [protocol](docs/PROTOCOL.md) that will be used by the engine
335
+ - definition and implementation of the [protocol](docs/PROTOCOL.md) that's used by the engine
274
336
 
275
- **Stage 1 is currently in progress** and will see the implementation of the actual Generation I & II
337
+ **Stage 1 is currently in progress** and involves the implementation of the actual Generation I & II
276
338
  battle engines, followed by Generation III & IV in stage 2. The implementation of further Pokémon
277
- generations is in scope for the project but should not be considered as part of the immediate
278
- roadmap (i.e. exploring the options for broadening support for old generation APIs will be given
279
- higher priority than implementing more modern generations). Furthermore, implementation of modern
280
- generations is soft-blocked on the [availability of high quality
339
+ generations is in scope for the project but shouldn't be considered part of the immediate roadmap
340
+ (i.e. exploring the options for broadening support for old generation APIs is given higher priority
341
+ than implementing more modern generations). Furthermore, implementation of modern generations is
342
+ soft-blocked on the [availability of high quality
281
343
  decompilations](https://github.com/orgs/pret/repositories) of the original games in question.
282
344
 
283
345
  Certain features will always be deemed **out of scope**:
@@ -295,10 +357,10 @@ The pkmn engine is distributed under the terms of the [MIT License](LICENSE).
295
357
  [^1]: In the case of Pokémon Showdown, only bugs which stem from a misimplementation of specific
296
358
  effects are reproduced in the engine, bugs which are the result of a misunderstanding of the
297
359
  fundamental mechanics of Pokémon or which simply arise due to specific Pokémon Showdown
298
- implementation details that are not replicable without making the same (incorrect) architectural
299
- choices are not. Furthermore, the "Pokémon Showdown" code referenced by this project includes
360
+ implementation details that aren't replicable without making the same (incorrect) architectural
361
+ choices aren't. Furthermore, the "Pokémon Showdown" code referenced by this project includes
300
362
  several [patches](docs/TESTING.md#patches) to improve accuracy and smooth over some of the more
301
363
  egregious implementation issues. In practical terms, the vast majority of games played out in the
302
- pkmn engine's compatibility mode and on this patched Pokémon Showdown simulator will be the same,
303
- it is only in a well defined and documented set of circumstances where the two implementations
364
+ pkmn engine's compatibility mode and on this patched Pokémon Showdown simulator are the same,
365
+ it's only in a well defined and documented set of circumstances where the two implementations
304
366
  diverge.
@@ -0,0 +1,7 @@
1
+ import { Choice, Player, Result } from '.';
2
+ export declare function check(showdown: boolean): void;
3
+ export declare function supports(showdown: boolean, log?: boolean): boolean;
4
+ export declare function update(index: number, showdown: boolean, battle: ArrayBuffer, c1?: Choice, c2?: Choice, log?: ArrayBuffer): Result;
5
+ export declare function choices(index: number, showdown: boolean, battle: ArrayBuffer, player: Player, choice: Choice['type'], buf: ArrayBuffer): Choice[];
6
+ export declare function choose(index: number, showdown: boolean, battle: ArrayBuffer, player: Player, choice: Choice['type'], buf: ArrayBuffer, fn: (n: number) => number): Choice;
7
+ export declare function size(index: number, type: 'choices' | 'log'): number;
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.check = check;
27
+ exports.supports = supports;
28
+ exports.update = update;
29
+ exports.choices = choices;
30
+ exports.choose = choose;
31
+ exports.size = size;
32
+ const path = __importStar(require("path"));
33
+ const _1 = require(".");
34
+ const ROOT = path.join(__dirname, '..', '..');
35
+ let ADDON = undefined;
36
+ function load() {
37
+ if (ADDON)
38
+ return ADDON;
39
+ let pkmn = undefined;
40
+ let showdown = undefined;
41
+ try {
42
+ pkmn = require(path.join(ROOT, 'build', 'lib', 'pkmn.node')).engine;
43
+ }
44
+ catch { }
45
+ try {
46
+ showdown =
47
+ require(path.join(ROOT, 'build', 'lib', 'pkmn-showdown.node')).engine;
48
+ }
49
+ catch { }
50
+ if (!pkmn && !showdown) {
51
+ throw new Error('Could not find native addons - did you run `npx install-pkmn-engine`?');
52
+ }
53
+ return (ADDON = [pkmn, showdown]);
54
+ }
55
+ function check(showdown) {
56
+ if (!load()[+showdown]) {
57
+ const opts = ADDON[+!showdown].options.log ? ['-log'] : [];
58
+ if (showdown)
59
+ opts.push('-Dshowdown');
60
+ throw new Error(`@pkmn/engine has ${showdown ? 'not' : 'only'} been configured to support Pokémon Showdown.` +
61
+ `\n(running \`npx install-pkmn-engine --options='${opts.join(' ')}'\` can fix this issue).`);
62
+ }
63
+ }
64
+ function supports(showdown, log) {
65
+ if (!load()[+showdown])
66
+ return false;
67
+ if (log === undefined)
68
+ return true;
69
+ return ADDON[+showdown].options.log === log;
70
+ }
71
+ function update(index, showdown, battle, c1, c2, log) {
72
+ return _1.Result.decode(ADDON[+showdown].bindings[index]
73
+ .update(battle, _1.Choice.encode(c1), _1.Choice.encode(c2), log));
74
+ }
75
+ function choices(index, showdown, battle, player, choice, buf) {
76
+ const request = choice[0] === 'p' ? 0 : choice[0] === 'm' ? 1 : 2;
77
+ const n = ADDON[+showdown].bindings[index].choices(battle, +(player !== 'p1'), request, buf);
78
+ // The top-level API signature means our hands our tied with respect to
79
+ // writing really fast bindings here. The simplest approach would be to return
80
+ // the ArrayBuffer the bindings populate as well as its size and only decode a
81
+ // Choice after the selection. However, given that we need to return
82
+ // `Choices[]` we need to decode all of them even if they're not all being
83
+ // used which is wasteful. This shouldn't be *that* bad as its a very small
84
+ // list, but its still wasted work. Switching the top-level API to return an
85
+ // Iterable<Choice> doesn't help as we need both the length and the ability to
86
+ // randomly access it, so the best way to make the current API fast would be
87
+ // to have the Zig bindings create Choice objects directly, only that won't
88
+ // scale well as it would require us to basically rewrite the low-level
89
+ // choices function for each generation within node.zig. We could do something
90
+ // really galaxy-brained and return some sort of frankenstein subclass of
91
+ // Array backed by ArrayBuffer which would lazily decode the Choice on access,
92
+ // but thats ultimately not worth the effort. You can't have both a high-level
93
+ // idiomatic API and performance here, hence why the choose function below
94
+ // exists.
95
+ const options = new Array(n);
96
+ const data = new Uint8Array(buf);
97
+ for (let i = 0; i < n; i++)
98
+ options[i] = _1.Choice.decode(data[i]);
99
+ return options;
100
+ }
101
+ function choose(index, showdown, battle, player, choice, buf, fn) {
102
+ const request = choice[0] === 'p' ? 0 : choice[0] === 'm' ? 1 : 2;
103
+ const n = ADDON[+showdown].bindings[index].choices(battle, +(player !== 'p1'), request, buf);
104
+ const data = new Uint8Array(buf);
105
+ return _1.Choice.decode(data[fn(n)]);
106
+ }
107
+ function size(index, type) {
108
+ const bindings = (ADDON[1] ?? ADDON[0]).bindings[index];
109
+ return type[0] === 'c' ? bindings.CHOICES_SIZE : bindings.LOGS_SIZE;
110
+ }
111
+ //# sourceMappingURL=addon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addon.js","sourceRoot":"","sources":["../../src/pkg/addon.ts"],"names":[],"mappings":"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"}
@@ -20,15 +20,15 @@
20
20
  },
21
21
  {
22
22
  "types": [
23
+ "Ground",
24
+ "Rock",
25
+ "Steel",
23
26
  "Normal",
24
27
  "Fighting",
25
28
  "Flying",
26
29
  "Poison",
27
- "Ground",
28
- "Rock",
29
30
  "Bug",
30
31
  "Ghost",
31
- "Steel",
32
32
  "???",
33
33
  "Fire",
34
34
  "Water",
@@ -40,15 +40,15 @@
40
40
  "Dark"
41
41
  ],
42
42
  "items": [
43
+ "softsand",
44
+ "hardstone",
45
+ "metalcoat",
43
46
  "pinkbow",
44
47
  "blackbelt",
45
48
  "sharpbeak",
46
49
  "poisonbarb",
47
- "softsand",
48
- "hardstone",
49
50
  "silverpowder",
50
51
  "spelltag",
51
- "metalcoat",
52
52
  "polkadotbow",
53
53
  "charcoal",
54
54
  "mysticwater",
@@ -65,21 +65,21 @@
65
65
  "stick",
66
66
  "thickclub",
67
67
  "focusband",
68
- "berryjuice",
69
68
  "scopelens",
70
69
  "leftovers",
71
70
  "berserkgene",
72
71
  "lightball",
72
+ "berry",
73
+ "berryjuice",
74
+ "goldberry",
75
+ "mintberry",
73
76
  "psncureberry",
74
77
  "przcureberry",
75
- "burntberry",
76
78
  "iceberry",
77
- "bitterberry",
78
- "mintberry",
79
+ "burntberry",
79
80
  "miracleberry",
81
+ "bitterberry",
80
82
  "mysteryberry",
81
- "berry",
82
- "goldberry",
83
83
  "masterball",
84
84
  "ultraball",
85
85
  "greatball",
@@ -4,15 +4,17 @@
4
4
  "Battle": 384,
5
5
  "Side": 184,
6
6
  "Pokemon": 24,
7
- "ActivePokemon": 32
7
+ "ActivePokemon": 32,
8
+ "Actions": 16,
9
+ "Summaries": 12
8
10
  },
9
11
  "offsets": {
10
12
  "Battle": {
11
13
  "sides": 0,
12
14
  "turn": 368,
13
15
  "last_damage": 370,
14
- "last_selected_indexes": 372,
15
- "rng": 373
16
+ "last_moves": 372,
17
+ "rng": 374
16
18
  },
17
19
  "Side": {
18
20
  "pokemon": 0,
@@ -77,9 +79,29 @@
77
79
  "state": 24,
78
80
  "substitute": 40,
79
81
  "transform": 48,
80
- "disabled_duration": 52,
81
- "disabled_move": 56,
82
+ "disable_duration": 52,
83
+ "disable_move": 56,
82
84
  "toxic": 59
85
+ },
86
+ "Action": {
87
+ "damage": 0,
88
+ "hit": 8,
89
+ "critical_hit": 10,
90
+ "secondary_chance": 12,
91
+ "speed_tie": 14,
92
+ "confused": 16,
93
+ "paralyzed": 18,
94
+ "duration": 20,
95
+ "durations": 24,
96
+ "move_slot": 40,
97
+ "multi_hit": 44,
98
+ "psywave": 48,
99
+ "metronome": 56
100
+ },
101
+ "Damage": {
102
+ "base": 0,
103
+ "final": 2,
104
+ "capped": 4
83
105
  }
84
106
  }
85
107
  }