@pkmn/engine 0.1.0-dev.ce4c0b2a → 0.1.0-dev.d127cb34

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