@pkmn/engine 0.1.0-dev.46307385 → 0.1.0-dev.4cc7c5c2

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.
@@ -121,12 +121,19 @@ pub const Cant = enum(u8) {
121
121
  Disable,
122
122
  Recharge,
123
123
  PP,
124
+
125
+ Attract,
124
126
  };
125
127
 
126
128
  pub const Heal = enum(u8) {
127
129
  None,
128
130
  Silent,
129
131
  Drain,
132
+
133
+ Leftovers,
134
+ Berry,
135
+ BerryJuice,
136
+ GoldBerry,
130
137
  };
131
138
 
132
139
  pub const Damage = enum(u8) {
@@ -136,6 +143,13 @@ pub const Damage = enum(u8) {
136
143
  Confusion,
137
144
  LeechSeed,
138
145
  RecoilOf,
146
+
147
+ Bind,
148
+ Wrap,
149
+ FireSpin,
150
+ Clamp,
151
+ Whirlpool,
152
+ Spikes,
139
153
  };
140
154
 
141
155
  pub const Status = enum(u8) {
@@ -180,6 +194,16 @@ pub const Activate = enum(u8) {
180
194
  Struggle,
181
195
  Substitute,
182
196
  Splash,
197
+
198
+ Attract,
199
+ LockOn,
200
+ Bind,
201
+ Wrap,
202
+ FireSpin,
203
+ Clamp,
204
+ Whirlpool,
205
+
206
+ BeatUp, // FIXME of
183
207
  };
184
208
 
185
209
  pub const Start = enum(u8) {
@@ -197,6 +221,19 @@ pub const Start = enum(u8) {
197
221
 
198
222
  Disable,
199
223
  Mimic,
224
+
225
+ Attract,
226
+ Nightmare,
227
+ Curse,
228
+ Foresight,
229
+ Encore,
230
+ FutureSight,
231
+
232
+ PerishSong0,
233
+ PerishSong1,
234
+ PerishSong2,
235
+ PerishSong3,
236
+ PerishSong3Silent,
200
237
  };
201
238
 
202
239
  pub const End = enum(u8) {
@@ -205,16 +242,27 @@ pub const End = enum(u8) {
205
242
  Bide,
206
243
  Substitute,
207
244
 
208
- // Silent
245
+ Nightmare,
246
+ Curse,
247
+ Foresight,
248
+ Encore,
249
+ FutureSight,
250
+ LeechSeed,
251
+ Bind,
252
+ Wrap,
253
+ FireSpin,
254
+ Clamp,
255
+ Whirlpool,
256
+
209
257
  DisableSilent,
210
258
  ConfusionSilent,
211
-
212
- Mist,
213
- FocusEnergy,
214
- LeechSeed,
215
- Toxic,
216
- LightScreen,
217
- Reflect,
259
+ MistSilent,
260
+ FocusEnergySilent,
261
+ LeechSeedSilent,
262
+ ToxicSilent,
263
+ LightScreenSilent,
264
+ ReflectSilent,
265
+ BideSilent,
218
266
  };
219
267
 
220
268
  pub const Immune = enum(u8) {
@@ -222,6 +270,28 @@ pub const Immune = enum(u8) {
222
270
  OHKO,
223
271
  };
224
272
 
273
+ pub const EndItem = enum(u8) {
274
+ None,
275
+ Eat,
276
+ };
277
+
278
+ pub const SetHP = enum(u8) {
279
+ None,
280
+ Silent,
281
+ };
282
+
283
+ pub const Side = enum(u8) {
284
+ Safeguard,
285
+ Reflect,
286
+ LightScreen,
287
+ Spikes,
288
+ };
289
+
290
+ pub const Weather = enum(u8) {
291
+ None,
292
+ Upkeep,
293
+ };
294
+
225
295
  /// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
226
296
  /// Ignores anything sent to it, though protocol logging should additionally be turned off
227
297
  /// entirely with `options.log`.
@@ -261,10 +331,22 @@ pub fn Log(comptime Writer: type) type {
261
331
  }
262
332
 
263
333
  pub fn switched(self: Self, ident: ID, pokemon: anytype) Error!void {
334
+ return switchDrag(self, .Switch, ident, pokemon);
335
+ }
336
+
337
+ fn switchDrag(self: Self, arg: ArgType, ident: ID, pokemon: anytype) Error!void {
264
338
  if (!enabled) return;
265
339
 
266
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @as(u8, @bitCast(ident)) });
267
- try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
340
+ try self.writer.writeAll(&.{ @intFromEnum(arg), @as(u8, @bitCast(ident)) });
341
+ if (@hasField(@TypeOf(pokemon.*), "dvs")) {
342
+ try self.writer.writeAll(&.{
343
+ @intFromEnum(pokemon.species),
344
+ @intFromEnum(pokemon.dvs.gender),
345
+ pokemon.level,
346
+ });
347
+ } else {
348
+ try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
349
+ }
268
350
  try self.writer.writeIntNative(u16, pokemon.hp);
269
351
  try self.writer.writeIntNative(u16, pokemon.stats.hp);
270
352
  try self.writer.writeAll(&.{pokemon.status});
@@ -585,6 +667,133 @@ pub fn Log(comptime Writer: type) type {
585
667
  });
586
668
  }
587
669
 
670
+ pub fn drag(self: Self, ident: ID, pokemon: anytype) Error!void {
671
+ return switchDrag(self, .Drag, ident, pokemon);
672
+ }
673
+
674
+ pub fn item(self: Self, target: ID, i: anytype, source: ID) Error!void {
675
+ if (!enabled) return;
676
+
677
+ try self.writer.writeAll(&.{
678
+ @intFromEnum(ArgType.Item),
679
+ @as(u8, @bitCast(target)),
680
+ @intFromEnum(i),
681
+ @as(u8, @bitCast(source)),
682
+ });
683
+ }
684
+
685
+ pub fn enditem(self: Self, ident: ID, i: anytype, reason: EndItem) Error!void {
686
+ if (!enabled) return;
687
+
688
+ try self.writer.writeAll(&.{
689
+ @intFromEnum(ArgType.EndItem),
690
+ @as(u8, @bitCast(ident)),
691
+ @intFromEnum(i),
692
+ @intFromEnum(reason),
693
+ });
694
+ }
695
+
696
+ pub fn cureteam(self: Self, source: ID) Error!void {
697
+ if (!enabled) return;
698
+
699
+ try self.writer.writeAll(&.{
700
+ @intFromEnum(ArgType.CureTeam),
701
+ @as(u8, @bitCast(source)),
702
+ });
703
+ }
704
+
705
+ pub fn sethp(self: Self, ident: ID, pokemon: anytype, reason: SetHP) Error!void {
706
+ if (!enabled) return;
707
+
708
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.SetHP), @as(u8, @bitCast(ident)) });
709
+ try self.writer.writeIntNative(u16, pokemon.hp);
710
+ try self.writer.writeIntNative(u16, pokemon.stats.hp);
711
+ try self.writer.writeAll(&.{pokemon.status});
712
+ try self.writer.writeByte(@intFromEnum(reason));
713
+ }
714
+
715
+ pub fn setboost(self: Self, ident: ID, num: i8) Error!void {
716
+ if (!enabled) return;
717
+
718
+ try self.writer.writeAll(&.{
719
+ @intFromEnum(ArgType.SetBoost),
720
+ @as(u8, @bitCast(ident)),
721
+ @as(u8, @intCast(num + 6)),
722
+ });
723
+ }
724
+
725
+ pub fn copyboost(self: Self, source: ID, target: ID) Error!void {
726
+ if (!enabled) return;
727
+
728
+ try self.writer.writeAll(&.{
729
+ @intFromEnum(ArgType.CopyBoost),
730
+ @as(u8, @bitCast(source)),
731
+ @as(u8, @bitCast(target)),
732
+ });
733
+ }
734
+
735
+ pub fn sidestart(self: Self, player: Player, reason: Side) Error!void {
736
+ if (!enabled) return;
737
+
738
+ try self.writer.writeAll(&.{
739
+ @intFromEnum(ArgType.SideStart),
740
+ @intFromEnum(player),
741
+ @intFromEnum(reason),
742
+ });
743
+ }
744
+
745
+ pub fn sideend(self: Self, player: Player, reason: Side) Error!void {
746
+ if (!enabled) return;
747
+
748
+ assert(@intFromEnum(reason) != @intFromEnum(Side.Spikes));
749
+ try self.writer.writeAll(&.{
750
+ @intFromEnum(ArgType.SideEnd),
751
+ @intFromEnum(player),
752
+ @intFromEnum(reason),
753
+ });
754
+ }
755
+
756
+ pub fn spikesend(self: Self, player: Player, m: anytype, source: ID) Error!void {
757
+ if (!enabled) return;
758
+
759
+ try self.writer.writeAll(&.{
760
+ @intFromEnum(ArgType.SideEnd),
761
+ @intFromEnum(player),
762
+ @intFromEnum(Side.Spikes),
763
+ @intFromEnum(m),
764
+ @as(u8, @bitCast(source)),
765
+ });
766
+ }
767
+
768
+ pub fn singlemove(self: Self, ident: ID, m: anytype) Error!void {
769
+ return single(self, .SingleMove, ident, m);
770
+ }
771
+
772
+ pub fn singleturn(self: Self, ident: ID, m: anytype) Error!void {
773
+ return single(self, .SingleTurn, ident, m);
774
+ }
775
+
776
+ fn single(self: Self, arg: ArgType, ident: ID, m: anytype) Error!void {
777
+ if (!enabled) return;
778
+
779
+ try self.writer.writeAll(&.{
780
+ @intFromEnum(arg),
781
+ @as(u8, @bitCast(ident)),
782
+ @intFromEnum(m),
783
+ });
784
+ }
785
+
786
+ pub fn weather(self: Self, w: anytype, reason: Weather) Error!void {
787
+ if (!enabled) return;
788
+
789
+ assert(!(w == .None and reason == .Upkeep));
790
+ try self.writer.writeAll(&.{
791
+ @intFromEnum(ArgType.Weather),
792
+ @intFromEnum(w),
793
+ @intFromEnum(reason),
794
+ });
795
+ }
796
+
588
797
  pub fn laststill(self: Self) Error!void {
589
798
  if (!enabled) return;
590
799
 
@@ -645,10 +854,14 @@ pub const ByteStream = struct {
645
854
  }
646
855
  };
