@pkmn/engine 0.1.0-dev.2c13d3ec → 0.1.0-dev.305a932f

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.
@@ -102,6 +102,9 @@ pub const ArgType = enum(u8) {
102
102
  // Gen 8
103
103
  CanDynamax,
104
104
  SwapSideConditions,
105
+
106
+ // Gen 9
107
+ Terastallize,
105
108
  };
106
109
 
107
110
  pub const Move = enum(u8) {
@@ -118,12 +121,19 @@ pub const Cant = enum(u8) {
118
121
  Disable,
119
122
  Recharge,
120
123
  PP,
124
+
125
+ Attract,
121
126
  };
122
127
 
123
128
  pub const Heal = enum(u8) {
124
129
  None,
125
130
  Silent,
126
131
  Drain,
132
+
133
+ Leftovers,
134
+ Berry,
135
+ BerryJuice,
136
+ GoldBerry,
127
137
  };
128
138
 
129
139
  pub const Damage = enum(u8) {
@@ -133,6 +143,13 @@ pub const Damage = enum(u8) {
133
143
  Confusion,
134
144
  LeechSeed,
135
145
  RecoilOf,
146
+
147
+ Bind,
148
+ Wrap,
149
+ FireSpin,
150
+ Clamp,
151
+ Whirlpool,
152
+ Spikes,
136
153
  };
137
154
 
138
155
  pub const Status = enum(u8) {
@@ -177,6 +194,16 @@ pub const Activate = enum(u8) {
177
194
  Struggle,
178
195
  Substitute,
179
196
  Splash,
197
+
198
+ Attract,
199
+ LockOn,
200
+ Bind,
201
+ Wrap,
202
+ FireSpin,
203
+ Clamp,
204
+ Whirlpool,
205
+
206
+ BeatUp, // FIXME of
180
207
  };
181
208
 
182
209
  pub const Start = enum(u8) {
@@ -194,6 +221,18 @@ pub const Start = enum(u8) {
194
221
 
195
222
  Disable,
196
223
  Mimic,
224
+
225
+ Nightmare,
226
+ Curse,
227
+ Foresight,
228
+ Encore,
229
+ FutureSight,
230
+
231
+ PerishSong0,
232
+ PerishSong1,
233
+ PerishSong2,
234
+ PerishSong3,
235
+ PerishSong3Silent,
197
236
  };
198
237
 
199
238
  pub const End = enum(u8) {
@@ -202,16 +241,27 @@ pub const End = enum(u8) {
202
241
  Bide,
203
242
  Substitute,
204
243
 
205
- // Silent
244
+ Nightmare,
245
+ Curse,
246
+ Foresight,
247
+ Encore,
248
+ FutureSight,
249
+ LeechSeed,
250
+ Bind,
251
+ Wrap,
252
+ FireSpin,
253
+ Clamp,
254
+ Whirlpool,
255
+
206
256
  DisableSilent,
207
257
  ConfusionSilent,
208
-
209
- Mist,
210
- FocusEnergy,
211
- LeechSeed,
212
- Toxic,
213
- LightScreen,
214
- Reflect,
258
+ MistSilent,
259
+ FocusEnergySilent,
260
+ LeechSeedSilent,
261
+ ToxicSilent,
262
+ LightScreenSilent,
263
+ ReflectSilent,
264
+ BideSilent,
215
265
  };
216
266
 
217
267
  pub const Immune = enum(u8) {
@@ -219,6 +269,28 @@ pub const Immune = enum(u8) {
219
269
  OHKO,
220
270
  };
221
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
+
222
294
  /// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
223
295
  /// Ignores anything sent to it, though protocol logging should additionally be turned off
224
296
  /// entirely with `options.log`.
@@ -258,10 +330,22 @@ pub fn Log(comptime Writer: type) type {
258
330
  }
259
331
 
260
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 {
261
337
  if (!enabled) return;
262
338
 
263
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @as(u8, @bitCast(ident)) });
264
- 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
+ }
265
349
  try self.writer.writeIntNative(u16, pokemon.hp);
266
350
  try self.writer.writeIntNative(u16, pokemon.stats.hp);
267
351
  try self.writer.writeAll(&.{pokemon.status});
@@ -582,6 +666,133 @@ pub fn Log(comptime Writer: type) type {
582
666
  });
583
667
  }
584
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
+
585
796
  pub fn laststill(self: Self) Error!void {
586
797
  if (!enabled) return;
587
798
 
@@ -642,10 +853,14 @@ pub const ByteStream = struct {
642
853
  }
643
854
  };
644
855
 
645
- pub const Kind = enum { Move, Species, Type, Status };
646
- pub const Formatter = fn (Kind, u8) []const u8;
856
+ pub const Kind = enum { Move, Species, Type, Status, Item, Weather };
647
857
 
648
- 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 {
649
864
  print("\n", .{});
650
865
 
651
866
  var i: usize = 0;
@@ -683,6 +898,18 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
683
898
  .Resisted => "|-resisted|",
684
899
  .Immune => "|-immune|",
685
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|",
686
913
  else => unreachable,
687
914
  };
688
915
  printc("{s}", .{name}, a, b, &i, 1, color);
@@ -698,17 +925,27 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
698
925
  .Move => {
699
926
  const source = ID.from(@intCast(a[i]));
700
927
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
701
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
928
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
702
929
  const target = ID.from(@intCast(a[i]));
703
930
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
704
931
  const reason: Move = @enumFromInt(a[i]);
705
932
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
706
- 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
+ }
707
936
  },
708
- .Switch => {
937
+ .Switch, .Drag => {
709
938
  const id = ID.from(@intCast(a[i]));
710
939
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
711
- 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
+ }
712
949
  printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
713
950
  switch (endian) {
714
951
  .Big => {
@@ -724,7 +961,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
724
961
  printc("/{d}", .{hp}, a, b, &i, 2, color);
725
962
  },
726
963
  }
727
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
964
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
728
965
  },
729
966
  .Cant => {
730
967
  const id = ID.from(@intCast(a[i]));
@@ -732,7 +969,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
732
969
  const reason: Cant = @enumFromInt(a[i]);
733
970
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
734
971
  if (reason == .Disable) {
735
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
972
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
736
973
  }
737
974
  },
738
975
  .Faint,
@@ -741,6 +978,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
741
978
  .Crit,
742
979
  .SuperEffective,
743
980
  .Resisted,
981
+ .CureTeam,
744
982
  => {
745
983
  const id = ID.from(@intCast(a[i]));
746
984
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
@@ -772,7 +1010,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
772
1010
  printc("/{d}", .{hp}, a, b, &i, 2, color);
773
1011
  },
774
1012
  }
