@pkmn/engine 0.1.0-dev.437f6a52 → 0.1.0-dev.44b2e6ec

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 (48) hide show
  1. package/README.md +77 -46
  2. package/build/pkg/addon.js.map +1 -1
  3. package/build/pkg/data/ids.json +12 -12
  4. package/build/pkg/data/layout.json +2 -2
  5. package/build/pkg/data/protocol.json +69 -12
  6. package/build/pkg/data.d.ts +3 -2
  7. package/build/pkg/data.js.map +1 -1
  8. package/build/pkg/gen1.js +2 -2
  9. package/build/pkg/gen1.js.map +1 -1
  10. package/build/pkg/index.d.ts +2 -1
  11. package/build/pkg/index.js.map +1 -1
  12. package/build/pkg/protocol.js +57 -38
  13. package/build/pkg/protocol.js.map +1 -1
  14. package/build/test/display.js.map +1 -1
  15. package/build/tools/debug.js +3 -1
  16. package/build/tools/debug.js.map +1 -1
  17. package/build.zig +91 -65
  18. package/package.json +43 -21
  19. package/src/bin/install-pkmn-engine +2 -2
  20. package/src/lib/binding/node.zig +7 -11
  21. package/src/lib/common/battle.zig +17 -0
  22. package/src/lib/common/data.zig +8 -20
  23. package/src/lib/common/js.zig +118 -0
  24. package/src/lib/common/optional.zig +67 -0
  25. package/src/lib/common/protocol.zig +795 -312
  26. package/src/lib/common/rational.zig +357 -0
  27. package/src/lib/common/rng.zig +15 -6
  28. package/src/lib/common/util.zig +12 -0
  29. package/src/lib/gen1/README.md +273 -193
  30. package/src/lib/gen1/calc.zig +426 -0
  31. package/src/lib/gen1/chance.zig +1060 -0
  32. package/src/lib/gen1/data/moves.zig +192 -180
  33. package/src/lib/gen1/data/species.zig +2 -2
  34. package/src/lib/gen1/data/types.zig +7 -7
  35. package/src/lib/gen1/data.zig +44 -51
  36. package/src/lib/gen1/helpers.zig +254 -116
  37. package/src/lib/gen1/mechanics.zig +330 -399
  38. package/src/lib/gen2/README.md +105 -85
  39. package/src/lib/gen2/calc.zig +143 -0
  40. package/src/lib/gen2/chance.zig +1314 -0
  41. package/src/lib/gen2/data/items.zig +12 -18
  42. package/src/lib/gen2/data/moves.zig +663 -569
  43. package/src/lib/gen2/data/species.zig +1 -1
  44. package/src/lib/gen2/data/types.zig +134 -31
  45. package/src/lib/gen2/data.zig +100 -73
  46. package/src/lib/gen2/generated.zig +806 -0
  47. package/src/lib/gen2/helpers.zig +8 -12
  48. package/src/lib/gen2/mechanics.zig +3502 -9
