@pkmn/engine 0.1.0-dev.c4dec0f7 → 0.1.0-dev.d716e940
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.
- package/README.md +50 -22
- package/build/pkg/addon.d.ts +7 -0
- package/build/pkg/addon.js +111 -0
- package/build/pkg/addon.js.map +1 -0
- package/build/pkg/data/layout.json +1 -1
- package/build/pkg/data.d.ts +1 -2
- package/build/pkg/data.js +3 -5
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +5 -4
- package/build/pkg/gen1.js +43 -24
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +15 -12
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +4 -2
- package/build/pkg/protocol.js +4 -2
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js +400 -0
- package/build/test/display.js.map +1 -0
- package/build/tools/debug.js +133 -0
- package/build/tools/debug.js.map +1 -0
- package/build.zig +24 -34
- package/package.json +40 -29
- package/src/bin/install-pkmn-engine +60 -33
- package/src/bin/pkmn-debug +62 -0
- package/src/lib/binding/node.zig +5 -5
- package/src/lib/binding/wasm.zig +3 -3
- package/src/lib/common/debug.zig +1 -0
- package/src/lib/common/options.zig +3 -3
- package/src/lib/common/protocol.zig +38 -38
- package/src/lib/gen1/README.md +119 -85
- package/src/lib/gen1/data.zig +19 -17
- package/src/lib/gen1/helpers.zig +3 -14
- package/src/lib/gen1/mechanics.zig +431 -313
- package/src/lib/gen2/data.zig +4 -4
- package/src/lib/pkmn.zig +7 -7
- package/src/test/display/pkmn.html.tmpl +368 -0
package/README.md
CHANGED
|
@@ -50,13 +50,13 @@ $ zig build --prefix /usr/local -Doptimize=ReleaseFast
|
|
|
50
50
|
|
|
51
51
|
The Zig website has [installation instructions](https://ziglang.org/learn/getting-started/) which
|
|
52
52
|
walk through how to install Zig on each platform - the engine code should work on Zig v0.11.0 dev
|
|
53
|
-
build
|
|
53
|
+
build 2750 or greater, though tracks Zig's master branch so this may change in the future if
|
|
54
54
|
breaking language changes are introduced:
|
|
55
55
|
|
|
56
56
|
`libpkmn` can be built with `-Dshowdown` to instead produce the Pokémon Showdown compatible
|
|
57
|
-
`libpkmn-showdown` library. Furthermore,
|
|
58
|
-
`libpkmn` and `libpkmn-showdown` objects available in the binary release are compiled with
|
|
59
|
-
|
|
57
|
+
`libpkmn-showdown` library. Furthermore, protocol message logging can be enabled through `-Dlog`.
|
|
58
|
+
The `libpkmn` and `libpkmn-showdown` objects available in the binary release are both compiled with
|
|
59
|
+
the `-Dlog` flag by default.
|
|
60
60
|
|
|
61
61
|
### `@pkmn/engine`
|
|
62
62
|
|
|
@@ -90,21 +90,21 @@ const pkmn = @import("lib/pkmn/build.zig");
|
|
|
90
90
|
|
|
91
91
|
pub fn build(b: *std.build.Builder) void {
|
|
92
92
|
...
|
|
93
|
-
exe.addModule("pkmn", pkmn.module(b, .{ .showdown = true, .
|
|
93
|
+
exe.addModule("pkmn", pkmn.module(b, .{ .showdown = true, .log = true }));
|
|
94
94
|
...
|
|
95
95
|
}
|
|
96
96
|
```
|
|
97
97
|
|
|
98
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
|
|
100
|
-
Alternatively, you may set options via a `pkmn_options` [root source file
|
|
99
|
+
configuring whether or not Pokémon Showdown compatibility mode or protocol message logging should be
|
|
100
|
+
enabled. Alternatively, you may set options via a `pkmn_options` [root source file
|
|
101
101
|
declaration](https://ziglang.org/documentation/master/#Root-Source-File). There are several
|
|
102
102
|
undocumented internal options that can be tweaked as well via build or root options, though these
|
|
103
103
|
options are not officially supported, affect correctness, and may change meaning or behavior without
|
|
104
104
|
warning. Use at your own risk.
|
|
105
105
|
|
|
106
106
|
```zig
|
|
107
|
-
pub const pkmn_options = .{ .showdown = true, .
|
|
107
|
+
pub const pkmn_options = .{ .showdown = true, .log = true };
|
|
108
108
|
```
|
|
109
109
|
|
|
110
110
|
## Usage
|
|
@@ -112,16 +112,16 @@ pub const pkmn_options = .{ .showdown = true, .trace = true };
|
|
|
112
112
|
For each Pokémon generation, the engine provides a battle structure with two functions - a function
|
|
113
113
|
to `update` the battle's state based on both players' choices and a function that defines which
|
|
114
114
|
`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 `-
|
|
116
|
-
is enabled each update will produce logs which can be decoded into a buffer (`LOGS_SIZE`
|
|
117
|
-
are provided to make it easy to allocate a buffer of the correct size). Each `update` will
|
|
118
|
-
result to indicate either that the battle has terminated or which types of choices will be
|
|
119
|
-
for each player.
|
|
115
|
+
as their first choice in order to switch in the first member of their party). If `-Dlog` protocol
|
|
116
|
+
logging is enabled each update will produce logs which can be decoded into a buffer (`LOGS_SIZE`
|
|
117
|
+
constants are provided to make it easy to allocate a buffer of the correct size). Each `update` will
|
|
118
|
+
return a result to indicate either that the battle has terminated or which types of choices will be
|
|
119
|
+
available for each player.
|
|
120
120
|
|
|
121
121
|
Unlike [Pokémon Showdown's
|
|
122
122
|
SIM-PROTOCOL](https://github.com/smogon/pokemon-showdown/blob/master/sim/SIM-PROTOCOL.md#choice-requests)
|
|
123
123
|
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 (`
|
|
124
|
+
choices on demand based on the result of the previous `update` and the battle state (`CHOICES_SIZE`
|
|
125
125
|
is a good size to initialize the buffer passed to `choices`). **Attempting to update the battle with
|
|
126
126
|
a choice not present in the options returned by `choices` is undefined behavior and may corrupt
|
|
127
127
|
state or cause the engine to crash.**
|
|
@@ -139,7 +139,7 @@ potential logs that may result.
|
|
|
139
139
|
### C
|
|
140
140
|
|
|
141
141
|
[`pkmn.h`](src/include/pkmn.h) exports the C API for `libpkmn`. Symbols are all prefixed with
|
|
142
|
-
`pkmn_` to avoid name collisions. If `-
|
|
142
|
+
`pkmn_` to avoid name collisions. If `-Dlog` is enabled and logging throws an error then the error
|
|
143
143
|
will be encoded in the `pkmn_result` and can be checked with `pkmn_error`.
|
|
144
144
|
|
|
145
145
|
```c
|
|
@@ -216,7 +216,7 @@ const std = @import("std");
|
|
|
216
216
|
const pkmn = @import("pkmn");
|
|
217
217
|
|
|
218
218
|
var random = std.rand.DefaultPrng.init(seed).random();
|
|
219
|
-
var
|
|
219
|
+
var choices: [pkmn.CHOICES_SIZE]pkmn.Choice = undefined;
|
|
220
220
|
|
|
221
221
|
var battle = ...
|
|
222
222
|
var log = ...
|
|
@@ -226,8 +226,8 @@ var c2 = pkmn.Choice{};
|
|
|
226
226
|
|
|
227
227
|
var result = try battle.update(c1, c2, log);
|
|
228
228
|
while (result.type == .None) : (result = try battle.update(c1, c2, log)) {
|
|
229
|
-
c1 =
|
|
230
|
-
c2 =
|
|
229
|
+
c1 = choices[random.uintLessThan(u8, battle.choices(.P1, result.p1, &choices))];
|
|
230
|
+
c2 = choices[random.uintLessThan(u8, battle.choices(.P2, result.p2, &choices))];
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
std.debug.print("{}\n", .{result.type});
|
|
@@ -250,10 +250,38 @@ following is a list of known `libpkmn` bindings written by developers outside of
|
|
|
250
250
|
organization](https://github.com/pkmn) that may be helpful (though note that these projects may not
|
|
251
251
|
necessarily be up-to-date/complete/correct - inclusion in this list does not imply endorsement):
|
|
252
252
|
|
|
253
|
-
| Language | License | URL
|
|
254
|
-
| ---------- | --------- |
|
|
255
|
-
| **C++** | `BSL-1.0` | https://github.com/pasyg/
|
|
256
|
-
| **Python** | `MIT` | https://github.com/AnnikaCodes/PyKMN
|
|
253
|
+
| Language | License | URL |
|
|
254
|
+
| ---------- | --------- | ------------------------------------ |
|
|
255
|
+
| **C++** | `BSL-1.0` | https://github.com/pasyg/wrapsire |
|
|
256
|
+
| **Python** | `MIT` | https://github.com/AnnikaCodes/PyKMN |
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
#### `pkmn-debug`
|
|
260
|
+
|
|
261
|
+
The [`@pkmn/engine`](#pkmnengine) package ships with a `pkmn-debug` tool which exists to decode the
|
|
262
|
+
binary data structures and protocols used by the engine and to output a [standalone
|
|
263
|
+
webpage](https://pkmn.cc/debug.html) that can be used for debugging. To use this tool in a folder
|
|
264
|
+
that has the `@pkmn/engine` package installed locally you can use `npx pkmn-debug`, though you may
|
|
265
|
+
also wish to install the package globally to be able to use this tool anywhere without
|
|
266
|
+
[`npx`](https://docs.npmjs.com/cli/v7/commands/npx):
|
|
267
|
+
|
|
268
|
+
```sh
|
|
269
|
+
$ npm install --global @pkmn/engine
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
By default, `pkmn-debug` expects to read [binary debug protocol](docs/PROTOCOL.md#debugging) from
|
|
273
|
+
[standard input](https://en.wikipedia.org/wiki/Standard_streams) and output HTML to standard output:
|
|
274
|
+
|
|
275
|
+
```sh
|
|
276
|
+
$ <cmd> | pkmn-debug > index.html
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Alternatively, if a single filename argument is passed to the `pkmn-debug` it will read from that
|
|
280
|
+
instead:
|
|
281
|
+
|
|
282
|
+
```sh
|
|
283
|
+
$ pkmn-debug <file> > index.html
|
|
284
|
+
```
|
|
257
285
|
|
|
258
286
|
## Status
|
|
259
287
|
|
|
@@ -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.size = exports.choose = exports.choices = exports.update = exports.supports = exports.check = void 0;
|
|
27
|
+
const path = __importStar(require("path"));
|
|
28
|
+
const _1 = require(".");
|
|
29
|
+
const ROOT = path.join(__dirname, '..', '..');
|
|
30
|
+
let ADDON = undefined;
|
|
31
|
+
function load() {
|
|
32
|
+
if (ADDON)
|
|
33
|
+
return ADDON;
|
|
34
|
+
let pkmn = undefined;
|
|
35
|
+
let showdown = undefined;
|
|
36
|
+
try {
|
|
37
|
+
pkmn = require(path.join(ROOT, 'build', 'lib', 'pkmn.node'));
|
|
38
|
+
}
|
|
39
|
+
catch { }
|
|
40
|
+
try {
|
|
41
|
+
showdown = require(path.join(ROOT, 'build', 'lib', 'pkmn-showdown.node'));
|
|
42
|
+
}
|
|
43
|
+
catch { }
|
|
44
|
+
if (!pkmn && !showdown) {
|
|
45
|
+
throw new Error('Could not find native addons - did you run `npx install-pkmn-engine`?');
|
|
46
|
+
}
|
|
47
|
+
return (ADDON = [pkmn, showdown]);
|
|
48
|
+
}
|
|
49
|
+
function check(showdown) {
|
|
50
|
+
if (!load()[+showdown]) {
|
|
51
|
+
const opts = ADDON[+!showdown].options.log ? ['-log'] : [];
|
|
52
|
+
if (showdown)
|
|
53
|
+
opts.push('-Dshowdown');
|
|
54
|
+
throw new Error(`@pkmn/engine has ${showdown ? 'not' : 'only'} been configured to support Pokémon Showdown.` +
|
|
55
|
+
`\n(running \`npx install-pkmn-engine --options='${opts.join(' ')}'\` can fix this issue).`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.check = check;
|
|
59
|
+
function supports(showdown, log) {
|
|
60
|
+
if (!load()[+showdown])
|
|
61
|
+
return false;
|
|
62
|
+
if (log === undefined)
|
|
63
|
+
return true;
|
|
64
|
+
return ADDON[+showdown].options.log === log;
|
|
65
|
+
}
|
|
66
|
+
exports.supports = supports;
|
|
67
|
+
function update(index, showdown, battle, c1, c2, log) {
|
|
68
|
+
return _1.Result.decode(ADDON[+showdown].bindings[index]
|
|
69
|
+
.update(battle, _1.Choice.encode(c1), _1.Choice.encode(c2), log));
|
|
70
|
+
}
|
|
71
|
+
exports.update = update;
|
|
72
|
+
function choices(index, showdown, battle, player, choice, buf) {
|
|
73
|
+
const request = choice[0] === 'p' ? 0 : choice[0] === 'm' ? 1 : 2;
|
|
74
|
+
const n = ADDON[+showdown].bindings[index].choices(battle, +(player !== 'p1'), request, buf);
|
|
75
|
+
// The top-level API signature means our hands our tied with respect to
|
|
76
|
+
// writing really fast bindings here. The simplest approach would be to return
|
|
77
|
+
// the ArrayBuffer the bindings populate as well as its size and only decode a
|
|
78
|
+
// Choice after the selection. However, given that we need to return
|
|
79
|
+
// `Choices[]` we need to decode all of them even if they're not all being
|
|
80
|
+
// used which is wasteful. This shouldn't be *that* bad as its a very small
|
|
81
|
+
// list, but its still wasted work. Switching the top-level API to return an
|
|
82
|
+
// Iterable<Choice> doesn't help as we need both the length and the ability to
|
|
83
|
+
// randomly access it, so the best way to make the current API fast would be
|
|
84
|
+
// to have the Zig bindings create Choice objects directly, only that won't
|
|
85
|
+
// scale well as it would require us to basically rewrite the low-level
|
|
86
|
+
// choices function for each generation within node.zig. We could do something
|
|
87
|
+
// really galaxy-brained and return some sort of frankenstein subclass of
|
|
88
|
+
// Array backed by ArrayBuffer which would lazily decode the Choice on access,
|
|
89
|
+
// but thats ultimately not worth the effort. You can't have both a high-level
|
|
90
|
+
// idiomatic API and performance here, hence why the choose function below
|
|
91
|
+
// exists.
|
|
92
|
+
const options = new Array(n);
|
|
93
|
+
const data = new Uint8Array(buf);
|
|
94
|
+
for (let i = 0; i < n; i++)
|
|
95
|
+
options[i] = _1.Choice.decode(data[i]);
|
|
96
|
+
return options;
|
|
97
|
+
}
|
|
98
|
+
exports.choices = choices;
|
|
99
|
+
function choose(index, showdown, battle, player, choice, buf, fn) {
|
|
100
|
+
const request = choice[0] === 'p' ? 0 : choice[0] === 'm' ? 1 : 2;
|
|
101
|
+
const n = ADDON[+showdown].bindings[index].choices(battle, +(player !== 'p1'), request, buf);
|
|
102
|
+
const data = new Uint8Array(buf);
|
|
103
|
+
return _1.Choice.decode(data[fn(n)]);
|
|
104
|
+
}
|
|
105
|
+
exports.choose = choose;
|
|
106
|
+
function size(index, type) {
|
|
107
|
+
const bindings = (ADDON[1] ?? ADDON[0]).bindings[index];
|
|
108
|
+
return type[0] === 'c' ? bindings.CHOICES_SIZE : bindings.LOGS_SIZE;
|
|
109
|
+
}
|
|
110
|
+
exports.size = size;
|
|
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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"}
|
package/build/pkg/data.d.ts
CHANGED
|
@@ -26,8 +26,7 @@ export declare const LAYOUT: {
|
|
|
26
26
|
};
|
|
27
27
|
}[];
|
|
28
28
|
export declare const Data: {
|
|
29
|
-
|
|
30
|
-
view(data: number[]): DataView;
|
|
29
|
+
view(buf: number[] | Buffer): DataView;
|
|
31
30
|
};
|
|
32
31
|
/**
|
|
33
32
|
* Translation table for encoding/decoding Pokémon Showdown string identifiers
|
package/build/pkg/data.js
CHANGED
|
@@ -27,11 +27,9 @@ for (const gen of exports.LAYOUT) {
|
|
|
27
27
|
gen.offsets.Battle.p2 = gen.offsets.Battle.sides + gen.sizes.Side;
|
|
28
28
|
}
|
|
29
29
|
exports.Data = new class {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
view(data) {
|
|
34
|
-
return new DataView(this.buffer(data).buffer);
|
|
30
|
+
view(buf) {
|
|
31
|
+
buf = Array.isArray(buf) ? Buffer.from(buf) : buf;
|
|
32
|
+
return new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
35
33
|
}
|
|
36
34
|
};
|
|
37
35
|
const LOOKUPS = [];
|
package/build/pkg/data.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/pkg/data.ts"],"names":[],"mappings":";;;;;;AAEA,+DAAsC;AACtC,qEAA6C;AAC7C,yEAAgD;AAEnC,QAAA,EAAE,GAAG,CAAC,GAAG,EAAE;IACtB,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC,CAAC,EAAE,CAAC;AAOQ,QAAA,GAAG,GAAG,kBAAc,CAAC;AAErB,QAAA,QAAQ,GAA+C,EAAE,CAAC;AACvE,KAAK,MAAM,IAAI,IAAI,uBAAY,EAAE;IAC/B,gBAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IACpB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,IAAI,IAAI,uBAAY,CAAC,IAAiC,CAAC,EAAE;QAClE,gBAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;KAC5B;CACF;AAEY,QAAA,MAAM,GAAG,qBAGpB,CAAC;AACH,KAAK,MAAM,GAAG,IAAI,cAAM,EAAE;IACxB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IACjD,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;CACnE;AAEY,QAAA,IAAI,GAAG,IAAI;IACtB,
|
|
1
|
+
{"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/pkg/data.ts"],"names":[],"mappings":"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"}
|
package/build/pkg/gen1.d.ts
CHANGED
|
@@ -39,10 +39,11 @@ export declare class Side implements Gen1.Side {
|
|
|
39
39
|
get(slot: Slot): Pokemon | undefined;
|
|
40
40
|
get lastUsedMove(): ID | undefined;
|
|
41
41
|
get lastSelectedMove(): ID | undefined;
|
|
42
|
-
get
|
|
42
|
+
get lastMoveIndex(): 1 | 2 | 3 | 4 | undefined;
|
|
43
|
+
get lastMoveCounterable(): boolean;
|
|
43
44
|
toJSON(): Gen1.Side;
|
|
44
45
|
static init(gen: Generation, lookup: Lookup, team: Partial<PokemonSet>[], data: DataView, offset: number): void;
|
|
45
|
-
static encode(gen: Generation, lookup: Lookup, battle: Data<Gen1.Battle>, side: Gen1.Side, data: DataView, offset: number): void;
|
|
46
|
+
static encode(gen: Generation, showdown: boolean, lookup: Lookup, battle: Data<Gen1.Battle>, side: Gen1.Side, data: DataView, offset: number): void;
|
|
46
47
|
}
|
|
47
48
|
export declare class Pokemon implements Gen1.Pokemon {
|
|
48
49
|
static Volatiles: {
|
|
@@ -77,11 +78,11 @@ export declare class Pokemon implements Gen1.Pokemon {
|
|
|
77
78
|
toxic: number;
|
|
78
79
|
};
|
|
79
80
|
private get sleep();
|
|
80
|
-
private get
|
|
81
|
+
private get ext();
|
|
81
82
|
private get toxic();
|
|
82
83
|
toJSON(): Gen1.Pokemon;
|
|
83
84
|
static init(gen: Generation, lookup: Lookup, set: Partial<PokemonSet>, data: DataView, offset: number, index: number): void;
|
|
84
|
-
static encodeStored(gen: Generation, lookup: Lookup, pokemon: Gen1.Pokemon, data: DataView, offset: number): void;
|
|
85
|
+
static encodeStored(gen: Generation, showdown: boolean, lookup: Lookup, pokemon: Gen1.Pokemon, data: DataView, offset: number): void;
|
|
85
86
|
static encodeActive(gen: Generation, lookup: Lookup, battle: Data<Gen1.Battle>, pokemon: Gen1.Pokemon | undefined, data: DataView, offset: number): void;
|
|
86
87
|
}
|
|
87
88
|
export declare class StoredPokemon {
|
package/build/pkg/gen1.js
CHANGED
|
@@ -50,7 +50,7 @@ class Battle {
|
|
|
50
50
|
this.config = config;
|
|
51
51
|
this.lookup = lookup;
|
|
52
52
|
this.data = data;
|
|
53
|
-
this.options = new ArrayBuffer(addon.size(0, '
|
|
53
|
+
this.options = new ArrayBuffer(addon.size(0, 'choices'));
|
|
54
54
|
this.buf = config.log ? new ArrayBuffer(addon.size(0, 'log')) : undefined;
|
|
55
55
|
this.log = config.log ? new DataView(this.buf) : undefined;
|
|
56
56
|
this.cache = [undefined, undefined];
|
|
@@ -86,7 +86,7 @@ class Battle {
|
|
|
86
86
|
return this.data.getUint16(OFFSETS.Battle.last_damage, data_2.LE);
|
|
87
87
|
}
|
|
88
88
|
get prng() {
|
|
89
|
-
const offset = OFFSETS.Battle.
|
|
89
|
+
const offset = OFFSETS.Battle.last_moves + (this.config.showdown ? 4 : 1);
|
|
90
90
|
// Pokémon Showdown's PRNGSeed is always big-endian
|
|
91
91
|
const seed = [0, 0, 0, 0];
|
|
92
92
|
if (this.config.showdown) {
|
|
@@ -127,20 +127,28 @@ class Battle {
|
|
|
127
127
|
const buf = new ArrayBuffer(SIZES.Battle);
|
|
128
128
|
const data = new DataView(buf);
|
|
129
129
|
let offset = OFFSETS.Battle.p1;
|
|
130
|
-
const
|
|
130
|
+
const lastMoves = [];
|
|
131
131
|
for (const side of battle.sides) {
|
|
132
|
-
Side.encode(gen, lookup, battle, side, data, offset);
|
|
132
|
+
Side.encode(gen, !!options.showdown, lookup, battle, side, data, offset);
|
|
133
133
|
offset += SIZES.Side;
|
|
134
|
-
|
|
134
|
+
if (options.showdown) {
|
|
135
|
+
lastMoves.push(+!!side.lastMoveCounterable);
|
|
136
|
+
lastMoves.push((side.lastMoveIndex ?? 0));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
lastMoves.push((+!!side.lastMoveCounterable << 3) | (side.lastMoveIndex ?? 0));
|
|
140
|
+
}
|
|
135
141
|
}
|
|
136
142
|
data.setUint16(OFFSETS.Battle.turn, battle.turn, data_2.LE);
|
|
137
143
|
data.setUint16(OFFSETS.Battle.last_damage, battle.lastDamage, data_2.LE);
|
|
138
144
|
if (options.showdown) {
|
|
139
|
-
data.
|
|
140
|
-
data.
|
|
145
|
+
data.setUint8(OFFSETS.Battle.last_moves, lastMoves[0]);
|
|
146
|
+
data.setUint8(OFFSETS.Battle.last_moves + 1, lastMoves[1]);
|
|
147
|
+
data.setUint8(OFFSETS.Battle.last_moves + 2, lastMoves[2]);
|
|
148
|
+
data.setUint8(OFFSETS.Battle.last_moves + 3, lastMoves[3]);
|
|
141
149
|
}
|
|
142
150
|
else {
|
|
143
|
-
data.setUint8(OFFSETS.Battle.
|
|
151
|
+
data.setUint8(OFFSETS.Battle.last_moves, (lastMoves[1] << 4) | lastMoves[0]);
|
|
144
152
|
}
|
|
145
153
|
encodePRNG(data, battle.prng);
|
|
146
154
|
return new Battle(lookup, data, options);
|
|
@@ -201,25 +209,38 @@ class Side {
|
|
|
201
209
|
const m = this.data.getUint8(this.offset + OFFSETS.Side.last_selected_move);
|
|
202
210
|
return m === 0 ? undefined : this.lookup.moveByNum(m);
|
|
203
211
|
}
|
|
204
|
-
get
|
|
212
|
+
get lastMoveIndex() {
|
|
205
213
|
let m;
|
|
206
214
|
if (this.battle.config.showdown) {
|
|
207
215
|
const off = this.id === 'p1' ? 0 : 2;
|
|
208
|
-
m = this.data.
|
|
216
|
+
m = this.data.getUint8(OFFSETS.Battle.last_moves + off);
|
|
209
217
|
}
|
|
210
218
|
else {
|
|
211
|
-
m = this.data.getUint8(OFFSETS.Battle.
|
|
212
|
-
m = this.id === 'p1' ?
|
|
219
|
+
m = this.data.getUint8(OFFSETS.Battle.last_moves);
|
|
220
|
+
m = (this.id === 'p1' ? m : (m >> 4)) & 0b111;
|
|
213
221
|
}
|
|
214
222
|
return m === 0 ? undefined : m;
|
|
215
223
|
}
|
|
224
|
+
get lastMoveCounterable() {
|
|
225
|
+
let m;
|
|
226
|
+
if (this.battle.config.showdown) {
|
|
227
|
+
const off = this.id === 'p1' ? 1 : 3;
|
|
228
|
+
m = this.data.getUint8(OFFSETS.Battle.last_moves + off);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
m = this.data.getUint8(OFFSETS.Battle.last_moves);
|
|
232
|
+
m = (this.id === 'p1' ? m : (m >> 4)) & 0b1000;
|
|
233
|
+
}
|
|
234
|
+
return m !== 0;
|
|
235
|
+
}
|
|
216
236
|
toJSON() {
|
|
217
237
|
return {
|
|
218
238
|
active: this.active?.toJSON(),
|
|
219
239
|
pokemon: Array.from(this.pokemon).map(p => p.toJSON()),
|
|
220
240
|
lastSelectedMove: this.lastSelectedMove,
|
|
221
241
|
lastUsedMove: this.lastUsedMove,
|
|
222
|
-
|
|
242
|
+
lastMoveIndex: this.lastMoveIndex,
|
|
243
|
+
lastMoveCounterable: this.lastMoveCounterable,
|
|
223
244
|
};
|
|
224
245
|
}
|
|
225
246
|
static init(gen, lookup, team, data, offset) {
|
|
@@ -230,11 +251,11 @@ class Side {
|
|
|
230
251
|
data.setUint8(offset + OFFSETS.Side.order + i, i + 1);
|
|
231
252
|
}
|
|
232
253
|
}
|
|
233
|
-
static encode(gen, lookup, battle, side, data, offset) {
|
|
254
|
+
static encode(gen, showdown, lookup, battle, side, data, offset) {
|
|
234
255
|
let i = 0;
|
|
235
256
|
for (const pokemon of side.pokemon) {
|
|
236
257
|
const off = offset + OFFSETS.Side.pokemon + SIZES.Pokemon * (pokemon.position - 1);
|
|
237
|
-
Pokemon.encodeStored(gen, lookup, pokemon, data, off);
|
|
258
|
+
Pokemon.encodeStored(gen, showdown, lookup, pokemon, data, off);
|
|
238
259
|
data.setUint8(offset + OFFSETS.Side.order + (pokemon.position - 1), i + 1);
|
|
239
260
|
i++;
|
|
240
261
|
}
|
|
@@ -424,13 +445,14 @@ class Pokemon {
|
|
|
424
445
|
return status === 'psn' && this.toxic ? 'tox' : status;
|
|
425
446
|
}
|
|
426
447
|
get statusData() {
|
|
427
|
-
|
|
448
|
+
const sleep = this.sleep;
|
|
449
|
+
return { sleep, self: !!sleep && this.ext, toxic: this.toxic };
|
|
428
450
|
}
|
|
429
451
|
get sleep() {
|
|
430
452
|
const val = this.data.getUint8(this.offset.stored + OFFSETS.Pokemon.status);
|
|
431
453
|
return val & 0b111;
|
|
432
454
|
}
|
|
433
|
-
get
|
|
455
|
+
get ext() {
|
|
434
456
|
return (this.data.getUint8(this.offset.stored + OFFSETS.Pokemon.status) >> 7) === 1;
|
|
435
457
|
}
|
|
436
458
|
get toxic() {
|
|
@@ -480,7 +502,7 @@ class Pokemon {
|
|
|
480
502
|
data.setUint8(stored + OFFSETS.Pokemon.types, encodeTypes(lookup, species.types));
|
|
481
503
|
data.setUint8(stored + OFFSETS.Pokemon.level, set.level ?? 100);
|
|
482
504
|
}
|
|
483
|
-
static encodeStored(gen, lookup, pokemon, data, offset) {
|
|
505
|
+
static encodeStored(gen, showdown, lookup, pokemon, data, offset) {
|
|
484
506
|
let off = 0;
|
|
485
507
|
const stats = pokemon.stored.stats;
|
|
486
508
|
for (const stat of gen.stats) {
|
|
@@ -499,7 +521,7 @@ class Pokemon {
|
|
|
499
521
|
data.setUint8(offset + OFFSETS.Pokemon.species, species.num);
|
|
500
522
|
data.setUint8(offset + OFFSETS.Pokemon.types, encodeTypes(lookup, species.types));
|
|
501
523
|
data.setUint8(offset + OFFSETS.Pokemon.level, pokemon.level);
|
|
502
|
-
data.setUint8(offset + OFFSETS.Pokemon.status, encodeStatus(pokemon));
|
|
524
|
+
data.setUint8(offset + OFFSETS.Pokemon.status, encodeStatus(pokemon, showdown));
|
|
503
525
|
}
|
|
504
526
|
static encodeActive(gen, lookup, battle, pokemon, data, offset) {
|
|
505
527
|
if (!pokemon)
|
|
@@ -646,18 +668,15 @@ function decodeSigned(n) {
|
|
|
646
668
|
function encodeSigned(n) {
|
|
647
669
|
return (n < 0) ? 0b10000 + n : n;
|
|
648
670
|
}
|
|
649
|
-
function encodeStatus(pokemon) {
|
|
671
|
+
function encodeStatus(pokemon, showdown) {
|
|
650
672
|
if (pokemon.statusData.sleep) {
|
|
651
673
|
if (pokemon.status !== 'slp') {
|
|
652
674
|
throw new Error('Pokemon is not asleep but has non-zero sleep turns');
|
|
653
675
|
}
|
|
654
676
|
return (pokemon.statusData.self ? 0x80 : 0) | pokemon.statusData.sleep;
|
|
655
677
|
}
|
|
656
|
-
else if (pokemon.statusData.self) {
|
|
657
|
-
throw new Error('Pokemon is not asleep but has self-inflicted sleep bit set');
|
|
658
|
-
}
|
|
659
678
|
switch (pokemon.status) {
|
|
660
|
-
case 'tox':
|
|
679
|
+
case 'tox': return showdown ? 0b10001000 : 1 << 3;
|
|
661
680
|
case 'psn': return 1 << 3;
|
|
662
681
|
case 'brn': return 1 << 4;
|
|
663
682
|
case 'frz': return 1 << 5;
|