775
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
1013
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
776
1014
  if (arg == .Damage) {
777
1015
  const reason: Damage = @enumFromInt(a[i]);
778
1016
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
@@ -792,15 +1030,17 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
792
1030
  .Status => {
793
1031
  const id = ID.from(@intCast(a[i]));
794
1032
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
795
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
1033
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
796
1034
  const reason: Status = @enumFromInt(a[i]);
797
1035
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
798
- 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
+ }
799
1039
  },
800
1040
  .CureStatus => {
801
1041
  const id = ID.from(@intCast(a[i]));
802
1042
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
803
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
1043
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
804
1044
  const reason: CureStatus = @enumFromInt(a[i]);
805
1045
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
806
1046
  },
@@ -815,15 +1055,15 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
815
1055
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
816
1056
  printc(" {s}", .{@tagName(@as(Fail, @enumFromInt(a[i])))}, a, b, &i, 1, color);
817
1057
  },
818
- .HitCount => {
1058
+ .HitCount, .SetBoost => {
819
1059
  const id = ID.from(@intCast(a[i]));
820
1060
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
821
1061
  printc(" {d}", .{a[i]}, a, b, &i, 1, color);
822
1062
  },
823
- .Prepare => {
1063
+ .Prepare, .SingleMove, .SingleTurn => {
824
1064
  const id = ID.from(@intCast(a[i]));
825
1065
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
826
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
1066
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
827
1067
  },
828
1068
  .Activate => {
829
1069
  const id = ID.from(@intCast(a[i]));
@@ -838,12 +1078,12 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
838
1078
  if (@as(Start, @enumFromInt(reason)) == .TypeChange) {
839
1079
  const types = @as(gen1.Types, @bitCast(a[i]));
840
1080
  const args = .{
841
- formatter(.Type, @intFromEnum(types.type1)),
842
- formatter(.Type, @intFromEnum(types.type2)),
1081
+ formatter(gen, .Type, @intFromEnum(types.type1)),
1082
+ formatter(gen, .Type, @intFromEnum(types.type2)),
843
1083
  };
844
1084
  printc(" {s}/{s}", args, a, b, &i, 1, color);
845
1085
  } else if (reason >= @intFromEnum(Start.Disable)) {
846
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
1086
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
847
1087
  }
848
1088
  },
849
1089
  .End => {
@@ -856,12 +1096,64 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
856
1096
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
857
1097
  printc(" {s}", .{@tagName(@as(Immune, @enumFromInt(a[i])))}, a, b, &i, 1, color);
858
1098
  },
859
- .Transform => {
1099
+ .Transform, .CopyBoost => {
860
1100
  const source = ID.from(@intCast(a[i]));
861
1101
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
862
1102
  const target = ID.from(@intCast(a[i]));
863
1103
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
864
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
+ },
865
1157
  else => unreachable,
866
1158
  }
867
1159
  print("\n", .{});
@@ -893,7 +1185,7 @@ fn printc(
893
1185
  }
894
1186
 
895
1187
  pub fn expectLog(
896
- comptime formatter: Formatter,
1188
+ comptime gen: anytype,
897
1189
  expected: []const u8,
898
1190
  actual: []const u8,
899
1191
  offset: usize,
@@ -912,8 +1204,8 @@ pub fn expectLog(
912
1204
 
913
1205
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
914
1206
  error.TestExpectedEqual => {
915
- format(formatter, expected, null, color);
916
- format(formatter, actual, expected, color);
1207
+ format(gen, expected, null, color);
1208
+ format(gen, actual, expected, color);
917
1209
  return err;
918
1210
  },
919
1211
  else => return err,
@@ -953,49 +1245,71 @@ const gen1 = struct {
953
1245
  pub const helpers = @import("../gen1/helpers.zig");
954
1246
  };
955
1247
 
1248
+ const gen2 = struct {
1249
+ pub usingnamespace @import("../gen2/data.zig");
1250
+ pub const helpers = @import("../gen2/helpers.zig");
1251
+ };
1252
+
956
1253
  var buf: [gen1.LOGS_SIZE]u8 = undefined;
957
- var stream = ByteStream{ .buffer = &buf };
1254
+ var stream: ByteStream = .{ .buffer = &buf };
958
1255
  var log: FixedLog = .{ .writer = stream.writer() };
959
1256
 
960
- const M = gen1.Move;
961
- 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;
962
1264
 
963
1265
  fn expectLog1(expected: []const u8, actual: []const u8) !void {
964
- return expectLog(gen1Formatter, expected, actual, 0);
1266
+ return expectLog(gen1, expected, actual, 0);
965
1267
  }
966
1268
 
967
- 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 {
968
1274
  return switch (kind) {
969
- .Move => @tagName(@as(M, @enumFromInt(byte))),
970
- .Species => @tagName(@as(S, @enumFromInt(byte))),
971
- .Type => @tagName(@as(gen1.Type, @enumFromInt(byte))),
972
- .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,
973
1287
  };
974
1288
  }
975
1289
 
976
1290
  test "|move|" {
977
- 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);
978
1292
  try expectLog1(
979
- &.{ N(ArgType.Move), 0b1100, N(M.Thunderbolt), 0b0101, N(Move.None) },
1293
+ &.{ N(ArgType.Move), 0b1100, N(M1.Thunderbolt), 0b0101, N(Move.None) },
980
1294
  buf[0..5],
981
1295
  );
982
1296
  stream.reset();
983
1297
 
984
- try log.move(p2.ident(4), M.Wrap, p1.ident(5), M.Wrap);
985
- 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);
986
1300
  try expectLog1(
987
1301
  &.{ N(ArgType.Move), 0b1100, wrap, 0b0101, N(Move.From), wrap },
988
1302
  buf[0..6],
989
1303
  );
990
1304
  stream.reset();
991
1305
 
992
- try log.move(p2.ident(4), M.SkullBash, .{}, null);
1306
+ try log.move(p2.ident(4), M1.SkullBash, .{}, null);
993
1307
  try log.laststill();
994
1308
  try expectLog1(
995
1309
  &.{
996
1310
  N(ArgType.Move),
997
1311
  0b1100,
998
- N(M.SkullBash),
1312
+ N(M1.SkullBash),
999
1313
  0,
1000
1314
  N(Move.None),
1001
1315
  N(ArgType.LastStill),
@@ -1004,13 +1318,13 @@ test "|move|" {
1004
1318
  );
1005
1319
  stream.reset();
1006
1320
 
1007
- 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);
1008
1322
  try log.lastmiss();
1009
1323
  try expectLog1(
1010
1324
  &.{
1011
1325
  N(ArgType.Move),
1012
1326
  0b1100,
1013
- N(M.Tackle),
1327
+ N(M1.Tackle),
1014
1328
  0b0101,
1015
1329
  N(Move.None),
1016
1330
  N(ArgType.LastMiss),
@@ -1029,8 +1343,8 @@ test "|switch|" {
1029
1343
  try log.switched(p2.ident(3), &snorlax);
1030
1344
  const par = 0b1000000;
1031
1345
  var expected: []const u8 = switch (endian) {
1032
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 91, 0, 200, 1, 144, par },
1033
- .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 },
1034
1348
  };
1035
1349
  try expectLog1(expected, buf[0..9]);
1036
1350
  stream.reset();
@@ -1040,8 +1354,8 @@ test "|switch|" {
1040
1354
  snorlax.status = 0;
1041
1355
  try log.switched(p2.ident(3), &snorlax);
1042
1356
  expected = switch (endian) {
1043
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 0, 0, 1, 144, 0 },
1044
- .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 },
1045
1359
  };
1046
1360
  try expectLog1(expected, buf[0..9]);
1047
1361
  stream.reset();
@@ -1049,11 +1363,30 @@ test "|switch|" {
1049
1363
  snorlax.hp = 400;
1050
1364
  try log.switched(p2.ident(3), &snorlax);
1051
1365
  expected = switch (endian) {
1052
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 1, 144, 1, 144, 0 },
1053
- .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 },
1054
1368
  };
1055
1369
  try expectLog1(expected, buf[0..9]);
1056
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();
1057
1390
  }
1058
1391
 
1059
1392
  test "|cant|" {
@@ -1061,8 +1394,8 @@ test "|cant|" {
1061
1394
  try expectLog1(&.{ N(ArgType.Cant), 0b1110, N(Cant.Bound) }, buf[0..3]);
1062
1395
  stream.reset();
1063
1396
 
1064
- try log.disabled(p1.ident(2), M.Earthquake);
1065
- 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]);
1066
1399
  stream.reset();
1067
1400
  }
1068
1401
 
@@ -1172,9 +1505,9 @@ test "|-status|" {
1172
1505
  try expectLog1(&.{ N(ArgType.Status), 0b1010, 0b1000, N(Status.Silent) }, buf[0..4]);
1173
1506
  stream.reset();
1174
1507
 
1175
- 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);
1176
1509
  try expectLog1(
1177
- &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M.BodySlam) },
1510
+ &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M1.BodySlam) },
1178
1511
  buf[0..5],