package/build.zig CHANGED
@@ -35,6 +35,7 @@ pub fn build(b: *std.Build) !void {
35
35
  const strip = b.option(bool, "strip", "Strip debugging symbols from binary") orelse false;
36
36
  const pic = b.option(bool, "pic", "Force position independent code") orelse false;
37
37
  const emit_asm = b.option(bool, "emit-asm", "Output .s (assembly code)") orelse false;
38
+ const emit_ll = b.option(bool, "emit-ll", "Output .ll (LLVM IR)") orelse false;
38
39
 
39
40
  const cmd = b.findProgram(&.{"strip"}, &.{}) catch null;
40
41
 
@@ -65,16 +66,16 @@ pub fn build(b: *std.Build) !void {
65
66
  const addon = b.fmt("{s}.node", .{name});
66
67
  const lib = b.addSharedLibrary(.{
67
68
  .name = addon,
69
+ .main_pkg_path = .{ .path = "." },
68
70
  .root_source_file = .{ .path = "src/lib/binding/node.zig" },
69
71
  .optimize = optimize,
70
72
  .target = target,
71
73
  });
72
74
  lib.addOptions("build_options", options);
73
- lib.setMainPkgPath("./");
74
- lib.addSystemIncludePath(headers);
75
+ lib.addSystemIncludePath(.{ .path = headers });
75
76
  lib.linkLibC();
76
77
  if (node_import_lib) |il| {
77
- lib.addObjectFile(il);
78
+ lib.addObjectFile(.{ .path = il });
78
79
  } else if ((try std.zig.system.NativeTargetInfo.detect(target)).target.os.tag == .windows) {
79
80
  try std.io.getStdErr().writeAll("Must provide --node-import-library path on Windows\n");
80
81
  std.process.exit(1);
@@ -92,8 +93,9 @@ pub fn build(b: *std.Build) !void {
92
93
  // rename the file ourself in install-pkmn-engine
93
94
  b.installArtifact(lib);
94
95
  } else if (wasm) {
95
- const lib = b.addSharedLibrary(.{
96
+ const exe = b.addExecutable(.{
96
97
  .name = name,
98
+ .main_pkg_path = .{ .path = "." },
97
99
  .root_source_file = .{ .path = "src/lib/binding/wasm.zig" },
98
100
  .optimize = switch (optimize) {
99
101
  .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
@@ -101,33 +103,43 @@ pub fn build(b: *std.Build) !void {
101
103
  },
102
104
  .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
103
105
  });
104
- lib.addOptions("build_options", options);
105
- lib.setMainPkgPath("./");
106
- lib.stack_size = wasm_stack_size;
107
- lib.rdynamic = true;
108
- lib.strip = strip;
109
- if (pic) lib.force_pic = pic;
106
+ exe.addOptions("build_options", options);
107
+ exe.export_symbol_names = &[_][]const u8{
108
+ "SHOWDOWN",
109
+ "LOG",
110
+ "CHANCE",
111
+ "CALC",
112
+ "GEN1_CHOICES_SIZE",
113
+ "GEN1_LOGS_SIZE",
114
+ };
115
+ exe.entry = .disabled;
116
+ exe.stack_size = wasm_stack_size;
117
+ exe.strip = strip;
118
+ if (pic) exe.force_pic = pic;
110
119
  const opt = b.findProgram(&.{"wasm-opt"}, &.{"./node_modules/.bin"}) catch null;
111
120
  if (optimize != .Debug and opt != null) {
112
121
  const out = b.fmt("build/lib/{s}.wasm", .{name});
113
122
  const sh = b.addSystemCommand(&.{ opt.?, "-O4" });
114
- sh.addArtifactArg(lib);
123
+ sh.addArtifactArg(exe);
115
124
  sh.addArg("-o");
116
125
  sh.addFileSourceArg(.{ .path = out });
117
126
  b.getInstallStep().dependOn(&sh.step);
127
+ } else {
128
+ b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{
129
+ .dest_dir = .{ .override = std.Build.InstallDir{ .lib = {} } },
130
+ }).step);
118
131
  }
119
- b.installArtifact(lib);
120
132
  } else if (dynamic) {
121
133
  const lib = b.addSharedLibrary(.{
122
134
  .name = name,
135
+ .main_pkg_path = .{ .path = "." },
123
136
  .root_source_file = .{ .path = "src/lib/binding/c.zig" },
124
137
  .version = try std.SemanticVersion.parse(version),
125
138
  .optimize = optimize,
126
139
  .target = target,
127
140
  });
128
141
  lib.addOptions("build_options", options);
129
- lib.setMainPkgPath("./");
130
- lib.addIncludePath("src/include");
142
+ lib.addIncludePath(.{ .path = "src/include" });
131
143
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
132
144
  if (pic) lib.force_pic = pic;
133
145
  b.installArtifact(lib);
@@ -135,17 +147,30 @@ pub fn build(b: *std.Build) !void {
135
147
  } else {
136
148
  const lib = b.addStaticLibrary(.{
137
149
  .name = name,
150
+ .main_pkg_path = .{ .path = "." },
138
151
  .root_source_file = .{ .path = "src/lib/binding/c.zig" },
139
152
  .optimize = optimize,
140
153
  .target = target,
141
154
  });
142
155
  lib.addOptions("build_options", options);
143
- lib.setMainPkgPath("./");
144
- lib.addIncludePath("src/include");
156
+ lib.addIncludePath(.{ .path = "src/include" });
145
157
  lib.bundle_compiler_rt = true;
146
158
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
147
159
  if (pic) lib.force_pic = pic;
148
- if (emit_asm) lib.emit_asm = .emit;
160
+ if (emit_asm) {
161
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(
162
+ lib.getEmittedAsm(),
163
+ .prefix,
164
+ b.fmt("{s}.s", .{name}),
165
+ ).step);
166
+ }
167
+ if (emit_ll) {
168
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(
169
+ lib.getEmittedLlvmIr(),
170
+ .prefix,
171
+ b.fmt("{s}.ll", .{name}),
172
+ ).step);
173
+ }
149
174
  b.installArtifact(lib);
150
175
  c = true;
151
176
  }
@@ -210,30 +235,32 @@ pub fn build(b: *std.Build) !void {
210
235
  var benchmark_config = tools;
211
236
  benchmark_config.general.optimize = .ReleaseFast;
212
237
  benchmark_config.general.strip = true;
213
- const benchmark = tool(b, "src/test/benchmark.zig", benchmark_config);
238
+ const benchmark = try tool(b, "src/test/benchmark.zig", benchmark_config);
214
239
 
215
240
  var fuzz_config = tools;
216
241
  fuzz_config.general.strip = false;
217
242
  fuzz_config.tool.name = "fuzz";
218
- const fuzz = tool(b, "src/test/fuzz.zig", fuzz_config);
219
-
220
- const dump = tool(b, "src/tools/dump.zig", tools);
221
- const serde = tool(b, "src/tools/serde.zig", tools);
222
- const transitions = tool(b, "src/tools/transitions.zig", tools);
223
-
224
- const lint_exe =
225
- b.addExecutable(.{ .name = "lint", .root_source_file = .{ .path = "src/tools/lint.zig" } });
226
- if (tests.build) tests.step.dependOn(&lint_exe.step);
227
- const lint = b.addRunArtifact(lint_exe);
228
-
229
- b.step("benchmark", "Run benchmark code").dependOn(&benchmark.step);
230
- b.step("dump", "Run protocol dump tool").dependOn(&dump.step);
231
- b.step("fuzz", "Run fuzz tester").dependOn(&fuzz.step);
232
- b.step("lint", "Lint source files").dependOn(&lint.step);
233
- b.step("serde", "Run serialization/deserialization tool").dependOn(&serde.step);
243
+ const fuzz = try tool(b, "src/test/fuzz.zig", fuzz_config);
244
+
245
+ const analyze = try tool(b, "src/tools/analyze.zig", tools);
246
+ const dump = try tool(b, "src/tools/dump.zig", tools);
247
+ const transitions = try tool(b, "src/tools/transitions.zig", tools);
248
+
249
+ // FIXME: serde randomly fails to build in some release configurations
250
+ var hack = tools;
251
+ if (optimize != .Debug) hack.tool.tests = null;
252
+ const serde = try tool(b, "src/tools/serde.zig", hack);
253
+
254
+ if (analyze) |t| b.step("analyze", "Run LLVM analysis tool").dependOn(&t.step);
255
+ if (benchmark) |t| b.step("benchmark", "Run benchmark code").dependOn(&t.step);
256
+ if (dump) |t| b.step("dump", "Run protocol dump tool").dependOn(&t.step);
257
+ if (fuzz) |t| b.step("fuzz", "Run fuzz tester").dependOn(&t.step);
258
+ if (serde) |t| b.step("serde", "Run serialization/deserialization tool").dependOn(&t.step);
234
259
  b.step("test", "Run all tests").dependOn(&tests.step);
235
260
  b.step("tools", "Install tools").dependOn(&ToolsStep.create(b, &exes).step);
236
- b.step("transitions", "Visualize transitions algorithm search").dependOn(&transitions.step);
261
+ if (transitions) |t| {
262
+ b.step("transitions", "Visualize transitions algorithm search").dependOn(&t.step);
263
+ }
237
264
  }
238
265
 
239
266
  fn maybeStrip(
@@ -263,12 +290,6 @@ const Config = struct {
263
290
  cmd: ?[]const u8,
264
291
  };
265
292
 
266
- const TESTS = .{
267
- "src/lib/common/test.zig",
268
- "src/lib/gen1/test.zig",
269
- "src/lib/gen2/test.zig",
270
- };
271
-
272
293
  const TestStep = struct {
273
294
  step: std.Build.Step,
274
295
  build: bool,
@@ -281,28 +302,29 @@ const TestStep = struct {
281
302
 
282
303
  const self = b.allocator.create(TestStep) catch @panic("OOM");
283
304
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Run all tests", .owner = b });
284
- self.* = TestStep{ .step = step, .build = test_filter == null };
285
-
286
- const paths: []const []const u8 =
287
- if (test_file) |t| &.{t} else if (coverage != null) &.{"src/lib/test.zig"} else &TESTS;
288
- for (paths) |path| {
289
- const tests = b.addTest(.{
290
- .name = std.fs.path.basename(std.fs.path.dirname(path).?),
291
- .root_source_file = .{ .path = path },
292
- .optimize = config.optimize,
293
- .target = config.target,
294
- .filter = test_filter,
295
- });
296
- tests.setMainPkgPath("./");
297
- tests.addOptions("build_options", options);
298
- tests.single_threaded = true;
299
- maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
300
- if (config.pic) tests.force_pic = config.pic;
301
- if (coverage) |c| {
302
- tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
303
- }
304
- self.step.dependOn(&b.addRunArtifact(tests).step);
305
+ self.* = .{ .step = step, .build = test_filter == null };
306
+
307
+ const path = test_file orelse "src/lib/test.zig";
308
+ const tests = b.addTest(.{
309
+ .name = b.fmt("{s}-{s}", .{
310
+ std.fs.path.basename(std.fs.path.dirname(path).?),
311
+ std.fs.path.stem(std.fs.path.basename(path)),
312
+ }),
313
+ .main_pkg_path = .{ .path = "." },
314
+ .root_source_file = .{ .path = path },
315
+ .optimize = config.optimize,
316
+ .target = config.target,
317
+ .filter = test_filter,
318
+ });
319
+ tests.addOptions("build_options", options);
320
+ tests.single_threaded = true;
321
+ maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
322
+ if (config.pic) tests.force_pic = config.pic;
323
+ if (coverage) |c| {
324
+ tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
305
325
  }
326
+ self.step.dependOn(&b.addRunArtifact(tests).step);
327
+
306
328
  return self;
307
329
  }
308
330
  };
@@ -317,7 +339,11 @@ const ToolConfig = struct {
317
339
  },
318
340
  };
319
341
 
320
- fn tool(b: *std.Build, path: []const u8, config: ToolConfig) *std.Build.RunStep {
342
+ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.RunStep {
343
+ std.fs.cwd().access(path, .{}) catch |err| switch (err) {
344
+ error.FileNotFound => return null,
345
+ else => |e| return e,
346
+ };
321
347
  var name = config.tool.name orelse std.fs.path.basename(path);
322
348
  const index = std.mem.lastIndexOfScalar(u8, name, '.');
323
349
  if (index) |i| name = name[0..i];
@@ -349,8 +375,8 @@ const ToolsStep = struct {
349
375
  pub fn create(b: *std.Build, exes: *std.ArrayList(*std.Build.CompileStep)) *ToolsStep {
350
376
  const self = b.allocator.create(ToolsStep) catch @panic("OOM");
351
377
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Install tools", .owner = b });
352
- self.* = ToolsStep{ .step = step };
353
- for (exes.items) |t| self.step.dependOn(&b.addInstallArtifact(t).step);
378
+ self.* = .{ .step = step };
379
+ for (exes.items) |t| self.step.dependOn(&b.addInstallArtifact(t, .{}).step);
354
380
  return self;
355
381
  }
356
382
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkmn/engine",
3
- "version": "0.1.0-dev.437f6a52",
3
+ "version": "0.1.0-dev.44b2e6ec",
4
4
  "description": "A minimal, complete, Pokémon battle simulation engine optimized for performance",
5
5
  "repository": "github:pkmn/engine",
6
6
  "license": "MIT",
@@ -34,22 +34,32 @@
34
34
  "src/bin/install-pkmn-engine",
35
35
  "src/lib/binding/node.zig",
36
36
  "src/lib/binding/wasm.zig",
37
+ "src/lib/common/battle.zig",
37
38
  "src/lib/common/data.zig",
38
39
  "src/lib/common/debug.zig",
40
+ "src/lib/common/js.zig",
41
+ "src/lib/common/optional.zig",
39
42
  "src/lib/common/options.zig",
40
43
  "src/lib/common/protocol.zig",
44
+ "src/lib/common/rational.zig",
41
45
  "src/lib/common/rng.zig",
46
+ "src/lib/common/util.zig",
47
+ "src/lib/gen1/calc.zig",
48
+ "src/lib/gen1/chance.zig",
42
49
  "src/lib/gen1/data.zig",
43
50
  "src/lib/gen1/data/moves.zig",
44
51
  "src/lib/gen1/data/species.zig",
45
52
  "src/lib/gen1/data/types.zig",
46
53
  "src/lib/gen1/helpers.zig",
47
54
  "src/lib/gen1/mechanics.zig",
55
+ "src/lib/gen2/calc.zig",
56
+ "src/lib/gen2/chance.zig",
48
57
  "src/lib/gen2/data.zig",
49
58
  "src/lib/gen2/data/items.zig",
50
59
  "src/lib/gen2/data/moves.zig",
51
60
  "src/lib/gen2/data/species.zig",
52
61
  "src/lib/gen2/data/types.zig",
62
+ "src/lib/gen2/generated.zig",
53
63
  "src/lib/gen2/helpers.zig",
54
64
  "src/lib/gen2/mechanics.zig",
55
65
  "src/lib/pkmn.zig",
@@ -66,30 +76,31 @@
66
76
  "access": "public"
67
77
  },
68
78
  "dependencies": {
69
- "@pkmn/data": "^0.7.44",
70
- "@pkmn/protocol": "^0.6.12"
79
+ "@pkmn/data": "^0.7.54",
80
+ "@pkmn/protocol": "^0.6.16"
71
81
  },
72
82
  "devDependencies": {
73
- "@pkmn/eslint-config": "^3.2.0",
74
- "@pkmn/img": "^0.2.12",
75
- "@pkmn/sets": "^5.0.4",
76
- "@pkmn/sim": "0.7.44",
77
- "@types/html-minifier": "^4.0.2",
78
- "@types/jest": "^29.5.2",
79
- "@types/minimist": "^1.2.2",
80
- "@types/mustache": "^4.2.2",
81
- "@types/node": "^20.3.1",
82
- "@vitest/coverage-c8": "^0.32.2",
83
- "binaryen": "^113.0.0",
84
- "eslint": "^8.43.0",
83
+ "@pkmn/eslint-config": "^5.3.0",
84
+ "@pkmn/img": "^0.2.18",
85
+ "@pkmn/sets": "^5.1.0",
86
+ "@pkmn/sim": "0.7.54",
87
+ "@types/html-minifier": "^4.0.4",
88
+ "@types/jest": "^29.5.6",
89
+ "@types/minimist": "^1.2.4",
90
+ "@types/mustache": "^4.2.4",
91
+ "@types/node": "^20.8.9",
92
+ "@vitest/coverage-c8": "^0.33.0",
93
+ "binaryen": "^116.0.0",
94
+ "eslint": "^8.52.0",
85
95
  "html-minifier": "^4.0.0",
86
96
  "json-stringify-pretty-compact": "3.0.0",
87
97
  "minimist": "^1.2.8",
88
98
  "mustache": "^4.2.0",
89
99
  "source-map-support": "^0.5.21",
100
+ "table": "^6.8.1",
90
101
  "trakr": "^0.2.0",
91
- "typescript": "^5.1.3",
92
- "vitest": "^0.32.2"
102
+ "typescript": "^5.2.2",
103
+ "vitest": "^0.34.6"
93
104
  },
94
105
  "scripts": {
95
106
  "lint": "eslint --cache src --ext ts,js && eslint src/bin/*",
@@ -111,7 +122,7 @@
111
122
  "ignorePatterns": [
112
123
  "dist/",
113
124
  "node_modules/",
114
- "src/examples/zig",
125
+ "examples/zig",
115
126
  "build/"
116
127
  ],
117
128
  "env": {
@@ -127,7 +138,7 @@
127
138
  "parserOptions": {
128
139
  "project": [
129
140
  "./tsconfig.json",
130
- "./src/examples/js/tsconfig.json"
141
+ "./examples/js/tsconfig.json"
131
142
  ]
132
143
  }
133
144
  },
@@ -140,7 +151,8 @@
140
151
  "rules": {
141
152
  "no-control-regex": "off",
142
153
  "@typescript-eslint/no-empty-interface": "off",
143
- "@typescript-eslint/no-shadow": "off"
154
+ "@typescript-eslint/no-shadow": "off",
155
+ "@typescript-eslint/no-unsafe-declaration-merging": "off"
144
156
  }
145
157
  },
146
158
  {
@@ -156,7 +168,17 @@
156
168
  "src/test/benchmark*.ts"
157
169
  ],
158
170
  "rules": {
159
- "@typescript-eslint/no-unused-vars": "off"
171
+ "@typescript-eslint/no-unused-vars": "off",
172
+ "@typescript-eslint/no-redundant-type-constituents": "off"
173
+ }
174
+ },
175
+ {
176
+ "files": [
177
+ "src/pkg/protocol.test.ts"
178
+ ],
179
+ "rules": {
180
+ "jest/no-standalone-expect": "off",
181
+ "jest/no-conditional-expect": "off"
160
182
  }
161
183
  },
162
184
  {
@@ -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: 11, patch: 0, dev: 3859};
13
+ const ZIG_VERSION = {major: 0, minor: 12, patch: 0, dev: 1396};
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';
@@ -358,7 +358,7 @@ const downloadImportLib = async () => {
358
358
  // either the default options or whatever was passed in
359
359
  if (!configs.size) {
360
360
  node = true;
361
- const DEFAULT = ['-Dshowdown', '-Dlog', '-Dchance', '-Dcalc'];
361
+ const DEFAULT = ['-Dshowdown'];
362
362
  configs.set('node', {type: 'node', options: options || DEFAULT});
363
363
  configs.set('wasm', {type: 'wasm', options: options || DEFAULT});
364
364
  }
@@ -19,7 +19,7 @@ export fn napi_register_module_v1(env: c.napi_env, exports: c.napi_value) c.napi
19
19
  }
20
20
 
21
21
  pub fn register(env: c.napi_env) c.napi_value {
22
- var object = js.Object.init(env);
22
+ const object = js.Object.init(env);
23
23
  const properties = [_]c.napi_property_descriptor{
24
24
  js.Property.init("options", .{ .value = options(env) }),
25
25
  js.Property.init("bindings", .{ .value = bindings(env) }),
@@ -29,7 +29,7 @@ pub fn register(env: c.napi_env) c.napi_value {
29
29
  }
30
30
 
31
31
  fn options(env: c.napi_env) c.napi_value {
32
- var object = js.Object.init(env);
32
+ const object = js.Object.init(env);
33
33
  const properties = [_]c.napi_property_descriptor{
34
34
  js.Property.init("showdown", .{ .value = js.Boolean.init(env, pkmn.options.showdown) }),
35
35
  js.Property.init("log", .{ .value = js.Boolean.init(env, pkmn.options.log) }),
@@ -41,7 +41,7 @@ fn options(env: c.napi_env) c.napi_value {
41
41
  }
42
42
 
43
43
  fn bindings(env: c.napi_env) c.napi_value {
44
- var array = js.Array.init(env, .{ .length = 1 });
44
+ const array = js.Array.init(env, .{ .length = 1 });
45
45
  js.Array.set(env, array, 0, bind(env, pkmn.gen1));
46
46
  return array;
47
47
  }
@@ -49,7 +49,7 @@ fn bindings(env: c.napi_env) c.napi_value {
49
49
  fn bind(env: c.napi_env, gen: anytype) c.napi_value {
50
50
  const choices_size: u32 = @intCast(gen.CHOICES_SIZE);
51
51
  const logs_size: u32 = @intCast(gen.LOGS_SIZE);
52
- var object = js.Object.init(env);
52
+ const object = js.Object.init(env);
53
53
  const properties = [_]c.napi_property_descriptor{
54
54
  js.Property.init("CHOICES_SIZE", .{ .value = js.Number.init(env, choices_size) }),
55
55
  js.Property.init("LOGS_SIZE", .{ .value = js.Number.init(env, logs_size) }),
@@ -72,7 +72,6 @@ fn update(gen: anytype) c.napi_callback {
72
72
  var len: usize = 0;
73
73
  assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
74
74
  assert(len == @sizeOf(gen.Battle(gen.PRNG)));
75
- assert(data != null);
76
75
 
77
76
  var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
78
77
  const c1: pkmn.Choice = @bitCast(js.Number.get(env, argv[1], u8));
@@ -85,10 +84,9 @@ fn update(gen: anytype) c.napi_callback {
85
84
  else => result: {
86
85
  assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
87
86
  assert(len == gen.LOGS_SIZE);
88
- assert(data != null);
89
87
 
90
- var buf = @as([*]u8, @ptrCast(data.?))[0..gen.LOGS_SIZE];
91
- var stream = pkmn.protocol.ByteStream{ .buffer = buf };
88
+ const buf = @as([*]u8, @ptrCast(data.?))[0..gen.LOGS_SIZE];
89
+ var stream: pkmn.protocol.ByteStream = .{ .buffer = buf };
92
90
  // TODO: extract out
93
91
  var opts = pkmn.battle.options(
94
92
  pkmn.protocol.FixedLog{ .writer = stream.writer() },
@@ -116,7 +114,6 @@ fn choices(gen: anytype) c.napi_callback {
116
114
  var len: usize = 0;
117
115
  assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
118
116
  assert(len == @sizeOf(gen.Battle(gen.PRNG)));
119
- assert(data != null);
120
117
 
121
118
  var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
122
119
  const player: pkmn.Player = @enumFromInt(js.Number.get(env, argv[1], u8));
@@ -124,9 +121,8 @@ fn choices(gen: anytype) c.napi_callback {
124
121
 
125
122
  assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
126
123
  assert(len == gen.CHOICES_SIZE);
127
- assert(data != null);
128
124
 
129
- var out = @as([*]pkmn.Choice, @ptrCast(data.?))[0..gen.CHOICES_SIZE];
125
+ const out = @as([*]pkmn.Choice, @ptrCast(data.?))[0..gen.CHOICES_SIZE];
130
126
  const n = battle.choices(player, request, out);
131
127
  return js.Number.init(env, @as(u8, @bitCast(n)));
132
128
  }
@@ -0,0 +1,17 @@
1
+ /// Stores state required by optional features to the engine that can be passed to a generation's
2
+ /// `Battle.update` function. All generations generically support protocol logging (enabled via
3
+ /// `-Dlog`), chance actions and probability tracking (enabled via `-Dchance`), and damage
4
+ /// computation and chance overrides (`-Dcalc`), though the concrete types for these features are
5
+ /// generation dependent.
6
+ pub fn Options(comptime Log: type, comptime Chance: type, comptime Calc: type) type {
7
+ return struct { log: Log, chance: Chance, calc: Calc };
8
+ }
9
+
10
+ /// Helper to create a battle `Options` object with the provided `log`, `chance`, and `calc`.
11
+ pub fn options(
12
+ log: anytype,
13
+ chance: anytype,
14
+ calc: anytype,
15
+ ) Options(@TypeOf(log), @TypeOf(chance), @TypeOf(calc)) {
16
+ return .{ .log = log, .chance = chance, .calc = calc };
17
+ }
@@ -9,12 +9,12 @@ pub const Player = enum(u1) {
9
9
  P2,
10
10
 
11
11
  /// Returns a player's opponent.
12
- pub inline fn foe(self: Player) Player {
12
+ pub fn foe(self: Player) Player {
13
13
  return @enumFromInt(~@intFromEnum(self));
14
14
  }
15
15
 
16
16
  /// Return's an identifier for the player's Pokémon at the one-indexed `id`.
17
- pub inline fn ident(self: Player, id: u3) ID {
17
+ pub fn ident(self: Player, id: u3) ID {
18
18
  assert(id > 0 and id <= 6);
19
19
  return .{ .id = id, .player = self };
20
20
  }
@@ -27,24 +27,20 @@ test Player {
27
27
  }
28
28
 
29
29
  /// An identifier for a specific Pokémon in battle.
30
- pub const ID = packed struct {
30
+ pub const ID = packed struct(u8) {
31
31
  /// The one-indexed team slot of the Pokémon
32
32
  id: u3 = 0,
33
33
  /// The Pokémon's trainer.
34
34
  player: Player = .P1,
35
35
  _: u4 = 0,
36
36
 
37
- comptime {
38
- assert(@sizeOf(ID) == 1);
39
- }
40
-
41
37
  /// Converts the identifier into a number.
42
- pub inline fn int(self: ID) u4 {
38
+ pub fn int(self: ID) u4 {
43
39
  return @intCast(@as(u8, @bitCast(self)));
44
40
  }
45
41
 
46
42
  /// Decodes the identifier from a number.
47
- pub inline fn from(id: u4) ID {
43
+ pub fn from(id: u4) ID {
48
44
  return @bitCast(@as(u8, id));
49
45
  }
50
46
  };
@@ -52,12 +48,12 @@ pub const ID = packed struct {
52
48
  test ID {
53
49
  try expectEqual(@as(u8, 0b0001), @as(u8, @bitCast(ID{ .player = .P1, .id = 1 })));
54
50
  try expectEqual(@as(u8, 0b1101), @as(u8, @bitCast(ID{ .player = .P2, .id = 5 })));
55
- const id = ID{ .player = .P2, .id = 4 };
51
+ const id: ID = .{ .player = .P2, .id = 4 };
56
52
  try expectEqual(id, ID.from(id.int()));
57
53
  }
58
54
 
59
55
  /// A choice made by a player during battle.
60
- pub const Choice = packed struct {
56
+ pub const Choice = packed struct(u8) {
61
57
  /// The choice type.
62
58
  type: Choice.Type = .Pass,
63
59
  /// The choice data:
@@ -73,10 +69,6 @@ pub const Choice = packed struct {
73
69
  Move,
74
70
  Switch,
75
71
  };
76
-
77
- comptime {
78
- assert(@sizeOf(Choice) == 1);
79
- }
80
72
  };
81
73
 
82
74
  test Choice {
@@ -89,7 +81,7 @@ test Choice {
89
81
  }
90
82
 
91
83
  /// The result of the battle - all results other than 'None' should be considered terminal.
92
- pub const Result = packed struct {
84
+ pub const Result = packed struct(u8) {
93
85
  /// The type of result from the perspective of Player 1.
94
86
  /// `Error` is not possible when in Pokémon Showdown compatibility mode.
95
87
  type: Result.Type = .None,
@@ -117,10 +109,6 @@ pub const Result = packed struct {
117
109
  pub const Error: Result = .{ .type = .Error };
118
110
  /// The default result.
119
111
  pub const Default: Result = .{ .p1 = .Move, .p2 = .Move };
120
-
121
- comptime {
122
- assert(@sizeOf(Result) == 1);
123
- }
124
112
  };
125
113
 
126
114
  test Result {