@pkmn/engine 0.1.0-dev.b01cb48c → 0.1.0-dev.b14f2221

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