1179
1512
  );
1180
1513
  stream.reset();
@@ -1245,8 +1578,8 @@ test "|-hitcount|" {
1245
1578
  }
1246
1579
 
1247
1580
  test "|-prepare|" {
1248
- try log.prepare(p2.ident(2), M.Dig);
1249
- 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]);
1250
1583
  stream.reset();
1251
1584
  }
1252
1585
 
@@ -1303,12 +1636,12 @@ test "|-start|" {
1303
1636
  );
1304
1637
  stream.reset();
1305
1638
 
1306
- try log.startEffect(p1.ident(2), .Disable, M.Surf);
1307
- 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]);
1308
1641
  stream.reset();
1309
1642
 
1310
- try log.startEffect(p1.ident(2), .Mimic, M.Surf);
1311
- 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]);
1312
1645
  stream.reset();
1313
1646
  }
1314
1647
 
@@ -1327,21 +1660,25 @@ test "|-ohko|" {
1327
1660
  try expectLog1(&.{N(ArgType.OHKO)}, buf[0..1]);
1328
1661
  stream.reset();
1329
1662
  }
1663
+
1330
1664
  test "|-crit|" {
1331
1665
  try log.crit(p2.ident(5));
1332
1666
  try expectLog1(&.{ N(ArgType.Crit), 0b1101 }, buf[0..2]);
1333
1667
  stream.reset();
1334
1668
  }
