@pkmn/engine 0.1.0-dev.683fba11 → 0.1.0-dev.6b383c80
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/LICENSE +1 -1
- package/README.md +22 -16
- package/build/pkg/addon/browser.js +6 -3
- package/build/pkg/addon/browser.js.map +1 -1
- package/build/pkg/addon/node.js +23 -10
- package/build/pkg/addon/node.js.map +1 -1
- package/build/pkg/addon/wasm.js +23 -14
- package/build/pkg/addon/wasm.js.map +1 -1
- package/build/pkg/addon.d.ts +5 -5
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +2 -1
- package/build/pkg/gen1.js +22 -9
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +2 -0
- package/build/pkg/index.js +17 -7
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +11 -2
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +54 -11
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +19 -94
- package/build/tools/display/debug.jsx.map +1 -1
- package/build/tools/display/index.js +18 -7
- package/build/tools/display/index.js.map +1 -1
- package/build/tools/display/ui.jsx +20 -9
- package/build/tools/display/ui.jsx.map +1 -1
- package/build/tools/display/util.js +140 -1
- package/build/tools/display/util.js.map +1 -1
- package/build.zig +255 -313
- package/package.json +29 -131
- package/src/bin/install-pkmn-engine +24 -22
- package/src/lib/bindings/c.zig +201 -0
- package/src/lib/bindings/node.zig +117 -0
- package/src/lib/bindings/wasm.zig +51 -0
- package/src/lib/common/array.zig +9 -16
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/debug.zig +46 -61
- package/src/lib/common/js.zig +3 -9
- package/src/lib/common/optional.zig +20 -25
- package/src/lib/common/protocol.zig +224 -189
- package/src/lib/common/rational.zig +275 -284
- package/src/lib/common/rng.zig +4 -4
- package/src/lib/common/util.zig +34 -31
- package/src/lib/gen1/calc.zig +141 -119
- package/src/lib/gen1/chance.zig +162 -101
- package/src/lib/gen1/data/types.zig +2 -2
- package/src/lib/gen1/data.zig +27 -24
- package/src/lib/gen1/helpers.zig +36 -26
- package/src/lib/gen1/mechanics.zig +45 -49
- package/src/lib/gen2/calc.zig +3 -6
- package/src/lib/gen2/chance.zig +55 -43
- package/src/lib/gen2/data/types.zig +6 -3
- package/src/lib/gen2/data.zig +20 -16
- package/src/lib/gen2/helpers.zig +27 -19
- package/src/lib/gen2/mechanics.zig +17 -17
- package/src/lib/napi.h +2 -0
- package/src/lib/node.zig +3 -118
- package/src/lib/pkmn.zig +94 -19
- package/src/lib/wasm.zig +9 -44
- package/src/tools/display/dom.ts +43 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pkmn/engine",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.6b383c80",
|
|
4
4
|
"description": "A minimal, complete, Pokémon battle simulation engine optimized for performance",
|
|
5
5
|
"repository": "github:pkmn/engine",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,6 +49,9 @@
|
|
|
49
49
|
"build/tools/display/ui.jsx",
|
|
50
50
|
"build/tools/display/util.js.map",
|
|
51
51
|
"build/tools/display/util.js",
|
|
52
|
+
"src/lib/bindings/c.zig",
|
|
53
|
+
"src/lib/bindings/node.zig",
|
|
54
|
+
"src/lib/bindings/wasm.zig",
|
|
52
55
|
"src/lib/common/array.zig",
|
|
53
56
|
"src/lib/common/battle.zig",
|
|
54
57
|
"src/lib/common/data.zig",
|
|
@@ -78,6 +81,7 @@
|
|
|
78
81
|
"src/lib/gen2/generated.zig",
|
|
79
82
|
"src/lib/gen2/helpers.zig",
|
|
80
83
|
"src/lib/gen2/mechanics.zig",
|
|
84
|
+
"src/lib/napi.h",
|
|
81
85
|
"src/lib/node.zig",
|
|
82
86
|
"src/lib/pkmn.zig",
|
|
83
87
|
"src/lib/wasm.zig",
|
|
@@ -95,42 +99,41 @@
|
|
|
95
99
|
"access": "public"
|
|
96
100
|
},
|
|
97
101
|
"dependencies": {
|
|
98
|
-
"@pkmn/data": "
|
|
99
|
-
"@pkmn/protocol": "^0.
|
|
102
|
+
"@pkmn/data": "0.9.35",
|
|
103
|
+
"@pkmn/protocol": "^0.7.3"
|
|
100
104
|
},
|
|
101
105
|
"devDependencies": {
|
|
102
|
-
"@pkmn/
|
|
103
|
-
"@pkmn/
|
|
104
|
-
"@pkmn/
|
|
105
|
-
"@pkmn/
|
|
106
|
-
"@pkmn/
|
|
107
|
-
"@
|
|
108
|
-
"@types/
|
|
106
|
+
"@pkmn/dex-types": "0.9.35",
|
|
107
|
+
"@pkmn/eslint-config": "^10.0.0",
|
|
108
|
+
"@pkmn/img": "^0.3.4",
|
|
109
|
+
"@pkmn/sets": "^5.2.0",
|
|
110
|
+
"@pkmn/sim": "0.9.31",
|
|
111
|
+
"@pkmn/smogon": "0.5.21",
|
|
112
|
+
"@types/html-minifier": "^4.0.6",
|
|
113
|
+
"@types/jest": "^30.0.0",
|
|
109
114
|
"@types/minimist": "^1.2.5",
|
|
110
|
-
"@types/mustache": "^4.2.
|
|
111
|
-
"@types/node": "^
|
|
112
|
-
"@types/react": "^
|
|
113
|
-
"@types/
|
|
114
|
-
"@
|
|
115
|
-
"@
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"eslint": "<=8",
|
|
115
|
+
"@types/mustache": "^4.2.6",
|
|
116
|
+
"@types/node": "^26.6.3",
|
|
117
|
+
"@types/react": "^19.3.0",
|
|
118
|
+
"@types/vscode": "^1.140.0",
|
|
119
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
120
|
+
"@vscode/vsce": "^4.0.0",
|
|
121
|
+
"binaryen": "^132.0.0",
|
|
122
|
+
"esbuild": "^0.28.2",
|
|
123
|
+
"eslint": "^10.11.0",
|
|
120
124
|
"html-minifier": "^4.0.0",
|
|
121
125
|
"json-stringify-pretty-compact": "3.0.0",
|
|
122
126
|
"minimist": "^1.2.8",
|
|
123
127
|
"mustache": "^4.2.0",
|
|
124
|
-
"semver": "^7.6.3",
|
|
125
128
|
"source-map-support": "^0.5.21",
|
|
126
|
-
"table": "^6.
|
|
129
|
+
"table": "^6.9.0",
|
|
127
130
|
"trakr": "^0.2.0",
|
|
128
|
-
"typescript": "^
|
|
129
|
-
"vitest": "^
|
|
131
|
+
"typescript": "^6.0.3",
|
|
132
|
+
"vitest": "^5.0.3"
|
|
130
133
|
},
|
|
131
134
|
"scripts": {
|
|
132
|
-
"lint": "eslint --cache src
|
|
133
|
-
"fix": "eslint --fix src
|
|
135
|
+
"lint": "eslint --cache src",
|
|
136
|
+
"fix": "eslint --fix src",
|
|
134
137
|
"compile": "tsc -p .",
|
|
135
138
|
"build": "npm run compile",
|
|
136
139
|
"test": "vitest src/pkg",
|
|
@@ -144,110 +147,5 @@
|
|
|
144
147
|
"integration": "npm run compile && node build/test/integration",
|
|
145
148
|
"extension": "npm -C src/tools/vscode run build",
|
|
146
149
|
"postinstall": "node src/bin/install-pkmn-engine"
|
|
147
|
-
},
|
|
148
|
-
"eslintConfig": {
|
|
149
|
-
"extends": "@pkmn",
|
|
150
|
-
"ignorePatterns": [
|
|
151
|
-
"dist/",
|
|
152
|
-
"node_modules/",
|
|
153
|
-
"examples/zig",
|
|
154
|
-
"build/",
|
|
155
|
-
"extension.js"
|
|
156
|
-
],
|
|
157
|
-
"env": {
|
|
158
|
-
"es6": true,
|
|
159
|
-
"node": true,
|
|
160
|
-
"browser": true
|
|
161
|
-
},
|
|
162
|
-
"overrides": [
|
|
163
|
-
{
|
|
164
|
-
"files": [
|
|
165
|
-
"**/*.ts"
|
|
166
|
-
],
|
|
167
|
-
"parserOptions": {
|
|
168
|
-
"project": [
|
|
169
|
-
"./tsconfig.json",
|
|
170
|
-
"./examples/js/tsconfig.json"
|
|
171
|
-
]
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
"files": [
|
|
176
|
-
"src/pkg/common.ts",
|
|
177
|
-
"src/pkg/index.ts",
|
|
178
|
-
"src/test/integration.ts"
|
|
179
|
-
],
|
|
180
|
-
"rules": {
|
|
181
|
-
"no-control-regex": "off",
|
|
182
|
-
"@typescript-eslint/no-empty-interface": "off",
|
|
183
|
-
"@typescript-eslint/no-shadow": "off",
|
|
184
|
-
"@typescript-eslint/no-unsafe-declaration-merging": "off"
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
"files": [
|
|
189
|
-
"src/pkg/addon/node.ts"
|
|
190
|
-
],
|
|
191
|
-
"rules": {
|
|
192
|
-
"@typescript-eslint/no-var-requires": "off"
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
"files": [
|
|
197
|
-
"src/test/benchmark*.ts"
|
|
198
|
-
],
|
|
199
|
-
"rules": {
|
|
200
|
-
"@typescript-eslint/no-unused-vars": "off",
|
|
201
|
-
"@typescript-eslint/no-redundant-type-constituents": "off"
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
"files": [
|
|
206
|
-
"src/pkg/protocol.test.ts"
|
|
207
|
-
],
|
|
208
|
-
"rules": {
|
|
209
|
-
"jest/no-standalone-expect": "off",
|
|
210
|
-
"jest/no-conditional-expect": "off"
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
"files": [
|
|
215
|
-
"src/test/*.test.ts"
|
|
216
|
-
],
|
|
217
|
-
"rules": {
|
|
218
|
-
"jest/no-standalone-expect": "off"
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
"files": [
|
|
223
|
-
"src/test/showdown/**"
|
|
224
|
-
],
|
|
225
|
-
"rules": {
|
|
226
|
-
"jest/expect-expect": [
|
|
227
|
-
"warn",
|
|
228
|
-
{
|
|
229
|
-
"assertFunctionNames": [
|
|
230
|
-
"expect",
|
|
231
|
-
"expectLog",
|
|
232
|
-
"verify"
|
|
233
|
-
]
|
|
234
|
-
}
|
|
235
|
-
]
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
{
|
|
239
|
-
"files": [
|
|
240
|
-
"src/tools/generate.ts"
|
|
241
|
-
],
|
|
242
|
-
"rules": {
|
|
243
|
-
"@typescript-eslint/restrict-template-expressions": [
|
|
244
|
-
"error",
|
|
245
|
-
{
|
|
246
|
-
"allowBoolean": true
|
|
247
|
-
}
|
|
248
|
-
]
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
]
|
|
252
150
|
}
|
|
253
151
|
}
|
|
@@ -10,7 +10,7 @@ const path = require('path');
|
|
|
10
10
|
const {pipeline} = require('stream/promises');
|
|
11
11
|
const tty = require('tty');
|
|
12
12
|
|
|
13
|
-
const ZIG_VERSION = {major: 0, minor:
|
|
13
|
+
const ZIG_VERSION = {major: 0, minor: 16, patch: 0};
|
|
14
14
|
const DEV = ZIG_VERSION.dev ? `-dev.${ZIG_VERSION.dev}` : '';
|
|
15
15
|
const VERSION = `${ZIG_VERSION.major}.${ZIG_VERSION.minor}.${ZIG_VERSION.patch}${DEV}`;
|
|
16
16
|
const INDEX = 'https://ziglang.org/download/index.json';
|
|
@@ -111,15 +111,31 @@ const unpack = async (input, output) => {
|
|
|
111
111
|
}
|
|
112
112
|
};
|
|
113
113
|
|
|
114
|
+
const parse = s => {
|
|
115
|
+
try {
|
|
116
|
+
return JSON.parse(s);
|
|
117
|
+
} catch (e) {
|
|
118
|
+
if (!(e instanceof SyntaxError)) throw e;
|
|
119
|
+
const json = s
|
|
120
|
+
// "key": -> "key": (ensures keys are quoted)
|
|
121
|
+
.replace(/\.([a-zA-Z_][a-zA-Z0-9_]*)\s*=/g, '"$1":')
|
|
122
|
+
// .{ -> { (converts ZON struct to JSON object)
|
|
123
|
+
.replace(/\.\{/g, '{')
|
|
124
|
+
// Remove trailing commas, which are invalid in JSON
|
|
125
|
+
.replace(/,\s*([}\]])/g, '$1');
|
|
126
|
+
return JSON.parse(json);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
114
130
|
const find = zig => {
|
|
115
131
|
try {
|
|
116
|
-
const {zig_exe, version} =
|
|
117
|
-
const [major, minor, patch, dev] = version.split('.').map(n => parseInt(n));
|
|
132
|
+
const {zig_exe, version} = parse(sh(zig, ['env']));
|
|
133
|
+
const [major, minor, patch, dev] = version.split('.').map(n => parseInt(n, 10));
|
|
118
134
|
|
|
119
135
|
const compatible = major > ZIG_VERSION.major ||
|
|
120
136
|
(major >= ZIG_VERSION.major && minor > ZIG_VERSION.minor) ||
|
|
121
137
|
(major >= ZIG_VERSION.major && minor >= ZIG_VERSION.minor && patch >= ZIG_VERSION.patch &&
|
|
122
|
-
(!ZIG_VERSION.dev || (dev && dev >= ZIG_VERSION.dev)));
|
|
138
|
+
(!ZIG_VERSION.dev || (dev && dev >= parseInt(ZIG_VERSION.dev, 10))));
|
|
123
139
|
|
|
124
140
|
if (compatible) {
|
|
125
141
|
log('Found existing compatible Zig executable:', zig_exe);
|
|
@@ -163,10 +179,9 @@ const install = async () => {
|
|
|
163
179
|
}
|
|
164
180
|
|
|
165
181
|
const index = JSON.parse(await fetch(INDEX));
|
|
166
|
-
|
|
167
|
-
// const version =
|
|
168
|
-
const
|
|
169
|
-
const release = index[VERSION][`${arch}-${platform}`];
|
|
182
|
+
const version = Object.keys(index)[+!ZIG_VERSION.dev];
|
|
183
|
+
// const version = VERSION; // TODO
|
|
184
|
+
const release = index[version][`${arch}-${platform}`];
|
|
170
185
|
const url = release.tarball;
|
|
171
186
|
|
|
172
187
|
let base = path.basename(url);
|
|
@@ -325,6 +340,7 @@ const downloadImportLib = async () => {
|
|
|
325
340
|
const libs = path.join(ROOT, 'build', 'lib');
|
|
326
341
|
if (fs.existsSync(libs)) {
|
|
327
342
|
for (const file of fs.readdirSync(libs)) {
|
|
343
|
+
if (!file.startsWith('pkmn')) continue;
|
|
328
344
|
const type = path.extname(file).slice(1);
|
|
329
345
|
if (type !== 'node' && type !== 'wasm') continue;
|
|
330
346
|
// If we don't copy the addon before loading it Windows will return an
|
|
@@ -385,20 +401,6 @@ const downloadImportLib = async () => {
|
|
|
385
401
|
const artifact = path.join('build', 'lib', `pkmn${suffix}.${config.type}`);
|
|
386
402
|
log(`Building ${artifact}${flags}`);
|
|
387
403
|
sh(zig, args);
|
|
388
|
-
// TODO: ziglang/zig#14647 broke emit_to so we get to rename the file ourselves...
|
|
389
|
-
if (config.type === 'node') {
|
|
390
|
-
const prefix = process.platform === 'win32' ? '' : 'lib';
|
|
391
|
-
const ext = process.platform === 'darwin'
|
|
392
|
-
? 'dylib' : process.platform === 'win32' ? 'dll' : 'so';
|
|
393
|
-
try {
|
|
394
|
-
const actual = path.join(ROOT, 'build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
|
|
395
|
-
fs.renameSync(actual, artifact);
|
|
396
|
-
} catch (err) {
|
|
397
|
-
// ziglang/zig#19743 changed this path
|
|
398
|
-
const actual = path.join(ROOT, 'build', 'bin', `${prefix}pkmn${suffix}.node.${ext}`);
|
|
399
|
-
fs.renameSync(actual, artifact);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
404
|
}
|
|
403
405
|
})().catch(e => {
|
|
404
406
|
console.error(e);
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
const pkmn = @import("../pkmn.zig");
|
|
2
|
+
const std = @import("std");
|
|
3
|
+
const util = @import("../common/util.zig");
|
|
4
|
+
|
|
5
|
+
const assert = std.debug.assert;
|
|
6
|
+
|
|
7
|
+
const ERROR: u8 = 0b1100;
|
|
8
|
+
|
|
9
|
+
pub const OPTIONS: extern struct {
|
|
10
|
+
showdown: bool,
|
|
11
|
+
log: bool,
|
|
12
|
+
chance: bool,
|
|
13
|
+
calc: bool,
|
|
14
|
+
} = .{
|
|
15
|
+
.showdown = pkmn.options.showdown,
|
|
16
|
+
.log = pkmn.options.log,
|
|
17
|
+
.chance = pkmn.options.chance,
|
|
18
|
+
.calc = pkmn.options.calc,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
pub const MAX_CHOICES = pkmn.MAX_CHOICES;
|
|
22
|
+
pub const CHOICES_SIZE = pkmn.CHOICES_SIZE;
|
|
23
|
+
pub const MAX_LOGS = pkmn.MAX_LOGS;
|
|
24
|
+
pub const LOGS_SIZE = pkmn.LOGS_SIZE;
|
|
25
|
+
|
|
26
|
+
pub fn choice_init(choice: u8, data: u8) callconv(.c) u8 {
|
|
27
|
+
assert(choice <= util.EnumFieldsLen(pkmn.Choice.Type));
|
|
28
|
+
assert(data <= 6);
|
|
29
|
+
return @bitCast(pkmn.Choice{ .type = @enumFromInt(choice), .data = @intCast(data) });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pub fn choice_type(choice: u8) callconv(.c) u8 {
|
|
33
|
+
return @intFromEnum(@as(pkmn.Choice, @bitCast(choice)).type);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn choice_data(choice: u8) callconv(.c) u8 {
|
|
37
|
+
return @as(u8, @as(pkmn.Choice, @bitCast(choice)).data);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub fn result_type(result: u8) callconv(.c) u8 {
|
|
41
|
+
return @intFromEnum(@as(pkmn.Result, @bitCast(result)).type);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
pub fn result_p1(result: u8) callconv(.c) u8 {
|
|
45
|
+
assert(!err(result));
|
|
46
|
+
return @intFromEnum(@as(pkmn.Result, @bitCast(result)).p1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn result_p2(result: u8) callconv(.c) u8 {
|
|
50
|
+
assert(!err(result));
|
|
51
|
+
return @intFromEnum(@as(pkmn.Result, @bitCast(result)).p2);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
pub fn err(result: u8) callconv(.c) bool {
|
|
55
|
+
return result == ERROR;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
pub fn psrng_init(prng: *pkmn.PSRNG, seed: u64) callconv(.c) void {
|
|
59
|
+
prng.src = .{ .seed = seed };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub fn psrng_next(prng: *pkmn.PSRNG) callconv(.c) u32 {
|
|
63
|
+
return prng.next();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pub fn rational_init(rational: *pkmn.Rational(f64)) callconv(.c) void {
|
|
67
|
+
rational.reset();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
pub fn rational_reduce(rational: *pkmn.Rational(f64)) callconv(.c) void {
|
|
71
|
+
rational.reduce();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
pub fn rational_numerator(rational: *const pkmn.Rational(f64)) callconv(.c) f64 {
|
|
75
|
+
return rational.p;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
pub fn rational_denominator(rational: *const pkmn.Rational(f64)) callconv(.c) f64 {
|
|
79
|
+
return rational.q;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const log_options = extern struct {
|
|
83
|
+
buf: [*]u8,
|
|
84
|
+
len: usize,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
pub fn gen(comptime num: comptime_int) type {
|
|
88
|
+
const g = @field(pkmn, "gen" ++ std.fmt.comptimePrint("{d}", .{num}));
|
|
89
|
+
|
|
90
|
+
return struct {
|
|
91
|
+
pub const MAX_CHOICES = g.MAX_CHOICES;
|
|
92
|
+
pub const CHOICES_SIZE = g.CHOICES_SIZE;
|
|
93
|
+
pub const MAX_LOGS = g.MAX_LOGS;
|
|
94
|
+
pub const LOGS_SIZE = g.LOGS_SIZE;
|
|
95
|
+
|
|
96
|
+
const chance_options = extern struct {
|
|
97
|
+
probability: pkmn.Rational(f64),
|
|
98
|
+
actions: g.chance.Actions,
|
|
99
|
+
durations: g.chance.Durations,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const calc_options = extern struct {
|
|
103
|
+
overrides: g.chance.Actions,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const battle_options = struct {
|
|
107
|
+
writer: pkmn.protocol.Writer,
|
|
108
|
+
log: pkmn.protocol.FixedLog,
|
|
109
|
+
chance: g.Chance(pkmn.Rational(f64)),
|
|
110
|
+
calc: g.Calc,
|
|
111
|
+
|
|
112
|
+
comptime {
|
|
113
|
+
assert(@sizeOf(battle_options) <= 128);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
pub fn battle_options_set(
|
|
118
|
+
options: *battle_options,
|
|
119
|
+
log: ?*const log_options,
|
|
120
|
+
chance: ?*const chance_options,
|
|
121
|
+
calc: ?*const calc_options,
|
|
122
|
+
) callconv(.c) void {
|
|
123
|
+
if (pkmn.options.log) {
|
|
124
|
+
if (log) |l| {
|
|
125
|
+
options.writer = .{ .buffer = l.buf[0..l.len] };
|
|
126
|
+
options.log = .{ .writer = &options.writer };
|
|
127
|
+
} else {
|
|
128
|
+
options.writer.reset();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (pkmn.options.chance) {
|
|
132
|
+
if (chance) |c| {
|
|
133
|
+
options.chance = .{
|
|
134
|
+
.probability = c.probability,
|
|
135
|
+
.actions = c.actions,
|
|
136
|
+
.durations = c.durations,
|
|
137
|
+
};
|
|
138
|
+
} else {
|
|
139
|
+
options.chance.reset();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (pkmn.options.calc) {
|
|
143
|
+
if (calc) |c| {
|
|
144
|
+
options.calc = .{ .overrides = c.overrides };
|
|
145
|
+
} else {
|
|
146
|
+
options.calc = .{};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
pub fn battle_options_chance_probability(
|
|
152
|
+
options: *battle_options,
|
|
153
|
+
) callconv(.c) *pkmn.Rational(f64) {
|
|
154
|
+
return &options.chance.probability;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
pub fn battle_options_chance_actions(
|
|
158
|
+
options: *battle_options,
|
|
159
|
+
) callconv(.c) *g.chance.Actions {
|
|
160
|
+
return &options.chance.actions;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
pub fn battle_options_chance_durations(
|
|
164
|
+
options: *battle_options,
|
|
165
|
+
) callconv(.c) *g.chance.Durations {
|
|
166
|
+
return &options.chance.durations;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
pub fn battle_options_calc_summaries(
|
|
170
|
+
options: *battle_options,
|
|
171
|
+
) callconv(.c) *g.calc.Summaries {
|
|
172
|
+
return &options.calc.summaries;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
pub fn battle_update(
|
|
176
|
+
battle: *g.Battle(g.PRNG),
|
|
177
|
+
c1: pkmn.Choice,
|
|
178
|
+
c2: pkmn.Choice,
|
|
179
|
+
opts: ?*battle_options,
|
|
180
|
+
) callconv(.c) pkmn.Result {
|
|
181
|
+
if ((pkmn.options.log or pkmn.options.chance or pkmn.options.calc) and opts != null) {
|
|
182
|
+
return battle.update(c1, c2, opts.?) catch return @bitCast(ERROR);
|
|
183
|
+
}
|
|
184
|
+
return battle.update(c1, c2, &g.NULL) catch unreachable;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
pub fn battle_choices(
|
|
188
|
+
battle: *const g.Battle(g.PRNG),
|
|
189
|
+
player: u8,
|
|
190
|
+
request: u8,
|
|
191
|
+
out: [*]u8,
|
|
192
|
+
n: usize,
|
|
193
|
+
) callconv(.c) u8 {
|
|
194
|
+
assert(player <= util.EnumFieldsLen(pkmn.Player));
|
|
195
|
+
assert(request <= util.EnumFieldsLen(pkmn.Choice.Type));
|
|
196
|
+
|
|
197
|
+
assert(!pkmn.options.showdown or n > 0);
|
|
198
|
+
return battle.choices(@enumFromInt(player), @enumFromInt(request), @ptrCast(out[0..n]));
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const c = @import("napi");
|
|
2
|
+
const js = @import("../common/js.zig");
|
|
3
|
+
const pkmn = @import("../pkmn.zig");
|
|
4
|
+
const std = @import("std");
|
|
5
|
+
|
|
6
|
+
const assert = std.debug.assert;
|
|
7
|
+
|
|
8
|
+
pub fn register(env: c.napi_env) c.napi_value {
|
|
9
|
+
const object = js.Object.init(env);
|
|
10
|
+
const properties = [_]c.napi_property_descriptor{
|
|
11
|
+
js.Property.init("options", .{ .value = options(env) }),
|
|
12
|
+
js.Property.init("bindings", .{ .value = bindings(env) }),
|
|
13
|
+
};
|
|
14
|
+
assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
|
|
15
|
+
return object;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fn options(env: c.napi_env) c.napi_value {
|
|
19
|
+
const object = js.Object.init(env);
|
|
20
|
+
const properties = [_]c.napi_property_descriptor{
|
|
21
|
+
js.Property.init("showdown", .{ .value = js.Boolean.init(env, pkmn.options.showdown) }),
|
|
22
|
+
js.Property.init("log", .{ .value = js.Boolean.init(env, pkmn.options.log) }),
|
|
23
|
+
js.Property.init("chance", .{ .value = js.Boolean.init(env, pkmn.options.chance) }),
|
|
24
|
+
js.Property.init("calc", .{ .value = js.Boolean.init(env, pkmn.options.calc) }),
|
|
25
|
+
};
|
|
26
|
+
assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
|
|
27
|
+
return object;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fn bindings(env: c.napi_env) c.napi_value {
|
|
31
|
+
const array = js.Array.init(env, .{ .length = 1 });
|
|
32
|
+
js.Array.set(env, array, 0, bind(env, pkmn.gen1));
|
|
33
|
+
return array;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fn bind(env: c.napi_env, gen: anytype) c.napi_value {
|
|
37
|
+
const choices_size: u32 = @intCast(gen.CHOICES_SIZE);
|
|
38
|
+
const logs_size: u32 = @intCast(gen.LOGS_SIZE);
|
|
39
|
+
const object = js.Object.init(env);
|
|
40
|
+
const properties = [_]c.napi_property_descriptor{
|
|
41
|
+
js.Property.init("CHOICES_SIZE", .{ .value = js.Number.init(env, choices_size) }),
|
|
42
|
+
js.Property.init("LOGS_SIZE", .{ .value = js.Number.init(env, logs_size) }),
|
|
43
|
+
js.Property.init("update", .{ .method = update(gen) }),
|
|
44
|
+
js.Property.init("choices", .{ .method = choices(gen) }),
|
|
45
|
+
};
|
|
46
|
+
assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
|
|
47
|
+
return object;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fn update(gen: anytype) c.napi_callback {
|
|
51
|
+
return struct {
|
|
52
|
+
fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.c) c.napi_value {
|
|
53
|
+
var argc: usize = 4;
|
|
54
|
+
var argv: [4]c.napi_value = undefined;
|
|
55
|
+
assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
|
|
56
|
+
assert(argc == 4);
|
|
57
|
+
|
|
58
|
+
var data: ?*anyopaque = undefined;
|
|
59
|
+
var len: usize = 0;
|
|
60
|
+
assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
|
|
61
|
+
assert(len == @sizeOf(gen.Battle(gen.PRNG)));
|
|
62
|
+
|
|
63
|
+
var battle: *gen.Battle(gen.PRNG) = @ptrCast(@alignCast(data.?));
|
|
64
|
+
const c1: pkmn.Choice = @bitCast(js.Number.get(env, argv[1], u8));
|
|
65
|
+
const c2: pkmn.Choice = @bitCast(js.Number.get(env, argv[2], u8));
|
|
66
|
+
|
|
67
|
+
var vtype: c.napi_valuetype = undefined;
|
|
68
|
+
assert(c.napi_typeof(env, argv[3], &vtype) == c.napi_ok);
|
|
69
|
+
const result = switch (vtype) {
|
|
70
|
+
c.napi_undefined, c.napi_null => battle.update(c1, c2, &gen.NULL),
|
|
71
|
+
else => result: {
|
|
72
|
+
assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
|
|
73
|
+
assert(len == gen.LOGS_SIZE);
|
|
74
|
+
|
|
75
|
+
const buf = @as([*]u8, @ptrCast(data.?))[0..gen.LOGS_SIZE];
|
|
76
|
+
var writer: pkmn.protocol.Writer = .{ .buffer = buf };
|
|
77
|
+
// TODO: extract out
|
|
78
|
+
var opts = pkmn.battle.options(
|
|
79
|
+
pkmn.protocol.FixedLog{ .writer = &writer },
|
|
80
|
+
gen.chance.NULL,
|
|
81
|
+
gen.calc.NULL,
|
|
82
|
+
);
|
|
83
|
+
break :result battle.update(c1, c2, &opts);
|
|
84
|
+
},
|
|
85
|
+
} catch unreachable;
|
|
86
|
+
|
|
87
|
+
return js.Number.init(env, @as(u8, @bitCast(result)));
|
|
88
|
+
}
|
|
89
|
+
}.call;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fn choices(gen: anytype) c.napi_callback {
|
|
93
|
+
return struct {
|
|
94
|
+
fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.c) c.napi_value {
|
|
95
|
+
var argc: usize = 4;
|
|
96
|
+
var argv: [4]c.napi_value = undefined;
|
|
97
|
+
assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
|
|
98
|
+
assert(argc == 4);
|
|
99
|
+
|
|
100
|
+
var data: ?*anyopaque = undefined;
|
|
101
|
+
var len: usize = 0;
|
|
102
|
+
assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
|
|
103
|
+
assert(len == @sizeOf(gen.Battle(gen.PRNG)));
|
|
104
|
+
|
|
105
|
+
var battle: *gen.Battle(gen.PRNG) = @ptrCast(@alignCast(data.?));
|
|
106
|
+
const player: pkmn.Player = @enumFromInt(js.Number.get(env, argv[1], u8));
|
|
107
|
+
const request: pkmn.Choice.Type = @enumFromInt(js.Number.get(env, argv[2], u8));
|
|
108
|
+
|
|
109
|
+
assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
|
|
110
|
+
assert(len == gen.CHOICES_SIZE);
|
|
111
|
+
|
|
112
|
+
const out = @as([*]pkmn.Choice, @ptrCast(data.?))[0..gen.CHOICES_SIZE];
|
|
113
|
+
const n = battle.choices(player, request, out);
|
|
114
|
+
return js.Number.init(env, @as(u8, @bitCast(n)));
|
|
115
|
+
}
|
|
116
|
+
}.call;
|
|
117
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const pkmn = @import("../pkmn.zig");
|
|
2
|
+
const std = @import("std");
|
|
3
|
+
const util = @import("../common/util.zig");
|
|
4
|
+
|
|
5
|
+
const assert = std.debug.assert;
|
|
6
|
+
|
|
7
|
+
pub const options = pkmn.options;
|
|
8
|
+
|
|
9
|
+
pub fn gen(comptime num: comptime_int) type {
|
|
10
|
+
const g = @field(pkmn, "gen" ++ std.fmt.comptimePrint("{d}", .{num}));
|
|
11
|
+
return struct {
|
|
12
|
+
pub const CHOICES_SIZE = size(g.CHOICES_SIZE);
|
|
13
|
+
pub const LOGS_SIZE = size(g.LOGS_SIZE);
|
|
14
|
+
|
|
15
|
+
pub fn update(
|
|
16
|
+
battle: *g.Battle(g.PRNG),
|
|
17
|
+
c1: pkmn.Choice,
|
|
18
|
+
c2: pkmn.Choice,
|
|
19
|
+
options_: ?[*]u8,
|
|
20
|
+
) callconv(.c) pkmn.Result {
|
|
21
|
+
return (if (options_) |o| result: {
|
|
22
|
+
const buf = @as([*]u8, @ptrCast(o))[0..g.LOGS_SIZE];
|
|
23
|
+
var writer: pkmn.protocol.Writer = .{ .buffer = buf };
|
|
24
|
+
// TODO: extract out
|
|
25
|
+
var opts = pkmn.battle.options(
|
|
26
|
+
pkmn.protocol.FixedLog{ .writer = &writer },
|
|
27
|
+
g.chance.NULL,
|
|
28
|
+
g.calc.NULL,
|
|
29
|
+
);
|
|
30
|
+
break :result battle.update(c1, c2, &opts);
|
|
31
|
+
} else battle.update(c1, c2, &g.NULL)) catch unreachable;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pub fn choices(
|
|
35
|
+
battle: *g.Battle(g.PRNG),
|
|
36
|
+
player: u8,
|
|
37
|
+
request: u8,
|
|
38
|
+
buf: [*]u8,
|
|
39
|
+
) callconv(.c) u8 {
|
|
40
|
+
assert(player <= util.EnumFieldsLen(pkmn.Player));
|
|
41
|
+
assert(request <= util.EnumFieldsLen(pkmn.Choice.Type));
|
|
42
|
+
|
|
43
|
+
const n = CHOICES_SIZE;
|
|
44
|
+
return battle.choices(@enumFromInt(player), @enumFromInt(request), @ptrCast(buf[0..n]));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fn size(n: usize) u32 {
|
|
50
|
+
return std.math.ceilPowerOfTwo(u32, @as(u32, @intCast(n))) catch unreachable;
|
|
51
|
+
}
|