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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +5 -5
  2. package/build/pkg/data/ids.json +12 -12
  3. package/build/pkg/data/layout.json +2 -2
  4. package/build/pkg/data/protocol.json +69 -12
  5. package/build/pkg/data.d.ts +2 -2
  6. package/build/pkg/gen1.js +2 -2
  7. package/build/pkg/gen1.js.map +1 -1
  8. package/build/pkg/protocol.js +56 -37
  9. package/build/pkg/protocol.js.map +1 -1
  10. package/build/tools/debug.js +3 -1
  11. package/build/tools/debug.js.map +1 -1
  12. package/build.zig +21 -15
  13. package/package.json +28 -16
  14. package/src/lib/binding/node.zig +1 -1
  15. package/src/lib/common/data.zig +5 -5
  16. package/src/lib/common/optional.zig +8 -1
  17. package/src/lib/common/protocol.zig +695 -270
  18. package/src/lib/common/rational.zig +5 -5
  19. package/src/lib/common/rng.zig +14 -5
  20. package/src/lib/gen1/README.md +28 -28
  21. package/src/lib/gen1/calc.zig +4 -4
  22. package/src/lib/gen1/chance.zig +53 -29
  23. package/src/lib/gen1/data/moves.zig +190 -176
  24. package/src/lib/gen1/data/species.zig +2 -2
  25. package/src/lib/gen1/data/types.zig +7 -7
  26. package/src/lib/gen1/data.zig +25 -25
  27. package/src/lib/gen1/helpers.zig +26 -41
  28. package/src/lib/gen1/mechanics.zig +283 -324
  29. package/src/lib/gen2/README.md +18 -72
  30. package/src/lib/gen2/calc.zig +143 -0
  31. package/src/lib/gen2/chance.zig +1314 -0
  32. package/src/lib/gen2/data/items.zig +12 -18
  33. package/src/lib/gen2/data/moves.zig +377 -344
  34. package/src/lib/gen2/data/species.zig +1 -1
  35. package/src/lib/gen2/data/types.zig +134 -31
  36. package/src/lib/gen2/data.zig +44 -36
  37. package/src/lib/gen2/generated.zig +808 -0
  38. package/src/lib/gen2/mechanics.zig +3000 -206
@@ -1,6 +1,8 @@
1
1
  const std = @import("std");
2
2
  const builtin = @import("builtin");
3
3
 
4
+ const pkmn = @import("../pkmn.zig");
5
+
4
6
  const data = @import("./data.zig");
5
7
  const options = @import("./options.zig");
6
8
 
