@pkmn/engine 0.1.0-dev.c4f94762 → 0.1.0-dev.c4ffaf39

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/build.zig CHANGED
@@ -1,26 +1,6 @@
1
1
  const std = @import("std");
2
2
  const builtin = @import("builtin");
3
3
 
4
- pub const Options = struct {
5
- showdown: ?bool = null,
6
- log: ?bool = null,
7
- chance: ?bool = null,
8
- calc: ?bool = null,
9
- };
10
-
11
- pub fn module(b: *std.Build, options: Options) *std.Build.Module {
12
- const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
13
- const build_options = b.addOptions();
14
- build_options.addOption(?bool, "showdown", options.showdown);
15
- build_options.addOption(?bool, "log", options.log);
16
- build_options.addOption(?bool, "chance", options.chance);
17
- build_options.addOption(?bool, "calc", options.calc);
18
- return b.createModule(.{
19
- .source_file = .{ .path = dirname ++ "/src/lib/pkmn.zig" },
20
- .dependencies = &.{.{ .name = "build_options", .module = build_options.createModule() }},
21
- });
22
- }
23
-
24
4
  pub fn build(b: *std.Build) !void {
25
5
  const target = b.standardTargetOptions(.{});
26
6
  const optimize = b.standardOptimizeOption(.{});
@@ -32,8 +12,8 @@ pub fn build(b: *std.Build) !void {
32
12
  const wasm_stack_size =
33
13
  b.option(u64, "wasm-stack-size", "The size of WASM stack") orelse std.wasm.page_size;
34
14
  const dynamic = b.option(bool, "dynamic", "Build a dynamic library") orelse false;
35
- const strip = b.option(bool, "strip", "Strip debugging symbols from binary") orelse false;
36
- const pic = b.option(bool, "pic", "Force position independent code") orelse false;
15
+ const strip = b.option(bool, "strip", "Strip debugging symbols from binary");
16
+ const pic = b.option(bool, "pic", "Force position independent code");
37
17
  const emit_asm = b.option(bool, "emit-asm", "Output .s (assembly code)") orelse false;
38
18
  const emit_ll = b.option(bool, "emit-ll", "Output .ll (LLVM IR)") orelse false;
39
19
 
@@ -44,7 +24,7 @@ pub fn build(b: *std.Build) !void {
44
24
  defer parsed.deinit();
45
25
  const version = parsed.value.object.get("version").?.string;
46
26
  const description = parsed.value.object.get("description").?.string;
47
- var repository = std.mem.split(u8, parsed.value.object.get("repository").?.string, ":");
27
+ var repository = std.mem.splitSequence(u8, parsed.value.object.get("repository").?.string, ":");
48
28
  std.debug.assert(std.mem.eql(u8, repository.first(), "github"));
49
29
 
50
30
  const showdown =
@@ -61,30 +41,37 @@ pub fn build(b: *std.Build) !void {
61
41
 
62
42
  const name = if (showdown) "pkmn-showdown" else "pkmn";
63
43
 
44
+ const module = b.addModule("pkmn", .{
45
+ .root_source_file = b.path("src/lib/pkmn.zig"),
46
+ .optimize = optimize,
47
+ .target = target,
48
+ .imports = &.{.{ .name = "build_options", .module = options.createModule() }},
49
+ });
50
+
64
51
  var c = false;
65
52
  if (node_headers) |headers| {
66
53
  const addon = b.fmt("{s}.node", .{name});
67
54
  const lib = b.addSharedLibrary(.{
68
55
  .name = addon,
69
- .main_pkg_path = .{ .path = "." },
70
- .root_source_file = .{ .path = "src/lib/binding/node.zig" },
56
+ .root_source_file = b.path("src/lib/node.zig"),
71
57
  .optimize = optimize,
72
58
  .target = target,
59
+ .strip = strip,
60
+ .pic = pic,
73
61
  });
74
- lib.addOptions("build_options", options);
75
- lib.addSystemIncludePath(.{ .path = headers });
62
+ lib.root_module.addOptions("build_options", options);
63
+ lib.addSystemIncludePath(b.path(headers));
76
64
  lib.linkLibC();
77
65
  if (node_import_lib) |il| {
78
- lib.addObjectFile(.{ .path = il });
79
- } else if ((try std.zig.system.NativeTargetInfo.detect(target)).target.os.tag == .windows) {
66
+ lib.addObjectFile(b.path(il));
67
+ } else if (target.result.os.tag == .windows) {
80
68
  try std.io.getStdErr().writeAll("Must provide --node-import-library path on Windows\n");
81
69
  std.process.exit(1);
82
70
  }
83
71
  lib.linker_allow_shlib_undefined = true;
84
72
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
85
- if (pic) lib.force_pic = pic;
86
73
  // Always emit to build/lib because this is where the driver code expects to find it
87
- // TODO(ziglang/zig#2231): using the following used to work (though was hacky):
74
+ // TODO: ziglang/zig#2231 - using the following used to work (though was hacky):
88
75
  //
89
76
  // lib.emit_bin = .{ .emit_to = b.fmt("build/lib/{s}", .{addon}) };
90
77
  // b.getInstallStep().dependOn(&lib.step);
@@ -95,16 +82,17 @@ pub fn build(b: *std.Build) !void {
95
82
  } else if (wasm) {
96
83
  const exe = b.addExecutable(.{
97
84
  .name = name,
98
- .main_pkg_path = .{ .path = "." },
99
- .root_source_file = .{ .path = "src/lib/binding/wasm.zig" },
85
+ .root_source_file = b.path("src/lib/wasm.zig"),
100
86
  .optimize = switch (optimize) {
101
87
  .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
102
88
  else => optimize,
103
89
  },
104
- .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
90
+ .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
91
+ .strip = strip,
92
+ .pic = pic,
105
93
  });
106
- exe.addOptions("build_options", options);
107
- exe.export_symbol_names = &[_][]const u8{
94
+ exe.root_module.addOptions("build_options", options);
95
+ exe.root_module.export_symbol_names = &[_][]const u8{
108
96
  "SHOWDOWN",
109
97
  "LOG",
110
98
  "CHANCE",
@@ -114,15 +102,13 @@ pub fn build(b: *std.Build) !void {
114
102
  };
115
103
  exe.entry = .disabled;
116
104
  exe.stack_size = wasm_stack_size;
117
- exe.strip = strip;
118
- if (pic) exe.force_pic = pic;
119
105
  const opt = b.findProgram(&.{"wasm-opt"}, &.{"./node_modules/.bin"}) catch null;
120
106
  if (optimize != .Debug and opt != null) {
121
107
  const out = b.fmt("build/lib/{s}.wasm", .{name});
122
108
  const sh = b.addSystemCommand(&.{ opt.?, "-O4" });
123
109
  sh.addArtifactArg(exe);
124
110
  sh.addArg("-o");
125
- sh.addFileSourceArg(.{ .path = out });
111
+ sh.addFileArg(b.path(out));
126
112
  b.getInstallStep().dependOn(&sh.step);
127
113
  } else {
128
114
  b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{
@@ -132,31 +118,31 @@ pub fn build(b: *std.Build) !void {
132
118
  } else if (dynamic) {
133
119
  const lib = b.addSharedLibrary(.{
134
120
  .name = name,
135
- .main_pkg_path = .{ .path = "." },
136
- .root_source_file = .{ .path = "src/lib/binding/c.zig" },
121
+ .root_source_file = b.path("src/lib/c.zig"),
137
122
  .version = try std.SemanticVersion.parse(version),
138
123
  .optimize = optimize,
139
124
  .target = target,
125
+ .strip = strip,
126
+ .pic = pic,
140
127
  });
141
- lib.addOptions("build_options", options);
142
- lib.addIncludePath(.{ .path = "src/include" });
128
+ lib.root_module.addOptions("build_options", options);
129
+ lib.addIncludePath(b.path("src/include"));
143
130
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
144
- if (pic) lib.force_pic = pic;
145
131
  b.installArtifact(lib);
146
132
  c = true;
147
133
  } else {
148
134
  const lib = b.addStaticLibrary(.{
149
135
  .name = name,
150
- .main_pkg_path = .{ .path = "." },
151
- .root_source_file = .{ .path = "src/lib/binding/c.zig" },
136
+ .root_source_file = b.path("src/lib/c.zig"),
152
137
  .optimize = optimize,
153
138
  .target = target,
139
+ .strip = strip,
140
+ .pic = pic,
154
141
  });
155
- lib.addOptions("build_options", options);
156
- lib.addIncludePath(.{ .path = "src/include" });
142
+ lib.root_module.addOptions("build_options", options);
143
+ lib.addIncludePath(b.path("src/include"));
157
144
  lib.bundle_compiler_rt = true;
158
145
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
159
- if (pic) lib.force_pic = pic;
160
146
  if (emit_asm) {
161
147
  b.getInstallStep().dependOn(&b.addInstallFileWithDir(
162
148
  lib.getEmittedAsm(),
@@ -177,14 +163,18 @@ pub fn build(b: *std.Build) !void {
177
163
 
178
164
  if (c) {
179
165
  const header = b.addInstallFileWithDir(
180
- .{ .path = "src/include/pkmn.h" },
166
+ b.path("src/include/pkmn.h"),
181
167
  .header,
182
168
  "pkmn.h",
183
169
  );
184
170
  b.getInstallStep().dependOn(&header.step);
185
171
 
186
172
  const pc = b.fmt("lib{s}.pc", .{name});
187
- const file = try b.cache_root.join(b.allocator, &.{pc});
173
+ const file = try std.fs.path.relative(
174
+ b.allocator,
175
+ try std.process.getCwdAlloc(b.allocator),
176
+ try b.cache_root.join(b.allocator, &.{pc}),
177
+ );
188
178
  const pkgconfig_file = try std.fs.cwd().createFile(file, .{});
189
179
 
190
180
  const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
@@ -217,14 +207,10 @@ pub fn build(b: *std.Build) !void {
217
207
  // TODO: tests can be run multiple times due to @imports
218
208
  const tests = TestStep.create(b, options, config);
219
209
 
220
- var exes = std.ArrayList(*std.Build.CompileStep).init(b.allocator);
210
+ var exes = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
221
211
  const tools: ToolConfig = .{
222
- .options = .{
223
- .showdown = showdown,
224
- .log = log,
225
- .chance = chance,
226
- .calc = calc,
227
- },
212
+ .showdown = showdown,
213
+ .module = module,
228
214
  .general = config,
229
215
  .tool = .{
230
216
  .tests = if (tests.build) tests else null,
@@ -265,13 +251,12 @@ pub fn build(b: *std.Build) !void {
265
251
 
266
252
  fn maybeStrip(
267
253
  b: *std.Build,
268
- artifact: *std.Build.CompileStep,
254
+ artifact: *std.Build.Step.Compile,
269
255
  step: *std.Build.Step,
270
- strip: bool,
256
+ strip: ?bool,
271
257
  cmd: ?[]const u8,
272
258
  ) void {
273
- artifact.strip = strip;
274
- if (!strip or cmd == null) return;
259
+ if (!(strip orelse false) or cmd == null) return;
275
260
  // Using `strip -r -u` for dynamic libraries is supposed to work on macOS but doesn't...
276
261
  const mac = builtin.os.tag == .macos;
277
262
  if (mac and artifact.isDynamicLibrary()) return;
@@ -283,10 +268,10 @@ fn maybeStrip(
283
268
  }
284
269
 
285
270
  const Config = struct {
286
- target: std.zig.CrossTarget,
271
+ target: std.Build.ResolvedTarget,
287
272
  optimize: std.builtin.OptimizeMode,
288
- pic: bool,
289
- strip: bool,
273
+ pic: ?bool,
274
+ strip: ?bool,
290
275
  cmd: ?[]const u8,
291
276
  };
292
277
 
@@ -294,9 +279,8 @@ const TestStep = struct {
294
279
  step: std.Build.Step,
295
280
  build: bool,
296
281
 
297
- pub fn create(b: *std.Build, options: *std.Build.OptionsStep, config: Config) *TestStep {
282
+ pub fn create(b: *std.Build, options: *std.Build.Step.Options, config: Config) *TestStep {
298
283
  const coverage = b.option([]const u8, "test-coverage", "Generate test coverage");
299
- const test_file = b.option([]const u8, "test-file", "Input file for test");
300
284
  const test_filter =
301
285
  b.option([]const u8, "test-filter", "Skip tests that do not match filter");
302
286
 
@@ -304,22 +288,17 @@ const TestStep = struct {
304
288
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Run all tests", .owner = b });
305
289
  self.* = .{ .step = step, .build = test_filter == null };
306
290
 
307
- const path = test_file orelse "src/lib/test.zig";
308
291
  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 },
292
+ .root_source_file = b.path("src/lib/test.zig"),
315
293
  .optimize = config.optimize,
316
294
  .target = config.target,
317
295
  .filter = test_filter,
296
+ .single_threaded = true,
297
+ .strip = config.strip,
298
+ .pic = config.pic,
318
299
  });
319
- tests.addOptions("build_options", options);
320
- tests.single_threaded = true;
300
+ tests.root_module.addOptions("build_options", options);
321
301
  maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
322
- if (config.pic) tests.force_pic = config.pic;
323
302
  if (coverage) |c| {
324
303
  tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
325
304
  }
@@ -330,16 +309,17 @@ const TestStep = struct {
330
309
  };
331
310
 
332
311
  const ToolConfig = struct {
333
- options: Options,
312
+ showdown: ?bool,
313
+ module: *std.Build.Module,
334
314
  general: Config,
335
315
  tool: struct {
336
316
  tests: ?*TestStep,
337
317
  name: ?[]const u8 = null,
338
- exes: *std.ArrayList(*std.Build.CompileStep),
318
+ exes: *std.ArrayList(*std.Build.Step.Compile),
339
319
  },
340
320
  };
341
321
 
342
- fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.RunStep {
322
+ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.Step.Run {
343
323
  std.fs.cwd().access(path, .{}) catch |err| switch (err) {
344
324
  error.FileNotFound => return null,
345
325
  else => |e| return e,
@@ -347,18 +327,19 @@ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.RunSte
347
327
  var name = config.tool.name orelse std.fs.path.basename(path);
348
328
  const index = std.mem.lastIndexOfScalar(u8, name, '.');
349
329
  if (index) |i| name = name[0..i];
350
- if (config.options.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
330
+ if (config.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
351
331
 
352
332
  const exe = b.addExecutable(.{
353
333
  .name = name,
354
- .root_source_file = .{ .path = path },
334
+ .root_source_file = b.path(path),
355
335
  .target = config.general.target,
356
336
  .optimize = config.general.optimize,
337
+ .single_threaded = true,
338
+ .strip = config.general.strip,
339
+ .pic = config.general.pic,
357
340
  });
358
- exe.addModule("pkmn", module(b, config.options));
341
+ exe.root_module.addImport("pkmn", config.module);
359
342
 
360
- exe.single_threaded = true;
361
- if (config.general.pic) exe.force_pic = config.general.pic;
362
343
  if (config.tool.tests) |ts| ts.step.dependOn(&exe.step);
363
344
  config.tool.exes.append(exe) catch @panic("OOM");
364
345
 
@@ -372,7 +353,7 @@ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.RunSte
372
353
  const ToolsStep = struct {
373
354
  step: std.Build.Step,
374
355
 
375
- pub fn create(b: *std.Build, exes: *std.ArrayList(*std.Build.CompileStep)) *ToolsStep {
356
+ pub fn create(b: *std.Build, exes: *std.ArrayList(*std.Build.Step.Compile)) *ToolsStep {
376
357
  const self = b.allocator.create(ToolsStep) catch @panic("OOM");
377
358
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Install tools", .owner = b });
378
359
  self.* = .{ .step = step };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkmn/engine",
3
- "version": "0.1.0-dev.c4f94762",
3
+ "version": "0.1.0-dev.c4ffaf39",
4
4
  "description": "A minimal, complete, Pokémon battle simulation engine optimized for performance",
5
5
  "repository": "github:pkmn/engine",
6
6
  "license": "MIT",
@@ -31,9 +31,6 @@
31
31
  "build/test/display.js",
32
32
  "build/tools/debug.js.map",
33
33
  "build/tools/debug.js",
34
- "src/bin/install-pkmn-engine",
35
- "src/lib/binding/node.zig",
36
- "src/lib/binding/wasm.zig",
37
34
  "src/lib/common/battle.zig",
38
35
  "src/lib/common/data.zig",
39
36
  "src/lib/common/debug.zig",
@@ -62,7 +59,9 @@
62
59
  "src/lib/gen2/generated.zig",
63
60
  "src/lib/gen2/helpers.zig",
64
61
  "src/lib/gen2/mechanics.zig",
62
+ "src/lib/node.zig",
65
63
  "src/lib/pkmn.zig",
64
+ "src/lib/wasm.zig",
66
65
  "src/test/display/pkmn.html.tmpl"
67
66
  ],
68
67
  "engines": {
@@ -76,31 +75,31 @@
76
75
  "access": "public"
77
76
  },
78
77
  "dependencies": {
79
- "@pkmn/data": "^0.8.1",
80
- "@pkmn/protocol": "^0.6.17"
78
+ "@pkmn/data": "^0.9.9",
79
+ "@pkmn/protocol": "^0.6.25"
81
80
  },
82
81
  "devDependencies": {
83
- "@pkmn/eslint-config": "^6.4.0",
84
- "@pkmn/img": "^0.2.20",
85
- "@pkmn/sets": "^5.1.0",
86
- "@pkmn/sim": "0.8.1",
82
+ "@pkmn/eslint-config": "^7.5.0",
83
+ "@pkmn/img": "^0.2.30",
84
+ "@pkmn/sets": "^5.1.2",
85
+ "@pkmn/sim": "0.9.9",
87
86
  "@types/html-minifier": "^4.0.5",
88
- "@types/jest": "^29.5.11",
87
+ "@types/jest": "^29.5.12",
89
88
  "@types/minimist": "^1.2.5",
90
89
  "@types/mustache": "^4.2.5",
91
- "@types/node": "^20.10.5",
92
- "@vitest/coverage-v8": "^1.0.4",
93
- "binaryen": "^116.0.0",
94
- "eslint": "^8.56.0",
90
+ "@types/node": "^20.14.10",
91
+ "@vitest/coverage-v8": "^2.0.2",
92
+ "binaryen": "^118.0.0",
93
+ "eslint": "<=8",
95
94
  "html-minifier": "^4.0.0",
96
- "json-stringify-pretty-compact": "3.0.0",
95
+ "json-stringify-pretty-compact": "4.0.0",
97
96
  "minimist": "^1.2.8",
98
97
  "mustache": "^4.2.0",
99
98
  "source-map-support": "^0.5.21",
100
- "table": "^6.8.1",
99
+ "table": "^6.8.2",
101
100
  "trakr": "^0.2.0",
102
- "typescript": "^5.3.3",
103
- "vitest": "^1.0.4"
101
+ "typescript": "^5.5.3",
102
+ "vitest": "^2.0.2"
104
103
  },
105
104
  "scripts": {
106
105
  "lint": "eslint --cache src --ext ts,js && eslint src/bin/*",
@@ -142,6 +141,14 @@
142
141
  ]
143
142
  }
144
143
  },
144
+ {
145
+ "files": [
146
+ "src/test/display.ts"
147
+ ],
148
+ "rules": {
149
+ "@typescript-eslint/no-unnecessary-type-assertion": "off"
150
+ }
151
+ },
145
152
  {
146
153
  "files": [
147
154
  "src/pkg/index.ts",
@@ -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: 12, patch: 0, dev: 1396};
13
+ const ZIG_VERSION = {major: 0, minor: 13, 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';
@@ -370,8 +370,10 @@ const downloadImportLib = async () => {
370
370
  const args = ['build', '-p', 'build', ...opts];
371
371
  if (!process.env.DEBUG_PKMN_ENGINE) args.push('-Doptimize=ReleaseFast', '-Dstrip');
372
372
  if (config.type === 'node') {
373
- args.push(`-Dnode-headers=${headers}`);
374
- if (process.platform === 'win32') args.push(`-Dnode-import-library=${lib}`);
373
+ args.push(`-Dnode-headers=${path.relative(ROOT, headers)}`);
374
+ if (process.platform === 'win32') {
375
+ args.push(`-Dnode-import-library=${path.relative(ROOT, lib)}`);
376
+ }
375
377
  } else {
376
378
  args.push('-Dwasm');
377
379
  }
@@ -386,8 +388,14 @@ const downloadImportLib = async () => {
386
388
  const prefix = process.platform === 'win32' ? '' : 'lib';
387
389
  const ext = process.platform === 'darwin'
388
390
  ? 'dylib' : process.platform === 'win32' ? 'dll' : 'so';
389
- const actual = path.join('build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
390
- fs.renameSync(path.join(ROOT, actual), path.join(ROOT, artifact));
391
+ try {
392
+ const actual = path.join('build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
393
+ fs.renameSync(actual, artifact);
394
+ } catch (err) {
395
+ // ziglang/zig#19743 changed this path
396
+ const actual = path.join('build', 'bin', `${prefix}pkmn${suffix}.node.${ext}`);
397
+ fs.renameSync(actual, artifact);
398
+ }
391
399
  }
392
400
  }
393
401
  })().catch(e => {
@@ -22,8 +22,8 @@ pub const Player = enum(u1) {
22
22
 
23
23
  test Player {
24
24
  try expectEqual(Player.P2, Player.P1.foe());
25
- try expectEqual(@as(u8, 0b0001), @as(u8, @bitCast(Player.P1.ident(1))));
26
- try expectEqual(@as(u8, 0b1101), @as(u8, @bitCast(Player.P2.ident(5))));
25
+ try expectEqual(0b0001, @as(u8, @bitCast(Player.P1.ident(1))));
26
+ try expectEqual(0b1101, @as(u8, @bitCast(Player.P2.ident(5))));
27
27
  }
28
28
 
29
29
  /// An identifier for a specific Pokémon in battle.
@@ -46,8 +46,8 @@ pub const ID = packed struct(u8) {
46
46
  };
47
47
 
48
48
  test ID {
49
- try expectEqual(@as(u8, 0b0001), @as(u8, @bitCast(ID{ .player = .P1, .id = 1 })));
50
- try expectEqual(@as(u8, 0b1101), @as(u8, @bitCast(ID{ .player = .P2, .id = 5 })));
49
+ try expectEqual(0b0001, @as(u8, @bitCast(ID{ .player = .P1, .id = 1 })));
50
+ try expectEqual(0b1101, @as(u8, @bitCast(ID{ .player = .P2, .id = 5 })));
51
51
  const id: ID = .{ .player = .P2, .id = 4 };
52
52
  try expectEqual(id, ID.from(id.int()));
53
53
  }
@@ -4,8 +4,8 @@ const debug = std.debug;
4
4
  const io = std.io;
5
5
 
6
6
  pub fn print(value: anytype) void {
7
- debug.getStderrMutex().lock();
8
- defer debug.getStderrMutex().unlock();
7
+ debug.lockStdErr();
8
+ defer debug.unlockStdErr();
9
9
  const stderr = io.getStdErr().writer();
10
10
 
11
11
  nosuspend {
@@ -46,7 +46,7 @@ test Optional {
46
46
  try expect(b != .true);
47
47
  try expect(b != .false);
48
48
 
49
- const Player = @import("./data.zig").Player;
49
+ const Player = @import("data.zig").Player;
50
50
  try expect(@bitSizeOf(Optional(Player)) == 2);
51
51
 
52
52
  const p: Optional(Player) = .P2;
@@ -10,6 +10,7 @@ pub const Options = struct {
10
10
  advance: ?bool = null,
11
11
  ebc: ?bool = null,
12
12
  key: ?bool = null,
13
+ miss: ?bool = null,
13
14
  internal: ?bool = null,
14
15
  };
15
16
 
@@ -25,6 +26,7 @@ pub const calc = get("calc", false);
25
26
  pub const advance = get("advance", true);
26
27
  pub const ebc = get("ebc", true);
27
28
  pub const key = get("key", false);
29
+ pub const miss = get("miss", true);
28
30
  pub const internal = get("internal", false);
29
31
 
30
32
  fn get(comptime name: []const u8, default: bool) bool {
@@ -3,8 +3,8 @@ const builtin = @import("builtin");
3
3
 
4
4
  const pkmn = @import("../pkmn.zig");
5
5
 
6
- const data = @import("./data.zig");
7
- const options = @import("./options.zig");
6
+ const data = @import("data.zig");
7
+ const options = @import("options.zig");
8
8
 
9
9
  const assert = std.debug.assert;
10
10
  const print = std.debug.print;
@@ -220,6 +220,7 @@ pub const Activate = enum(u8) {
220
220
  BeatUp, // FIXME of
221
221
 
222
222
  Magnitude,
223
+ Spite,
223
224
  };
224
225
 
225
226
  pub const Start = enum(u8) {
@@ -544,6 +545,7 @@ pub fn Log(comptime Writer: type) type {
544
545
  // ident: ID, reason: Activate
545
546
  // ident: ID, reason: .SubstituteBlock, m: <Move>
546
547
  // ident: ID, reason: .Magnitude, num: u8
548
+ // ident: ID, reason: .Spite, m: <Move>, num: u8
547
549
  pub fn activate(self: Self, args: anytype) Error!void {
548
550
  if (!enabled) return;
549
551
 
@@ -561,6 +563,9 @@ pub fn Log(comptime Writer: type) type {
561
563
  assert(reason == .Magnitude);
562
564
  try self.writer.writeByte(args[2]);
563
565
  }
566
+ } else if (args.len == 4) {
567
+ assert(reason == .Spite);
568
+ try self.writer.writeAll(&.{ @intFromEnum(args[2]), args[3] });
564
569
  }
565
570
  }
566
571
 
@@ -1202,14 +1207,11 @@ pub fn expectLog(
1202
1207
  ) !void {
1203
1208
  if (!enabled) return;
1204
1209
 
1205
- const color = color: {
1206
- if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
1207
- break :color true;
1208
- } else if (std.process.hasEnvVarConstant("NO_COLOR")) {
1209
- break :color false;
1210
- } else {
1211
- break :color std.io.getStdErr().supportsAnsiEscapeCodes();
1212
- }
1210
+ const color = if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR"))
1211
+ true
1212
+ else switch (std.io.tty.detectConfig(std.io.getStdErr())) {
1213
+ .escape_codes => true,
1214
+ else => false,
1213
1215
  };
1214
1216
 
1215
1217
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
@@ -1248,20 +1250,13 @@ fn N(e: anytype) u8 {
1248
1250
  const p1 = Player.P1;
1249
1251
  const p2 = Player.P2;
1250
1252
 
1251
- const gen1 = struct {
1252
- pub usingnamespace @import("../gen1/data.zig");
1253
- pub const helpers = @import("../gen1/helpers.zig");
1254
- };
1255
-
1256
- const gen2 = struct {
1257
- pub usingnamespace @import("../gen2/data.zig");
1258
- pub const helpers = @import("../gen2/helpers.zig");
1259
- };
1260
-
1261
1253
  var buf: [pkmn.LOGS_SIZE]u8 = undefined;
1262
1254
  var stream: ByteStream = .{ .buffer = &buf };
1263
1255
  var log: FixedLog = .{ .writer = stream.writer() };
1264
1256
 
1257
+ const gen1 = pkmn.gen1;
1258
+ const gen2 = pkmn.gen2;
1259
+
1265
1260
  const M1 = gen1.Move;
1266
1261
  const S1 = gen1.Species;
1267
1262
 
@@ -1,6 +1,6 @@
1
1
  const std = @import("std");
2
2
 
3
- const options = @import("./options.zig");
3
+ const options = @import("options.zig");
4
4
 
5
5
  const assert = std.debug.assert;
6
6
  const expectEqual = std.testing.expectEqual;
@@ -66,11 +66,15 @@ pub const PSRNG = extern struct {
66
66
  (@as(u64, self.range(u16, 0, 0x10000)) << 16) |
67
67
  (@as(u64, self.range(u16, 0, 0x10000)));
68
68
  }
69
+
70
+ pub fn Bound(comptime T: type) type {
71
+ return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
72
+ }
69
73
  };
70
74
 
71
75
  test PSRNG {
72
76
  var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
73
- try expectEqual(@as(u8, 121), psrng.range(u8, 0, 256));
77
+ try expectEqual(121, psrng.range(u8, 0, 256));
74
78
  try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
75
79
  }
76
80
 
@@ -107,9 +111,9 @@ test Gen12 {
107
111
  try expectEqual(e, rng.next());
108
112
  }
109
113
 
110
- try expectEqual(@as(u8, 16), Gen12.percent(6) + 1);
111
- try expectEqual(@as(u8, 16), Gen12.percent(7) - 1);
112
- try expectEqual(@as(u8, 128), Gen12.percent(50) + 1);
114
+ try expectEqual(16, Gen12.percent(6) + 1);
115
+ try expectEqual(16, Gen12.percent(7) - 1);
116
+ try expectEqual(128, Gen12.percent(50) + 1);
113
117
  }
114
118
 
115
119
  // https://pkmn.cc/pokeemerald/src/random.c
@@ -197,7 +201,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
197
201
  for (0..n) |_| _ = self.next();
198
202
  }
199
203
 
200
- pub fn range(self: *Self, comptime T: type, from: T, to: Bound(T)) T {
204
+ pub fn range(self: *Self, comptime T: type, from: T, to: PSRNG.Bound(T)) T {
201
205
  assert(showdown);
202
206
  return @intCast(@as(u64, self.next()) * (to - from) / divisor + from);
203
207
  }
@@ -206,7 +210,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
206
210
  self: *Self,
207
211
  comptime T: type,
208
212
  numerator: T,
209
- denominator: Bound(T),
213
+ denominator: PSRNG.Bound(T),
210
214
  ) bool {
211
215
  assert(showdown);
212
216
  assert(denominator > 0);
@@ -237,7 +241,3 @@ fn Output(comptime gen: comptime_int) type {
237
241
  else => unreachable,
238
242
  };
239
243
  }
240
-
241
- fn Bound(comptime T: type) type {
242
- return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
243
- }