@pkmn/engine 0.1.0-dev.12e7292c → 0.1.0-dev.130de754

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 (84) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +41 -25
  3. package/build/pkg/addon/browser.d.ts +3 -0
  4. package/build/pkg/addon/browser.js +47 -0
  5. package/build/pkg/addon/browser.js.map +1 -0
  6. package/build/pkg/addon/node.d.ts +3 -0
  7. package/build/pkg/addon/node.js +110 -0
  8. package/build/pkg/addon/node.js.map +1 -0
  9. package/build/pkg/addon/wasm.d.ts +2 -0
  10. package/build/pkg/addon/wasm.js +53 -0
  11. package/build/pkg/addon/wasm.js.map +1 -0
  12. package/build/pkg/addon.d.ts +26 -4
  13. package/build/pkg/addon.js +39 -71
  14. package/build/pkg/addon.js.map +1 -1
  15. package/build/pkg/data/layout.json +15 -2
  16. package/build/pkg/data/protocol.json +23 -9
  17. package/build/pkg/data.d.ts +27 -5
  18. package/build/pkg/data.js.map +1 -1
  19. package/build/pkg/gen1.d.ts +15 -18
  20. package/build/pkg/gen1.js +28 -19
  21. package/build/pkg/gen1.js.map +1 -1
  22. package/build/pkg/index.d.ts +42 -91
  23. package/build/pkg/index.js +23 -70
  24. package/build/pkg/index.js.map +1 -1
  25. package/build/pkg/protocol.d.ts +29 -1
  26. package/build/pkg/protocol.js +109 -107
  27. package/build/pkg/protocol.js.map +1 -1
  28. package/build/tools/debug.js +84 -75
  29. package/build/tools/debug.js.map +1 -1
  30. package/build/tools/display/debug.jsx +66 -0
  31. package/build/tools/display/debug.jsx.map +1 -0
  32. package/build/tools/display/index.js +152 -0
  33. package/build/tools/display/index.js.map +1 -0
  34. package/build/tools/display/ui.jsx +360 -0
  35. package/build/tools/display/ui.jsx.map +1 -0
  36. package/build/tools/display/util.js +157 -0
  37. package/build/tools/display/util.js.map +1 -0
  38. package/build.zig +310 -203
  39. package/package.json +60 -134
  40. package/src/bin/install-pkmn-engine +70 -53
  41. package/src/bin/pkmn-debug +1 -1
  42. package/src/lib/bindings/c.zig +201 -0
  43. package/src/lib/{binding → bindings}/node.zig +15 -32
  44. package/src/lib/bindings/wasm.zig +51 -0
  45. package/src/lib/common/array.zig +70 -0
  46. package/src/lib/common/data.zig +4 -4
  47. package/src/lib/common/debug.zig +46 -30
  48. package/src/lib/common/js.zig +5 -9
  49. package/src/lib/common/optional.zig +21 -22
  50. package/src/lib/common/options.zig +6 -0
  51. package/src/lib/common/protocol.zig +253 -223
  52. package/src/lib/common/rational.zig +340 -254
  53. package/src/lib/common/rng.zig +11 -13
  54. package/src/lib/common/util.zig +53 -1
  55. package/src/lib/gen1/calc.zig +724 -175
  56. package/src/lib/gen1/chance.zig +494 -308
  57. package/src/lib/gen1/data/moves.zig +2 -4
  58. package/src/lib/gen1/data/species.zig +2 -4
  59. package/src/lib/gen1/data/types.zig +3 -4
  60. package/src/lib/gen1/data.zig +49 -49
  61. package/src/lib/gen1/helpers.zig +115 -562
  62. package/src/lib/gen1/mechanics.zig +411 -293
  63. package/src/lib/gen2/calc.zig +35 -28
  64. package/src/lib/gen2/chance.zig +122 -518
  65. package/src/lib/gen2/data/items.zig +1 -3
  66. package/src/lib/gen2/data/moves.zig +2 -4
  67. package/src/lib/gen2/data/species.zig +1 -3
  68. package/src/lib/gen2/data/types.zig +7 -5
  69. package/src/lib/gen2/data.zig +39 -38
  70. package/src/lib/gen2/generated.zig +16 -26
  71. package/src/lib/gen2/helpers.zig +68 -39
  72. package/src/lib/gen2/mechanics.zig +217 -174
  73. package/src/lib/napi.h +2 -0
  74. package/src/lib/node.zig +14 -0
  75. package/src/lib/pkmn.zig +123 -29
  76. package/src/lib/wasm.zig +12 -0
  77. package/src/tools/display/dom.ts +108 -0
  78. package/src/tools/display/ui.css +354 -0
  79. package/build/test/display.js +0 -400
  80. package/build/test/display.js.map +0 -1
  81. package/src/lib/binding/wasm.zig +0 -12
  82. package/src/lib/gen1/README.md +0 -894
  83. package/src/lib/gen2/README.md +0 -329
  84. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,18 +1,16 @@
1
- const std = @import("std");
2
1
  const builtin = @import("builtin");
3
-
2
+ const data = @import("data.zig");
3
+ const options = @import("options.zig");
4
4
  const pkmn = @import("../pkmn.zig");
5
-
6
- const data = @import("./data.zig");
7
- const options = @import("./options.zig");
5
+ const std = @import("std");
8
6
 
9
7
  const assert = std.debug.assert;
10
- const print = std.debug.print;
11
-
12
8
  const enabled = options.log;
13
-
14
- const Player = data.Player;
15
9
  const ID = data.ID;
10
+ const Player = data.Player;
11
+ const print = std.debug.print;
12
+
13
+ const endian = builtin.cpu.arch.endian();
16
14
 
