@pkmn/engine 0.1.0-dev.dd5b9081 → 0.1.0-dev.dfd46bbb

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) {
@@ -137,7 +144,16 @@ pub const Damage = enum(u8) {
137
144
  LeechSeed,
138
145
  RecoilOf,
139
146
 
147
+ Bind,
148
+ Wrap,
149
+ FireSpin,
150
+ Clamp,
151
+ Whirlpool,
140
152
  Spikes,
153
+
154
+ Nightmare,
155
+ Curse,
156
+ Sandstorm,
141
157
  };
142
158
 
143
159
  pub const Status = enum(u8) {
@@ -180,8 +196,23 @@ pub const Activate = enum(u8) {
180
196
  Haze,
181
197
  Mist,
182
198
  Struggle,
183
- Substitute,
199
+ Substitute, // FIXME SubstituteDamage
184
200
  Splash,
201
+
202
+ Rage, // TODO
203
+
204
+ Attract,
205
+ LockOn,
206
+ Bind,
207
+ Wrap,
208
+ FireSpin,
209
+ Clamp,
210
+ Whirlpool,
211
+ SubstituteBlock,
212
+
213
+ DestinyBond,
214
+
215
+ BeatUp, // FIXME of
185
216
  };
186
217
 
187
218
  pub const Start = enum(u8) {
@@ -199,6 +230,19 @@ pub const Start = enum(u8) {
199
230
 
200
231
  Disable,
201
232
  Mimic,
233
+
234
+ Attract,
235
+ Nightmare,
236
+ Curse,
237
+ Foresight,
238
+ Encore,
239
+ FutureSight,
240
+
241
+ PerishSong0,
242
+ PerishSong1,
243
+ PerishSong2,
244
+ PerishSong3,
245
+ PerishSong3Silent,
202
246
  };
203
247
 
204
248
  pub const End = enum(u8) {
@@ -207,16 +251,30 @@ pub const End = enum(u8) {
207
251
  Bide,
208
252
  Substitute,
209
253
 
210
- // Silent
254
+ Nightmare,
255
+ Curse,
256
+ Foresight,
257
+ Encore,
258
+ FutureSight,
259
+ LeechSeed,
260
+
261
+ Bind,
262
+ Wrap,
263
+ FireSpin,
264
+ Clamp,
265
+ Whirlpool,
266
+
211
267
  DisableSilent,
212
268
  ConfusionSilent,
213
-
214
- Mist,
215
- FocusEnergy,
216
- LeechSeed,
217
- Toxic,
218
- LightScreen,
219
- Reflect,
269
+ MistSilent,
270
+ FocusEnergySilent,
271
+ LeechSeedSilent,
272
+ ToxicSilent,
273
+ LightScreenSilent,
274
+ ReflectSilent,
275
+ BideSilent,
276
+
277
+ LeechSeedFrom,
220
278
  };
221
279
 
222
280
  pub const Immune = enum(u8) {
@@ -224,6 +282,28 @@ pub const Immune = enum(u8) {
224
282
  OHKO,
225
283
  };
226
284
 
285
+ pub const EndItem = enum(u8) {
286
+ None,
287
+ Eat,
288
+ };
289
+
290
+ pub const SetHP = enum(u8) {
291
+ None,
292
+ Silent,
293
+ };
294
+
295
+ pub const Side = enum(u8) {
296
+ Safeguard,
297
+ Reflect,
298
+ LightScreen,
299
+ Spikes,
300
+ };
301
+
302
+ pub const Weather = enum(u8) {
303
+ None,
304
+ Upkeep,
305
+ };
306
+
227
307
  /// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
228
308
  /// Ignores anything sent to it, though protocol logging should additionally be turned off
229
309
  /// entirely with `options.log`.
@@ -238,7 +318,7 @@ pub fn Log(comptime Writer: type) type {
238
318
 
239
319
  pub const Error = Writer.Error;
240
320
 
241
- pub fn move(self: Self, source: ID, m: anytype, target: ID, from: anytype) Error!void {
321
+ pub fn move(self: Self, source: ID, m: anytype, target: ID) Error!void {
242
322
  if (!enabled) return;
243
323
 
244
324
  assert(m != .None);
@@ -247,25 +327,34 @@ pub fn Log(comptime Writer: type) type {
247
327
  @as(u8, @bitCast(source)),
248
328
  @intFromEnum(m),
249
329
  @as(u8, @bitCast(target)),
330
+ @intFromEnum(Move.None),
250
331
  });
251
- const none = &[_]u8{@intFromEnum(Move.None)};
252
- try self.writer.writeAll(switch (@typeInfo(@TypeOf(from))) {
253
- .Null => none,
254
- .Optional => if (from) |f| blk: {
255
- assert(@intFromEnum(f) != 0);
256
- break :blk &[_]u8{ @intFromEnum(Move.From), @intFromEnum(f) };
257
- } else none,
258
- else => blk: {
259
- assert(@intFromEnum(from) != 0);
260
- break :blk &[_]u8{ @intFromEnum(Move.From), @intFromEnum(from) };
261
- },
332
+ }
333
+
334
+ pub fn moveFrom(self: Self, source: ID, m: anytype, target: ID, from: anytype) Error!void {
335
+ if (!enabled) return;
336
+
337
+ assert(m != .None);
338
+ try self.writer.writeAll(&.{
339
+ @intFromEnum(ArgType.Move),
340
+ @as(u8, @bitCast(source)),
341
+ @intFromEnum(m),
342
+ @as(u8, @bitCast(target)),
262
343
  });
344
+ try self.writer.writeAll(if (@intFromEnum(from) == 0)
345
+ &.{@intFromEnum(Move.None)}
346
+ else
347
+ &.{ @intFromEnum(Move.From), @intFromEnum(from) });
263
348
  }
264
349
 
265
350
  pub fn switched(self: Self, ident: ID, pokemon: anytype) Error!void {
351
+ return switchDrag(self, .Switch, ident, pokemon);
352
+ }
353
+
354
+ fn switchDrag(self: Self, arg: ArgType, ident: ID, pokemon: anytype) Error!void {
266
355
  if (!enabled) return;
267
356
 
268
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @as(u8, @bitCast(ident)) });
357
+ try self.writer.writeAll(&.{ @intFromEnum(arg), @as(u8, @bitCast(ident)) });
269
358
  if (@hasField(@TypeOf(pokemon.*), "dvs")) {
270
359
  try self.writer.writeAll(&.{
271
360
  @intFromEnum(pokemon.species),
@@ -487,6 +576,7 @@ pub fn Log(comptime Writer: type) type {
487
576
  pub fn activate(self: Self, ident: ID, reason: Activate) Error!void {
488
577
  if (!enabled) return;
489
578
 
579
+ assert(reason != .SubstituteBlock); // TODO
490
580
  try self.writer.writeAll(&.{
491
581
  @intFromEnum(ArgType.Activate),
492
582
  @as(u8, @bitCast(ident)),
@@ -494,6 +584,18 @@ pub fn Log(comptime Writer: type) type {
494
584
  });
495
585
  }
496
586
 
587
+ pub fn activateMove(self: Self, ident: ID, reason: Activate, m: anytype) Error!void {
588
+ if (!enabled) return;
589
+
590
+ assert(reason == .SubstituteBlock); // TODO
591
+ try self.writer.writeAll(&.{
592
+ @intFromEnum(ArgType.Activate),
593
+ @as(u8, @bitCast(ident)),
594
+ @intFromEnum(reason),
595
+ @intFromEnum(m),
596
+ });
597
+ }
598
+
497
599
  pub fn fieldactivate(self: Self) Error!void {
498
600
  if (!enabled) return;
499
601
 
@@ -595,6 +697,132 @@ pub fn Log(comptime Writer: type) type {
595
697
  });
596
698
  }
597
699
 
700
+ pub fn drag(self: Self, ident: ID, pokemon: anytype) Error!void {
701
+ return switchDrag(self, .Drag, ident, pokemon);
702
+ }
703
+
704
+ pub fn item(self: Self, target: ID, i: anytype, source: ID) Error!void {
705
+ if (!enabled) return;
706
+
707
+ try self.writer.writeAll(&.{
708
+ @intFromEnum(ArgType.Item),
709
+ @as(u8, @bitCast(target)),
710
+ @intFromEnum(i),
711
+ @as(u8, @bitCast(source)),
712
+ });
713
+ }
714
+
715
+ pub fn enditem(self: Self, ident: ID, i: anytype, reason: EndItem) Error!void {
716
+ if (!enabled) return;
717
+
718
+ try self.writer.writeAll(&.{
719
+ @intFromEnum(ArgType.EndItem),
720
+ @as(u8, @bitCast(ident)),
721
+ @intFromEnum(i),
722
+ @intFromEnum(reason),
723
+ });
724
+ }
725
+
726
+ pub fn cureteam(self: Self, source: ID) Error!void {
727
+ if (!enabled) return;
728
+
729
+ try self.writer.writeAll(&.{
730
+ @intFromEnum(ArgType.CureTeam),
731
+ @as(u8, @bitCast(source)),
732
+ });
733
+ }
734
+
735
+ pub fn sethp(self: Self, ident: ID, pokemon: anytype, reason: SetHP) Error!void {
736
+ if (!enabled) return;
737
+
738
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.SetHP), @as(u8, @bitCast(ident)) });
739
+ try self.writer.writeIntNative(u16, pokemon.hp);
740
+ try self.writer.writeIntNative(u16, pokemon.stats.hp);
741
+ try self.writer.writeAll(&.{pokemon.status});
742
+ try self.writer.writeByte(@intFromEnum(reason));
743
+ }
744
+
745
+ pub fn setboost(self: Self, ident: ID, num: i8) Error!void {
746
+ if (!enabled) return;
747
+
748
+ try self.writer.writeAll(&.{
749
+ @intFromEnum(ArgType.SetBoost),
750
+ @as(u8, @bitCast(ident)),
751
+ @as(u8, @intCast(num + 6)),
752
+ });
753
+ }
754
+
755
+ pub fn copyboost(self: Self, source: ID, target: ID) Error!void {
756
+ if (!enabled) return;
757
+
758
+ try self.writer.writeAll(&.{
759
+ @intFromEnum(ArgType.CopyBoost),
760
+ @as(u8, @bitCast(source)),
761
+ @as(u8, @bitCast(target)),
762
+ });
763
+ }
764
+
765
+ pub fn sidestart(self: Self, player: Player, reason: Side) Error!void {
766
+ if (!enabled) return;
767
+
768
+ try self.writer.writeAll(&.{
769
+ @intFromEnum(ArgType.SideStart),
770
+ @intFromEnum(player),
771
+ @intFromEnum(reason),
772
+ });
773
+ }
774
+
775
+ pub fn sideend(self: Self, player: Player, reason: Side) Error!void {
776
+ if (!enabled) return;
777
+
778
+ assert(@intFromEnum(reason) != @intFromEnum(Side.Spikes));
779
+ try self.writer.writeAll(&.{
780
+ @intFromEnum(ArgType.SideEnd),
781
+ @intFromEnum(player),
782
+ @intFromEnum(reason),
783
+ });
784
+ }
785
+
786
+ pub fn spikesend(self: Self, source: ID) Error!void {
787
+ if (!enabled) return;
788
+
789
+ try self.writer.writeAll(&.{
790
+ @intFromEnum(ArgType.SideEnd),
791
+ @intFromEnum(source.player),
792
+ @intFromEnum(Side.Spikes),
793
+ @as(u8, @bitCast(source)),
794
+ });
795
+ }
796
+
797
+ pub fn singlemove(self: Self, ident: ID, m: anytype) Error!void {
798
+ return single(self, .SingleMove, ident, m);
799
+ }
800
+
801
+ pub fn singleturn(self: Self, ident: ID, m: anytype) Error!void {
802
+ return single(self, .SingleTurn, ident, m);
803
+ }
804
+
805
+ fn single(self: Self, arg: ArgType, ident: ID, m: anytype) Error!void {
806
+ if (!enabled) return;
807
+
808
+ try self.writer.writeAll(&.{
809
+ @intFromEnum(arg),
810
+ @as(u8, @bitCast(ident)),
811
+ @intFromEnum(m),
812
+ });
813
+ }
814
+
815
+ pub fn weather(self: Self, w: anytype, reason: Weather) Error!void {
816
+ if (!enabled) return;
817
+
818
+ assert(!(w == .None and reason == .Upkeep));
819
+ try self.writer.writeAll(&.{
820
+ @intFromEnum(ArgType.Weather),
821
+ @intFromEnum(w),
822
+ @intFromEnum(reason),
823
+ });
824
+ }
825
+
598
826
  pub fn laststill(self: Self) Error!void {
599
827
  if (!enabled) return;
600
828
 
@@ -655,7 +883,7 @@ pub const ByteStream = struct {
655
883
  }
656
884
  };
657
885
 
658
- pub const Kind = enum { Move, Species, Type, Status };
886
+ pub const Kind = enum { Move, Species, Type, Status, Item, Weather };
659
887
 
660
888
  pub fn format(
661
889
  comptime gen: anytype,
@@ -700,6 +928,18 @@ pub fn format(
700
928
  .Resisted => "|-resisted|",
701
929
  .Immune => "|-immune|",
702
930
  .Transform => "|-transform|",
931
+ .Drag => "|drag|",
932
+ .Item => "|-item|",
933
+ .EndItem => "|-enditem|",
934
+ .CureTeam => "|-cureteam|",
935
+ .SetHP => "|-sethp|",
936
+ .SetBoost => "|-setboost|",
937
+ .CopyBoost => "|-copyboost|",
938
+ .SideStart => "|-sidestart|",
939
+ .SideEnd => "|-sideend|",
940
+ .SingleMove => "|-singlemove|",
941
+ .SingleTurn => "|-singleturn|",
942
+ .Weather => "|-weather|",
703
943
  else => unreachable,
704
944
  };
705
945
  printc("{s}", .{name}, a, b, &i, 1, color);
@@ -724,7 +964,7 @@ pub fn format(
724
964
  printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
725
965
  }
726
966
  },
727
- .Switch => {
967
+ .Switch, .Drag => {
728
968
  const id = ID.from(@intCast(a[i]));
729
969
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
730
970
  printc(" {s}", .{formatter(gen, .Species, a[i])}, a, b, &i, 1, color);
@@ -768,6 +1008,7 @@ pub fn format(
768
1008
  .Crit,
769
1009
  .SuperEffective,
770
1010
  .Resisted,
1011
+ .CureTeam,
771
1012
  => {
772
1013
  const id = ID.from(@intCast(a[i]));
773
1014
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
@@ -844,12 +1085,12 @@ pub fn format(
844
1085
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
845
1086
  printc(" {s}", .{@tagName(@as(Fail, @enumFromInt(a[i])))}, a, b, &i, 1, color);
846
1087
  },
847
- .HitCount => {
1088
+ .HitCount, .SetBoost => {
848
1089
  const id = ID.from(@intCast(a[i]));
849
1090
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
850
1091
  printc(" {d}", .{a[i]}, a, b, &i, 1, color);
851
1092
  },
852
- .Prepare => {
1093
+ .Prepare, .SingleMove, .SingleTurn => {
853
1094
  const id = ID.from(@intCast(a[i]));
854
1095
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
855
1096
  printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
@@ -885,12 +1126,64 @@ pub fn format(
885
1126
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
886
1127
  printc(" {s}", .{@tagName(@as(Immune, @enumFromInt(a[i])))}, a, b, &i, 1, color);
887
1128
  },
888
- .Transform => {
1129
+ .Transform, .CopyBoost => {
889
1130
  const source = ID.from(@intCast(a[i]));
890
1131
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
891
1132
  const target = ID.from(@intCast(a[i]));
892
1133
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
893
1134
  },
1135
+ .Item, .EndItem => {
1136
+ var id = ID.from(@intCast(a[i]));
1137
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1138
+ printc(" {s}", .{formatter(gen, .Item, a[i])}, a, b, &i, 1, color);
1139
+ if (arg == .Item) {
1140
+ id = ID.from(@intCast(a[i]));
1141
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1142
+ } else {
1143
+ const reason: EndItem = @enumFromInt(a[i]);
1144
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1145
+ }
1146
+ },
1147
+ .SetHP => {
1148
+ const id = ID.from(@intCast(a[i]));
1149
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1150
+ switch (endian) {
1151
+ .Big => {
1152
+ var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1153
+ printc(" {d}", .{hp}, a, b, &i, 2, color);
1154
+ hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1155
+ printc("/{d}", .{hp}, a, b, &i, 2, color);
1156
+ },
1157
+ .Little => {
1158
+ var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1159
+ printc(" {d}", .{hp}, a, b, &i, 2, color);
1160
+ hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1161
+ printc("/{d}", .{hp}, a, b, &i, 2, color);
1162
+ },
1163
+ }
1164
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
1165
+ printc(" {s}", .{@tagName(@as(SetHP, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1166
+ },
1167
+ .SideStart => {
1168
+ const id = ID.from(@intCast(a[i]));
1169
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1170
+ printc(" {s}", .{@tagName(@as(Side, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1171
+ },
1172
+ .SideEnd => {
1173
+ var id = ID.from(@intCast(a[i]));
1174
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1175
+ const reason: Side = @enumFromInt(a[i]);
1176
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1177
+ if (reason == .Spikes) {
1178
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
1179
+ id = ID.from(@intCast(a[i]));
1180
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1181
+ }
1182
+ },
1183
+ .Weather => {
1184
+ printc(" {s}", .{formatter(gen, .Weather, a[i])}, a, b, &i, 1, color);
1185
+ printc(" {s}", .{@tagName(@as(Weather, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1186
+ },
894
1187
  else => unreachable,
895
1188
  }
896
1189
  print("\n", .{});
@@ -988,11 +1281,16 @@ const gen2 = struct {
988
1281
  };
989
1282
 
990
1283
  var buf: [gen1.LOGS_SIZE]u8 = undefined;
991
- var stream = ByteStream{ .buffer = &buf };
1284
+ var stream: ByteStream = .{ .buffer = &buf };
992
1285
  var log: FixedLog = .{ .writer = stream.writer() };
993
1286
 
994
- const M = gen1.Move;
995
- const S = gen1.Species;
1287
+ const M1 = gen1.Move;
1288
+ const S1 = gen1.Species;
1289
+
1290
+ const M2 = gen2.Move;
1291
+ const S2 = gen2.Species;
1292
+ const I2 = gen2.Item;
1293
+ const W2 = gen2.Weather;
996
1294
 
997
1295
  fn expectLog1(expected: []const u8, actual: []const u8) !void {
998
1296
  return expectLog(gen1, expected, actual, 0);
@@ -1008,32 +1306,39 @@ fn formatter(comptime gen: anytype, kind: Kind, byte: u8) []const u8 {
1008
1306
  .Species => @tagName(@as(gen.Species, @enumFromInt(byte))),
1009
1307
  .Type => @tagName(@as(gen.Type, @enumFromInt(byte))),
1010
1308
  .Status => gen.Status.name(byte),
1309
+ .Item => if (@hasDecl(gen, "Item"))
1310
+ @tagName(@as(gen.Item, @enumFromInt(byte)))
1311
+ else
1312
+ unreachable,
1313
+ .Weather => if (@hasDecl(gen, "Weather"))
1314
+ @tagName(@as(gen.Weather, @enumFromInt(byte)))
1315
+ else
1316
+ unreachable,
1011
1317
  };
1012
1318
  }
1013
1319
 
1014
1320
  test "|move|" {
1015
- try log.move(p2.ident(4), M.Thunderbolt, p1.ident(5), null);
1321
+ try log.move(p2.ident(4), M1.Thunderbolt, p1.ident(5));
1016
1322
  try expectLog1(
1017
- &.{ N(ArgType.Move), 0b1100, N(M.Thunderbolt), 0b0101, N(Move.None) },
1323
+ &.{ N(ArgType.Move), 0b1100, N(M1.Thunderbolt), 0b0101, N(Move.None) },
1018
1324
  buf[0..5],
1019
1325
  );
1020
1326
  stream.reset();
1021
1327
 
1022
- try log.move(p2.ident(4), M.Wrap, p1.ident(5), M.Wrap);
1023
- const wrap = N(M.Wrap);
1328
+ try log.moveFrom(p2.ident(4), M1.Pound, p1.ident(5), M1.Metronome);
1024
1329
  try expectLog1(
1025
- &.{ N(ArgType.Move), 0b1100, wrap, 0b0101, N(Move.From), wrap },
1330
+ &.{ N(ArgType.Move), 0b1100, N(M1.Pound), 0b0101, N(Move.From), N(M1.Metronome) },
1026
1331
  buf[0..6],
1027
1332
  );
1028
1333
  stream.reset();
1029
1334
 
1030
- try log.move(p2.ident(4), M.SkullBash, .{}, null);
1335
+ try log.move(p2.ident(4), M1.SkullBash, .{});
1031
1336
  try log.laststill();
1032
1337
  try expectLog1(
1033
1338
  &.{
1034
1339
  N(ArgType.Move),
1035
1340
  0b1100,
1036
- N(M.SkullBash),
1341
+ N(M1.SkullBash),
1037
1342
  0,
1038
1343
  N(Move.None),
1039
1344
  N(ArgType.LastStill),
@@ -1042,13 +1347,13 @@ test "|move|" {
1042
1347
  );
1043
1348
  stream.reset();
1044
1349
 
1045
- try log.move(p2.ident(4), M.Tackle, p1.ident(5), null);
1350
+ try log.move(p2.ident(4), M1.Tackle, p1.ident(5));
1046
1351
  try log.lastmiss();
1047
1352
  try expectLog1(
1048
1353
  &.{
1049
1354
  N(ArgType.Move),
1050
1355
  0b1100,
1051
- N(M.Tackle),
1356
+ N(M1.Tackle),
1052
1357
  0b0101,
1053
1358
  N(Move.None),
1054
1359
  N(ArgType.LastMiss),
@@ -1067,8 +1372,8 @@ test "|switch|" {
1067
1372
  try log.switched(p2.ident(3), &snorlax);
1068
1373
  const par = 0b1000000;
1069
1374
  var expected: []const u8 = switch (endian) {
1070
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 91, 0, 200, 1, 144, par },
1071
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 91, 200, 0, 144, 1, par },
1375
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
1376
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
1072
1377
  };
1073
1378
  try expectLog1(expected, buf[0..9]);
1074
1379
  stream.reset();
@@ -1078,8 +1383,8 @@ test "|switch|" {
1078
1383
  snorlax.status = 0;
1079
1384
  try log.switched(p2.ident(3), &snorlax);
1080
1385
  expected = switch (endian) {
1081
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 0, 0, 1, 144, 0 },
1082
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 0, 0, 144, 1, 0 },
1386
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
1387
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
1083
1388
  };
1084
1389
  try expectLog1(expected, buf[0..9]);
1085
1390
  stream.reset();
@@ -1087,8 +1392,8 @@ test "|switch|" {
1087
1392
  snorlax.hp = 400;
1088
1393
  try log.switched(p2.ident(3), &snorlax);
1089
1394
  expected = switch (endian) {
1090
- .Big => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 1, 144, 1, 144, 0 },
1091
- .Little => &.{ N(ArgType.Switch), 0b1011, N(S.Snorlax), 100, 144, 1, 144, 1, 0 },
1395
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
1396
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
1092
1397
  };
1093
1398
  try expectLog1(expected, buf[0..9]);
1094
1399
  stream.reset();
@@ -1102,7 +1407,7 @@ test "|switch|" {
1102
1407
  expected = &(.{
1103
1408
  N(ArgType.Switch),
1104
1409
  0b1011,
1105
- N(gen2.Species.Blissey),
1410
+ N(S2.Blissey),
1106
1411
  N(gen2.Gender.Female),
1107
1412
  91,
1108
1413
  } ++ switch (endian) {
@@ -1118,8 +1423,8 @@ test "|cant|" {
1118
1423
  try expectLog1(&.{ N(ArgType.Cant), 0b1110, N(Cant.Bound) }, buf[0..3]);
1119
1424
  stream.reset();
1120
1425
 
1121
- try log.disabled(p1.ident(2), M.Earthquake);
1122
- try expectLog1(&.{ N(ArgType.Cant), 2, N(Cant.Disable), N(M.Earthquake) }, buf[0..4]);
1426
+ try log.disabled(p1.ident(2), M1.Earthquake);
1427
+ try expectLog1(&.{ N(ArgType.Cant), 2, N(Cant.Disable), N(M1.Earthquake) }, buf[0..4]);
1123
1428
  stream.reset();
1124
1429
  }
1125
1430
 
@@ -1229,9 +1534,9 @@ test "|-status|" {
1229
1534
  try expectLog1(&.{ N(ArgType.Status), 0b1010, 0b1000, N(Status.Silent) }, buf[0..4]);
1230
1535
  stream.reset();
1231
1536
 
1232
- try log.statusFrom(p1.ident(1), gen1.Status.init(.PAR), M.BodySlam);
1537
+ try log.statusFrom(p1.ident(1), gen1.Status.init(.PAR), M1.BodySlam);
1233
1538
  try expectLog1(
1234
- &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M.BodySlam) },
1539
+ &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M1.BodySlam) },
1235
1540
  buf[0..5],
1236
1541
  );
1237
1542
  stream.reset();
@@ -1302,8 +1607,8 @@ test "|-hitcount|" {
1302
1607
  }
1303
1608
 
1304
1609
  test "|-prepare|" {
1305
- try log.prepare(p2.ident(2), M.Dig);
1306
- try expectLog1(&.{ N(ArgType.Prepare), 0b1010, N(M.Dig) }, buf[0..3]);
1610
+ try log.prepare(p2.ident(2), M1.Dig);
1611
+ try expectLog1(&.{ N(ArgType.Prepare), 0b1010, N(M1.Dig) }, buf[0..3]);
1307
1612
  stream.reset();
1308
1613
  }
1309
1614
 
@@ -1360,12 +1665,12 @@ test "|-start|" {
1360
1665
  );
1361
1666
  stream.reset();
1362
1667
 
1363
- try log.startEffect(p1.ident(2), .Disable, M.Surf);
1364
- try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Disable), N(M.Surf) }, buf[0..4]);
1668
+ try log.startEffect(p1.ident(2), .Disable, M1.Surf);
1669
+ try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Disable), N(M1.Surf) }, buf[0..4]);
1365
1670
  stream.reset();
1366
1671
 
1367
- try log.startEffect(p1.ident(2), .Mimic, M.Surf);
1368
- try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Mimic), N(M.Surf) }, buf[0..4]);
1672
+ try log.startEffect(p1.ident(2), .Mimic, M1.Surf);
1673
+ try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Mimic), N(M1.Surf) }, buf[0..4]);
1369
1674
  stream.reset();
1370
1675
  }
1371
1676
 
@@ -1384,21 +1689,25 @@ test "|-ohko|" {
1384
1689
  try expectLog1(&.{N(ArgType.OHKO)}, buf[0..1]);
1385
1690
  stream.reset();
1386
1691
  }
1692
+
1387
1693
  test "|-crit|" {
1388
1694
  try log.crit(p2.ident(5));
1389
1695
  try expectLog1(&.{ N(ArgType.Crit), 0b1101 }, buf[0..2]);
1390
1696
  stream.reset();
1391
1697
  }
1698
+
1392
1699
  test "|-supereffective|" {
1393
1700
  try log.supereffective(p1.ident(1));
1394
1701
  try expectLog1(&.{ N(ArgType.SuperEffective), 0b0001 }, buf[0..2]);
1395
1702
  stream.reset();
1396
1703
  }
1704
+
1397
1705
  test "|-resisted|" {
1398
1706
  try log.resisted(p2.ident(2));
1399
1707
  try expectLog1(&.{ N(ArgType.Resisted), 0b1010 }, buf[0..2]);
1400
1708
  stream.reset();
1401
1709
  }
1710
+
1402
1711
  test "|-immune|" {
1403
1712
  try log.immune(p1.ident(3), .None);
1404
1713
  try expectLog1(&.{ N(ArgType.Immune), 0b0011, N(Immune.None) }, buf[0..3]);
@@ -1408,8 +1717,124 @@ test "|-immune|" {
1408
1717
  try expectLog1(&.{ N(ArgType.Immune), 0b1010, N(Immune.OHKO) }, buf[0..3]);
1409
1718
  stream.reset();
1410
1719
  }
1720
+
1411
1721
  test "|-transform|" {
1412
1722
  try log.transform(p2.ident(4), p1.ident(5));
1413
1723
  try expectLog1(&.{ N(ArgType.Transform), 0b1100, 0b0101 }, buf[0..3]);
1414
1724
  stream.reset();
1415
1725
  }
1726
+
1727
+ test "|drag|" {
1728
+ var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.Splash} });
1729
+ blissey.level = 91;
1730
+ blissey.hp = 200;
1731
+ blissey.stats.hp = 400;
1732
+ blissey.status = gen2.Status.init(.PAR);
1733
+ try log.drag(p2.ident(3), &blissey);
1734
+ const par = 0b1000000;
1735
+ const expected = &(.{
1736
+ N(ArgType.Drag),
1737
+ 0b1011,
1738
+ N(S2.Blissey),
1739
+ N(gen2.Gender.Female),
1740
+ 91,
1741
+ } ++ switch (endian) {
1742
+ .Big => .{ 0, 200, 1, 144, par },
1743
+ .Little => .{ 200, 0, 144, 1, par },
1744
+ });
1745
+ try expectLog2(expected, buf[0..10]);
1746
+ stream.reset();
1747
+ }
1748
+
1749
+ test "|-item|" {
1750
+ try log.item(p2.ident(2), I2.GoldBerry, p1.ident(4));
1751
+ try expectLog2(&.{ N(ArgType.Item), 0b1010, N(I2.GoldBerry), 0b0100 }, buf[0..4]);
1752
+ stream.reset();
1753
+ }
1754
+
1755
+ test "|-enditem|" {
1756
+ try log.enditem(p1.ident(1), I2.BerserkGene, .None);
1757
+ try expectLog2(&.{ N(ArgType.EndItem), 0b0001, N(I2.BerserkGene), N(EndItem.None) }, buf[0..4]);
1758
+ stream.reset();
1759
+
1760
+ try log.enditem(p2.ident(4), I2.PRZCureBerry, .Eat);
1761
+ try expectLog2(&.{ N(ArgType.EndItem), 0b1100, N(I2.PRZCureBerry), N(EndItem.Eat) }, buf[0..4]);
1762
+ stream.reset();
1763
+ }
1764
+
1765
+ test "|-cureteam|" {
1766
+ try log.cureteam(p2.ident(5));
1767
+ try expectLog2(&.{ N(ArgType.CureTeam), 0b1101 }, buf[0..2]);
1768
+ stream.reset();
1769
+ }
1770
+
1771
+ test "|-sethp|" {
1772
+ var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.PainSplit} });
1773
+ blissey.hp = 612;
1774
+ try log.sethp(p2.ident(2), &blissey, .Silent);
1775
+ var expected: []const u8 = switch (endian) {
1776
+ .Big => &.{ N(ArgType.SetHP), 0b1010, 2, 100, 2, 201, 0, N(SetHP.Silent) },
1777
+ .Little => &.{ N(ArgType.SetHP), 0b1010, 100, 2, 201, 2, 0, N(SetHP.Silent) },
1778
+ };
1779
+ try expectLog2(expected, buf[0..8]);
1780
+ stream.reset();
1781
+ }
1782
+
1783
+ test "|-setboost|" {
1784
+ try log.setboost(p2.ident(6), 6);
1785
+ try expectLog2(&.{ N(ArgType.SetBoost), 0b1110, 12 }, buf[0..3]);
1786
+ stream.reset();
1787
+
1788
+ try log.setboost(p2.ident(3), 2);
1789
+ try expectLog2(&.{ N(ArgType.SetBoost), 0b1011, 8 }, buf[0..3]);
1790
+ stream.reset();
1791
+ }
1792
+
1793
+ test "|-copyboost|" {
1794
+ try log.copyboost(p2.ident(3), p1.ident(6));
1795
+ try expectLog2(&.{ N(ArgType.CopyBoost), 0b1011, 0b0110 }, buf[0..3]);
1796
+ stream.reset();
1797
+ }
1798
+
1799
+ test "|-sidestart|" {
1800
+ try log.sidestart(.P2, .Reflect);
1801
+ try expectLog2(&.{ N(ArgType.SideStart), 1, N(Side.Reflect) }, buf[0..3]);
1802
+ stream.reset();
1803
+ }
1804
+
1805
+ test "|-sideend|" {
1806
+ try log.sideend(.P2, .LightScreen);
1807
+ try expectLog2(&.{ N(ArgType.SideEnd), 1, N(Side.LightScreen) }, buf[0..3]);
1808
+ stream.reset();
1809
+
1810
+ try log.spikesend(p1.ident(3));
1811
+ try expectLog2(&.{
1812
+ N(ArgType.SideEnd),
1813
+ 0,
1814
+ N(Side.Spikes),
1815
+ 0b0011,
1816
+ }, buf[0..4]);
1817
+ stream.reset();
1818
+ }
1819
+
1820
+ test "|-singlemove|" {
1821
+ try log.singlemove(p2.ident(2), M2.DestinyBond);
1822
+ try expectLog2(&.{ N(ArgType.SingleMove), 0b1010, N(M2.DestinyBond) }, buf[0..3]);
1823
+ stream.reset();
1824
+ }
1825
+
1826
+ test "|-singleturn|" {
1827
+ try log.singleturn(p1.ident(3), M2.Protect);
1828
+ try expectLog2(&.{ N(ArgType.SingleTurn), 0b0011, N(M2.Protect) }, buf[0..3]);
1829
+ stream.reset();
1830
+ }
1831
+
1832
+ test "|-weather|" {
1833
+ try log.weather(W2.Rain, .Upkeep);
1834
+ try expectLog2(&.{ N(ArgType.Weather), N(W2.Rain), N(Weather.Upkeep) }, buf[0..3]);
1835
+ stream.reset();
1836
+
1837
+ try log.weather(W2.None, .None);
1838
+ try expectLog2(&.{ N(ArgType.Weather), N(W2.None), N(Weather.None) }, buf[0..3]);
1839
+ stream.reset();
1840
+ }