@pkmn/engine 0.1.0-dev.f3aaee39 → 0.1.0-dev.f6c1a379

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