17
15
  pub const ArgType = enum(u8) {
18
16
  None,
@@ -71,7 +69,7 @@ pub const ArgType = enum(u8) {
71
69
  EndAbility,
72
70
  ClearNegativeBoost,
73
71
  FormeChange,
74
- NoTarget,
72
+ LastNoTarget, // FIXME
75
73
 
76
74
  // Gen 4
77
75
  SwapBoost,
@@ -218,6 +216,7 @@ pub const Activate = enum(u8) {
218
216
  BeatUp, // FIXME of
219
217
 
220
218
  Magnitude,
219
+ Spite,
221
220
  };
222
221
 
223
222
  pub const Start = enum(u8) {
@@ -309,19 +308,29 @@ pub const Weather = enum(u8) {
309
308
  Upkeep,
310
309
  };
311
310
 
312
- /// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
313
- /// Ignores anything sent to it, though protocol logging should additionally be turned off
314
- /// entirely with `options.log`.
315
- pub const NULL = Log(@TypeOf(std.io.null_writer)){ .writer = std.io.null_writer };
316
-
317
- /// Logs protocol information to its `Writer` during a battle update when `options.log` is enabled.
318
- pub fn Log(comptime Writer: type) type {
311
+ /// Logs protocol information to its `WriterT` during a battle update when `options.log` is enabled.
312
+ pub fn Log(comptime WriterT: type) type {
319
313
  return struct {
320
314
  const Self = @This();
321
315
 
322
- writer: Writer,
316
+ writer: WriterT,
323
317
 
324
- pub const Error = Writer.Error;
318
+ pub const Error = err(WriterT);
319
+
320
+ fn err(comptime T: type) type {
321
+ const msg = "Invalid Writer type " ++ @typeName(T) ++ "'";
322
+ return switch (@typeInfo(T)) {
323
+ .pointer => |ptr_info| switch (ptr_info.size) {
324
+ .one => switch (@typeInfo(ptr_info.child)) {
325
+ .@"struct" => err(ptr_info.child),
326
+ else => @compileError(msg),
327
+ },
328
+ else => @compileError(msg),
329
+ },
330
+ .@"struct" => if (@hasDecl(T, "Error")) T.Error else @compileError(msg),
331
+ else => @compileError(msg),
332
+ };
333
+ }
325
334
 
326
335
  // source: ID, move: <Move>, target: ID, from?: <Move>
327
336
  pub fn move(self: Self, args: anytype) Error!void {
@@ -359,8 +368,8 @@ pub fn Log(comptime Writer: type) type {
359
368
  } else {
360
369
  try self.writer.writeAll(&.{ @intFromEnum(args[1].species), args[1].level });
361
370
  }
362
- try self.writer.writeIntNative(u16, args[1].hp);
363
- try self.writer.writeIntNative(u16, args[1].stats.hp);
371
+ try self.writer.writeInt(u16, args[1].hp, endian);
372
+ try self.writer.writeInt(u16, args[1].stats.hp, endian);
364
373
  try self.writer.writeAll(&.{args[1].status});
365
374
  }
366
375
 
@@ -391,7 +400,7 @@ pub fn Log(comptime Writer: type) type {
391
400
  if (!enabled) return;
392
401
 
393
402
  try self.writer.writeByte(@intFromEnum(ArgType.Turn));
394
- try self.writer.writeIntNative(u16, args[0]);
403
+ try self.writer.writeInt(u16, args[0], endian);
395
404
  try self.writer.writeByte(@intFromEnum(ArgType.None));
396
405
  }
397
406
 
@@ -423,8 +432,8 @@ pub fn Log(comptime Writer: type) type {
423
432
  @intFromEnum(ArgType.Damage),
424
433
  @as(u8, @bitCast(args[0])),
425
434
  });
426
- try self.writer.writeIntNative(u16, args[1].hp);
427
- try self.writer.writeIntNative(u16, args[1].stats.hp);
435
+ try self.writer.writeInt(u16, args[1].hp, endian);
436
+ try self.writer.writeInt(u16, args[1].stats.hp, endian);
428
437
  try self.writer.writeAll(&.{ args[1].status, @intFromEnum(@as(Damage, args[2])) });
429
438
  if (args.len == 4) try self.writer.writeByte(@as(u8, @bitCast(args[3])));
430
439
  }
@@ -436,8 +445,8 @@ pub fn Log(comptime Writer: type) type {
436
445
 
437
446
  assert(args[2] != .Drain or args.len == 4);
438
447
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(args[0])) });
439
- try self.writer.writeIntNative(u16, args[1].hp);
440
- try self.writer.writeIntNative(u16, args[1].stats.hp);
448
+ try self.writer.writeInt(u16, args[1].hp, endian);
449
+ try self.writer.writeInt(u16, args[1].stats.hp, endian);
441
450
  try self.writer.writeAll(&.{ args[1].status, @intFromEnum(@as(Heal, args[2])) });
442
451
  if (args.len == 4) try self.writer.writeByte(@as(u8, @bitCast(args[3])));
443
452
  }
@@ -542,6 +551,7 @@ pub fn Log(comptime Writer: type) type {
542
551
  // ident: ID, reason: Activate
543
552
  // ident: ID, reason: .SubstituteBlock, m: <Move>
544
553
  // ident: ID, reason: .Magnitude, num: u8
554
+ // ident: ID, reason: .Spite, m: <Move>, num: u8
545
555
  pub fn activate(self: Self, args: anytype) Error!void {
546
556
  if (!enabled) return;
547
557
 
@@ -559,6 +569,9 @@ pub fn Log(comptime Writer: type) type {
559
569
  assert(reason == .Magnitude);
560
570
  try self.writer.writeByte(args[2]);
561
571
  }
572
+ } else if (args.len == 4) {
573
+ assert(reason == .Spite);
574
+ try self.writer.writeAll(&.{ @intFromEnum(args[2]), args[3] });
562
575
  }
563
576
  }
564
577
 
@@ -706,8 +719,8 @@ pub fn Log(comptime Writer: type) type {
706
719
  if (!enabled) return;
707
720
 
708
721
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.SetHP), @as(u8, @bitCast(args[0])) });
709
- try self.writer.writeIntNative(u16, args[1].hp);
710
- try self.writer.writeIntNative(u16, args[1].stats.hp);
722
+ try self.writer.writeInt(u16, args[1].hp, endian);
723
+ try self.writer.writeInt(u16, args[1].stats.hp, endian);
711
724
  try self.writer.writeAll(&.{args[1].status});
712
725
  try self.writer.writeByte(@intFromEnum(@as(SetHP, args[2])));
713
726
  }
@@ -808,56 +821,68 @@ pub fn Log(comptime Writer: type) type {
808
821
  };
809
822
  }
810
823
 
811
- /// `Log` type backed by the optimized `ByteStream.Writer`.
812
- pub const FixedLog = Log(ByteStream.Writer);
824
+ /// `Log` type backed by the optimized `Writer`.
825
+ pub const FixedLog = Log(*Writer);
813
826
 