1669
+
1335
1670
  test "|-supereffective|" {
1336
1671
  try log.supereffective(p1.ident(1));
1337
1672
  try expectLog1(&.{ N(ArgType.SuperEffective), 0b0001 }, buf[0..2]);
1338
1673
  stream.reset();
1339
1674
  }
1675
+
1340
1676
  test "|-resisted|" {
1341
1677
  try log.resisted(p2.ident(2));
1342
1678
  try expectLog1(&.{ N(ArgType.Resisted), 0b1010 }, buf[0..2]);
1343
1679
  stream.reset();
1344
1680
  }
1681
+
1345
1682
  test "|-immune|" {
1346
1683
  try log.immune(p1.ident(3), .None);
1347
1684
  try expectLog1(&.{ N(ArgType.Immune), 0b0011, N(Immune.None) }, buf[0..3]);
@@ -1351,8 +1688,125 @@ test "|-immune|" {
1351
1688
  try expectLog1(&.{ N(ArgType.Immune), 0b1010, N(Immune.OHKO) }, buf[0..3]);
1352
1689
  stream.reset();
1353
1690
  }
1691
+
1354
1692
  test "|-transform|" {
1355
1693
  try log.transform(p2.ident(4), p1.ident(5));
1356
1694
  try expectLog1(&.{ N(ArgType.Transform), 0b1100, 0b0101 }, buf[0..3]);
1357
1695
  stream.reset();
1358
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
+ }