@@ -102,6 +104,7 @@ pub const ArgType = enum(u8) {
102
104
  // Gen 8
103
105
  CanDynamax,
104
106
  SwapSideConditions,
107
+ UpdatePoke,
105
108
 
106
109
  // Gen 9
107
110
  Terastallize,
@@ -121,12 +124,19 @@ pub const Cant = enum(u8) {
121
124
  Disable,
122
125
  Recharge,
123
126
  PP,
127
+
128
+ Attract,
124
129
  };
125
130
 
126
131
  pub const Heal = enum(u8) {
127
132
  None,
128
133
  Silent,
129
134
  Drain,
135
+
136
+ Leftovers,
137
+ Berry,
138
+ BerryJuice,
139
+ GoldBerry,
130
140
  };
131
141
 
132
142
  pub const Damage = enum(u8) {
@@ -137,7 +147,16 @@ pub const Damage = enum(u8) {
137
147
  LeechSeed,
138
148
  RecoilOf,
139
149
 
150
+ Bind,
151
+ Wrap,
152
+ FireSpin,
153
+ Clamp,
154
+ Whirlpool,
140
155
  Spikes,
156
+
157
+ Nightmare,
158
+ Curse,
159
+ Sandstorm,
141
160
  };
142
161
 
143
162
  pub const Status = enum(u8) {
@@ -180,8 +199,25 @@ pub const Activate = enum(u8) {
180
199
  Haze,
181
200
  Mist,
182
201
  Struggle,
183
- Substitute,
202
+ Substitute, // FIXME SubstituteDamage
184
203
  Splash,
204
+
205
+ Rage, // TODO
206
+
207
+ Attract,
208
+ LockOn,
209
+ Bind,
210
+ Wrap,
211
+ FireSpin,
212
+ Clamp,
213
+ Whirlpool,
214
+ SubstituteBlock,
215
+
216
+ DestinyBond,
217
+
218
+ BeatUp, // FIXME of
219
+
220
+ Magnitude,
185
221
  };
186
222
 
187
223
  pub const Start = enum(u8) {
@@ -199,6 +235,19 @@ pub const Start = enum(u8) {
199
235
 
200
236
  Disable,
201
237
  Mimic,
238
+
239
+ Attract,
240
+ Nightmare,
241
+ Curse,
242
+ Foresight,
243
+ Encore,
244
+ FutureSight,
245
+
246
+ PerishSong0,
247
+ PerishSong1,
248
+ PerishSong2,
249
+ PerishSong3,
250
+ PerishSong3Silent,
202
251
  };
203
252
 
204
253
  pub const End = enum(u8) {
@@ -207,16 +256,30 @@ pub const End = enum(u8) {
207
256
  Bide,
208
257
  Substitute,
209
258
 
210
- // Silent
259
+ Nightmare,
260
+ Curse,
261
+ Foresight,
262
+ Encore,
263
+ FutureSight,
264
+ LeechSeed,
265
+
266
+ Bind,
267
+ Wrap,
268
+ FireSpin,
269
+ Clamp,
270
+ Whirlpool,
271
+
211
272
  DisableSilent,
212
273
  ConfusionSilent,
213
-
214
- Mist,
215
- FocusEnergy,
216
- LeechSeed,
217
- Toxic,
218
- LightScreen,
219
- Reflect,
274
+ MistSilent,
275
+ FocusEnergySilent,
276
+ LeechSeedSilent,
277
+ ToxicSilent,
278
+ LightScreenSilent,
279
+ ReflectSilent,
280
+ BideSilent,
281
+
282
+ LeechSeedFrom,
220
283
  };
221
284
 
222
285
  pub const Immune = enum(u8) {
@@ -224,6 +287,28 @@ pub const Immune = enum(u8) {
224
287
  OHKO,
225
288
  };
226
289
 
290
+ pub const EndItem = enum(u8) {
291
+ None,
292
+ Eat,
293
+ };
294
+
295
+ pub const SetHP = enum(u8) {
296
+ None,
297
+ Silent,
298
+ };
299
+
300
+ pub const Side = enum(u8) {
301
+ Safeguard,
302
+ Reflect,
303
+ LightScreen,
304
+ Spikes,
305
+ };
306
+
307
+ pub const Weather = enum(u8) {
308
+ None,
309
+ Upkeep,
310
+ };
311
+
227
312
  /// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
228
313
  /// Ignores anything sent to it, though protocol logging should additionally be turned off
229
314
  /// entirely with `options.log`.
@@ -238,370 +323,484 @@ pub fn Log(comptime Writer: type) type {
238
323
 
239
324
  pub const Error = Writer.Error;
240
325
 
241
- pub fn move(self: Self, source: ID, m: anytype, target: ID, from: anytype) Error!void {
326
+ // source: ID, move: <Move>, target: ID, from?: <Move>
327
+ pub fn move(self: Self, args: anytype) Error!void {
242
328
  if (!enabled) return;
243
329
 
244
- assert(m != .None);
330
+ assert(args[1] != .None);
245
331
  try self.writer.writeAll(&.{
246
332
  @intFromEnum(ArgType.Move),
247
- @as(u8, @bitCast(source)),
248
- @intFromEnum(m),
249
- @as(u8, @bitCast(target)),
250
- });
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
- },
333
+ @as(u8, @bitCast(args[0])),
334
+ @intFromEnum(args[1]),
335
+ @as(u8, @bitCast(args[2])),
262
336
  });
337
+ try self.writer.writeAll(if (args.len < 4 or @intFromEnum(args[3]) == 0)
338
+ &.{@intFromEnum(Move.None)}
339
+ else
340
+ &.{ @intFromEnum(Move.From), @intFromEnum(args[3]) });
341
+ }
342
+
343
+ // ident: ID, pokemon: <Pokemon>
344
+ pub fn switched(self: Self, args: anytype) Error!void {
345
+ return switchDrag(self, .Switch, args);
263
346
  }
264
347
 
265
- pub fn switched(self: Self, ident: ID, pokemon: anytype) Error!void {
348
+ // ident: ID, pokemon: <Pokemon>
349
+ fn switchDrag(self: Self, arg: ArgType, args: anytype) Error!void {
266
350
  if (!enabled) return;
267
351
 
268
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @as(u8, @bitCast(ident)) });
269
- if (@hasField(@TypeOf(pokemon.*), "dvs")) {
352
+ try self.writer.writeAll(&.{ @intFromEnum(arg), @as(u8, @bitCast(args[0])) });
353
+ if (@hasField(@TypeOf(args[1].*), "dvs")) {
270
354
  try self.writer.writeAll(&.{
271
- @intFromEnum(pokemon.species),
272
- @intFromEnum(pokemon.dvs.gender),
273
- pokemon.level,
355
+ @intFromEnum(args[1].species),
356
+ @intFromEnum(args[1].dvs.gender),
357
+ args[1].level,
274
358
  });
275
359
  } else {
276
- try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
360
+ try self.writer.writeAll(&.{ @intFromEnum(args[1].species), args[1].level });
277
361
  }
278
- try self.writer.writeIntNative(u16, pokemon.hp);
279
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
280
- try self.writer.writeAll(&.{pokemon.status});
281
- }
282
-
283
- pub fn cant(self: Self, ident: ID, reason: Cant) Error!void {
284
- if (!enabled) return;
285
-
286
- assert(reason != .Disable);
287
- try self.writer.writeAll(&.{
288
- @intFromEnum(ArgType.Cant),
289
- @as(u8, @bitCast(ident)),
290
- @intFromEnum(reason),
291
- });
362
+ try self.writer.writeIntNative(u16, args[1].hp);
363
+ try self.writer.writeIntNative(u16, args[1].stats.hp);
364
+ try self.writer.writeAll(&.{args[1].status});
292
365
  }
293
366
 
294
- pub fn disabled(self: Self, ident: ID, m: anytype) Error!void {
367
+ // ident: ID, reason: Cant
368
+ // ident: ID, reason: .Disable, move: <Move>
369
+ pub fn cant(self: Self, args: anytype) Error!void {
295
370
  if (!enabled) return;
296
371
 
372
+ assert(args[1] != .Disable or args.len == 3);
297
373
  try self.writer.writeAll(&.{
298
374
  @intFromEnum(ArgType.Cant),
299
- @as(u8, @bitCast(ident)),
300
- @intFromEnum(Cant.Disable),
301
- @intFromEnum(m),
375
+ @as(u8, @bitCast(args[0])),
376
+ @intFromEnum(@as(Cant, args[1])),
302
377
  });
378
+ if (args.len == 3) try self.writer.writeByte(@intFromEnum(args[2]));
303
379
  }
304
380
 
305
- pub fn faint(self: Self, ident: ID, done: bool) Error!void {
381
+ // ident: ID, done: bool
382
+ pub fn faint(self: Self, args: anytype) Error!void {
306
383
  if (!enabled) return;
307
384
 
308
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @as(u8, @bitCast(ident)) });
309
- if (done) try self.writer.writeByte(@intFromEnum(ArgType.None));
385
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @as(u8, @bitCast(args[0])) });
386
+ if (args[1]) try self.writer.writeByte(@intFromEnum(ArgType.None));
310
387
  }
311
388
 
312
- pub fn turn(self: Self, num: u16) Error!void {
389
+ // num: u16
390
+ pub fn turn(self: Self, args: anytype) Error!void {
313
391
  if (!enabled) return;
314
392
 
315
393
  try self.writer.writeByte(@intFromEnum(ArgType.Turn));
316
- try self.writer.writeIntNative(u16, num);
394
+ try self.writer.writeIntNative(u16, args[0]);
317
395
  try self.writer.writeByte(@intFromEnum(ArgType.None));
318
396
  }
319
397
 
320
- pub fn win(self: Self, player: Player) Error!void {
398
+ // player: Player
399
+ pub fn win(self: Self, args: anytype) Error!void {
321
400
  if (!enabled) return;
322
401
 
323
402
  try self.writer.writeAll(&.{
324
403
  @intFromEnum(ArgType.Win),
325
- @intFromEnum(player),
404
+ @intFromEnum(@as(Player, args[0])),
326
405
  @intFromEnum(ArgType.None),
327
406
  });
328
407
  }
329
408
 
330
- pub fn tie(self: Self) Error!void {
409
+ // -
410
+ pub fn tie(self: Self, _: anytype) Error!void {
331
411
  if (!enabled) return;
332
412
 
333
413
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Tie), @intFromEnum(ArgType.None) });
334
414
  }
335
415
 
336
- pub fn damage(self: Self, ident: ID, pokemon: anytype, reason: Damage) Error!void {
416
+ // ident: ID, pokemon: <Pokemon>, reason: Damage
417
+ // ident: ID, pokemon: <Pokemon>, reason: .RecoilOf, source: ID
418
+ pub fn damage(self: Self, args: anytype) Error!void {
337
419
  if (!enabled) return;
338
420
 
339
- assert(@intFromEnum(reason) <= @intFromEnum(Damage.LeechSeed));
340
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
341
- try self.writer.writeIntNative(u16, pokemon.hp);
342
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
343
- try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
421
+ assert(args[2] != .RecoilOf or args.len == 4);
422
+ try self.writer.writeAll(&.{
423
+ @intFromEnum(ArgType.Damage),
424
+ @as(u8, @bitCast(args[0])),
425
+ });
426
+ try self.writer.writeIntNative(u16, args[1].hp);
427
+ try self.writer.writeIntNative(u16, args[1].stats.hp);
428
+ try self.writer.writeAll(&.{ args[1].status, @intFromEnum(@as(Damage, args[2])) });
429
+ if (args.len == 4) try self.writer.writeByte(@as(u8, @bitCast(args[3])));
344
430
  }
345
431
 
346
- pub fn damageOf(
347
- self: Self,
348
- ident: ID,
349
- pokemon: anytype,
350
- reason: Damage,
351
- source: ID,
352
- ) Error!void {
432
+ // ident: ID, pokemon: <Pokemon>, reason: Heal
433
+ // ident: ID, pokemon: <Pokemon>, reason: .Drain, target: ID
434
+ pub fn heal(self: Self, args: anytype) Error!void {
353
435
  if (!enabled) return;
354
436
 
355
- assert(@intFromEnum(reason) == @intFromEnum(Damage.RecoilOf));
356
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
357
- try self.writer.writeIntNative(u16, pokemon.hp);
358
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
359
- try self.writer.writeAll(&.{
360
- pokemon.status,
361
- @intFromEnum(reason),
362
- @as(u8, @bitCast(source)),
363
- });
437
+ assert(args[2] != .Drain or args.len == 4);
438
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(args[0])) });
439
+ try self.writer.writeIntNative(u16, args[1].hp);
440
+ try self.writer.writeIntNative(u16, args[1].stats.hp);
441
+ try self.writer.writeAll(&.{ args[1].status, @intFromEnum(@as(Heal, args[2])) });
442
+ if (args.len == 4) try self.writer.writeByte(@as(u8, @bitCast(args[3])));
364
443
  }
365
444
 
366
- pub fn heal(self: Self, ident: ID, pokemon: anytype, reason: Heal) Error!void {
445
+ // ident: ID, value: u8, reason: Status
446
+ // ident: ID, value: u8, reason: .From, m: <Move>
447
+ pub fn status(self: Self, args: anytype) Error!void {
367
448
  if (!enabled) return;
368
449
 
369
- assert(reason != .Drain);
370
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(ident)) });
371
- try self.writer.writeIntNative(u16, pokemon.hp);
372
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
373
- try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
450
+ assert(args[2] != .From or args.len == 4);
451
+ try self.writer.writeAll(&.{
452
+ @intFromEnum(ArgType.Status),
453
+ @as(u8, @bitCast(args[0])),
454
+ args[1],
455
+ @intFromEnum(@as(Status, args[2])),
456
+ });
457
+ if (args.len == 4) try self.writer.writeByte(@intFromEnum(args[3]));
374
458
  }
375
459
 
376
- pub fn drain(self: Self, source: ID, pokemon: anytype, target: ID) Error!void {
460
+ // ident: ID, value: u8, reason: CureStatus
461
+ pub fn curestatus(self: Self, args: anytype) Error!void {
377
462
  if (!enabled) return;
378
463
 
379
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(source)) });
380
- try self.writer.writeIntNative(u16, pokemon.hp);
381
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
382
464
  try self.writer.writeAll(&.{
383
- pokemon.status,
384
- @intFromEnum(Heal.Drain),
385
- @as(u8, @bitCast(target)),
465
+ @intFromEnum(ArgType.CureStatus),
466
+ @as(u8, @bitCast(args[0])),
467
+ args[1],
468
+ @intFromEnum(@as(CureStatus, args[2])),
386
469
  });