814
- /// Stripped down version of `std.io.FixedBufferStream` optimized for efficiently writing the
815
- /// individual protocol bytes. Note that the `ByteStream.Writer` is **not** a `std.io.Writer` and
816
- /// should not be used for general purpose writing.
817
- pub const ByteStream = struct {
827
+ /// Minimal logging helper optimized for efficiently writing the individual protocol bytes into a
828
+ /// fixed buffer. Note that this is **not** a `std.Io.Writer` and should not be used for general
829
+ /// purpose writing.
830
+ pub const Writer = struct {
818
831
  buffer: []u8,
819
832
  pos: usize = 0,
820
833
 
821
- pub const Writer = struct {
822
- stream: *ByteStream,
834
+ pub const Error = error{NoSpaceLeft};
823
835
 
824
- pub const Error = error{NoSpaceLeft};
836
+ pub fn writeByte(self: *Writer, byte: u8) Error!void {
837
+ if (self.pos >= self.buffer.len) return error.NoSpaceLeft;
838
+ self.buffer[self.pos] = byte;
839
+ self.pos += 1;
840
+ }
825
841
 
826
- pub fn writeAll(self: Writer, bytes: []const u8) Error!void {
827
- for (bytes) |b| try self.writeByte(b);
828
- }
842
+ pub fn writeAll(self: *Writer, bytes: []const u8) Error!void {
843
+ const npos = self.pos + bytes.len;
844
+ if (npos > self.buffer.len) return error.NoSpaceLeft;
845
+ @memcpy(self.buffer[self.pos..npos], bytes);
846
+ self.pos = npos;
847
+ }
829
848
 
830
- pub fn writeByte(self: Writer, byte: u8) Error!void {
831
- try self.stream.writeByte(byte);
832
- }
849
+ pub fn writeInt(self: *Writer, comptime T: type, v: T, end: std.builtin.Endian) Error!void {
850
+ const bytes = @divExact(@typeInfo(T).int.bits, 8);
851
+ const npos = self.pos + bytes;
852
+ if (npos > self.buffer.len) return error.NoSpaceLeft;
853
+ std.mem.writeInt(T, self.buffer[self.pos..][0..bytes], v, end);
854
+ self.pos = npos;
855
+ }
833
856
 
834
- pub fn writeIntNative(self: Writer, comptime T: type, value: T) Error!void {
835
- // TODO: rework this to write directly to the buffer?
836
- var bytes: [(@typeInfo(T).Int.bits + 7) / 8]u8 = undefined;
837
- std.mem.writeIntNative(T, &bytes, value);
838
- return self.writeAll(&bytes);
839
- }
840
- };
857
+ pub fn reset(self: *Writer) void {
858
+ self.pos = 0;
859
+ }
860
+ };
861
+
862
+ /// Null object pattern implementation of `Log` backed by a null writer. Ignores anything sent to
863
+ /// it, though protocol logging should additionally be turned off entirely with `options.log`.
864
+ pub const NULL = Log(NullWriter){ .writer = .{} };
841
865
 
842
- pub fn writer(self: *ByteStream) Writer {
843
- return .{ .stream = self };
866
+ const NullWriter = struct {
867
+ pub const Error = error{};
868
+
869
+ pub fn writeByte(self: NullWriter, byte: u8) Error!void {
870
+ _ = .{ self, byte };
844
871
  }
845
872
 
846
- pub fn writeByte(self: *ByteStream, byte: u8) Writer.Error!void {
847
- if (self.pos >= self.buffer.len) return error.NoSpaceLeft;
848
- self.buffer[self.pos] = byte;
849
- self.pos += 1;
873
+ pub fn writeAll(self: NullWriter, bytes: []const u8) Error!void {
874
+ _ = .{ self, bytes };
850
875
  }
851
876
 
852
- pub fn reset(self: *ByteStream) void {
853
- self.pos = 0;
877
+ pub fn writeInt(self: NullWriter, comptime T: type, v: T, end: std.builtin.Endian) Error!void {
878
+ _ = .{ self, T, v, end };
854
879
  }
855
880
  };
856
881
 
857
882
  pub const Kind = enum { Move, Species, Type, Status, Item, Weather };
858
883
 
859
884
  pub fn format(
860
- comptime gen: anytype,
885
+ gen: anytype,
861
886
  a: []const u8,
862
887
  b: ?[]const u8,
863
888
  color: bool,
@@ -924,10 +949,10 @@ pub fn format(
924
949
  .OHKO,
925
950
  => {},
926
951
  .Move => {
927
- const source = ID.from(@intCast(a[i]));
952
+ const source: ID = .from(@intCast(a[i]));
928
953
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
929
954
  printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
930
- const target = ID.from(@intCast(a[i]));
955
+ const target: ID = .from(@intCast(a[i]));
931
956
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
932
957
  const reason: Move = @enumFromInt(a[i]);
933
958
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
@@ -936,26 +961,26 @@ pub fn format(
936
961
  }
937
962
  },
938
963
  .Switch, .Drag => {
939
- const id = ID.from(@intCast(a[i]));
964
+ const id: ID = .from(@intCast(a[i]));
940
965
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
941
966
  printc(" {s}", .{formatter(gen, .Species, a[i])}, a, b, &i, 1, color);
942
967
  if (@hasDecl(gen, "Gender")) {
943
968
  if (a[i] == N(gen.Gender.Unknown)) {
944
969
  i += 1;
945
970
  } else {
946
- var gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
971
+ const gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
947
972
  printc(", {s}", .{gender}, a, b, &i, 1, color);
948
973
  }
949
974
  }
950
975
  printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
951
976
  switch (endian) {
952
- .Big => {
977
+ .big => {
953
978
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
954
979
  printc(" {d}", .{hp}, a, b, &i, 2, color);
955
980
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
956
981
  printc("/{d}", .{hp}, a, b, &i, 2, color);
957
982
  },
958
- .Little => {
983
+ .little => {
959
984
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
960
985
  printc(" {d}", .{hp}, a, b, &i, 2, color);
961
986
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -965,7 +990,7 @@ pub fn format(
965
990
  printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
966
991
  },
967
992
  .Cant => {
968
- const id = ID.from(@intCast(a[i]));
993
+ const id: ID = .from(@intCast(a[i]));
969
994
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
970
995
  const reason: Cant = @enumFromInt(a[i]);
971
996
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
@@ -981,13 +1006,13 @@ pub fn format(
981
1006
  .Resisted,
982
1007
  .CureTeam,
983
1008
  => {
984
- const id = ID.from(@intCast(a[i]));
1009
+ const id: ID = .from(@intCast(a[i]));
985
1010
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
986
1011
  },
987
1012
  .Turn => {
988
1013
  const turn = switch (endian) {
989
- .Big => @as(u16, a[i]) << 8 | @as(u16, a[i + 1]),
990
- .Little => @as(u16, a[i + 1]) << 8 | @as(u16, a[i]),
1014
+ .big => @as(u16, a[i]) << 8 | @as(u16, a[i + 1]),
1015
+ .little => @as(u16, a[i + 1]) << 8 | @as(u16, a[i]),
991
1016
  };
992
1017
  printc(" {d}", .{turn}, a, b, &i, 2, color);
993
1018
  },
@@ -995,16 +1020,16 @@ pub fn format(
995
1020
  printc(" {s}", .{@tagName(@as(Player, @enumFromInt(a[i])))}, a, b, &i, 1, color);
996
1021
  },
997
1022
  .Damage, .Heal => {
998
- var id = ID.from(@intCast(a[i]));
1023
+ var id: ID = .from(@intCast(a[i]));
999
1024
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1000
1025
  switch (endian) {
1001
- .Big => {
1026
+ .big => {
1002
1027
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1003
1028
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1004
1029
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1005
1030
  printc("/{d}", .{hp}, a, b, &i, 2, color);
1006
1031
  },
1007
- .Little => {
1032
+ .little => {
1008
1033
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1009
1034
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1010
1035
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -1016,20 +1041,20 @@ pub fn format(
1016
1041
  const reason: Damage = @enumFromInt(a[i]);
1017
1042
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1018
1043
  if (reason == .RecoilOf) {
1019
- id = ID.from(@intCast(a[i]));
1044
+ id = .from(@intCast(a[i]));
1020
1045
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1021
1046
  }
1022
1047
  } else {
1023
1048
  const reason: Heal = @enumFromInt(a[i]);
1024
1049
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1025
1050
  if (reason == .Drain) {
1026
- id = ID.from(@intCast(a[i]));
1051
+ id = .from(@intCast(a[i]));
1027
1052
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1028
1053
  }
1029
1054
  }
1030
1055
  },
1031
1056
  .Status => {
1032
- const id = ID.from(@intCast(a[i]));
1057
+ const id: ID = .from(@intCast(a[i]));
1033
1058
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1034
1059
  printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
1035
1060
  const reason: Status = @enumFromInt(a[i]);
@@ -1039,35 +1064,35 @@ pub fn format(
1039
1064
  }
1040
1065
  },
1041
1066
  .CureStatus => {
1042
- const id = ID.from(@intCast(a[i]));
1067
+ const id: ID = .from(@intCast(a[i]));
1043
1068
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1044
1069
  printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
1045
1070
  const reason: CureStatus = @enumFromInt(a[i]);
1046
1071
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1047
1072
  },
1048
1073
  .Boost => {
1049
- const id = ID.from(@intCast(a[i]));
1074
+ const id: ID = .from(@intCast(a[i]));
1050
1075
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1051
1076
  printc(" {s}", .{@tagName(@as(Boost, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1052
1077
  printc(" {d}", .{a[i]}, a, b, &i, 1, color);
1053
1078
  },
1054
1079
  .Fail => {
1055
- const id = ID.from(@intCast(a[i]));
1080
+ const id: ID = .from(@intCast(a[i]));
1056
1081
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1057
1082
  printc(" {s}", .{@tagName(@as(Fail, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1058
1083
  },
1059
1084
  .HitCount, .SetBoost => {
1060
- const id = ID.from(@intCast(a[i]));
1085
+ const id: ID = .from(@intCast(a[i]));
1061
1086
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1062
1087
  printc(" {d}", .{a[i]}, a, b, &i, 1, color);
1063
1088
  },
1064
1089
  .Prepare, .SingleMove, .SingleTurn => {
1065
- const id = ID.from(@intCast(a[i]));
1090
+ const id: ID = .from(@intCast(a[i]));
1066
1091
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1067
1092
  printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
1068
1093
  },
1069
1094
  .Activate => {
1070
- const id = ID.from(@intCast(a[i]));
1095
+ const id: ID = .from(@intCast(a[i]));
1071
1096
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1072
1097
  const reason: Activate = @enumFromInt(a[i]);
1073
1098
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
@@ -1078,7 +1103,7 @@ pub fn format(
1078
1103
  }
1079
1104
  },
1080
1105
  .Start => {
1081
- const id = ID.from(@intCast(a[i]));
1106
+ const id: ID = .from(@intCast(a[i]));
1082
1107
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1083
1108
  const reason = a[i];
1084
1109
  printc(" {s}", .{@tagName(@as(Start, @enumFromInt(reason)))}, a, b, &i, 1, color);
@@ -1095,27 +1120,27 @@ pub fn format(
1095
1120
  }
1096
1121
  },
1097
1122
  .End => {
1098
- const id = ID.from(@intCast(a[i]));
1123
+ const id: ID = .from(@intCast(a[i]));
1099
1124
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1100
1125
  printc(" {s}", .{@tagName(@as(End, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1101
1126
  },
1102
1127
  .Immune => {
1103
- const id = ID.from(@intCast(a[i]));
1128
+ const id: ID = .from(@intCast(a[i]));
1104
1129
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1105
1130
  printc(" {s}", .{@tagName(@as(Immune, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1106
1131
  },
1107
1132
  .Transform, .CopyBoost => {
1108
- const source = ID.from(@intCast(a[i]));
1133
+ const source: ID = .from(@intCast(a[i]));
1109
1134
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
1110
- const target = ID.from(@intCast(a[i]));
1135
+ const target: ID = .from(@intCast(a[i]));
1111
1136
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
1112
1137
  },
1113
1138
  .Item, .EndItem => {
1114
- var id = ID.from(@intCast(a[i]));
1139
+ var id: ID = .from(@intCast(a[i]));
1115
1140
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1116
1141
  printc(" {s}", .{formatter(gen, .Item, a[i])}, a, b, &i, 1, color);
1117
1142
  if (arg == .Item) {
1118
- id = ID.from(@intCast(a[i]));
1143
+ id = .from(@intCast(a[i]));
1119
1144
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1120
1145
  } else {
1121
1146
  const reason: EndItem = @enumFromInt(a[i]);
@@ -1123,16 +1148,16 @@ pub fn format(
1123
1148
  }
1124
1149
  },
1125
1150
  .SetHP => {
1126
- const id = ID.from(@intCast(a[i]));
1151
+ const id: ID = .from(@intCast(a[i]));
1127
1152
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1128
1153
  switch (endian) {
1129
- .Big => {
1154
+ .big => {
1130
1155
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1131
1156
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1132
1157
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1133
1158
  printc("/{d}", .{hp}, a, b, &i, 2, color);
1134
1159
  },
1135
- .Little => {
1160
+ .little => {
1136
1161
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1137
1162
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1138
1163
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -1143,18 +1168,18 @@ pub fn format(
1143
1168
  printc(" {s}", .{@tagName(@as(SetHP, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1144
1169
  },
1145
1170
  .SideStart => {
1146
- const id = ID.from(@intCast(a[i]));
1171
+ const id: ID = .from(@intCast(a[i]));
1147
1172
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1148
1173
  printc(" {s}", .{@tagName(@as(Side, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1149
1174
  },
1150
1175
  .SideEnd => {
1151
- var id = ID.from(@intCast(a[i]));
1176
+ var id: ID = .from(@intCast(a[i]));
1152
1177
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1153
1178
  const reason: Side = @enumFromInt(a[i]);
1154
1179
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1155
1180
  if (reason == .Spikes) {
1156
1181
  printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
1157
- id = ID.from(@intCast(a[i]));
1182
+ id = .from(@intCast(a[i]));
1158
1183
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1159
1184
  }
1160
1185
  },
@@ -1200,15 +1225,7 @@ pub fn expectLog(
1200
1225
  ) !void {
1201
1226
  if (!enabled) return;
1202
1227
 
1203
- const color = color: {
1204
- if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
1205
- break :color true;
1206
- } else if (std.process.hasEnvVarConstant("NO_COLOR")) {
1207
- break :color false;
1208
- } else {
1209
- break :color std.io.getStdErr().supportsAnsiEscapeCodes();
1210
- }
1211
- };
1228
+ const color = detect();
1212
1229
 
1213
1230
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
1214
1231
  error.TestExpectedEqual => {
@@ -1216,7 +1233,29 @@ pub fn expectLog(
1216
1233
  format(gen, actual, expected, color);
1217
1234
  return err;
1218
1235
  },
1219
- else => return err,
1236
+ };
1237
+ }
1238
+
1239
+ fn detect() bool {
1240
+ const io = std.testing.io;
1241
+ var env = std.testing.environ.createMap(std.testing.allocator) catch unreachable;
1242
+ defer env.deinit();
1243
+
1244
+ const val = env.get("ZIG_DEBUG_COLOR");
1245
+ if (val != null and val.?.len != 0) return true;
1246
+
1247
+ const NO_COLOR = std.zig.EnvVar.NO_COLOR.isSet(&env);
1248
+ const CLICOLOR_FORCE = std.zig.EnvVar.CLICOLOR_FORCE.isSet(&env);
1249
+
1250
+ const stderr = std.Io.File.stderr().writer(io, &.{});
1251
+ return switch (std.Io.Terminal.Mode.detect(
1252
+ io,
1253
+ stderr.file,
1254
+ NO_COLOR,
1255
+ CLICOLOR_FORCE,
1256
+ ) catch unreachable) {
1257
+ .escape_codes => true,
1258
+ else => false,
1220
1259
  };
1221
1260
  }
1222
1261
 
@@ -1224,7 +1263,7 @@ fn expectEqualBytes(expected: []const u8, actual: []const u8, offset: usize) !vo
1224
1263
  for (offset..@min(expected.len, actual.len)) |i| {
1225
1264
  if (expected[i] != actual[i]) {
1226
1265
  print(
1227
- "index {} incorrect. expected 0x{X:0>2}, found 0x{X:0>2}\n",
1266
+ "index {d} incorrect. expected 0x{X:0>2}, found 0x{X:0>2}\n",
1228
1267
  .{ i, expected[i], actual[i] },
1229
1268
  );
1230
1269
  return error.TestExpectedEqual;
@@ -1239,8 +1278,6 @@ fn expectEqualBytes(expected: []const u8, actual: []const u8, offset: usize) !vo
1239
1278
  }
1240
1279
  }
1241
1280
 
1242
- const endian = builtin.target.cpu.arch.endian();
1243
-
1244
1281
  fn N(e: anytype) u8 {
1245
1282
  return @intFromEnum(e);
1246
1283
  }
@@ -1248,19 +1285,12 @@ fn N(e: anytype) u8 {
1248
1285
  const p1 = Player.P1;
1249
1286
  const p2 = Player.P2;
1250
1287
 
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
1288
  var buf: [pkmn.LOGS_SIZE]u8 = undefined;
1262
- var stream: ByteStream = .{ .buffer = &buf };
1263
- var log: FixedLog = .{ .writer = stream.writer() };
1289
+ var writer: Writer = .{ .buffer = &buf };
1290
+ var log: FixedLog = .{ .writer = &writer };
1291
+
1292
+ const gen1 = pkmn.gen1;
1293
+ const gen2 = pkmn.gen2;
1264
1294
 
1265
1295
  const M1 = gen1.Move;
1266
1296
  const S1 = gen1.Species;
@@ -1301,14 +1331,14 @@ test "|move|" {
1301
1331
  &.{ N(ArgType.Move), 0b1100, N(M1.Thunderbolt), 0b0101, N(Move.None) },
1302
1332
  buf[0..5],
1303
1333
  );
1304
- stream.reset();
1334
+ writer.reset();
1305
1335
 
1306
1336
  try log.move(.{ p2.ident(4), M1.Pound, p1.ident(5), M1.Metronome });
1307
1337
  try expectLog1(
1308
1338
  &.{ N(ArgType.Move), 0b1100, N(M1.Pound), 0b0101, N(Move.From), N(M1.Metronome) },
1309
1339
  buf[0..6],
1310
1340
  );
1311
- stream.reset();
1341
+ writer.reset();
1312
1342
 
1313
1343
  try log.move(.{ p2.ident(4), M1.SkullBash, ID{} });
1314
1344
  try log.laststill(.{});
@@ -1323,7 +1353,7 @@ test "|move|" {
1323
1353
  },
1324
1354
  buf[0..6],
1325
1355
  );
1326
- stream.reset();
1356
+ writer.reset();
1327
1357
 
1328
1358
  try log.move(.{ p2.ident(4), M1.Tackle, p1.ident(5) });
1329
1359
  try log.lastmiss(.{});
@@ -1338,7 +1368,7 @@ test "|move|" {
1338
1368
  },
1339
1369
  buf[0..6],
1340
1370
  );
1341
- stream.reset();
1371
+ writer.reset();
1342
1372
  }
1343
1373
 
1344
1374
  test "|switch|" {
@@ -1350,31 +1380,31 @@ test "|switch|" {
1350
1380
  try log.switched(.{ p2.ident(3), &snorlax });
1351
1381
  const par = 0b1000000;
1352
1382
  var expected: []const u8 = switch (endian) {
1353
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
1354
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
1383
+ .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
1384
+ .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
1355
1385
  };
1356
1386
  try expectLog1(expected, buf[0..9]);
1357
- stream.reset();
1387
+ writer.reset();
1358
1388
 
1359
1389
  snorlax.level = 100;
1360
1390
  snorlax.hp = 0;
1361
1391
  snorlax.status = 0;
1362
1392
  try log.switched(.{ p2.ident(3), &snorlax });
1363
1393
  expected = switch (endian) {
1364
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
1365
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
1394
+ .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
1395
+ .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
1366
1396
  };
1367
1397
  try expectLog1(expected, buf[0..9]);
1368
- stream.reset();
1398
+ writer.reset();
1369
1399
 
1370
1400
  snorlax.hp = 400;
1371
1401
  try log.switched(.{ p2.ident(3), &snorlax });
1372
1402
  expected = switch (endian) {
1373
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
1374
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
1403
+ .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
1404
+ .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
1375
1405
  };
1376
1406
  try expectLog1(expected, buf[0..9]);
1377
- stream.reset();
1407
+ writer.reset();
1378
1408
 
1379
1409
  var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.Splash} });
1380
1410
  blissey.level = 91;
@@ -1389,53 +1419,53 @@ test "|switch|" {
1389
1419
  N(gen2.Gender.Female),
1390
1420
  91,
1391
1421
  } ++ switch (endian) {
1392
- .Big => .{ 0, 200, 1, 144, par },
1393
- .Little => .{ 200, 0, 144, 1, par },
1422
+ .big => .{ 0, 200, 1, 144, par },
1423
+ .little => .{ 200, 0, 144, 1, par },
1394
1424
  });
1395
1425
  try expectLog2(expected, buf[0..10]);
1396
- stream.reset();
1426
+ writer.reset();
1397
1427
  }
1398
1428
 
1399
1429
  test "|cant|" {
1400
1430
  try log.cant(.{ p2.ident(6), .Bound });
1401
1431
  try expectLog1(&.{ N(ArgType.Cant), 0b1110, N(Cant.Bound) }, buf[0..3]);
1402
- stream.reset();
1432
+ writer.reset();
1403
1433
 
1404
1434
  try log.cant(.{ p1.ident(2), .Disable, M1.Earthquake });
1405
1435
  try expectLog1(&.{ N(ArgType.Cant), 2, N(Cant.Disable), N(M1.Earthquake) }, buf[0..4]);
1406
- stream.reset();
1436
+ writer.reset();
1407
1437
  }
1408
1438
 
1409
1439
  test "|faint|" {
1410
1440
  try log.faint(.{ p2.ident(2), false });
1411
1441
  try expectLog1(&.{ N(ArgType.Faint), 0b1010 }, buf[0..2]);
1412
- stream.reset();
1442
+ writer.reset();
1413
1443
 
1414
1444
  try log.faint(.{ p2.ident(2), true });
1415
1445
  try expectLog1(&.{ N(ArgType.Faint), 0b1010, N(ArgType.None) }, buf[0..3]);
1416
- stream.reset();
1446
+ writer.reset();
1417
1447
  }
1418
1448
 
1419
1449
  test "|turn|" {
1420
1450
  try log.turn(.{42});
1421
- var expected = switch (endian) {
1422
- .Big => &.{ N(ArgType.Turn), 0, 42, N(ArgType.None) },
1423
- .Little => &.{ N(ArgType.Turn), 42, 0, N(ArgType.None) },
1451
+ const expected = switch (endian) {
1452
+ .big => &.{ N(ArgType.Turn), 0, 42, N(ArgType.None) },
1453
+ .little => &.{ N(ArgType.Turn), 42, 0, N(ArgType.None) },
1424
1454
  };
1425
1455
  try expectLog1(expected, buf[0..4]);
1426
- stream.reset();
1456
+ writer.reset();
1427
1457
  }
1428
1458
 
1429
1459
  test "|win|" {
1430
1460
  try log.win(.{.P2});
1431
1461
  try expectLog1(&.{ N(ArgType.Win), 1, N(ArgType.None) }, buf[0..3]);
1432
- stream.reset();
1462
+ writer.reset();
1433
1463
  }
1434
1464
 
1435
1465
  test "|tie|" {
1436
1466
  try log.tie(.{});
1437
1467
  try expectLog1(&.{ N(ArgType.Tie), N(ArgType.None) }, buf[0..2]);
1438
- stream.reset();
1468
+ writer.reset();
1439
1469
  }
1440
1470
 
1441
1471
  test "|-damage|" {
@@ -1444,31 +1474,31 @@ test "|-damage|" {
1444
1474
  chansey.status = gen1.Status.slp(1);
1445
1475
  try log.damage(.{ p2.ident(2), &chansey, .None });
1446
1476
  var expected: []const u8 = switch (endian) {
1447
- .Big => &.{ N(ArgType.Damage), 0b1010, 2, 100, 2, 191, 1, N(Damage.None) },
1448
- .Little => &.{ N(ArgType.Damage), 0b1010, 100, 2, 191, 2, 1, N(Damage.None) },
1477
+ .big => &.{ N(ArgType.Damage), 0b1010, 2, 100, 2, 191, 1, N(Damage.None) },
1478
+ .little => &.{ N(ArgType.Damage), 0b1010, 100, 2, 191, 2, 1, N(Damage.None) },
1449
1479
  };
1450
1480
  try expectLog1(expected, buf[0..8]);
1451
- stream.reset();
1481
+ writer.reset();
1452
1482
 
1453
1483
  chansey.hp = 100;
1454
1484
  chansey.stats.hp = 256;
1455
1485
  chansey.status = 0;
1456
1486
  try log.damage(.{ p2.ident(2), &chansey, .Confusion });
1457
1487
  expected = switch (endian) {
1458
- .Big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0, N(Damage.Confusion) },
1459
- .Little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0, N(Damage.Confusion) },
1488
+ .big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0, N(Damage.Confusion) },
1489
+ .little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0, N(Damage.Confusion) },
1460
1490
  };
1461
1491
  try expectLog1(expected, buf[0..8]);
1462
- stream.reset();
1492
+ writer.reset();
1463
1493
 
1464
1494
  chansey.status = gen1.Status.init(.PSN);
1465
1495
  try log.damage(.{ p2.ident(2), &chansey, .RecoilOf, p1.ident(1) });
1466
1496
  expected = switch (endian) {
1467
- .Big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0b1000, N(Damage.RecoilOf), 1 },
1468
- .Little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0b1000, N(Damage.RecoilOf), 1 },
1497
+ .big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0b1000, N(Damage.RecoilOf), 1 },
1498
+ .little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0b1000, N(Damage.RecoilOf), 1 },
1469
1499
  };
1470
1500
  try expectLog1(expected, buf[0..9]);
1471
- stream.reset();
1501
+ writer.reset();
1472
1502
  }
1473
1503
 
1474
1504
  test "|-heal|" {
@@ -1477,53 +1507,53 @@ test "|-heal|" {
1477
1507
  chansey.status = gen1.Status.slp(1);
1478
1508
  try log.heal(.{ p2.ident(2), &chansey, .None });
1479
1509
  var expected: []const u8 = switch (endian) {
1480
- .Big => &.{ N(ArgType.Heal), 0b1010, 2, 100, 2, 191, 1, N(Heal.None) },
1481
- .Little => &.{ N(ArgType.Heal), 0b1010, 100, 2, 191, 2, 1, N(Heal.None) },
1510
+ .big => &.{ N(ArgType.Heal), 0b1010, 2, 100, 2, 191, 1, N(Heal.None) },
1511
+ .little => &.{ N(ArgType.Heal), 0b1010, 100, 2, 191, 2, 1, N(Heal.None) },
1482
1512
  };
1483
1513
  try expectLog1(expected, buf[0..8]);
1484
- stream.reset();
1514
+ writer.reset();
1485
1515
 
1486
1516
  chansey.hp = 100;
1487
1517
  chansey.stats.hp = 256;
1488
1518
  chansey.status = 0;
1489
1519
  try log.heal(.{ p2.ident(2), &chansey, .Silent });
1490
1520
  expected = switch (endian) {
1491
- .Big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Silent) },
1492
- .Little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Silent) },
1521
+ .big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Silent) },
1522
+ .little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Silent) },
1493
1523
  };
1494
1524
  try expectLog1(expected, buf[0..8]);
1495
- stream.reset();
1525
+ writer.reset();
1496
1526
 
1497
1527
  try log.heal(.{ p2.ident(2), &chansey, .Drain, p1.ident(1) });
1498
1528
  expected = switch (endian) {
1499
- .Big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Drain), 1 },
1500
- .Little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Drain), 1 },
1529
+ .big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Drain), 1 },
1530
+ .little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Drain), 1 },
1501
1531
  };
1502
1532
  try expectLog1(expected, buf[0..9]);
1503
- stream.reset();
1533
+ writer.reset();
1504
1534
  }
1505
1535
 
1506
1536
  test "|-status|" {
1507
1537
  try log.status(.{ p2.ident(6), gen1.Status.init(.BRN), .None });
1508
1538
  try expectLog1(&.{ N(ArgType.Status), 0b1110, 0b10000, N(Status.None) }, buf[0..4]);
1509
- stream.reset();
1539
+ writer.reset();
1510
1540
 
1511
1541
  try log.status(.{ p2.ident(2), gen1.Status.init(.PSN), .Silent });
1512
1542
  try expectLog1(&.{ N(ArgType.Status), 0b1010, 0b1000, N(Status.Silent) }, buf[0..4]);
1513
- stream.reset();
1543
+ writer.reset();
1514
1544
 
1515
1545
  try log.status(.{ p1.ident(1), gen1.Status.init(.PAR), .From, M1.BodySlam });
1516
1546
  try expectLog1(
1517
1547
  &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M1.BodySlam) },
1518
1548
  buf[0..5],
1519
1549
  );
1520
- stream.reset();
1550
+ writer.reset();
1521
1551
  }
1522
1552
 
1523
1553
  test "|-curestatus|" {
1524
1554
  try log.curestatus(.{ p2.ident(6), gen1.Status.slp(7), .Message });
1525
1555
  try expectLog1(&.{ N(ArgType.CureStatus), 0b1110, 0b111, N(CureStatus.Message) }, buf[0..4]);
1526
- stream.reset();
1556
+ writer.reset();
1527
1557
 
1528
1558
  try log.curestatus(.{ p1.ident(2), gen1.Status.TOX, .Silent });
1529
1559
  try expectLog1(&.{
@@ -1532,86 +1562,86 @@ test "|-curestatus|" {
1532
1562
  0b10001000,
1533
1563
  N(CureStatus.Silent),
1534
1564
  }, buf[0..4]);
1535
- stream.reset();
1565
+ writer.reset();
1536
1566
  }
1537
1567
 
1538
1568
  test "|-boost|" {
1539
1569
  try log.boost(.{ p2.ident(6), .Speed, 2 });
1540
1570
  try expectLog1(&.{ N(ArgType.Boost), 0b1110, N(Boost.Speed), 8 }, buf[0..4]);
1541
- stream.reset();
1571
+ writer.reset();
1542
1572
 
1543
1573
  try log.boost(.{ p1.ident(2), .Rage, 1 });
1544
1574
  try expectLog1(&.{ N(ArgType.Boost), 0b0010, N(Boost.Rage), 7 }, buf[0..4]);
1545
- stream.reset();
1575
+ writer.reset();
1546
1576
 
1547
1577
  try log.boost(.{ p2.ident(3), .Defense, -2 });
1548
1578
  try expectLog1(&.{ N(ArgType.Boost), 0b1011, N(Boost.Defense), 4 }, buf[0..4]);
1549
- stream.reset();
1579
+ writer.reset();
1550
1580
  }
1551
1581
 
1552
1582
  test "|-clearallboost|" {
1553
1583
  try log.clearallboost(.{});
1554
1584
  try expectLog1(&.{N(ArgType.ClearAllBoost)}, buf[0..1]);
1555
- stream.reset();
1585
+ writer.reset();
1556
1586
  }
1557
1587
 
1558
1588
  test "|-fail|" {
1559
1589
  try log.fail(.{ p2.ident(6), .None });
1560
1590
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.None) }, buf[0..3]);
1561
- stream.reset();
1591
+ writer.reset();
1562
1592
 
1563
1593
  try log.fail(.{ p2.ident(6), .Sleep });
1564
1594
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Sleep) }, buf[0..3]);
1565
- stream.reset();
1595
+ writer.reset();
1566
1596
 
1567
1597
  try log.fail(.{ p2.ident(6), .Substitute });
1568
1598
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Substitute) }, buf[0..3]);
1569
- stream.reset();
1599
+ writer.reset();
1570
1600
 
1571
1601
  try log.fail(.{ p2.ident(6), .Weak });
1572
1602
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Weak) }, buf[0..3]);
1573
- stream.reset();
1603
+ writer.reset();
1574
1604
  }
1575
1605
 
1576
1606
  test "|-miss|" {
1577
1607
  try log.miss(.{p2.ident(4)});
1578
1608
  try expectLog1(&.{ N(ArgType.Miss), 0b1100 }, buf[0..2]);
1579
- stream.reset();
1609
+ writer.reset();
1580
1610
  }
1581
1611
  test "|-hitcount|" {
1582
1612
  try log.hitcount(.{ p2.ident(1), 5 });
1583
1613
  try expectLog1(&.{ N(ArgType.HitCount), 0b1001, 5 }, buf[0..3]);
1584
- stream.reset();
1614
+ writer.reset();
1585
1615
  }
1586
1616
 
1587
1617
  test "|-prepare|" {
1588
1618
  try log.prepare(.{ p2.ident(2), M1.Dig });
1589
1619
  try expectLog1(&.{ N(ArgType.Prepare), 0b1010, N(M1.Dig) }, buf[0..3]);
1590
- stream.reset();
1620
+ writer.reset();
1591
1621
  }
1592
1622
 
1593
1623
  test "|-mustrecharge|" {
1594
1624
  try log.mustrecharge(.{p1.ident(6)});
1595
1625
  try expectLog1(&.{ N(ArgType.MustRecharge), 0b0110 }, buf[0..2]);
1596
- stream.reset();
1626
+ writer.reset();
1597
1627
  }
1598
1628
 
1599
1629
  test "|-activate|" {
1600
1630
  try log.activate(.{ p1.ident(2), .Struggle });
1601
1631
  try expectLog1(&.{ N(ArgType.Activate), 0b0010, N(Activate.Struggle) }, buf[0..3]);
1602
- stream.reset();
1632
+ writer.reset();
1603
1633
 
1604
1634
  try log.activate(.{ p2.ident(4), .Mist });
1605
1635
  try expectLog1(&.{ N(ArgType.Activate), 0b1100, N(Activate.Mist) }, buf[0..3]);
1606
- stream.reset();
1636
+ writer.reset();
1607
1637
 
1608
1638
  try log.activate(.{ p2.ident(6), .Substitute });
1609
1639
  try expectLog1(&.{ N(ArgType.Activate), 0b1110, N(Activate.Substitute) }, buf[0..3]);
1610
- stream.reset();
1640
+ writer.reset();
1611
1641
 
1612
1642
  try log.activate(.{ p1.ident(2), .Splash });
1613
1643
  try expectLog1(&.{ N(ArgType.Activate), 0b0010, N(Activate.Splash) }, buf[0..3]);
1614
- stream.reset();
1644
+ writer.reset();
1615
1645
 
1616
1646
  try log.activate(.{ p1.ident(4), .SubstituteBlock, M2.Spite });
1617
1647
  try expectLog1(&.{
@@ -1620,27 +1650,27 @@ test "|-activate|" {
1620
1650
  N(Activate.SubstituteBlock),
1621
1651
  N(M2.Spite),
1622
1652
  }, buf[0..4]);
1623
- stream.reset();
1653
+ writer.reset();
1624
1654
 
1625
1655
  try log.activate(.{ p1.ident(3), .Magnitude, 5 });
1626
1656
  try expectLog1(&.{ N(ArgType.Activate), 0b0011, N(Activate.Magnitude), 5 }, buf[0..4]);
1627
- stream.reset();
1657
+ writer.reset();
1628
1658
  }
1629
1659
 
1630
1660
  test "|-fieldactivate|" {
1631
1661
  try log.fieldactivate(.{});
1632
1662
  try expectLog1(&.{N(ArgType.FieldActivate)}, buf[0..1]);
1633
- stream.reset();
1663
+ writer.reset();
1634
1664
  }
1635
1665
 
1636
1666
  test "|-start|" {
1637
1667
  try log.start(.{ p2.ident(6), .Bide });
1638
1668
  try expectLog1(&.{ N(ArgType.Start), 0b1110, N(Start.Bide) }, buf[0..3]);
1639
- stream.reset();
1669
+ writer.reset();
1640
1670
 
1641
1671
  try log.start(.{ p1.ident(2), .ConfusionSilent });
1642
1672
  try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.ConfusionSilent) }, buf[0..3]);
1643
- stream.reset();
1673
+ writer.reset();
1644
1674
 
1645
1675
  try log.start(.{
1646
1676
  p2.ident(6),
@@ -1652,7 +1682,7 @@ test "|-start|" {
1652
1682
  &.{ N(ArgType.Start), 0b1110, N(Start.TypeChange), 0b1000_1000, 0b1101 },
1653
1683
  buf[0..5],
1654
1684
  );
1655
- stream.reset();
1685
+ writer.reset();
1656
1686
 
1657
1687
  try log.start(.{
1658
1688
  p1.ident(2),
@@ -1664,65 +1694,65 @@ test "|-start|" {
1664
1694
  &.{ N(ArgType.Start), 0b0010, N(Start.TypeChange), 0b0011_0110, 0b1100 },
1665
1695
  buf[0..5],
1666
1696
  );
1667
- stream.reset();
1697
+ writer.reset();
1668
1698
 
1669
1699
  try log.start(.{ p1.ident(2), .Disable, M1.Surf });
1670
1700
  try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Disable), N(M1.Surf) }, buf[0..4]);
1671
- stream.reset();
1701
+ writer.reset();
1672
1702
 
1673
1703
  try log.start(.{ p1.ident(2), .Mimic, M1.Surf });
1674
1704
  try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Mimic), N(M1.Surf) }, buf[0..4]);
1675
- stream.reset();
1705
+ writer.reset();
1676
1706
  }
1677
1707
 
1678
1708
  test "|-end|" {
1679
1709
  try log.end(.{ p2.ident(6), .Bide });
1680
1710
  try expectLog1(&.{ N(ArgType.End), 0b1110, N(End.Bide) }, buf[0..3]);
1681
- stream.reset();
1711
+ writer.reset();
1682
1712
 
1683
1713
  try log.end(.{ p1.ident(2), .ConfusionSilent });
1684
1714
  try expectLog1(&.{ N(ArgType.End), 0b0010, N(End.ConfusionSilent) }, buf[0..3]);
1685
- stream.reset();
1715
+ writer.reset();
1686
1716
  }
1687
1717
 
1688
1718
  test "|-ohko|" {
1689
1719
  try log.ohko(.{});
1690
1720
  try expectLog1(&.{N(ArgType.OHKO)}, buf[0..1]);
1691
- stream.reset();
1721
+ writer.reset();
1692
1722
  }
1693
1723
 
1694
1724
  test "|-crit|" {
1695
1725
  try log.crit(.{p2.ident(5)});
1696
1726
  try expectLog1(&.{ N(ArgType.Crit), 0b1101 }, buf[0..2]);
1697
- stream.reset();
1727
+ writer.reset();
1698
1728
  }
1699
1729
 
1700
1730
  test "|-supereffective|" {
1701
1731
  try log.supereffective(.{p1.ident(1)});
1702
1732
  try expectLog1(&.{ N(ArgType.SuperEffective), 0b0001 }, buf[0..2]);
1703
- stream.reset();
1733
+ writer.reset();
1704
1734
  }
1705
1735
 
1706
1736
  test "|-resisted|" {
1707
1737
  try log.resisted(.{p2.ident(2)});
1708
1738
  try expectLog1(&.{ N(ArgType.Resisted), 0b1010 }, buf[0..2]);
1709
- stream.reset();
1739
+ writer.reset();
1710
1740
  }
1711
1741
 
1712
1742
  test "|-immune|" {
1713
1743
  try log.immune(.{ p1.ident(3), .None });
1714
1744
  try expectLog1(&.{ N(ArgType.Immune), 0b0011, N(Immune.None) }, buf[0..3]);
1715
- stream.reset();
1745
+ writer.reset();
1716
1746
 
1717
1747
  try log.immune(.{ p2.ident(2), .OHKO });
1718
1748
  try expectLog1(&.{ N(ArgType.Immune), 0b1010, N(Immune.OHKO) }, buf[0..3]);
1719
- stream.reset();
1749
+ writer.reset();
1720
1750
  }
1721
1751
 
1722
1752
  test "|-transform|" {
1723
1753
  try log.transform(.{ p2.ident(4), p1.ident(5) });
1724
1754
  try expectLog1(&.{ N(ArgType.Transform), 0b1100, 0b0101 }, buf[0..3]);
1725
- stream.reset();
1755
+ writer.reset();
1726
1756
  }
1727
1757
 
1728
1758
  test "|drag|" {
@@ -1740,73 +1770,73 @@ test "|drag|" {
1740
1770
  N(gen2.Gender.Female),
1741
1771
  91,
1742
1772
  } ++ switch (endian) {
1743
- .Big => .{ 0, 200, 1, 144, par },
1744
- .Little => .{ 200, 0, 144, 1, par },
1773
+ .big => .{ 0, 200, 1, 144, par },
1774
+ .little => .{ 200, 0, 144, 1, par },
1745
1775
  });
1746
1776
  try expectLog2(expected, buf[0..10]);
1747
- stream.reset();
1777
+ writer.reset();
1748
1778
  }
1749
1779
 
1750
1780
  test "|-item|" {
1751
1781
  try log.item(.{ p2.ident(2), I2.GoldBerry, p1.ident(4) });
1752
1782
  try expectLog2(&.{ N(ArgType.Item), 0b1010, N(I2.GoldBerry), 0b0100 }, buf[0..4]);
1753
- stream.reset();
1783
+ writer.reset();
1754
1784
  }
1755
1785
 
1756
1786
  test "|-enditem|" {
1757
1787
  try log.enditem(.{ p1.ident(1), I2.BerserkGene, .None });
1758
1788
  try expectLog2(&.{ N(ArgType.EndItem), 0b0001, N(I2.BerserkGene), N(EndItem.None) }, buf[0..4]);
1759
- stream.reset();
1789
+ writer.reset();
1760
1790
 
1761
1791
  try log.enditem(.{ p2.ident(4), I2.PRZCureBerry, .Eat });
1762
1792
  try expectLog2(&.{ N(ArgType.EndItem), 0b1100, N(I2.PRZCureBerry), N(EndItem.Eat) }, buf[0..4]);
1763
- stream.reset();
1793
+ writer.reset();
1764
1794
  }
1765
1795
 
1766
1796
  test "|-cureteam|" {
1767
1797
  try log.cureteam(.{p2.ident(5)});
1768
1798
  try expectLog2(&.{ N(ArgType.CureTeam), 0b1101 }, buf[0..2]);
1769
- stream.reset();
1799
+ writer.reset();
1770
1800
  }
1771
1801
 
1772
1802
  test "|-sethp|" {
1773
1803
  var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.PainSplit} });