647
856
 
648
- pub const Kind = enum { Move, Species, Type, Status };
649
- pub const Formatter = fn (Kind, u8) []const u8;
857
+ pub const Kind = enum { Move, Species, Type, Status, Item, Weather };
650
858
 
651
- pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, color: bool) void {
859
+ pub fn format(
860
+ comptime gen: anytype,
861
+ a: []const u8,
862
+ b: ?[]const u8,
863
+ color: bool,
864
+ ) void {
652
865
  print("\n", .{});
653
866
 
654
867
  var i: usize = 0;
@@ -686,6 +899,18 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
686
899
  .Resisted => "|-resisted|",
687
900
  .Immune => "|-immune|",
688
901
  .Transform => "|-transform|",
902
+ .Drag => "|drag|",
903
+ .Item => "|-item|",
904
+ .EndItem => "|-enditem|",
905
+ .CureTeam => "|-cureteam|",
906
+ .SetHP => "|-sethp|",
907
+ .SetBoost => "|-setboost|",
908
+ .CopyBoost => "|-copyboost|",
909
+ .SideStart => "|-sidestart|",
910
+ .SideEnd => "|-sideend|",
911
+ .SingleMove => "|-singlemove|",
912
+ .SingleTurn => "|-singleturn|",
913
+ .Weather => "|-weather|",
689
914
  else => unreachable,
690
915
  };
691
916
  printc("{s}", .{name}, a, b, &i, 1, color);
@@ -701,17 +926,27 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
701
926
  .Move => {
702
927
  const source = ID.from(@intCast(a[i]));
703
928
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
704
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
929
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
705
930
  const target = ID.from(@intCast(a[i]));
706
931
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
707
932
  const reason: Move = @enumFromInt(a[i]);
708
933
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
709
- if (reason == .From) printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
934
+ if (reason == .From) {
935
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
936
+ }
710
937
  },
711
- .Switch => {
938
+ .Switch, .Drag => {
712
939
  const id = ID.from(@intCast(a[i]));
713
940
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
714
- printc(" {s}", .{formatter(.Species, a[i])}, a, b, &i, 1, color);
941
+ printc(" {s}", .{formatter(gen, .Species, a[i])}, a, b, &i, 1, color);
942
+ if (@hasDecl(gen, "Gender")) {
943
+ if (a[i] == N(gen.Gender.Unknown)) {
944
+ i += 1;
945
+ } else {
946
+ var gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
947
+ printc(", {s}", .{gender}, a, b, &i, 1, color);
948
+ }
949
+ }
715
950
  printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
716
951
  switch (endian) {
717
952
  .Big => {
@@ -727,7 +962,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
727
962
  printc("/{d}", .{hp}, a, b, &i, 2, color);
728
963
  },
729
964
  }
730
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
965
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
731
966
  },
732
967
  .Cant => {
733
968
  const id = ID.from(@intCast(a[i]));
@@ -735,7 +970,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
735
970
  const reason: Cant = @enumFromInt(a[i]);
736
971
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
737
972
  if (reason == .Disable) {
738
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
973
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
739
974
  }
740
975
  },
741
976
  .Faint,
@@ -744,6 +979,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
744
979
  .Crit,
745
980
  .SuperEffective,
746
981
  .Resisted,
982
+ .CureTeam,
747
983
  => {
748
984
  const id = ID.from(@intCast(a[i]));
749
985
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
@@ -775,7 +1011,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
775
1011
  printc("/{d}", .{hp}, a, b, &i, 2, color);
776
1012
  },
777
1013
  }
778
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
1014
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
779
1015
  if (arg == .Damage) {
780
1016
  const reason: Damage = @enumFromInt(a[i]);
781
1017
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
@@ -795,15 +1031,17 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
795
1031
  .Status => {
796
1032
  const id = ID.from(@intCast(a[i]));
797
1033
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
798
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
1034
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
799
1035
  const reason: Status = @enumFromInt(a[i]);
800
1036
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
801
- if (reason == .From) printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
1037
+ if (reason == .From) {
1038
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
1039
+ }
802
1040
  },
803
1041
  .CureStatus => {
804
1042
  const id = ID.from(@intCast(a[i]));
805
1043
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
806
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
1044
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
807
1045
  const reason: CureStatus = @enumFromInt(a[i]);
808
1046
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
809
1047
  },
@@ -818,15 +1056,15 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
818
1056
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
819
1057
  printc(" {s}", .{@tagName(@as(Fail, @enumFromInt(a[i])))}, a, b, &i, 1, color);
820
1058
  },
821
- .HitCount => {
1059
+ .HitCount, .SetBoost => {
822
1060
  const id = ID.from(@intCast(a[i]));
823
1061
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
824
1062
  printc(" {d}", .{a[i]}, a, b, &i, 1, color);
825
1063
  },
826
- .Prepare => {
1064
+ .Prepare, .SingleMove, .SingleTurn => {
827
1065
  const id = ID.from(@intCast(a[i]));
828
1066
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
829
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
1067
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
830
1068
  },
831
1069
  .Activate => {
832
1070
  const id = ID.from(@intCast(a[i]));
@@ -841,12 +1079,12 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
841
1079
  if (@as(Start, @enumFromInt(reason)) == .TypeChange) {
842
1080
  const types = @as(gen1.Types, @bitCast(a[i]));
843
1081
  const args = .{
844
- formatter(.Type, @intFromEnum(types.type1)),
845
- formatter(.Type, @intFromEnum(types.type2)),
1082
+ formatter(gen, .Type, @intFromEnum(types.type1)),
1083
+ formatter(gen, .Type, @intFromEnum(types.type2)),
846
1084
  };
847
1085
  printc(" {s}/{s}", args, a, b, &i, 1, color);
848
1086
  } else if (reason >= @intFromEnum(Start.Disable)) {
849
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
1087
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
850
1088
  }
851
1089
  },
852
1090
  .End => {
@@ -859,12 +1097,64 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
859
1097
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
860
1098
  printc(" {s}", .{@tagName(@as(Immune, @enumFromInt(a[i])))}, a, b, &i, 1, color);
861
1099
  },
862
- .Transform => {
1100
+ .Transform, .CopyBoost => {
863
1101
  const source = ID.from(@intCast(a[i]));
864
1102
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
865
1103
  const target = ID.from(@intCast(a[i]));
866
1104
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
867
1105
  },
1106
+ .Item, .EndItem => {
1107
+ var id = ID.from(@intCast(a[i]));
1108
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1109
+ printc(" {s}", .{formatter(gen, .Item, a[i])}, a, b, &i, 1, color);
1110
+ if (arg == .Item) {
1111
+ id = ID.from(@intCast(a[i]));
1112
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1113
+ } else {
1114
+ const reason: EndItem = @enumFromInt(a[i]);
1115
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1116
+ }
1117
+ },
1118
+ .SetHP => {
1119
+ const id = ID.from(@intCast(a[i]));
1120
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1121
+ switch (endian) {
1122
+ .Big => {
1123
+ var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1124
+ printc(" {d}", .{hp}, a, b, &i, 2, color);
1125
+ hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1126
+ printc("/{d}", .{hp}, a, b, &i, 2, color);
1127
+ },
1128
+ .Little => {
1129
+ var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1130
+ printc(" {d}", .{hp}, a, b, &i, 2, color);
1131
+ hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1132
+ printc("/{d}", .{hp}, a, b, &i, 2, color);
1133
+ },
1134
+ }
1135
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
1136
+ printc(" {s}", .{@tagName(@as(SetHP, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1137
+ },
1138
+ .SideStart => {
1139
+ const id = ID.from(@intCast(a[i]));
1140
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1141
+ printc(" {s}", .{@tagName(@as(Side, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1142
+ },
1143
+ .SideEnd => {
1144
+ var id = ID.from(@intCast(a[i]));
1145
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1146
+ const reason: Side = @enumFromInt(a[i]);
1147
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1148
+ if (reason == .Spikes) {
1149
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
1150
+ id = ID.from(@intCast(a[i]));
1151
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1152
+ }
1153
+ },
1154
+ .Weather => {
1155
+ printc(" {s}", .{formatter(gen, .Weather, a[i])}, a, b, &i, 1, color);
1156
+ printc(" {s}", .{@tagName(@as(Weather, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1157
+ },
868
1158
  else => unreachable,
869
1159
  }
870
1160
  print("\n", .{});
@@ -896,7 +1186,7 @@ fn printc(
896
1186
  }
897
1187
 
898
1188
  pub fn expectLog(
899
- comptime formatter: Formatter,
1189
+ comptime gen: anytype,
900
1190
  expected: []const u8,
901
1191
  actual: []const u8,
902
1192
  offset: usize,
@@ -915,8 +1205,8 @@ pub fn expectLog(
915
1205
 
916
1206
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
917
1207
  error.TestExpectedEqual => {
918
- format(formatter, expected, null, color);
919
- format(formatter, actual, expected, color);
1208
+ format(gen, expected, null, color);
1209
+ format(gen, actual, expected, color);
920
1210
  return err;
921
1211
  },
922
1212
  else => return err,
@@ -956,49 +1246,71 @@ const gen1 = struct {
956
1246
  pub const helpers = @import("../gen1/helpers.zig");
957
1247
  };
958
1248
 
1249
+ const gen2 = struct {
1250
+ pub usingnamespace @import("../gen2/data.zig");
1251
+ pub const helpers = @import("../gen2/helpers.zig");
1252
+ };
1253
+
959
1254
  var buf: [gen1.LOGS_SIZE]u8 = undefined;
960
- var stream = ByteStream{ .buffer = &buf };
1255
+ var stream: ByteStream = .{ .buffer = &buf };
961
1256
  var log: FixedLog = .{ .writer = stream.writer() };
962
1257
 
963
- const M = gen1.Move;
964
- const S = gen1.Species;
1258
+ const M1 = gen1.Move;
1259
+ const S1 = gen1.Species;
1260
+
1261
+ const M2 = gen2.Move;
1262
+ const S2 = gen2.Species;
1263
+ const I2 = gen2.Item;
1264
+ const W2 = gen2.Weather;
965
1265
 
966
1266
  fn expectLog1(expected: []const u8, actual: []const u8) !void {
967
- return expectLog(gen1Formatter, expected, actual, 0);
1267
+ return expectLog(gen1, expected, actual, 0);
968
1268
  }
969
1269
 
970
- fn gen1Formatter(kind: Kind, byte: u8) []const u8 {
1270
+ fn expectLog2(expected: []const u8, actual: []const u8) !void {
1271
+ return expectLog(gen2, expected, actual, 0);
1272
+ }
1273
+
1274
+ fn formatter(comptime gen: anytype, kind: Kind, byte: u8) []const u8 {
971
1275
  return switch (kind) {
972
- .Move => @tagName(@as(M, @enumFromInt(byte))),
973
- .Species => @tagName(@as(S, @enumFromInt(byte))),
974
- .Type => @tagName(@as(gen1.Type, @enumFromInt(byte))),
975
- .Status => gen1.Status.name(byte),
1276
+ .Move => @tagName(@as(gen.Move, @enumFromInt(byte))),
1277
+ .Species => @tagName(@as(gen.Species, @enumFromInt(byte))),
1278
+ .Type => @tagName(@as(gen.Type, @enumFromInt(byte))),
1279
+ .Status => gen.Status.name(byte),
1280
+ .Item => if (@hasDecl(gen, "Item"))
1281
+ @tagName(@as(gen.Item, @enumFromInt(byte)))
1282
+ else
1283
+ unreachable,
1284
+ .Weather => if (@hasDecl(gen, "Weather"))
1285
+ @tagName(@as(gen.Weather, @enumFromInt(byte)))
1286
+ else
1287
+ unreachable,
976
1288
  };
977
1289
  }
978
1290
 
979
1291
  test "|move|" {
980
- try log.move(p2.ident(4), M.Thunderbolt, p1.ident(5), null);
1292
+ try log.move(p2.ident(4), M1.Thunderbolt, p1.ident(5), null);
981
1293
  try expectLog1(
982
- &.{ N(ArgType.Move), 0b1100, N(M.Thunderbolt), 0b0101, N(Move.None) },
1294
+ &.{ N(ArgType.Move), 0b1100, N(M1.Thunderbolt), 0b0101, N(Move.None) },
983
1295
  buf[0..5],
984
1296
  );
985
1297
  stream.reset();
986
1298
 
987
- try log.move(p2.ident(4), M.Wrap, p1.ident(5), M.Wrap);
988
- const wrap = N(M.Wrap);
1299
+ try log.move(p2.ident(4), M1.Wrap, p1.ident(5), M1.Wrap);
1300
+ const wrap = N(M1.Wrap);
989
1301
  try expectLog1(
990
1302
  &.{ N(ArgType.Move), 0b1100, wrap, 0b0101, N(Move.From), wrap },
991
1303
  buf[0..6],
992
1304
  );
993
1305
  stream.reset();
994
1306
 
995
- try log.move(p2.ident(4), M.SkullBash, .{}, null);
1307
+ try log.move(p2.ident(4), M1.SkullBash, .{}, null);
996
1308
  try log.laststill();
997
1309
  try expectLog1(
998
1310
  &.{
999
1311
  N(ArgType.Move),
1000
1312
  0b1100,
1001
- N(M.SkullBash),
1313
+ N(M1.SkullBash),
1002
1314
  0,
1003
1315
  N(Move.None),
1004
1316
  N(ArgType.LastStill),
@@ -1007,13 +1319,13 @@ test "|move|" {
1007
1319
  );
1008
1320
  stream.reset();
1009
1321
 
1010
- try log.move(p2.ident(4), M.Tackle, p1.ident(5), null);
1322
+ try log.move(p2.ident(4), M1.Tackle, p1.ident(5), null);
1011
1323
  try log.lastmiss();
1012
1324
  try expectLog1(
1013
1325
  &.{
1014
1326
  N(ArgType.Move),
1015
1327
  0b1100,
1016
- N(M.Tackle),
1328
+ N(M1.Tackle),
1017
1329
  0b0101,
1018
1330
  N(Move.None),
1019
1331
  N(ArgType.LastMiss),
@@ -1032,8 +1344,8 @@ test "|switch|" {
1032
1344
  try log.switched(p2.ident(3), &snorlax);
1033
1345
  const par = 0b1000000;
1034
1346
  var expected: []const u8 = switch (endian) {
1035
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 91, 0, 200, 1, 144, par },
1036
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 91, 200, 0, 144, 1, par },
1347
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
1348
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
1037
1349
  };
1038
1350
  try expectLog1(expected, buf[0..9]);
1039
1351
  stream.reset();
@@ -1043,8 +1355,8 @@ test "|switch|" {
1043
1355
  snorlax.status = 0;
1044
1356
  try log.switched(p2.ident(3), &snorlax);
1045
1357
  expected = switch (endian) {
1046
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 0, 0, 1, 144, 0 },
1047
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 0, 0, 144, 1, 0 },
1358
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
1359
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
1048
1360
  };
1049
1361
  try expectLog1(expected, buf[0..9]);
1050
1362
  stream.reset();
@@ -1052,11 +1364,30 @@ test "|switch|" {
1052
1364
  snorlax.hp = 400;
1053
1365
  try log.switched(p2.ident(3), &snorlax);
1054
1366
  expected = switch (endian) {
1055
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 1, 144, 1, 144, 0 },
1056
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 144, 1, 144, 1, 0 },
1367
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
1368
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
1057
1369
  };
1058
1370
  try expectLog1(expected, buf[0..9]);
1059
1371
  stream.reset();
1372
+
1373
+ var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.Splash} });
1374
+ blissey.level = 91;
1375
+ blissey.hp = 200;
1376
+ blissey.stats.hp = 400;
1377
+ blissey.status = gen2.Status.init(.PAR);
1378
+ try log.switched(p2.ident(3), &blissey);
1379
+ expected = &(.{
1380
+ N(ArgType.Switch),
1381
+ 0b1011,
1382
+ N(S2.Blissey),
1383
+ N(gen2.Gender.Female),
1384
+ 91,
1385
+ } ++ switch (endian) {
1386
+ .Big => .{ 0, 200, 1, 144, par },
1387
+ .Little => .{ 200, 0, 144, 1, par },
1388
+ });
1389
+ try expectLog2(expected, buf[0..10]);
1390
+ stream.reset();
1060
1391
  }
1061
1392
 
1062
1393
  test "|cant|" {
@@ -1064,8 +1395,8 @@ test "|cant|" {
1064
1395
  try expectLog1(&.{ N(ArgType.Cant), 0b1110, N(Cant.Bound) }, buf[0..3]);
1065
1396
  stream.reset();
1066
1397
 
1067
- try log.disabled(p1.ident(2), M.Earthquake);
1068
- try expectLog1(&.{ N(ArgType.Cant), 2, N(Cant.Disable), N(M.Earthquake) }, buf[0..4]);
1398
+ try log.disabled(p1.ident(2), M1.Earthquake);
1399
+ try expectLog1(&.{ N(ArgType.Cant), 2, N(Cant.Disable), N(M1.Earthquake) }, buf[0..4]);
1069
1400
  stream.reset();
1070
1401
  }
1071
1402
 
@@ -1175,9 +1506,9 @@ test "|-status|" {
1175
1506
  try expectLog1(&.{ N(ArgType.Status), 0b1010, 0b1000, N(Status.Silent) }, buf[0..4]);
1176
1507
  stream.reset();
1177
1508
 
1178
- try log.statusFrom(p1.ident(1), gen1.Status.init(.PAR), M.BodySlam);
1509
+ try log.statusFrom(p1.ident(1), gen1.Status.init(.PAR), M1.BodySlam);
1179
1510
  try expectLog1(
1180
- &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M.BodySlam) },
1511
+ &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M1.BodySlam) },
1181
1512
  buf[0..5],
1182
1513
  );
1183
1514
  stream.reset();
@@ -1248,8 +1579,8 @@ test "|-hitcount|" {
1248
1579
  }
1249
1580
 
1250
1581
  test "|-prepare|" {
1251
- try log.prepare(p2.ident(2), M.Dig);
1252
- try expectLog1(&.{ N(ArgType.Prepare), 0b1010, N(M.Dig) }, buf[0..3]);
1582
+ try log.prepare(p2.ident(2), M1.Dig);
1583
+ try expectLog1(&.{ N(ArgType.Prepare), 0b1010, N(M1.Dig) }, buf[0..3]);
1253
1584
  stream.reset();
1254
1585
  }
1255
1586
 
@@ -1306,12 +1637,12 @@ test "|-start|" {
1306
1637
  );
1307
1638
  stream.reset();
1308
1639
 
1309
- try log.startEffect(p1.ident(2), .Disable, M.Surf);
1310
- try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Disable), N(M.Surf) }, buf[0..4]);
1640
+ try log.startEffect(p1.ident(2), .Disable, M1.Surf);
1641
+ try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Disable), N(M1.Surf) }, buf[0..4]);
1311
1642
  stream.reset();
1312
1643
 
1313
- try log.startEffect(p1.ident(2), .Mimic, M.Surf);
1314
- try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Mimic), N(M.Surf) }, buf[0..4]);
1644
+ try log.startEffect(p1.ident(2), .Mimic, M1.Surf);
1645
+ try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Mimic), N(M1.Surf) }, buf[0..4]);
1315
1646
  stream.reset();
1316
1647
  }
1317
1648
 
@@ -1330,21 +1661,25 @@ test "|-ohko|" {
1330
1661
  try expectLog1(&.{N(ArgType.OHKO)}, buf[0..1]);
1331
1662
  stream.reset();
1332
1663
  }
1664
+
1333
1665
  test "|-crit|" {
1334
1666
  try log.crit(p2.ident(5));
1335
1667
  try expectLog1(&.{ N(ArgType.Crit), 0b1101 }, buf[0..2]);
1336
1668
  stream.reset();
1337
1669
  }
1670
+
1338
1671
  test "|-supereffective|" {
1339
1672
  try log.supereffective(p1.ident(1));
1340
1673
  try expectLog1(&.{ N(ArgType.SuperEffective), 0b0001 }, buf[0..2]);
1341
1674
  stream.reset();
1342
1675
  }
1676
+
1343
1677
  test "|-resisted|" {
1344
1678
  try log.resisted(p2.ident(2));
1345
1679
  try expectLog1(&.{ N(ArgType.Resisted), 0b1010 }, buf[0..2]);
1346
1680
  stream.reset();
1347
1681
  }
1682
+
1348
1683
  test "|-immune|" {
1349
1684
  try log.immune(p1.ident(3), .None);
1350
1685
  try expectLog1(&.{ N(ArgType.Immune), 0b0011, N(Immune.None) }, buf[0..3]);
@@ -1354,8 +1689,125 @@ test "|-immune|" {
1354
1689
  try expectLog1(&.{ N(ArgType.Immune), 0b1010, N(Immune.OHKO) }, buf[0..3]);
1355
1690
  stream.reset();
1356
1691
  }
1692
+
1357
1693
  test "|-transform|" {
1358
1694
  try log.transform(p2.ident(4), p1.ident(5));
1359
1695
  try expectLog1(&.{ N(ArgType.Transform), 0b1100, 0b0101 }, buf[0..3]);
1360
1696
  stream.reset();
1361
1697
  }
1698
+
1699
+ test "|drag|" {
1700
+ var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.Splash} });
1701
+ blissey.level = 91;
1702
+ blissey.hp = 200;
1703
+ blissey.stats.hp = 400;
1704
+ blissey.status = gen2.Status.init(.PAR);
1705
+ try log.drag(p2.ident(3), &blissey);
1706
+ const par = 0b1000000;
1707
+ const expected = &(.{
1708
+ N(ArgType.Drag),
1709
+ 0b1011,
1710
+ N(S2.Blissey),
1711
+ N(gen2.Gender.Female),
1712
+ 91,
1713
+ } ++ switch (endian) {
1714
+ .Big => .{ 0, 200, 1, 144, par },
1715
+ .Little => .{ 200, 0, 144, 1, par },
1716
+ });
1717
+ try expectLog2(expected, buf[0..10]);
1718
+ stream.reset();
1719
+ }
1720
+
1721
+ test "|-item|" {
1722
+ try log.item(p2.ident(2), I2.GoldBerry, p1.ident(4));
1723
+ try expectLog2(&.{ N(ArgType.Item), 0b1010, N(I2.GoldBerry), 0b0100 }, buf[0..4]);
1724
+ stream.reset();
1725
+ }
1726
+
1727
+ test "|-enditem|" {
1728
+ try log.enditem(p1.ident(1), I2.BerserkGene, .None);
1729
+ try expectLog2(&.{ N(ArgType.EndItem), 0b0001, N(I2.BerserkGene), N(EndItem.None) }, buf[0..4]);
1730
+ stream.reset();
1731
+
1732
+ try log.enditem(p2.ident(4), I2.PRZCureBerry, .Eat);
1733
+ try expectLog2(&.{ N(ArgType.EndItem), 0b1100, N(I2.PRZCureBerry), N(EndItem.Eat) }, buf[0..4]);
1734
+ stream.reset();
1735
+ }
1736
+
1737
+ test "|-cureteam|" {
1738
+ try log.cureteam(p2.ident(5));
1739
+ try expectLog2(&.{ N(ArgType.CureTeam), 0b1101 }, buf[0..2]);
1740
+ stream.reset();
1741
+ }
1742
+
1743
+ test "|-sethp|" {
1744
+ var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.PainSplit} });
1745
+ blissey.hp = 612;
1746
+ try log.sethp(p2.ident(2), &blissey, .Silent);
1747
+ var expected: []const u8 = switch (endian) {
1748
+ .Big => &.{ N(ArgType.SetHP), 0b1010, 2, 100, 2, 201, 0, N(SetHP.Silent) },
1749
+ .Little => &.{ N(ArgType.SetHP), 0b1010, 100, 2, 201, 2, 0, N(SetHP.Silent) },
1750
+ };
1751
+ try expectLog2(expected, buf[0..8]);
1752
+ stream.reset();
1753
+ }
1754
+
1755
+ test "|-setboost|" {
1756
+ try log.setboost(p2.ident(6), 6);
1757
+ try expectLog2(&.{ N(ArgType.SetBoost), 0b1110, 12 }, buf[0..3]);
1758
+ stream.reset();
1759
+
1760
+ try log.setboost(p2.ident(3), 2);
1761
+ try expectLog2(&.{ N(ArgType.SetBoost), 0b1011, 8 }, buf[0..3]);
1762
+ stream.reset();
1763
+ }
1764
+
1765
+ test "|-copyboost|" {
1766
+ try log.copyboost(p2.ident(3), p1.ident(6));
1767
+ try expectLog2(&.{ N(ArgType.CopyBoost), 0b1011, 0b0110 }, buf[0..3]);
1768
+ stream.reset();
1769
+ }
1770
+
1771
+ test "|-sidestart|" {
1772
+ try log.sidestart(.P2, .Reflect);
1773
+ try expectLog2(&.{ N(ArgType.SideStart), 1, N(Side.Reflect) }, buf[0..3]);
1774
+ stream.reset();
1775
+ }
1776
+
1777
+ test "|-sideend|" {
1778
+ try log.sideend(.P2, .LightScreen);
1779
+ try expectLog2(&.{ N(ArgType.SideEnd), 1, N(Side.LightScreen) }, buf[0..3]);
1780
+ stream.reset();
1781
+
1782
+ try log.spikesend(.P1, M2.RapidSpin, p1.ident(3));
1783
+ try expectLog2(&.{
1784
+ N(ArgType.SideEnd),
1785
+ 0,
1786
+ N(Side.Spikes),
1787
+ N(M2.RapidSpin),
1788
+ 0b0011,
1789
+ }, buf[0..5]);
1790
+ stream.reset();
1791
+ }
1792
+
1793
+ test "|-singlemove|" {
1794
+ try log.singlemove(p2.ident(2), M2.DestinyBond);
1795
+ try expectLog2(&.{ N(ArgType.SingleMove), 0b1010, N(M2.DestinyBond) }, buf[0..3]);
1796
+ stream.reset();
1797
+ }
1798
+
1799
+ test "|-singleturn|" {
1800
+ try log.singleturn(p1.ident(3), M2.Protect);
1801
+ try expectLog2(&.{ N(ArgType.SingleTurn), 0b0011, N(M2.Protect) }, buf[0..3]);
1802
+ stream.reset();
1803
+ }
1804
+
1805
+ test "|-weather|" {
1806
+ try log.weather(W2.Rain, .Upkeep);
1807
+ try expectLog2(&.{ N(ArgType.Weather), N(W2.Rain), N(Weather.Upkeep) }, buf[0..3]);
1808
+ stream.reset();
1809
+
1810
+ try log.weather(W2.None, .None);
1811
+ try expectLog2(&.{ N(ArgType.Weather), N(W2.None), N(Weather.None) }, buf[0..3]);
1812
+ stream.reset();
1813
+ }