@pkmn/engine 0.1.0-dev.09d1baec → 0.1.0-dev.0e82a5ac

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