1774
1804
  blissey.hp = 612;
1775
1805
  try log.sethp(.{ p2.ident(2), &blissey, .Silent });
1776
- var expected: []const u8 = switch (endian) {
1777
- .Big => &.{ N(ArgType.SetHP), 0b1010, 2, 100, 2, 201, 0, N(SetHP.Silent) },
1778
- .Little => &.{ N(ArgType.SetHP), 0b1010, 100, 2, 201, 2, 0, N(SetHP.Silent) },
1806
+ const expected: []const u8 = switch (endian) {
1807
+ .big => &.{ N(ArgType.SetHP), 0b1010, 2, 100, 2, 201, 0, N(SetHP.Silent) },
1808
+ .little => &.{ N(ArgType.SetHP), 0b1010, 100, 2, 201, 2, 0, N(SetHP.Silent) },
1779
1809
  };
1780
1810
  try expectLog2(expected, buf[0..8]);
1781
- stream.reset();
1811
+ writer.reset();
1782
1812
  }
1783
1813
 
1784
1814
  test "|-setboost|" {
1785
1815
  try log.setboost(.{ p2.ident(6), 6 });
1786
1816
  try expectLog2(&.{ N(ArgType.SetBoost), 0b1110, 12 }, buf[0..3]);
1787
- stream.reset();
1817
+ writer.reset();
1788
1818
 
1789
1819
  try log.setboost(.{ p2.ident(3), 2 });
1790
1820
  try expectLog2(&.{ N(ArgType.SetBoost), 0b1011, 8 }, buf[0..3]);
1791
- stream.reset();
1821
+ writer.reset();
1792
1822
  }