387
470
  }
388
471
 
389
- pub fn status(self: Self, ident: ID, value: u8, reason: Status) Error!void {
472
+ // ident: ID, reason: Boost, num: i8
473
+ pub fn boost(self: Self, args: anytype) Error!void {
390
474
  if (!enabled) return;
391
475
 
392
- assert(reason != .From);
476
+ assert(args[2] != 0 and (args[1] != .Rage or args[2] > 0));
393
477
  try self.writer.writeAll(&.{
394
- @intFromEnum(ArgType.Status),
395
- @as(u8, @bitCast(ident)),
396
- value,
397
- @intFromEnum(reason),
478
+ @intFromEnum(ArgType.Boost),
479
+ @as(u8, @bitCast(args[0])),
480
+ @intFromEnum(@as(Boost, args[1])),
481
+ @as(u8, @intCast(@as(i8, args[2]) + 6)),
398
482
  });
399
483
  }
400
484
 
401
- pub fn statusFrom(self: Self, ident: ID, value: u8, m: anytype) Error!void {
485
+ // -
486
+ pub fn clearallboost(self: Self, _: anytype) Error!void {
487
+ if (!enabled) return;
488
+
489
+ try self.writer.writeAll(&.{@intFromEnum(ArgType.ClearAllBoost)});
490
+ }
491
+
492
+ // ident: ID, reason: Fail
493
+ pub fn fail(self: Self, args: anytype) Error!void {
402
494
  if (!enabled) return;
403
495
 
404
496
  try self.writer.writeAll(&.{
405
- @intFromEnum(ArgType.Status),
406
- @as(u8, @bitCast(ident)),
407
- value,
408
- @intFromEnum(Status.From),
409
- @intFromEnum(m),
497
+ @intFromEnum(ArgType.Fail),
498
+ @as(u8, @bitCast(args[0])),
499
+ @intFromEnum(@as(Fail, args[1])),
410
500
  });
411
501
  }
412
502
 
413
- pub fn curestatus(self: Self, ident: ID, value: u8, reason: CureStatus) Error!void {
503
+ // source: ID
504
+ pub fn miss(self: Self, args: anytype) Error!void {
505
+ if (!enabled) return;
506
+
507
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @as(u8, @bitCast(args[0])) });
508
+ }
509
+
510
+ // ident: ID, num: u8
511
+ pub fn hitcount(self: Self, args: anytype) Error!void {
414
512
  if (!enabled) return;
415
513
 
416
514
  try self.writer.writeAll(&.{
417
- @intFromEnum(ArgType.CureStatus),
418
- @as(u8, @bitCast(ident)),
419
- value,
420
- @intFromEnum(reason),
515
+ @intFromEnum(ArgType.HitCount),
516
+ @as(u8, @bitCast(args[0])),
517
+ args[1],
421
518
  });
422
519
  }
423
520
 
424
- pub fn boost(self: Self, ident: ID, reason: Boost, num: i8) Error!void {
521
+ // source: ID, m: <Move>
522
+ pub fn prepare(self: Self, args: anytype) Error!void {
425
523
  if (!enabled) return;
426
524
 
427
- assert(num != 0 and (reason != .Rage or num > 0));
428
525
  try self.writer.writeAll(&.{
429
- @intFromEnum(ArgType.Boost),
430
- @as(u8, @bitCast(ident)),
431
- @intFromEnum(reason),
432
- @as(u8, @intCast(num + 6)),
526
+ @intFromEnum(ArgType.Prepare),
527
+ @as(u8, @bitCast(args[0])),
528
+ @intFromEnum(args[1]),
433
529
  });
434
530
  }
435
531
 
436
- pub fn clearallboost(self: Self) Error!void {
532
+ // ident: ID
533
+ pub fn mustrecharge(self: Self, args: anytype) Error!void {
437
534
  if (!enabled) return;
438
535
 
439
- try self.writer.writeAll(&.{@intFromEnum(ArgType.ClearAllBoost)});
536
+ try self.writer.writeAll(&.{
537
+ @intFromEnum(ArgType.MustRecharge),
538
+ @as(u8, @bitCast(args[0])),
539
+ });
440
540
  }
441
541
 
442
- pub fn fail(self: Self, ident: ID, reason: Fail) Error!void {
542
+ // ident: ID, reason: Activate
543
+ // ident: ID, reason: .SubstituteBlock, m: <Move>
544
+ // ident: ID, reason: .Magnitude, num: u8
545
+ pub fn activate(self: Self, args: anytype) Error!void {
443
546
  if (!enabled) return;
444
547
 
548
+ assert(args.len <= 4);
549
+ const reason: Activate = args[1];
445
550
  try self.writer.writeAll(&.{
446
- @intFromEnum(ArgType.Fail),
447
- @as(u8, @bitCast(ident)),
551
+ @intFromEnum(ArgType.Activate),
552
+ @as(u8, @bitCast(args[0])),
448
553
  @intFromEnum(reason),
449
554
  });
555
+ if (args.len == 3) {
556
+ if (reason == .SubstituteBlock) {
557
+ try self.writer.writeByte(@intFromEnum(args[2]));
558
+ } else {
559
+ assert(reason == .Magnitude);
560
+ try self.writer.writeByte(args[2]);
561
+ }
562
+ }
450
563
  }
451
564
 
452
- pub fn miss(self: Self, source: ID) Error!void {
565
+ // -
566
+ pub fn fieldactivate(self: Self, _: anytype) Error!void {
453
567
  if (!enabled) return;
454
568
 
455
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @as(u8, @bitCast(source)) });
569
+ try self.writer.writeAll(&.{@intFromEnum(ArgType.FieldActivate)});
456
570
  }
457
571
 
458
- pub fn hitcount(self: Self, ident: ID, num: u8) Error!void {
572
+ // ident: ID, reason: Start
573
+ // ident: ID, reason: .Disable | .Mimic | .Encore, m: <Move>
574
+ // ident: ID, reason: .TypeChange, types: <Types>, target: ID
575
+ pub fn start(self: Self, args: anytype) Error!void {
459
576
  if (!enabled) return;
460
577
 
578
+ assert(args.len <= 4);
579
+ const reason: Start = args[1];
461
580
  try self.writer.writeAll(&.{
462
- @intFromEnum(ArgType.HitCount),
463
- @as(u8, @bitCast(ident)),
464
- num,
581
+ @intFromEnum(ArgType.Start),
582
+ @as(u8, @bitCast(args[0])),
583
+ @intFromEnum(reason),
465
584
  });
585
+ if (args.len == 3) {
586
+ assert(reason == .Disable or reason == .Mimic or reason == .Encore);
587
+ try self.writer.writeByte(@intFromEnum(args[2]));
588
+ } else if (args.len == 4) {
589
+ assert(reason == .TypeChange);
590
+ // FIXME: u16 types in Generation II
591
+ try self.writer.writeAll(&.{
592
+ @as(u8, @bitCast(args[2])),
593
+ @as(u8, @bitCast(args[3])),
594
+ });
595
+ }
466
596
  }
467
597
 
468
- pub fn prepare(self: Self, source: ID, m: anytype) Error!void {
598
+ // ident: ID, reason: End
599
+ pub fn end(self: Self, args: anytype) Error!void {
469
600
  if (!enabled) return;
470
601
 
471
602
  try self.writer.writeAll(&.{
472
- @intFromEnum(ArgType.Prepare),
473
- @as(u8, @bitCast(source)),
474
- @intFromEnum(m),
603
+ @intFromEnum(ArgType.End),
604
+ @as(u8, @bitCast(args[0])),
605
+ @intFromEnum(@as(End, args[1])),
475
606
  });
476
607
  }
477
608
 
478
- pub fn mustrecharge(self: Self, ident: ID) Error!void {
609
+ // -
610
+ pub fn ohko(self: Self, _: anytype) Error!void {
611
+ if (!enabled) return;
612
+
613
+ try self.writer.writeAll(&.{@intFromEnum(ArgType.OHKO)});
614
+ }
615
+
616
+ // ident: ID
617
+ pub fn crit(self: Self, args: anytype) Error!void {
618
+ if (!enabled) return;
619
+
620
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @as(u8, @bitCast(args[0])) });
621
+ }
622
+
623
+ // ident: ID
624
+ pub fn supereffective(self: Self, args: anytype) Error!void {
479
625
  if (!enabled) return;
480
626
 
481
627
  try self.writer.writeAll(&.{
482
- @intFromEnum(ArgType.MustRecharge),
483
- @as(u8, @bitCast(ident)),
628
+ @intFromEnum(ArgType.SuperEffective),
629
+ @as(u8, @bitCast(args[0])),
484
630
  });
485
631
  }
486
632
 
487
- pub fn activate(self: Self, ident: ID, reason: Activate) Error!void {
633
+ // ident: ID
634
+ pub fn resisted(self: Self, args: anytype) Error!void {
488
635
  if (!enabled) return;
489
636
 
490
637
  try self.writer.writeAll(&.{
491
- @intFromEnum(ArgType.Activate),
492
- @as(u8, @bitCast(ident)),
493
- @intFromEnum(reason),
638
+ @intFromEnum(ArgType.Resisted),
639
+ @as(u8, @bitCast(args[0])),
494
640
  });
495
641
  }
496
642
 
497
- pub fn fieldactivate(self: Self) Error!void {
643
+ // ident: ID, reason: Immune
644
+ pub fn immune(self: Self, args: anytype) Error!void {
498
645
  if (!enabled) return;
499
646
 
500
- try self.writer.writeAll(&.{@intFromEnum(ArgType.FieldActivate)});
647
+ try self.writer.writeAll(&.{
648
+ @intFromEnum(ArgType.Immune),
649
+ @as(u8, @bitCast(args[0])),
650
+ @intFromEnum(@as(Immune, args[1])),
651
+ });
501
652
  }
502
653
 
503
- pub fn start(self: Self, ident: ID, reason: Start) Error!void {
654
+ // source: ID, target: ID
655
+ pub fn transform(self: Self, args: anytype) Error!void {
504
656
  if (!enabled) return;
505
657
 
506
- assert(@intFromEnum(reason) < @intFromEnum(Start.TypeChange));
507
658
  try self.writer.writeAll(&.{
508
- @intFromEnum(ArgType.Start),
509
- @as(u8, @bitCast(ident)),
510
- @intFromEnum(reason),
659
+ @intFromEnum(ArgType.Transform),
660
+ @as(u8, @bitCast(args[0])),
661
+ @as(u8, @bitCast(args[1])),
511
662
  });
512
663
  }
513
664
 
514
- pub fn typechange(self: Self, source: ID, types: anytype, target: ID) Error!void {
665
+ // ident: ID, pokemon: <Pokemon>
666
+ pub fn drag(self: Self, args: anytype) Error!void {
667
+ return switchDrag(self, .Drag, args);
668
+ }
669
+
670
+ // target: ID, item: <Item>, source: ID
671
+ pub fn item(self: Self, args: anytype) Error!void {
515
672
  if (!enabled) return;
516
673
 
517
674
  try self.writer.writeAll(&.{
518
- @intFromEnum(ArgType.Start),
519
- @as(u8, @bitCast(source)),
520
- @intFromEnum(Start.TypeChange),
521
- @as(u8, @bitCast(types)),
522
- @as(u8, @bitCast(target)),
675
+ @intFromEnum(ArgType.Item),
676
+ @as(u8, @bitCast(args[0])),
677
+ @intFromEnum(args[1]),
678
+ @as(u8, @bitCast(args[2])),
523
679
  });
524
680
  }
525
681
 
526
- pub fn startEffect(self: Self, ident: ID, reason: Start, m: anytype) Error!void {
682
+ // ident: ID, item: <Item>, reason: EndItem
683
+ pub fn enditem(self: Self, args: anytype) Error!void {
527
684
  if (!enabled) return;
528
685
 
529
- assert(@intFromEnum(reason) > @intFromEnum(Start.TypeChange));
530
686
  try self.writer.writeAll(&.{
531
- @intFromEnum(ArgType.Start),
532
- @as(u8, @bitCast(ident)),
533
- @intFromEnum(reason),
534
- @intFromEnum(m),
687
+ @intFromEnum(ArgType.EndItem),
688
+ @as(u8, @bitCast(args[0])),
689
+ @intFromEnum(args[1]),
690
+ @intFromEnum(@as(EndItem, args[2])),
535
691
  });
536
692
  }
537
693
 
538
- pub fn end(self: Self, ident: ID, reason: End) Error!void {
694
+ // source: ID
695
+ pub fn cureteam(self: Self, args: anytype) Error!void {
539
696
  if (!enabled) return;
540
697
 
541
698
  try self.writer.writeAll(&.{
542
- @intFromEnum(ArgType.End),
543
- @as(u8, @bitCast(ident)),
544
- @intFromEnum(reason),
699
+ @intFromEnum(ArgType.CureTeam),
700
+ @as(u8, @bitCast(args[0])),
545
701
  });
546
702
  }
547
703
 
548
- pub fn ohko(self: Self) Error!void {
704
+ // ident: ID, pokemon: <Pokemon>, reason: SetHP
705
+ pub fn sethp(self: Self, args: anytype) Error!void {
549
706
  if (!enabled) return;
550
707
 
551
- try self.writer.writeAll(&.{@intFromEnum(ArgType.OHKO)});
708
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.SetHP), @as(u8, @bitCast(args[0])) });
709
+ try self.writer.writeIntNative(u16, args[1].hp);
710
+ try self.writer.writeIntNative(u16, args[1].stats.hp);
711
+ try self.writer.writeAll(&.{args[1].status});
712
+ try self.writer.writeByte(@intFromEnum(@as(SetHP, args[2])));
552
713
  }
553
714
 
554
- pub fn crit(self: Self, ident: ID) Error!void {
715
+ // ident: ID, num: i8
716
+ pub fn setboost(self: Self, args: anytype) Error!void {
555
717
  if (!enabled) return;
556
718
 
557
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @as(u8, @bitCast(ident)) });
719
+ try self.writer.writeAll(&.{
720
+ @intFromEnum(ArgType.SetBoost),
721
+ @as(u8, @bitCast(args[0])),
722
+ @as(u8, @intCast(args[1] + 6)),
723
+ });
558
724
  }
559
725
 
560
- pub fn supereffective(self: Self, ident: ID) Error!void {
726
+ // source: ID, target: ID
727
+ pub fn copyboost(self: Self, args: anytype) Error!void {
561
728
  if (!enabled) return;
562
729
 
563
730
  try self.writer.writeAll(&.{
564
- @intFromEnum(ArgType.SuperEffective),
565
- @as(u8, @bitCast(ident)),
731
+ @intFromEnum(ArgType.CopyBoost),
732
+ @as(u8, @bitCast(args[0])),
733
+ @as(u8, @bitCast(args[1])),
566
734
  });
567
735
  }
568
736
 
569
- pub fn resisted(self: Self, ident: ID) Error!void {
737
+ // player: Player, reason: Side
738
+ pub fn sidestart(self: Self, args: anytype) Error!void {
570
739
  if (!enabled) return;
571
740
 
572
741
  try self.writer.writeAll(&.{
573
- @intFromEnum(ArgType.Resisted),
574
- @as(u8, @bitCast(ident)),
742
+ @intFromEnum(ArgType.SideStart),
743
+ @intFromEnum(@as(Player, args[0])),
744
+ @intFromEnum(@as(Side, args[1])),
575
745
  });
576
746
  }
577
747
 
578
- pub fn immune(self: Self, ident: ID, reason: Immune) Error!void {
748
+ // player: Player, reason: Side
749
+ // player: Player, reason: .Spikes, source: ID
750
+ pub fn sideend(self: Self, args: anytype) Error!void {
579
751
  if (!enabled) return;
580
752
 
753
+ assert(args[1] != .Spikes or args.len == 3);
581
754
  try self.writer.writeAll(&.{
582
- @intFromEnum(ArgType.Immune),
583
- @as(u8, @bitCast(ident)),
584
- @intFromEnum(reason),
755
+ @intFromEnum(ArgType.SideEnd),
756
+ @intFromEnum(@as(Player, args[0])),
757
+ @intFromEnum(@as(Side, args[1])),
585
758
  });
759
+ if (args.len == 3) try self.writer.writeByte(@as(u8, @bitCast(args[2])));
760
+ }
761
+
762
+ // ident: ID, move: <Move>
763
+ pub fn singlemove(self: Self, args: anytype) Error!void {
764
+ return single(self, .SingleMove, args);
765
+ }
766
+
767
+ // ident: ID, move: <Move>
768
+ pub fn singleturn(self: Self, args: anytype) Error!void {
769
+ return single(self, .SingleTurn, args);
586
770
  }
587
771
 
588
- pub fn transform(self: Self, source: ID, target: ID) Error!void {
772
+ // ident: ID, move: <Move>
773
+ fn single(self: Self, arg: ArgType, args: anytype) Error!void {
589
774
  if (!enabled) return;
590
775
 
591
776
  try self.writer.writeAll(&.{
592
- @intFromEnum(ArgType.Transform),
593
- @as(u8, @bitCast(source)),
594
- @as(u8, @bitCast(target)),
777
+ @intFromEnum(arg),
778
+ @as(u8, @bitCast(args[0])),
779
+ @intFromEnum(args[1]),
595
780
  });
596
781
  }
597
782
 
598
- pub fn laststill(self: Self) Error!void {
783
+ // weather: <Weather>, reason: Weather
784
+ pub fn weather(self: Self, args: anytype) Error!void {
785
+ if (!enabled) return;
786
+
787
+ assert(!(args[0] == .None and args[1] == .Upkeep));
788
+ try self.writer.writeAll(&.{
789
+ @intFromEnum(ArgType.Weather),
790
+ @intFromEnum(args[0]),
791
+ @intFromEnum(@as(Weather, args[1])),
792
+ });
793
+ }
794
+
795
+ // -
796
+ pub fn laststill(self: Self, _: anytype) Error!void {
599
797
  if (!enabled) return;
600
798
 
601
799
  try self.writer.writeAll(&.{@intFromEnum(ArgType.LastStill)});
602
800
  }
603
801
 
604
- pub fn lastmiss(self: Self) Error!void {
802
+ // -
803
+ pub fn lastmiss(self: Self, _: anytype) Error!void {
605
804
  if (!enabled) return;
606
805
 
607
806
  try self.writer.writeAll(&.{@intFromEnum(ArgType.LastMiss)});
@@ -655,7 +854,7 @@ pub const ByteStream = struct {
655
854
  }
656
855
  };
657
856
 
658
- pub const Kind = enum { Move, Species, Type, Status };
857
+ pub const Kind = enum { Move, Species, Type, Status, Item, Weather };
659
858
 
660
859
  pub fn format(
661
860
  comptime gen: anytype,
@@ -700,6 +899,18 @@ pub fn format(
700
899
  .Resisted => "|-resisted|",
701
900
  .Immune => "|-immune|",
702
901
  .Transform => "|-transform|",
902
+ .Drag => "|drag|",
903
+ .Item => "|-item|",
904
+ .EndItem => "|-enditem|",
905
+ .CureTeam => "|-cureteam|",
906
+ .SetHP => "|-sethp|",
907
+ .SetBoost => "|-setboost|",
908
+ .CopyBoost => "|-copyboost|",
909
+ .SideStart => "|-sidestart|",
910
+ .SideEnd => "|-sideend|",
911
+ .SingleMove => "|-singlemove|",
912
+ .SingleTurn => "|-singleturn|",
913
+ .Weather => "|-weather|",
703
914
  else => unreachable,
704
915
  };
705
916
  printc("{s}", .{name}, a, b, &i, 1, color);
@@ -724,7 +935,7 @@ pub fn format(
724
935
  printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
725
936
  }
726
937
  },
727
- .Switch => {
938
+ .Switch, .Drag => {
728
939
  const id = ID.from(@intCast(a[i]));
729
940
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
730
941
  printc(" {s}", .{formatter(gen, .Species, a[i])}, a, b, &i, 1, color);
@@ -768,6 +979,7 @@ pub fn format(
768
979
  .Crit,
769
980
  .SuperEffective,
770
981
  .Resisted,
982
+ .CureTeam,
771
983
  => {
772
984
  const id = ID.from(@intCast(a[i]));
773
985
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
@@ -844,12 +1056,12 @@ pub fn format(
844
1056
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
845
1057
  printc(" {s}", .{@tagName(@as(Fail, @enumFromInt(a[i])))}, a, b, &i, 1, color);
846
1058
  },
847
- .HitCount => {
1059
+ .HitCount, .SetBoost => {
848
1060
  const id = ID.from(@intCast(a[i]));
849
1061
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
850
1062
  printc(" {d}", .{a[i]}, a, b, &i, 1, color);
851
1063
  },
852
- .Prepare => {
1064
+ .Prepare, .SingleMove, .SingleTurn => {
853
1065
  const id = ID.from(@intCast(a[i]));
854
1066
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
855
1067
  printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
@@ -857,7 +1069,13 @@ pub fn format(
857
1069
  .Activate => {
858
1070
  const id = ID.from(@intCast(a[i]));
859
1071
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
860
- printc(" {s}", .{@tagName(@as(Activate, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1072
+ const reason: Activate = @enumFromInt(a[i]);
1073
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1074
+ if (reason == .SubstituteBlock) {
1075
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
1076
+ } else if (reason == .Magnitude) {
1077
+ printc(" {d}", .{a[i]}, a, b, &i, 1, color);
1078
+ }
861
1079
  },
862
1080
  .Start => {
863
1081
  const id = ID.from(@intCast(a[i]));
@@ -865,7 +1083,7 @@ pub fn format(
865
1083
  const reason = a[i];
866
1084
  printc(" {s}", .{@tagName(@as(Start, @enumFromInt(reason)))}, a, b, &i, 1, color);
867
1085
  if (@as(Start, @enumFromInt(reason)) == .TypeChange) {
868
- const types = @as(gen1.Types, @bitCast(a[i]));
1086
+ const types = @as(gen.Types, @bitCast(a[i]));
869
1087
  const args = .{
870
1088
  formatter(gen, .Type, @intFromEnum(types.type1)),
871
1089
  formatter(gen, .Type, @intFromEnum(types.type2)),
@@ -885,12 +1103,64 @@ pub fn format(
885
1103
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
886
1104
  printc(" {s}", .{@tagName(@as(Immune, @enumFromInt(a[i])))}, a, b, &i, 1, color);
887
1105
  },
888
- .Transform => {
1106
+ .Transform, .CopyBoost => {
889
1107
  const source = ID.from(@intCast(a[i]));
890
1108
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
891
1109
  const target = ID.from(@intCast(a[i]));
892
1110
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
893
1111
  },
1112
+ .Item, .EndItem => {
1113
+ var id = ID.from(@intCast(a[i]));
1114
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1115
+ printc(" {s}", .{formatter(gen, .Item, a[i])}, a, b, &i, 1, color);
1116
+ if (arg == .Item) {
1117
+ id = ID.from(@intCast(a[i]));
1118
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1119
+ } else {
1120
+ const reason: EndItem = @enumFromInt(a[i]);
1121
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1122
+ }
1123
+ },
1124
+ .SetHP => {
1125
+ const id = ID.from(@intCast(a[i]));
1126
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1127
+ switch (endian) {
1128
+ .Big => {
1129
+ var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1130
+ printc(" {d}", .{hp}, a, b, &i, 2, color);
1131
+ hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1132
+ printc("/{d}", .{hp}, a, b, &i, 2, color);
1133
+ },
1134
+ .Little => {
1135
+ var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1136
+ printc(" {d}", .{hp}, a, b, &i, 2, color);
1137
+ hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1138
+ printc("/{d}", .{hp}, a, b, &i, 2, color);
1139
+ },
1140
+ }
1141
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
1142
+ printc(" {s}", .{@tagName(@as(SetHP, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1143
+ },
1144
+ .SideStart => {
1145
+ const id = ID.from(@intCast(a[i]));
1146
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1147
+ printc(" {s}", .{@tagName(@as(Side, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1148
+ },
1149
+ .SideEnd => {
1150
+ var id = ID.from(@intCast(a[i]));
1151
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1152
+ const reason: Side = @enumFromInt(a[i]);
1153
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1154
+ if (reason == .Spikes) {
1155
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
1156
+ id = ID.from(@intCast(a[i]));
1157
+ printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1158
+ }
1159
+ },
1160
+ .Weather => {
1161
+ printc(" {s}", .{formatter(gen, .Weather, a[i])}, a, b, &i, 1, color);
1162
+ printc(" {s}", .{@tagName(@as(Weather, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1163
+ },
894
1164
  else => unreachable,
895
1165
  }
896
1166
  print("\n", .{});
@@ -987,12 +1257,17 @@ const gen2 = struct {
987
1257
  pub const helpers = @import("../gen2/helpers.zig");
988
1258
  };
989
1259
 
990
- var buf: [gen1.LOGS_SIZE]u8 = undefined;
991
- var stream = ByteStream{ .buffer = &buf };
1260
+ var buf: [pkmn.LOGS_SIZE]u8 = undefined;
1261
+ var stream: ByteStream = .{ .buffer = &buf };
992
1262
  var log: FixedLog = .{ .writer = stream.writer() };
993
1263
 
994
- const M = gen1.Move;
995
- const S = gen1.Species;
1264
+ const M1 = gen1.Move;
1265
+ const S1 = gen1.Species;
1266
+
1267
+ const M2 = gen2.Move;
1268
+ const S2 = gen2.Species;
1269
+ const I2 = gen2.Item;
1270
+ const W2 = gen2.Weather;
996
1271
 
997
1272
  fn expectLog1(expected: []const u8, actual: []const u8) !void {
998
1273
  return expectLog(gen1, expected, actual, 0);
@@ -1008,32 +1283,39 @@ fn formatter(comptime gen: anytype, kind: Kind, byte: u8) []const u8 {
1008
1283
  .Species => @tagName(@as(gen.Species, @enumFromInt(byte))),
1009
1284
  .Type => @tagName(@as(gen.Type, @enumFromInt(byte))),
1010
1285
  .Status => gen.Status.name(byte),
1286
+ .Item => if (@hasDecl(gen, "Item"))
1287
+ @tagName(@as(gen.Item, @enumFromInt(byte)))
1288
+ else
1289
+ unreachable,
1290
+ .Weather => if (@hasDecl(gen, "Weather"))
1291
+ @tagName(@as(gen.Weather, @enumFromInt(byte)))
1292
+ else
1293
+ unreachable,
1011
1294
  };
1012
1295
  }
1013
1296
 
1014
1297
  test "|move|" {
1015
- try log.move(p2.ident(4), M.Thunderbolt, p1.ident(5), null);
1298
+ try log.move(.{ p2.ident(4), M1.Thunderbolt, p1.ident(5) });
1016
1299
  try expectLog1(
1017
- &.{ N(ArgType.Move), 0b1100, N(M.Thunderbolt), 0b0101, N(Move.None) },
1300
+ &.{ N(ArgType.Move), 0b1100, N(M1.Thunderbolt), 0b0101, N(Move.None) },
1018
1301
  buf[0..5],
1019
1302
  );
1020
1303
  stream.reset();
1021
1304
 
1022
- try log.move(p2.ident(4), M.Wrap, p1.ident(5), M.Wrap);
1023
- const wrap = N(M.Wrap);
1305
+ try log.move(.{ p2.ident(4), M1.Pound, p1.ident(5), M1.Metronome });
1024
1306
  try expectLog1(
1025
- &.{ N(ArgType.Move), 0b1100, wrap, 0b0101, N(Move.From), wrap },
1307
+ &.{ N(ArgType.Move), 0b1100, N(M1.Pound), 0b0101, N(Move.From), N(M1.Metronome) },
1026
1308
  buf[0..6],
1027
1309
  );
1028
1310
  stream.reset();
1029
1311
 
1030
- try log.move(p2.ident(4), M.SkullBash, .{}, null);
1031
- try log.laststill();
1312
+ try log.move(.{ p2.ident(4), M1.SkullBash, ID{} });
1313
+ try log.laststill(.{});
1032
1314
  try expectLog1(
1033
1315
  &.{
1034
1316
  N(ArgType.Move),
1035
1317
  0b1100,
1036
- N(M.SkullBash),
1318
+ N(M1.SkullBash),
1037
1319
  0,
1038
1320
  N(Move.None),
1039
1321
  N(ArgType.LastStill),
@@ -1042,13 +1324,13 @@ test "|move|" {
1042
1324
  );
1043
1325
  stream.reset();
1044
1326
 
1045
- try log.move(p2.ident(4), M.Tackle, p1.ident(5), null);
1046
- try log.lastmiss();
1327
+ try log.move(.{ p2.ident(4), M1.Tackle, p1.ident(5) });
1328
+ try log.lastmiss(.{});
1047
1329
  try expectLog1(
1048
1330
  &.{
1049
1331
  N(ArgType.Move),
1050
1332
  0b1100,
1051
- N(M.Tackle),
1333
+ N(M1.Tackle),
1052
1334
  0b0101,
1053
1335
  N(Move.None),
1054
1336
  N(ArgType.LastMiss),
@@ -1064,11 +1346,11 @@ test "|switch|" {
1064
1346
  snorlax.hp = 200;
1065
1347
  snorlax.stats.hp = 400;
1066
1348
  snorlax.status = gen1.Status.init(.PAR);
1067
- try log.switched(p2.ident(3), &snorlax);
1349
+ try log.switched(.{ p2.ident(3), &snorlax });
1068
1350
  const par = 0b1000000;
1069
1351
  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 },
1352
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
1353
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
1072
1354
  };
1073
1355
  try expectLog1(expected, buf[0..9]);
1074
1356
  stream.reset();
@@ -1076,19 +1358,19 @@ test "|switch|" {
1076
1358
  snorlax.level = 100;
1077
1359
  snorlax.hp = 0;
1078
1360
  snorlax.status = 0;
1079
- try log.switched(p2.ident(3), &snorlax);
1361
+ try log.switched(.{ p2.ident(3), &snorlax });
1080
1362
  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 },
1363
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
1364
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
1083
1365
  };
1084
1366
  try expectLog1(expected, buf[0..9]);
1085
1367
  stream.reset();
1086
1368
 
1087
1369
  snorlax.hp = 400;
1088
- try log.switched(p2.ident(3), &snorlax);
1370
+ try log.switched(.{ p2.ident(3), &snorlax });
1089
1371
  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 },
1372
+ .Big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
1373
+ .Little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
1092
1374
  };
1093
1375
  try expectLog1(expected, buf[0..9]);
1094
1376
  stream.reset();
@@ -1098,11 +1380,11 @@ test "|switch|" {
1098
1380
  blissey.hp = 200;
1099
1381
  blissey.stats.hp = 400;
1100
1382
  blissey.status = gen2.Status.init(.PAR);
1101
- try log.switched(p2.ident(3), &blissey);
1383
+ try log.switched(.{ p2.ident(3), &blissey });
1102
1384
  expected = &(.{
1103
1385
  N(ArgType.Switch),
1104
1386
  0b1011,
1105
- N(gen2.Species.Blissey),
1387
+ N(S2.Blissey),
1106
1388
  N(gen2.Gender.Female),
1107
1389
  91,
1108
1390
  } ++ switch (endian) {
@@ -1114,27 +1396,27 @@ test "|switch|" {
1114
1396
  }
1115
1397
 
1116
1398
  test "|cant|" {
1117
- try log.cant(p2.ident(6), .Bound);
1399
+ try log.cant(.{ p2.ident(6), .Bound });
1118
1400
  try expectLog1(&.{ N(ArgType.Cant), 0b1110, N(Cant.Bound) }, buf[0..3]);
1119
1401
  stream.reset();
1120
1402
 
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]);
1403
+ try log.cant(.{ p1.ident(2), .Disable, M1.Earthquake });
1404
+ try expectLog1(&.{ N(ArgType.Cant), 2, N(Cant.Disable), N(M1.Earthquake) }, buf[0..4]);
1123
1405
  stream.reset();
1124
1406
  }
1125
1407
 
1126
1408
  test "|faint|" {
1127
- try log.faint(p2.ident(2), false);
1409
+ try log.faint(.{ p2.ident(2), false });
1128
1410
  try expectLog1(&.{ N(ArgType.Faint), 0b1010 }, buf[0..2]);
1129
1411
  stream.reset();
1130
1412
 
1131
- try log.faint(p2.ident(2), true);
1413
+ try log.faint(.{ p2.ident(2), true });
1132
1414
  try expectLog1(&.{ N(ArgType.Faint), 0b1010, N(ArgType.None) }, buf[0..3]);
1133
1415
  stream.reset();
1134
1416
  }
1135
1417
 
1136
1418
  test "|turn|" {
1137
- try log.turn(42);
1419
+ try log.turn(.{42});
1138
1420
  var expected = switch (endian) {
1139
1421
  .Big => &.{ N(ArgType.Turn), 0, 42, N(ArgType.None) },
1140
1422
  .Little => &.{ N(ArgType.Turn), 42, 0, N(ArgType.None) },
@@ -1144,13 +1426,13 @@ test "|turn|" {
1144
1426
  }
1145
1427
 
1146
1428
  test "|win|" {
1147
- try log.win(.P2);
1429
+ try log.win(.{.P2});
1148
1430
  try expectLog1(&.{ N(ArgType.Win), 1, N(ArgType.None) }, buf[0..3]);
1149
1431
  stream.reset();
1150
1432
  }
1151
1433
 
1152
1434
  test "|tie|" {
1153
- try log.tie();
1435
+ try log.tie(.{});
1154
1436
  try expectLog1(&.{ N(ArgType.Tie), N(ArgType.None) }, buf[0..2]);
1155
1437
  stream.reset();
1156
1438
  }
@@ -1159,7 +1441,7 @@ test "|-damage|" {
1159
1441
  var chansey = gen1.helpers.Pokemon.init(.{ .species = .Chansey, .moves = &.{.Splash} });
1160
1442
  chansey.hp = 612;
1161
1443
  chansey.status = gen1.Status.slp(1);
1162
- try log.damage(p2.ident(2), &chansey, .None);
1444
+ try log.damage(.{ p2.ident(2), &chansey, .None });
1163
1445
  var expected: []const u8 = switch (endian) {
1164
1446
  .Big => &.{ N(ArgType.Damage), 0b1010, 2, 100, 2, 191, 1, N(Damage.None) },
1165
1447
  .Little => &.{ N(ArgType.Damage), 0b1010, 100, 2, 191, 2, 1, N(Damage.None) },
@@ -1170,7 +1452,7 @@ test "|-damage|" {
1170
1452
  chansey.hp = 100;
1171
1453
  chansey.stats.hp = 256;
1172
1454
  chansey.status = 0;
1173
- try log.damage(p2.ident(2), &chansey, .Confusion);
1455
+ try log.damage(.{ p2.ident(2), &chansey, .Confusion });
1174
1456
  expected = switch (endian) {
1175
1457
  .Big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0, N(Damage.Confusion) },
1176
1458
  .Little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0, N(Damage.Confusion) },
@@ -1179,7 +1461,7 @@ test "|-damage|" {
1179
1461
  stream.reset();
1180
1462
 
1181
1463
  chansey.status = gen1.Status.init(.PSN);
1182
- try log.damageOf(p2.ident(2), &chansey, .RecoilOf, p1.ident(1));
1464
+ try log.damage(.{ p2.ident(2), &chansey, .RecoilOf, p1.ident(1) });
1183
1465
  expected = switch (endian) {
1184
1466
  .Big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0b1000, N(Damage.RecoilOf), 1 },
1185
1467
  .Little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0b1000, N(Damage.RecoilOf), 1 },
@@ -1192,7 +1474,7 @@ test "|-heal|" {
1192
1474
  var chansey = gen1.helpers.Pokemon.init(.{ .species = .Chansey, .moves = &.{.Splash} });
1193
1475
  chansey.hp = 612;
1194
1476
  chansey.status = gen1.Status.slp(1);
1195
- try log.heal(p2.ident(2), &chansey, .None);
1477
+ try log.heal(.{ p2.ident(2), &chansey, .None });
1196
1478
  var expected: []const u8 = switch (endian) {
1197
1479
  .Big => &.{ N(ArgType.Heal), 0b1010, 2, 100, 2, 191, 1, N(Heal.None) },
1198
1480
  .Little => &.{ N(ArgType.Heal), 0b1010, 100, 2, 191, 2, 1, N(Heal.None) },
@@ -1203,7 +1485,7 @@ test "|-heal|" {
1203
1485
  chansey.hp = 100;
1204
1486
  chansey.stats.hp = 256;
1205
1487
  chansey.status = 0;
1206
- try log.heal(p2.ident(2), &chansey, .Silent);
1488
+ try log.heal(.{ p2.ident(2), &chansey, .Silent });
1207
1489
  expected = switch (endian) {
1208
1490
  .Big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Silent) },
1209
1491
  .Little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Silent) },
@@ -1211,7 +1493,7 @@ test "|-heal|" {
1211
1493
  try expectLog1(expected, buf[0..8]);
1212
1494
  stream.reset();
1213
1495
 
1214
- try log.drain(p2.ident(2), &chansey, p1.ident(1));
1496
+ try log.heal(.{ p2.ident(2), &chansey, .Drain, p1.ident(1) });
1215
1497
  expected = switch (endian) {
1216
1498
  .Big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Drain), 1 },
1217
1499
  .Little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Drain), 1 },
@@ -1221,28 +1503,28 @@ test "|-heal|" {
1221
1503
  }
1222
1504
 
1223
1505
  test "|-status|" {
1224
- try log.status(p2.ident(6), gen1.Status.init(.BRN), .None);
1506
+ try log.status(.{ p2.ident(6), gen1.Status.init(.BRN), .None });
1225
1507
  try expectLog1(&.{ N(ArgType.Status), 0b1110, 0b10000, N(Status.None) }, buf[0..4]);
1226
1508
  stream.reset();
1227
1509
 
1228
- try log.status(p2.ident(2), gen1.Status.init(.PSN), .Silent);
1510
+ try log.status(.{ p2.ident(2), gen1.Status.init(.PSN), .Silent });
1229
1511
  try expectLog1(&.{ N(ArgType.Status), 0b1010, 0b1000, N(Status.Silent) }, buf[0..4]);
1230
1512
  stream.reset();
1231
1513
 
1232
- try log.statusFrom(p1.ident(1), gen1.Status.init(.PAR), M.BodySlam);
1514
+ try log.status(.{ p1.ident(1), gen1.Status.init(.PAR), .From, M1.BodySlam });
1233
1515
  try expectLog1(
1234
- &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M.BodySlam) },
1516
+ &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M1.BodySlam) },
1235
1517
  buf[0..5],
1236
1518
  );
1237
1519
  stream.reset();
1238
1520
  }
1239
1521
 
1240
1522
  test "|-curestatus|" {
1241
- try log.curestatus(p2.ident(6), gen1.Status.slp(7), .Message);
1523
+ try log.curestatus(.{ p2.ident(6), gen1.Status.slp(7), .Message });
1242
1524
  try expectLog1(&.{ N(ArgType.CureStatus), 0b1110, 0b111, N(CureStatus.Message) }, buf[0..4]);
1243
1525
  stream.reset();
1244
1526
 
1245
- try log.curestatus(p1.ident(2), gen1.Status.TOX, .Silent);
1527
+ try log.curestatus(.{ p1.ident(2), gen1.Status.TOX, .Silent });
1246
1528
  try expectLog1(&.{
1247
1529
  N(ArgType.CureStatus),
1248
1530
  0b0010,
@@ -1253,163 +1535,306 @@ test "|-curestatus|" {
1253
1535
  }
1254
1536
 
1255
1537
  test "|-boost|" {
1256
- try log.boost(p2.ident(6), .Speed, 2);
1538
+ try log.boost(.{ p2.ident(6), .Speed, 2 });
1257
1539
  try expectLog1(&.{ N(ArgType.Boost), 0b1110, N(Boost.Speed), 8 }, buf[0..4]);
1258
1540
  stream.reset();
1259
1541
 
1260
- try log.boost(p1.ident(2), .Rage, 1);
1542
+ try log.boost(.{ p1.ident(2), .Rage, 1 });
1261
1543
  try expectLog1(&.{ N(ArgType.Boost), 0b0010, N(Boost.Rage), 7 }, buf[0..4]);
1262
1544
  stream.reset();
1263
1545
 
1264
- try log.boost(p2.ident(3), .Defense, -2);
1546
+ try log.boost(.{ p2.ident(3), .Defense, -2 });
1265
1547
  try expectLog1(&.{ N(ArgType.Boost), 0b1011, N(Boost.Defense), 4 }, buf[0..4]);
1266
1548
  stream.reset();
1267
1549
  }
1268
1550
 
1269
1551
  test "|-clearallboost|" {
1270
- try log.clearallboost();
1552
+ try log.clearallboost(.{});
1271
1553
  try expectLog1(&.{N(ArgType.ClearAllBoost)}, buf[0..1]);
1272
1554
  stream.reset();
1273
1555
  }
1274
1556
 
1275
1557
  test "|-fail|" {
1276
- try log.fail(p2.ident(6), .None);
1558
+ try log.fail(.{ p2.ident(6), .None });
1277
1559
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.None) }, buf[0..3]);
1278
1560
  stream.reset();
1279
1561
 
1280
- try log.fail(p2.ident(6), .Sleep);
1562
+ try log.fail(.{ p2.ident(6), .Sleep });
1281
1563
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Sleep) }, buf[0..3]);
1282
1564
  stream.reset();
1283
1565
 
1284
- try log.fail(p2.ident(6), .Substitute);
1566
+ try log.fail(.{ p2.ident(6), .Substitute });
1285
1567
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Substitute) }, buf[0..3]);
1286
1568
  stream.reset();
1287
1569
 
1288
- try log.fail(p2.ident(6), .Weak);
1570
+ try log.fail(.{ p2.ident(6), .Weak });
1289
1571
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Weak) }, buf[0..3]);
1290
1572
  stream.reset();
1291
1573
  }
1292
1574
 
1293
1575
  test "|-miss|" {
1294
- try log.miss(p2.ident(4));
1576
+ try log.miss(.{p2.ident(4)});
1295
1577
  try expectLog1(&.{ N(ArgType.Miss), 0b1100 }, buf[0..2]);
1296
1578
  stream.reset();
1297
1579
  }
1298
1580
  test "|-hitcount|" {
1299
- try log.hitcount(p2.ident(1), 5);
1581
+ try log.hitcount(.{ p2.ident(1), 5 });
1300
1582
  try expectLog1(&.{ N(ArgType.HitCount), 0b1001, 5 }, buf[0..3]);
1301
1583
  stream.reset();
1302
1584
  }
1303
1585
 
1304
1586
  test "|-prepare|" {
1305
- try log.prepare(p2.ident(2), M.Dig);
1306
- try expectLog1(&.{ N(ArgType.Prepare), 0b1010, N(M.Dig) }, buf[0..3]);
1587
+ try log.prepare(.{ p2.ident(2), M1.Dig });
1588
+ try expectLog1(&.{ N(ArgType.Prepare), 0b1010, N(M1.Dig) }, buf[0..3]);
1307
1589
  stream.reset();
1308
1590
  }
1309
1591
 
1310
1592
  test "|-mustrecharge|" {
1311
- try log.mustrecharge(p1.ident(6));
1593
+ try log.mustrecharge(.{p1.ident(6)});
1312
1594
  try expectLog1(&.{ N(ArgType.MustRecharge), 0b0110 }, buf[0..2]);
1313
1595
  stream.reset();
1314
1596
  }
1315
1597
 
1316
1598
  test "|-activate|" {
1317
- try log.activate(p1.ident(2), .Struggle);
1599
+ try log.activate(.{ p1.ident(2), .Struggle });
1318
1600
  try expectLog1(&.{ N(ArgType.Activate), 0b0010, N(Activate.Struggle) }, buf[0..3]);
1319
1601
  stream.reset();
1320
1602
 
1321
- try log.activate(p2.ident(4), .Mist);
1603
+ try log.activate(.{ p2.ident(4), .Mist });
1322
1604
  try expectLog1(&.{ N(ArgType.Activate), 0b1100, N(Activate.Mist) }, buf[0..3]);
1323
1605
  stream.reset();
1324
1606
 
1325
- try log.activate(p2.ident(6), .Substitute);
1607
+ try log.activate(.{ p2.ident(6), .Substitute });
1326
1608
  try expectLog1(&.{ N(ArgType.Activate), 0b1110, N(Activate.Substitute) }, buf[0..3]);
1327
1609
  stream.reset();
1328
1610
 
1329
- try log.activate(p1.ident(2), .Splash);
1611
+ try log.activate(.{ p1.ident(2), .Splash });
1330
1612
  try expectLog1(&.{ N(ArgType.Activate), 0b0010, N(Activate.Splash) }, buf[0..3]);
1331
1613
  stream.reset();
1614
+
1615
+ try log.activate(.{ p1.ident(4), .SubstituteBlock, M2.Spite });
1616
+ try expectLog1(&.{
1617
+ N(ArgType.Activate),
1618
+ 0b0100,
1619
+ N(Activate.SubstituteBlock),
1620
+ N(M2.Spite),
1621
+ }, buf[0..4]);
1622
+ stream.reset();
1623
+
1624
+ try log.activate(.{ p1.ident(3), .Magnitude, 5 });
1625
+ try expectLog1(&.{ N(ArgType.Activate), 0b0011, N(Activate.Magnitude), 5 }, buf[0..4]);
1626
+ stream.reset();
1332
1627
  }
1333
1628
 
1334
1629
  test "|-fieldactivate|" {
1335
- try log.fieldactivate();
1630
+ try log.fieldactivate(.{});
1336
1631
  try expectLog1(&.{N(ArgType.FieldActivate)}, buf[0..1]);
1337
1632
  stream.reset();
1338
1633
  }
1339
1634
 
1340
1635
  test "|-start|" {
1341
- try log.start(p2.ident(6), .Bide);
1636
+ try log.start(.{ p2.ident(6), .Bide });
1342
1637
  try expectLog1(&.{ N(ArgType.Start), 0b1110, N(Start.Bide) }, buf[0..3]);
1343
1638
  stream.reset();
1344
1639
 
1345
- try log.start(p1.ident(2), .ConfusionSilent);
1640
+ try log.start(.{ p1.ident(2), .ConfusionSilent });
1346
1641
  try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.ConfusionSilent) }, buf[0..3]);
1347
1642
  stream.reset();
1348
1643
 
1349
- try log.typechange(p2.ident(6), gen1.Types{ .type1 = .Fire, .type2 = .Fire }, p2.ident(5));
1644
+ try log.start(.{
1645
+ p2.ident(6),
1646
+ .TypeChange,
1647
+ gen1.Types{ .type1 = .Fire, .type2 = .Fire },
1648
+ p2.ident(5),
1649
+ });
1350
1650
  try expectLog1(
1351
1651
  &.{ N(ArgType.Start), 0b1110, N(Start.TypeChange), 0b1000_1000, 0b1101 },
1352
1652
  buf[0..5],
1353
1653
  );
1354
1654
  stream.reset();
1355
1655
 
1356
- try log.typechange(p1.ident(2), gen1.Types{ .type1 = .Bug, .type2 = .Poison }, p2.ident(4));
1656
+ try log.start(.{
1657
+ p1.ident(2),
1658
+ .TypeChange,
1659
+ gen1.Types{ .type1 = .Bug, .type2 = .Poison },
1660
+ p2.ident(4),
1661
+ });
1357
1662
  try expectLog1(
1358
1663
  &.{ N(ArgType.Start), 0b0010, N(Start.TypeChange), 0b0011_0110, 0b1100 },
1359
1664
  buf[0..5],
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.start(.{ 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.start(.{ 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
 
1372
1677
  test "|-end|" {
1373
- try log.end(p2.ident(6), .Bide);
1678
+ try log.end(.{ p2.ident(6), .Bide });
1374
1679
  try expectLog1(&.{ N(ArgType.End), 0b1110, N(End.Bide) }, buf[0..3]);
1375
1680
  stream.reset();
1376
1681
 
1377
- try log.end(p1.ident(2), .ConfusionSilent);
1682
+ try log.end(.{ p1.ident(2), .ConfusionSilent });
1378
1683
  try expectLog1(&.{ N(ArgType.End), 0b0010, N(End.ConfusionSilent) }, buf[0..3]);
1379
1684
  stream.reset();
1380
1685
  }
1381
1686
 
1382
1687
  test "|-ohko|" {
1383
- try log.ohko();
1688
+ try log.ohko(.{});
1384
1689
  try expectLog1(&.{N(ArgType.OHKO)}, buf[0..1]);
1385
1690
  stream.reset();
1386
1691
  }
1692
+
1387
1693
  test "|-crit|" {
1388
- try log.crit(p2.ident(5));
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
- try log.supereffective(p1.ident(1));
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
- try log.resisted(p2.ident(2));
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
- try log.immune(p1.ident(3), .None);
1712
+ try log.immune(.{ p1.ident(3), .None });
1404
1713
  try expectLog1(&.{ N(ArgType.Immune), 0b0011, N(Immune.None) }, buf[0..3]);
1405
1714
  stream.reset();
1406
1715
 
1407
- try log.immune(p2.ident(2), .OHKO);
1716
+ try log.immune(.{ p2.ident(2), .OHKO });
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
- try log.transform(p2.ident(4), p1.ident(5));
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.sideend(.{ .P1, .Spikes, 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
+ }