1793
1823
 
1794
1824
  test "|-copyboost|" {
1795
1825
  try log.copyboost(.{ p2.ident(3), p1.ident(6) });
1796
1826
  try expectLog2(&.{ N(ArgType.CopyBoost), 0b1011, 0b0110 }, buf[0..3]);
1797
- stream.reset();
1827
+ writer.reset();
1798
1828
  }
1799
1829
 
1800
1830
  test "|-sidestart|" {
1801
1831
  try log.sidestart(.{ .P2, .Reflect });
1802
1832
  try expectLog2(&.{ N(ArgType.SideStart), 1, N(Side.Reflect) }, buf[0..3]);
1803
- stream.reset();
1833
+ writer.reset();
1804
1834
  }
1805
1835
 
1806
1836
  test "|-sideend|" {
1807
1837
  try log.sideend(.{ .P2, .LightScreen });
1808
1838
  try expectLog2(&.{ N(ArgType.SideEnd), 1, N(Side.LightScreen) }, buf[0..3]);
1809
- stream.reset();
1839
+ writer.reset();
1810
1840
 
1811
1841
  try log.sideend(.{ .P1, .Spikes, p1.ident(3) });
1812
1842
  try expectLog2(&.{
@@ -1815,27 +1845,27 @@ test "|-sideend|" {
1815
1845
  N(Side.Spikes),
1816
1846
  0b0011,
1817
1847
  }, buf[0..4]);
1818
- stream.reset();
1848
+ writer.reset();
1819
1849
  }
1820
1850
 
1821
1851
  test "|-singlemove|" {
1822
1852
  try log.singlemove(.{ p2.ident(2), M2.DestinyBond });
1823
1853
  try expectLog2(&.{ N(ArgType.SingleMove), 0b1010, N(M2.DestinyBond) }, buf[0..3]);
1824
- stream.reset();
1854
+ writer.reset();
1825
1855
  }
1826
1856
 
1827
1857
  test "|-singleturn|" {
1828
1858
  try log.singleturn(.{ p1.ident(3), M2.Protect });
1829
1859
  try expectLog2(&.{ N(ArgType.SingleTurn), 0b0011, N(M2.Protect) }, buf[0..3]);
1830
- stream.reset();
1860
+ writer.reset();
1831
1861
  }
1832
1862
 
1833
1863
  test "|-weather|" {
1834
1864
  try log.weather(.{ W2.Rain, .Upkeep });
1835
1865
  try expectLog2(&.{ N(ArgType.Weather), N(W2.Rain), N(Weather.Upkeep) }, buf[0..3]);
1836
- stream.reset();
1866
+ writer.reset();
1837
1867
 
1838
1868
  try log.weather(.{ W2.None, .None });
1839
1869
  try expectLog2(&.{ N(ArgType.Weather), N(W2.None), N(Weather.None) }, buf[0..3]);
1840
- stream.reset();
1870
+ writer.reset();
1841
1871
  }