@pkmn/engine 0.1.0-dev.305a932f → 0.1.0-dev.32adfe77

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 (45) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +37 -14
  3. package/build/pkg/addon.js.map +1 -1
  4. package/build/pkg/data/layout.json +2 -2
  5. package/build/pkg/data.d.ts +3 -2
  6. package/build/pkg/data.js.map +1 -1
  7. package/build/pkg/gen1.js +2 -2
  8. package/build/pkg/gen1.js.map +1 -1
  9. package/build/pkg/index.d.ts +2 -1
  10. package/build/pkg/index.js.map +1 -1
  11. package/build/pkg/protocol.js +1 -1
  12. package/build/pkg/protocol.js.map +1 -1
  13. package/build/test/display.js.map +1 -1
  14. package/build/tools/debug.js +3 -1
  15. package/build/tools/debug.js.map +1 -1
  16. package/build.zig +78 -68
  17. package/package.json +34 -23
  18. package/src/bin/install-pkmn-engine +14 -14
  19. package/src/lib/common/data.zig +8 -8
  20. package/src/lib/common/optional.zig +9 -2
  21. package/src/lib/common/protocol.zig +402 -383
  22. package/src/lib/common/rational.zig +11 -7
  23. package/src/lib/common/rng.zig +20 -11
  24. package/src/lib/gen1/README.md +28 -28
  25. package/src/lib/gen1/calc.zig +7 -7
  26. package/src/lib/gen1/chance.zig +70 -68
  27. package/src/lib/gen1/data/moves.zig +24 -10
  28. package/src/lib/gen1/data/species.zig +3 -3
  29. package/src/lib/gen1/data/types.zig +5 -5
  30. package/src/lib/gen1/data.zig +36 -36
  31. package/src/lib/gen1/helpers.zig +21 -36
  32. package/src/lib/gen1/mechanics.zig +333 -344
  33. package/src/lib/gen2/README.md +1 -2
  34. package/src/lib/gen2/calc.zig +143 -0
  35. package/src/lib/gen2/chance.zig +1314 -0
  36. package/src/lib/gen2/data/items.zig +3 -3
  37. package/src/lib/gen2/data/moves.zig +32 -15
  38. package/src/lib/gen2/data/species.zig +1 -1
  39. package/src/lib/gen2/data/types.zig +75 -28
  40. package/src/lib/gen2/data.zig +37 -25
  41. package/src/lib/gen2/generated.zig +806 -0
  42. package/src/lib/gen2/mechanics.zig +2612 -349
  43. package/src/lib/{binding/node.zig → node.zig} +9 -12
  44. package/src/lib/pkmn.zig +26 -3
  45. package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
@@ -1,8 +1,10 @@
1
1
  const std = @import("std");
2
2
  const builtin = @import("builtin");
3
3
 
4
- const data = @import("./data.zig");
5
- const options = @import("./options.zig");
4
+ const pkmn = @import("../pkmn.zig");
5
+
6
+ const data = @import("data.zig");
7
+ const options = @import("options.zig");
6
8
 
7
9
  const assert = std.debug.assert;
8
10
  const print = std.debug.print;
@@ -12,6 +14,8 @@ const enabled = options.log;
12
14
  const Player = data.Player;
13
15
  const ID = data.ID;
14
16
 
17
+ const endian = builtin.cpu.arch.endian();
18
+
15
19
  pub const ArgType = enum(u8) {
16
20
  None,
17
21
 
@@ -69,7 +73,7 @@ pub const ArgType = enum(u8) {
69
73
  EndAbility,
70
74
  ClearNegativeBoost,
71
75
  FormeChange,
72
- NoTarget,
76
+ LastNoTarget, // FIXME
73
77
 
74
78
  // Gen 4
75
79
  SwapBoost,
@@ -102,6 +106,7 @@ pub const ArgType = enum(u8) {
102
106
  // Gen 8
103
107
  CanDynamax,
104
108
  SwapSideConditions,
109
+ UpdatePoke,
105
110
 
106
111
  // Gen 9
107
112
  Terastallize,
@@ -150,6 +155,10 @@ pub const Damage = enum(u8) {
150
155
  Clamp,
151
156
  Whirlpool,
152
157
  Spikes,
158
+
159
+ Nightmare,
160
+ Curse,
161
+ Sandstorm,
153
162
  };
154
163
 
155
164
  pub const Status = enum(u8) {
@@ -192,9 +201,11 @@ pub const Activate = enum(u8) {
192
201
  Haze,
193
202
  Mist,
194
203
  Struggle,
195
- Substitute,
204
+ Substitute, // FIXME SubstituteDamage
196
205
  Splash,
197
206
 
207
+ Rage, // TODO
208
+
198
209
  Attract,
199
210
  LockOn,
200
211
  Bind,
@@ -202,8 +213,13 @@ pub const Activate = enum(u8) {
202
213
  FireSpin,
203
214
  Clamp,
204
215
  Whirlpool,
216
+ SubstituteBlock,
217
+
218
+ DestinyBond,
205
219
 
206
220
  BeatUp, // FIXME of
221
+
222
+ Magnitude,
207
223
  };
208
224
 
209
225
  pub const Start = enum(u8) {
@@ -222,6 +238,7 @@ pub const Start = enum(u8) {
222
238
  Disable,
223
239
  Mimic,
224
240
 
241
+ Attract,
225
242
  Nightmare,
226
243
  Curse,
227
244
  Foresight,
@@ -247,6 +264,7 @@ pub const End = enum(u8) {
247
264
  Encore,
248
265
  FutureSight,
249
266
  LeechSeed,
267
+
250
268
  Bind,
251
269
  Wrap,
252
270
  FireSpin,
@@ -262,6 +280,8 @@ pub const End = enum(u8) {
262
280
  LightScreenSilent,
263
281
  ReflectSilent,
264
282
  BideSilent,
283
+
284
+ LeechSeedFrom,
265
285
  };
266
286
 
267
287
  pub const Immune = enum(u8) {
@@ -305,501 +325,484 @@ pub fn Log(comptime Writer: type) type {
305
325
 
306
326
  pub const Error = Writer.Error;
307
327
 
308
- pub fn move(self: Self, source: ID, m: anytype, target: ID, from: anytype) Error!void {
328
+ // source: ID, move: <Move>, target: ID, from?: <Move>
329
+ pub fn move(self: Self, args: anytype) Error!void {
309
330
  if (!enabled) return;
310
331
 
311
- assert(m != .None);
332
+ assert(args[1] != .None);
312
333
  try self.writer.writeAll(&.{
313
334
  @intFromEnum(ArgType.Move),
314
- @as(u8, @bitCast(source)),
315
- @intFromEnum(m),
316
- @as(u8, @bitCast(target)),
317
- });
318
- const none = &[_]u8{@intFromEnum(Move.None)};
319
- try self.writer.writeAll(switch (@typeInfo(@TypeOf(from))) {
320
- .Null => none,
321
- .Optional => if (from) |f| blk: {
322
- assert(@intFromEnum(f) != 0);
323
- break :blk &[_]u8{ @intFromEnum(Move.From), @intFromEnum(f) };
324
- } else none,
325
- else => blk: {
326
- assert(@intFromEnum(from) != 0);
327
- break :blk &[_]u8{ @intFromEnum(Move.From), @intFromEnum(from) };
328
- },
335
+ @as(u8, @bitCast(args[0])),
336
+ @intFromEnum(args[1]),
337
+ @as(u8, @bitCast(args[2])),
329
338
  });
339
+ try self.writer.writeAll(if (args.len < 4 or @intFromEnum(args[3]) == 0)
340
+ &.{@intFromEnum(Move.None)}
341
+ else
342
+ &.{ @intFromEnum(Move.From), @intFromEnum(args[3]) });
330
343
  }
331
344
 
332
- pub fn switched(self: Self, ident: ID, pokemon: anytype) Error!void {
333
- return switchDrag(self, .Switch, ident, pokemon);
345
+ // ident: ID, pokemon: <Pokemon>
346
+ pub fn switched(self: Self, args: anytype) Error!void {
347
+ return switchDrag(self, .Switch, args);
334
348
  }
335
349
 
336
- fn switchDrag(self: Self, arg: ArgType, ident: ID, pokemon: anytype) Error!void {
350
+ // ident: ID, pokemon: <Pokemon>
351
+ fn switchDrag(self: Self, arg: ArgType, args: anytype) Error!void {
337
352
  if (!enabled) return;
338
353
 
339
- try self.writer.writeAll(&.{ @intFromEnum(arg), @as(u8, @bitCast(ident)) });
340
- if (@hasField(@TypeOf(pokemon.*), "dvs")) {
354
+ try self.writer.writeAll(&.{ @intFromEnum(arg), @as(u8, @bitCast(args[0])) });
355
+ if (@hasField(@TypeOf(args[1].*), "dvs")) {
341
356
  try self.writer.writeAll(&.{
342
- @intFromEnum(pokemon.species),
343
- @intFromEnum(pokemon.dvs.gender),
344
- pokemon.level,
357
+ @intFromEnum(args[1].species),
358
+ @intFromEnum(args[1].dvs.gender),
359
+ args[1].level,
345
360
  });
346
361
  } else {
347
- try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
362
+ try self.writer.writeAll(&.{ @intFromEnum(args[1].species), args[1].level });
348
363
  }
349
- try self.writer.writeIntNative(u16, pokemon.hp);
350
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
351
- try self.writer.writeAll(&.{pokemon.status});
364
+ try self.writer.writeInt(u16, args[1].hp, endian);
365
+ try self.writer.writeInt(u16, args[1].stats.hp, endian);
366
+ try self.writer.writeAll(&.{args[1].status});
352
367
  }
353
368
 
354
- pub fn cant(self: Self, ident: ID, reason: Cant) Error!void {
369
+ // ident: ID, reason: Cant
370
+ // ident: ID, reason: .Disable, move: <Move>
371
+ pub fn cant(self: Self, args: anytype) Error!void {
355
372
  if (!enabled) return;
356
373
 
357
- assert(reason != .Disable);
374
+ assert(args[1] != .Disable or args.len == 3);
358
375
  try self.writer.writeAll(&.{
359
376
  @intFromEnum(ArgType.Cant),
360
- @as(u8, @bitCast(ident)),
361
- @intFromEnum(reason),
362
- });
363
- }
364
-
365
- pub fn disabled(self: Self, ident: ID, m: anytype) Error!void {
366
- if (!enabled) return;
367
-
368
- try self.writer.writeAll(&.{
369
- @intFromEnum(ArgType.Cant),
370
- @as(u8, @bitCast(ident)),
371
- @intFromEnum(Cant.Disable),
372
- @intFromEnum(m),
377
+ @as(u8, @bitCast(args[0])),
378
+ @intFromEnum(@as(Cant, args[1])),
373
379
  });
380
+ if (args.len == 3) try self.writer.writeByte(@intFromEnum(args[2]));
374
381
  }
375
382
 
376
- pub fn faint(self: Self, ident: ID, done: bool) Error!void {
383
+ // ident: ID, done: bool
384
+ pub fn faint(self: Self, args: anytype) Error!void {
377
385
  if (!enabled) return;
378
386
 
379
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @as(u8, @bitCast(ident)) });
380
- if (done) try self.writer.writeByte(@intFromEnum(ArgType.None));
387
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @as(u8, @bitCast(args[0])) });
388
+ if (args[1]) try self.writer.writeByte(@intFromEnum(ArgType.None));
381
389
  }
382
390
 
383
- pub fn turn(self: Self, num: u16) Error!void {
391
+ // num: u16
392
+ pub fn turn(self: Self, args: anytype) Error!void {
384
393
  if (!enabled) return;
385
394
 
386
395
  try self.writer.writeByte(@intFromEnum(ArgType.Turn));
387
- try self.writer.writeIntNative(u16, num);
396
+ try self.writer.writeInt(u16, args[0], endian);
388
397
  try self.writer.writeByte(@intFromEnum(ArgType.None));
389
398
  }
390
399
 
391
- pub fn win(self: Self, player: Player) Error!void {
400
+ // player: Player
401
+ pub fn win(self: Self, args: anytype) Error!void {
392
402
  if (!enabled) return;
393
403
 
394
404
  try self.writer.writeAll(&.{
395
405
  @intFromEnum(ArgType.Win),
396
- @intFromEnum(player),
406
+ @intFromEnum(@as(Player, args[0])),
397
407
  @intFromEnum(ArgType.None),
398
408
  });
399
409
  }
400
410
 
401
- pub fn tie(self: Self) Error!void {
411
+ // -
412
+ pub fn tie(self: Self, _: anytype) Error!void {
402
413
  if (!enabled) return;
403
414
 
404
415
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Tie), @intFromEnum(ArgType.None) });
405
416
  }
406
417
 
407
- pub fn damage(self: Self, ident: ID, pokemon: anytype, reason: Damage) Error!void {
408
- if (!enabled) return;
409
-
410
- assert(@intFromEnum(reason) <= @intFromEnum(Damage.LeechSeed));
411
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
412
- try self.writer.writeIntNative(u16, pokemon.hp);
413
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
414
- try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
415
- }
416
-
417
- pub fn damageOf(
418
- self: Self,
419
- ident: ID,
420
- pokemon: anytype,
421
- reason: Damage,
422
- source: ID,
423
- ) Error!void {
418
+ // ident: ID, pokemon: <Pokemon>, reason: Damage
419
+ // ident: ID, pokemon: <Pokemon>, reason: .RecoilOf, source: ID
420
+ pub fn damage(self: Self, args: anytype) Error!void {
424
421
  if (!enabled) return;
425
422
 
426
- assert(@intFromEnum(reason) == @intFromEnum(Damage.RecoilOf));
427
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
428
- try self.writer.writeIntNative(u16, pokemon.hp);
429
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
423
+ assert(args[2] != .RecoilOf or args.len == 4);
430
424
  try self.writer.writeAll(&.{
431
- pokemon.status,
432
- @intFromEnum(reason),
433
- @as(u8, @bitCast(source)),
434
- });
435
- }
436
-
437
- pub fn heal(self: Self, ident: ID, pokemon: anytype, reason: Heal) Error!void {
438
- if (!enabled) return;
439
-
440
- assert(reason != .Drain);
441
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(ident)) });
442
- try self.writer.writeIntNative(u16, pokemon.hp);
443
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
444
- try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
445
- }
446
-
447
- pub fn drain(self: Self, source: ID, pokemon: anytype, target: ID) Error!void {
448
- if (!enabled) return;
449
-
450
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(source)) });
451
- try self.writer.writeIntNative(u16, pokemon.hp);
452
- try self.writer.writeIntNative(u16, pokemon.stats.hp);
453
- try self.writer.writeAll(&.{
454
- pokemon.status,
455
- @intFromEnum(Heal.Drain),
456
- @as(u8, @bitCast(target)),
425
+ @intFromEnum(ArgType.Damage),
426
+ @as(u8, @bitCast(args[0])),
457
427
  });
428
+ try self.writer.writeInt(u16, args[1].hp, endian);
429
+ try self.writer.writeInt(u16, args[1].stats.hp, endian);
430
+ try self.writer.writeAll(&.{ args[1].status, @intFromEnum(@as(Damage, args[2])) });
431
+ if (args.len == 4) try self.writer.writeByte(@as(u8, @bitCast(args[3])));
458
432
  }
459
433
 
460
- pub fn status(self: Self, ident: ID, value: u8, reason: Status) Error!void {
434
+ // ident: ID, pokemon: <Pokemon>, reason: Heal
435
+ // ident: ID, pokemon: <Pokemon>, reason: .Drain, target: ID
436
+ pub fn heal(self: Self, args: anytype) Error!void {
461
437
  if (!enabled) return;
462
438
 
463
- assert(reason != .From);
464
- try self.writer.writeAll(&.{
465
- @intFromEnum(ArgType.Status),
466
- @as(u8, @bitCast(ident)),
467
- value,
468
- @intFromEnum(reason),
469
- });
439
+ assert(args[2] != .Drain or args.len == 4);
440
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(args[0])) });
441
+ try self.writer.writeInt(u16, args[1].hp, endian);
442
+ try self.writer.writeInt(u16, args[1].stats.hp, endian);
443
+ try self.writer.writeAll(&.{ args[1].status, @intFromEnum(@as(Heal, args[2])) });
444
+ if (args.len == 4) try self.writer.writeByte(@as(u8, @bitCast(args[3])));
470
445
  }
471
446
 
472
- pub fn statusFrom(self: Self, ident: ID, value: u8, m: anytype) Error!void {
447
+ // ident: ID, value: u8, reason: Status
448
+ // ident: ID, value: u8, reason: .From, m: <Move>
449
+ pub fn status(self: Self, args: anytype) Error!void {
473
450
  if (!enabled) return;
474
451
 
452
+ assert(args[2] != .From or args.len == 4);
475
453
  try self.writer.writeAll(&.{
476
454
  @intFromEnum(ArgType.Status),
477
- @as(u8, @bitCast(ident)),
478
- value,
479
- @intFromEnum(Status.From),
480
- @intFromEnum(m),
455
+ @as(u8, @bitCast(args[0])),
456
+ args[1],
457
+ @intFromEnum(@as(Status, args[2])),
481
458
  });
459
+ if (args.len == 4) try self.writer.writeByte(@intFromEnum(args[3]));
482
460
  }
483
461
 
484
- pub fn curestatus(self: Self, ident: ID, value: u8, reason: CureStatus) Error!void {
462
+ // ident: ID, value: u8, reason: CureStatus
463
+ pub fn curestatus(self: Self, args: anytype) Error!void {
485
464
  if (!enabled) return;
486
465
 
487
466
  try self.writer.writeAll(&.{
488
467
  @intFromEnum(ArgType.CureStatus),
489
- @as(u8, @bitCast(ident)),
490
- value,
491
- @intFromEnum(reason),
468
+ @as(u8, @bitCast(args[0])),
469
+ args[1],
470
+ @intFromEnum(@as(CureStatus, args[2])),
492
471
  });
493
472
  }
494
473
 
495
- pub fn boost(self: Self, ident: ID, reason: Boost, num: i8) Error!void {
474
+ // ident: ID, reason: Boost, num: i8
475
+ pub fn boost(self: Self, args: anytype) Error!void {
496
476
  if (!enabled) return;
497
477
 
498
- assert(num != 0 and (reason != .Rage or num > 0));
478
+ assert(args[2] != 0 and (args[1] != .Rage or args[2] > 0));
499
479
  try self.writer.writeAll(&.{
500
480
  @intFromEnum(ArgType.Boost),
501
- @as(u8, @bitCast(ident)),
502
- @intFromEnum(reason),
503
- @as(u8, @intCast(num + 6)),
481
+ @as(u8, @bitCast(args[0])),
482
+ @intFromEnum(@as(Boost, args[1])),
483
+ @as(u8, @intCast(@as(i8, args[2]) + 6)),
504
484
  });
505
485
  }
506
486
 
507
- pub fn clearallboost(self: Self) Error!void {
487
+ // -
488
+ pub fn clearallboost(self: Self, _: anytype) Error!void {
508
489
  if (!enabled) return;
509
490
 
510
491
  try self.writer.writeAll(&.{@intFromEnum(ArgType.ClearAllBoost)});
511
492
  }
512
493
 
513
- pub fn fail(self: Self, ident: ID, reason: Fail) Error!void {
494
+ // ident: ID, reason: Fail
495
+ pub fn fail(self: Self, args: anytype) Error!void {
514
496
  if (!enabled) return;
515
497
 
516
498
  try self.writer.writeAll(&.{
517
499
  @intFromEnum(ArgType.Fail),
518
- @as(u8, @bitCast(ident)),
519
- @intFromEnum(reason),
500
+ @as(u8, @bitCast(args[0])),
501
+ @intFromEnum(@as(Fail, args[1])),
520
502
  });
521
503
  }
522
504
 
523
- pub fn miss(self: Self, source: ID) Error!void {
505
+ // source: ID
506
+ pub fn miss(self: Self, args: anytype) Error!void {
524
507
  if (!enabled) return;
525
508
 
526
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @as(u8, @bitCast(source)) });
509
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @as(u8, @bitCast(args[0])) });
527
510
  }
528
511
 
529
- pub fn hitcount(self: Self, ident: ID, num: u8) Error!void {
512
+ // ident: ID, num: u8
513
+ pub fn hitcount(self: Self, args: anytype) Error!void {
530
514
  if (!enabled) return;
531
515
 
532
516
  try self.writer.writeAll(&.{
533
517
  @intFromEnum(ArgType.HitCount),
534
- @as(u8, @bitCast(ident)),
535
- num,
518
+ @as(u8, @bitCast(args[0])),
519
+ args[1],
536
520
  });
537
521
  }
538
522
 
539
- pub fn prepare(self: Self, source: ID, m: anytype) Error!void {
523
+ // source: ID, m: <Move>
524
+ pub fn prepare(self: Self, args: anytype) Error!void {
540
525
  if (!enabled) return;
541
526
 
542
527
  try self.writer.writeAll(&.{
543
528
  @intFromEnum(ArgType.Prepare),
544
- @as(u8, @bitCast(source)),
545
- @intFromEnum(m),
529
+ @as(u8, @bitCast(args[0])),
530
+ @intFromEnum(args[1]),
546
531
  });
547
532
  }
548
533
 
549
- pub fn mustrecharge(self: Self, ident: ID) Error!void {
534
+ // ident: ID
535
+ pub fn mustrecharge(self: Self, args: anytype) Error!void {
550
536
  if (!enabled) return;
551
537
 
552
538
  try self.writer.writeAll(&.{
553
539
  @intFromEnum(ArgType.MustRecharge),
554
- @as(u8, @bitCast(ident)),
540
+ @as(u8, @bitCast(args[0])),
555
541
  });
556
542
  }
557
543
 
558
- pub fn activate(self: Self, ident: ID, reason: Activate) Error!void {
544
+ // ident: ID, reason: Activate
545
+ // ident: ID, reason: .SubstituteBlock, m: <Move>
546
+ // ident: ID, reason: .Magnitude, num: u8
547
+ pub fn activate(self: Self, args: anytype) Error!void {
559
548
  if (!enabled) return;
560
549
 
550
+ assert(args.len <= 4);
551
+ const reason: Activate = args[1];
561
552
  try self.writer.writeAll(&.{
562
553
  @intFromEnum(ArgType.Activate),
563
- @as(u8, @bitCast(ident)),
554
+ @as(u8, @bitCast(args[0])),
564
555
  @intFromEnum(reason),
565
556
  });
557
+ if (args.len == 3) {
558
+ if (reason == .SubstituteBlock) {
559
+ try self.writer.writeByte(@intFromEnum(args[2]));
560
+ } else {
561
+ assert(reason == .Magnitude);
562
+ try self.writer.writeByte(args[2]);
563
+ }
564
+ }
566
565
  }
567
566
 
568
- pub fn fieldactivate(self: Self) Error!void {
567
+ // -
568
+ pub fn fieldactivate(self: Self, _: anytype) Error!void {
569
569
  if (!enabled) return;
570
570
 
571
571
  try self.writer.writeAll(&.{@intFromEnum(ArgType.FieldActivate)});
572
572
  }
573
573
 
574
- pub fn start(self: Self, ident: ID, reason: Start) Error!void {
574
+ // ident: ID, reason: Start
575
+ // ident: ID, reason: .Disable | .Mimic | .Encore, m: <Move>
576
+ // ident: ID, reason: .TypeChange, types: <Types>, target: ID
577
+ pub fn start(self: Self, args: anytype) Error!void {
575
578
  if (!enabled) return;
576
579
 
577
- assert(@intFromEnum(reason) < @intFromEnum(Start.TypeChange));
580
+ assert(args.len <= 4);
581
+ const reason: Start = args[1];
578
582
  try self.writer.writeAll(&.{
579
583
  @intFromEnum(ArgType.Start),
580
- @as(u8, @bitCast(ident)),
584
+ @as(u8, @bitCast(args[0])),
581
585
  @intFromEnum(reason),
582
586
  });
587
+ if (args.len == 3) {
588
+ assert(reason == .Disable or reason == .Mimic or reason == .Encore);
589
+ try self.writer.writeByte(@intFromEnum(args[2]));
590
+ } else if (args.len == 4) {
591
+ assert(reason == .TypeChange);
592
+ // FIXME: u16 types in Generation II
593
+ try self.writer.writeAll(&.{
594
+ @as(u8, @bitCast(args[2])),
595
+ @as(u8, @bitCast(args[3])),
596
+ });
597
+ }
583
598
  }
584
599
 
585
- pub fn typechange(self: Self, source: ID, types: anytype, target: ID) Error!void {
586
- if (!enabled) return;
587
-
588
- try self.writer.writeAll(&.{
589
- @intFromEnum(ArgType.Start),
590
- @as(u8, @bitCast(source)),
591
- @intFromEnum(Start.TypeChange),
592
- @as(u8, @bitCast(types)),
593
- @as(u8, @bitCast(target)),
594
- });
595
- }
596
-
597
- pub fn startEffect(self: Self, ident: ID, reason: Start, m: anytype) Error!void {
598
- if (!enabled) return;
599
-
600
- assert(@intFromEnum(reason) > @intFromEnum(Start.TypeChange));
601
- try self.writer.writeAll(&.{
602
- @intFromEnum(ArgType.Start),
603
- @as(u8, @bitCast(ident)),
604
- @intFromEnum(reason),
605
- @intFromEnum(m),
606
- });
607
- }
608
-
609
- pub fn end(self: Self, ident: ID, reason: End) Error!void {
600
+ // ident: ID, reason: End
601
+ pub fn end(self: Self, args: anytype) Error!void {
610
602
  if (!enabled) return;
611
603
 
612
604
  try self.writer.writeAll(&.{
613
605
  @intFromEnum(ArgType.End),
614
- @as(u8, @bitCast(ident)),
615
- @intFromEnum(reason),
606
+ @as(u8, @bitCast(args[0])),
607
+ @intFromEnum(@as(End, args[1])),
616
608
  });
617
609
  }
618
610
 
619
- pub fn ohko(self: Self) Error!void {
611
+ // -
612
+ pub fn ohko(self: Self, _: anytype) Error!void {
620
613
  if (!enabled) return;
621
614
 
622
615
  try self.writer.writeAll(&.{@intFromEnum(ArgType.OHKO)});
623
616
  }
624
617
 
625
- pub fn crit(self: Self, ident: ID) Error!void {
618
+ // ident: ID
619
+ pub fn crit(self: Self, args: anytype) Error!void {
626
620
  if (!enabled) return;
627
621
 
628
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @as(u8, @bitCast(ident)) });
622
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @as(u8, @bitCast(args[0])) });
629
623
  }
630
624
 
631
- pub fn supereffective(self: Self, ident: ID) Error!void {
625
+ // ident: ID
626
+ pub fn supereffective(self: Self, args: anytype) Error!void {
632
627
  if (!enabled) return;
633
628
 
634
629
  try self.writer.writeAll(&.{
635
630
  @intFromEnum(ArgType.SuperEffective),
636
- @as(u8, @bitCast(ident)),
631
+ @as(u8, @bitCast(args[0])),
637
632
  });
638
633
  }
639
634
 
640
- pub fn resisted(self: Self, ident: ID) Error!void {
635
+ // ident: ID
636
+ pub fn resisted(self: Self, args: anytype) Error!void {
641
637
  if (!enabled) return;
642
638
 
643
639
  try self.writer.writeAll(&.{
644
640
  @intFromEnum(ArgType.Resisted),
645
- @as(u8, @bitCast(ident)),
641
+ @as(u8, @bitCast(args[0])),
646
642
  });
647
643
  }
648
644
 
649
- pub fn immune(self: Self, ident: ID, reason: Immune) Error!void {
645
+ // ident: ID, reason: Immune
646
+ pub fn immune(self: Self, args: anytype) Error!void {
650
647
  if (!enabled) return;
651
648
 
652
649
  try self.writer.writeAll(&.{
653
650
  @intFromEnum(ArgType.Immune),
654
- @as(u8, @bitCast(ident)),
655
- @intFromEnum(reason),
651
+ @as(u8, @bitCast(args[0])),
652
+ @intFromEnum(@as(Immune, args[1])),
656
653
  });
657
654
  }
658
655
 
659
- pub fn transform(self: Self, source: ID, target: ID) Error!void {
656
+ // source: ID, target: ID
657
+ pub fn transform(self: Self, args: anytype) Error!void {
660
658
  if (!enabled) return;
661
659
 
662
660
  try self.writer.writeAll(&.{
663
661
  @intFromEnum(ArgType.Transform),
664
- @as(u8, @bitCast(source)),
665
- @as(u8, @bitCast(target)),
662
+ @as(u8, @bitCast(args[0])),
663
+ @as(u8, @bitCast(args[1])),
666
664
  });
667
665
  }
668
666
 
669
- pub fn drag(self: Self, ident: ID, pokemon: anytype) Error!void {
670
- return switchDrag(self, .Drag, ident, pokemon);
667
+ // ident: ID, pokemon: <Pokemon>
668
+ pub fn drag(self: Self, args: anytype) Error!void {
669
+ return switchDrag(self, .Drag, args);
671
670
  }
672
671
 
673
- pub fn item(self: Self, target: ID, i: anytype, source: ID) Error!void {
672
+ // target: ID, item: <Item>, source: ID
673
+ pub fn item(self: Self, args: anytype) Error!void {
674
674
  if (!enabled) return;
675
675
 
676
676
  try self.writer.writeAll(&.{
677
677
  @intFromEnum(ArgType.Item),
678
- @as(u8, @bitCast(target)),
679
- @intFromEnum(i),
680
- @as(u8, @bitCast(source)),
678
+ @as(u8, @bitCast(args[0])),
679
+ @intFromEnum(args[1]),
680
+ @as(u8, @bitCast(args[2])),
681
681
  });
682
682
  }
683
683
 
684
- pub fn enditem(self: Self, ident: ID, i: anytype, reason: EndItem) Error!void {
684
+ // ident: ID, item: <Item>, reason: EndItem
685
+ pub fn enditem(self: Self, args: anytype) Error!void {
685
686
  if (!enabled) return;
686
687
 
687
688
  try self.writer.writeAll(&.{
688
689
  @intFromEnum(ArgType.EndItem),
689
- @as(u8, @bitCast(ident)),
690
- @intFromEnum(i),
691
- @intFromEnum(reason),
690
+ @as(u8, @bitCast(args[0])),
691
+ @intFromEnum(args[1]),
692
+ @intFromEnum(@as(EndItem, args[2])),
692
693
  });
693
694
  }
694
695
 
695
- pub fn cureteam(self: Self, source: ID) Error!void {
696
+ // source: ID
697
+ pub fn cureteam(self: Self, args: anytype) Error!void {
696
698
  if (!enabled) return;
697
699
 
698
700
  try self.writer.writeAll(&.{
699
701
  @intFromEnum(ArgType.CureTeam),
700
- @as(u8, @bitCast(source)),
702
+ @as(u8, @bitCast(args[0])),
701
703
  });
702
704
  }
703
705
 
704
- pub fn sethp(self: Self, ident: ID, pokemon: anytype, reason: SetHP) Error!void {
706
+ // ident: ID, pokemon: <Pokemon>, reason: SetHP
707
+ pub fn sethp(self: Self, args: anytype) Error!void {
705
708
  if (!enabled) return;
706
709
 
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));
710
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.SetHP), @as(u8, @bitCast(args[0])) });
711
+ try self.writer.writeInt(u16, args[1].hp, endian);
712
+ try self.writer.writeInt(u16, args[1].stats.hp, endian);
713
+ try self.writer.writeAll(&.{args[1].status});
714
+ try self.writer.writeByte(@intFromEnum(@as(SetHP, args[2])));
712
715
  }
713
716
 
714
- pub fn setboost(self: Self, ident: ID, num: i8) Error!void {
717
+ // ident: ID, num: i8
718
+ pub fn setboost(self: Self, args: anytype) Error!void {
715
719
  if (!enabled) return;
716
720
 
717
721
  try self.writer.writeAll(&.{
718
722
  @intFromEnum(ArgType.SetBoost),
719
- @as(u8, @bitCast(ident)),
720
- @as(u8, @intCast(num + 6)),
723
+ @as(u8, @bitCast(args[0])),
724
+ @as(u8, @intCast(args[1] + 6)),
721
725
  });
722
726
  }
723
727
 
724
- pub fn copyboost(self: Self, source: ID, target: ID) Error!void {
728
+ // source: ID, target: ID
729
+ pub fn copyboost(self: Self, args: anytype) Error!void {
725
730
  if (!enabled) return;
726
731
 
727
732
  try self.writer.writeAll(&.{
728
733
  @intFromEnum(ArgType.CopyBoost),
729
- @as(u8, @bitCast(source)),
730
- @as(u8, @bitCast(target)),
734
+ @as(u8, @bitCast(args[0])),
735
+ @as(u8, @bitCast(args[1])),
731
736
  });
732
737
  }
733
738
 
734
- pub fn sidestart(self: Self, player: Player, reason: Side) Error!void {
739
+ // player: Player, reason: Side
740
+ pub fn sidestart(self: Self, args: anytype) Error!void {
735
741
  if (!enabled) return;
736
742
 
737
743
  try self.writer.writeAll(&.{
738
744
  @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),
745
+ @intFromEnum(@as(Player, args[0])),
746
+ @intFromEnum(@as(Side, args[1])),
752
747
  });
753
748
  }
754
749
 
755
- pub fn spikesend(self: Self, player: Player, m: anytype, source: ID) Error!void {
750
+ // player: Player, reason: Side
751
+ // player: Player, reason: .Spikes, source: ID
752
+ pub fn sideend(self: Self, args: anytype) Error!void {
756
753
  if (!enabled) return;
757
754
 
755
+ assert(args[1] != .Spikes or args.len == 3);
758
756
  try self.writer.writeAll(&.{
759
757
  @intFromEnum(ArgType.SideEnd),
760
- @intFromEnum(player),
761
- @intFromEnum(Side.Spikes),
762
- @intFromEnum(m),
763
- @as(u8, @bitCast(source)),
758
+ @intFromEnum(@as(Player, args[0])),
759
+ @intFromEnum(@as(Side, args[1])),
764
760
  });
761
+ if (args.len == 3) try self.writer.writeByte(@as(u8, @bitCast(args[2])));
765
762
  }
766
763
 
767
- pub fn singlemove(self: Self, ident: ID, m: anytype) Error!void {
768
- return single(self, .SingleMove, ident, m);
764
+ // ident: ID, move: <Move>
765
+ pub fn singlemove(self: Self, args: anytype) Error!void {
766
+ return single(self, .SingleMove, args);
769
767
  }
770
768
 
771
- pub fn singleturn(self: Self, ident: ID, m: anytype) Error!void {
772
- return single(self, .SingleTurn, ident, m);
769
+ // ident: ID, move: <Move>
770
+ pub fn singleturn(self: Self, args: anytype) Error!void {
771
+ return single(self, .SingleTurn, args);
773
772
  }
774
773
 
775
- fn single(self: Self, arg: ArgType, ident: ID, m: anytype) Error!void {
774
+ // ident: ID, move: <Move>
775
+ fn single(self: Self, arg: ArgType, args: anytype) Error!void {
776
776
  if (!enabled) return;
777
777
 
778
778
  try self.writer.writeAll(&.{
779
779
  @intFromEnum(arg),
780
- @as(u8, @bitCast(ident)),
781
- @intFromEnum(m),
780
+ @as(u8, @bitCast(args[0])),
781
+ @intFromEnum(args[1]),
782
782
  });
783
783
  }
784
784
 
785
- pub fn weather(self: Self, w: anytype, reason: Weather) Error!void {
785
+ // weather: <Weather>, reason: Weather
786
+ pub fn weather(self: Self, args: anytype) Error!void {
786
787
  if (!enabled) return;
787
788
 
788
- assert(!(w == .None and reason == .Upkeep));
789
+ assert(!(args[0] == .None and args[1] == .Upkeep));
789
790
  try self.writer.writeAll(&.{
790
791
  @intFromEnum(ArgType.Weather),
791
- @intFromEnum(w),
792
- @intFromEnum(reason),
792
+ @intFromEnum(args[0]),
793
+ @intFromEnum(@as(Weather, args[1])),
793
794
  });
794
795
  }
795
796
 
796
- pub fn laststill(self: Self) Error!void {
797
+ // -
798
+ pub fn laststill(self: Self, _: anytype) Error!void {
797
799
  if (!enabled) return;
798
800
 
799
801
  try self.writer.writeAll(&.{@intFromEnum(ArgType.LastStill)});
800
802
  }
801
803
 
802
- pub fn lastmiss(self: Self) Error!void {
804
+ // -
805
+ pub fn lastmiss(self: Self, _: anytype) Error!void {
803
806
  if (!enabled) return;
804
807
 
805
808
  try self.writer.writeAll(&.{@intFromEnum(ArgType.LastMiss)});
@@ -830,10 +833,10 @@ pub const ByteStream = struct {
830
833
  try self.stream.writeByte(byte);
831
834
  }
832
835
 
833
- pub fn writeIntNative(self: Writer, comptime T: type, value: T) Error!void {
836
+ pub fn writeInt(self: Writer, comptime T: type, v: T, end: std.builtin.Endian) Error!void {
834
837
  // TODO: rework this to write directly to the buffer?
835
- var bytes: [(@typeInfo(T).Int.bits + 7) / 8]u8 = undefined;
836
- std.mem.writeIntNative(T, &bytes, value);
838
+ var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined;
839
+ std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(v)), &bytes, v, end);
837
840
  return self.writeAll(&bytes);
838
841
  }
839
842
  };
@@ -942,19 +945,19 @@ pub fn format(
942
945
  if (a[i] == N(gen.Gender.Unknown)) {
943
946
  i += 1;
944
947
  } else {
945
- var gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
948
+ const gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
946
949
  printc(", {s}", .{gender}, a, b, &i, 1, color);
947
950
  }
948
951
  }
949
952
  printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
950
953
  switch (endian) {
951
- .Big => {
954
+ .big => {
952
955
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
953
956
  printc(" {d}", .{hp}, a, b, &i, 2, color);
954
957
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
955
958
  printc("/{d}", .{hp}, a, b, &i, 2, color);
956
959
  },
957
- .Little => {
960
+ .little => {
958
961
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
959
962
  printc(" {d}", .{hp}, a, b, &i, 2, color);
960
963
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -985,8 +988,8 @@ pub fn format(
985
988
  },
986
989
  .Turn => {
987
990
  const turn = switch (endian) {
988
- .Big => @as(u16, a[i]) << 8 | @as(u16, a[i + 1]),
989
- .Little => @as(u16, a[i + 1]) << 8 | @as(u16, a[i]),
991
+ .big => @as(u16, a[i]) << 8 | @as(u16, a[i + 1]),
992
+ .little => @as(u16, a[i + 1]) << 8 | @as(u16, a[i]),
990
993
  };
991
994
  printc(" {d}", .{turn}, a, b, &i, 2, color);
992
995
  },
@@ -997,13 +1000,13 @@ pub fn format(
997
1000
  var id = ID.from(@intCast(a[i]));
998
1001
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
999
1002
  switch (endian) {
1000
- .Big => {
1003
+ .big => {
1001
1004
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1002
1005
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1003
1006
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1004
1007
  printc("/{d}", .{hp}, a, b, &i, 2, color);
1005
1008
  },
1006
- .Little => {
1009
+ .little => {
1007
1010
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1008
1011
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1009
1012
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -1068,7 +1071,13 @@ pub fn format(
1068
1071
  .Activate => {
1069
1072
  const id = ID.from(@intCast(a[i]));
1070
1073
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1071
- printc(" {s}", .{@tagName(@as(Activate, @enumFromInt(a[i])))}, a, b, &i, 1, color);
1074
+ const reason: Activate = @enumFromInt(a[i]);
1075
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
1076
+ if (reason == .SubstituteBlock) {
1077
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
1078
+ } else if (reason == .Magnitude) {
1079
+ printc(" {d}", .{a[i]}, a, b, &i, 1, color);
1080
+ }
1072
1081
  },
1073
1082
  .Start => {
1074
1083
  const id = ID.from(@intCast(a[i]));
@@ -1076,6 +1085,7 @@ pub fn format(
1076
1085
  const reason = a[i];
1077
1086
  printc(" {s}", .{@tagName(@as(Start, @enumFromInt(reason)))}, a, b, &i, 1, color);
1078
1087
  if (@as(Start, @enumFromInt(reason)) == .TypeChange) {
1088
+ // FIXME
1079
1089
  const types = @as(gen1.Types, @bitCast(a[i]));
1080
1090
  const args = .{
1081
1091
  formatter(gen, .Type, @intFromEnum(types.type1)),
@@ -1118,13 +1128,13 @@ pub fn format(
1118
1128
  const id = ID.from(@intCast(a[i]));
1119
1129
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1120
1130
  switch (endian) {
1121
- .Big => {
1131
+ .big => {
1122
1132
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1123
1133
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1124
1134
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1125
1135
  printc("/{d}", .{hp}, a, b, &i, 2, color);
1126
1136
  },
1127
- .Little => {
1137
+ .little => {
1128
1138
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1129
1139
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1130
1140
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -1192,14 +1202,11 @@ pub fn expectLog(
1192
1202
  ) !void {
1193
1203
  if (!enabled) return;
1194
1204
 
1195
- const color = color: {
1196
- if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
1197
- break :color true;
1198
- } else if (std.process.hasEnvVarConstant("NO_COLOR")) {
1199
- break :color false;
1200
- } else {
1201
- break :color std.io.getStdErr().supportsAnsiEscapeCodes();
1202
- }
1205
+ const color = if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR"))
1206
+ true
1207
+ else switch (std.io.tty.detectConfig(std.io.getStdErr())) {
1208
+ .escape_codes => true,
1209
+ else => false,
1203
1210
  };
1204
1211
 
1205
1212
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
@@ -1231,8 +1238,6 @@ fn expectEqualBytes(expected: []const u8, actual: []const u8, offset: usize) !vo
1231
1238
  }
1232
1239
  }
1233
1240
 
1234
- const endian = builtin.target.cpu.arch.endian();
1235
-
1236
1241
  fn N(e: anytype) u8 {
1237
1242
  return @intFromEnum(e);
1238
1243
  }
@@ -1240,20 +1245,13 @@ fn N(e: anytype) u8 {
1240
1245
  const p1 = Player.P1;
1241
1246
  const p2 = Player.P2;
1242
1247
 
1243
- const gen1 = struct {
1244
- pub usingnamespace @import("../gen1/data.zig");
1245
- pub const helpers = @import("../gen1/helpers.zig");
1246
- };
1247
-
1248
- const gen2 = struct {
1249
- pub usingnamespace @import("../gen2/data.zig");
1250
- pub const helpers = @import("../gen2/helpers.zig");
1251
- };
1252
-
1253
- var buf: [gen1.LOGS_SIZE]u8 = undefined;
1248
+ var buf: [pkmn.LOGS_SIZE]u8 = undefined;
1254
1249
  var stream: ByteStream = .{ .buffer = &buf };
1255
1250
  var log: FixedLog = .{ .writer = stream.writer() };
1256
1251
 
1252
+ const gen1 = pkmn.gen1;
1253
+ const gen2 = pkmn.gen2;
1254
+
1257
1255
  const M1 = gen1.Move;
1258
1256
  const S1 = gen1.Species;
1259
1257
 
@@ -1288,23 +1286,22 @@ fn formatter(comptime gen: anytype, kind: Kind, byte: u8) []const u8 {
1288
1286
  }
1289
1287
 
1290
1288
  test "|move|" {
1291
- try log.move(p2.ident(4), M1.Thunderbolt, p1.ident(5), null);
1289
+ try log.move(.{ p2.ident(4), M1.Thunderbolt, p1.ident(5) });
1292
1290
  try expectLog1(
1293
1291
  &.{ N(ArgType.Move), 0b1100, N(M1.Thunderbolt), 0b0101, N(Move.None) },
1294
1292
  buf[0..5],
1295
1293
  );
1296
1294
  stream.reset();
1297
1295
 
1298
- try log.move(p2.ident(4), M1.Wrap, p1.ident(5), M1.Wrap);
1299
- const wrap = N(M1.Wrap);
1296
+ try log.move(.{ p2.ident(4), M1.Pound, p1.ident(5), M1.Metronome });
1300
1297
  try expectLog1(
1301
- &.{ N(ArgType.Move), 0b1100, wrap, 0b0101, N(Move.From), wrap },
1298
+ &.{ N(ArgType.Move), 0b1100, N(M1.Pound), 0b0101, N(Move.From), N(M1.Metronome) },
1302
1299
  buf[0..6],
1303
1300
  );
1304
1301
  stream.reset();
1305
1302
 
1306
- try log.move(p2.ident(4), M1.SkullBash, .{}, null);
1307
- try log.laststill();
1303
+ try log.move(.{ p2.ident(4), M1.SkullBash, ID{} });
1304
+ try log.laststill(.{});
1308
1305
  try expectLog1(
1309
1306
  &.{
1310
1307
  N(ArgType.Move),
@@ -1318,8 +1315,8 @@ test "|move|" {
1318
1315
  );
1319
1316
  stream.reset();
1320
1317
 
1321
- try log.move(p2.ident(4), M1.Tackle, p1.ident(5), null);
1322
- try log.lastmiss();
1318
+ try log.move(.{ p2.ident(4), M1.Tackle, p1.ident(5) });
1319
+ try log.lastmiss(.{});
1323
1320
  try expectLog1(
1324
1321
  &.{
1325
1322
  N(ArgType.Move),
@@ -1340,11 +1337,11 @@ test "|switch|" {
1340
1337
  snorlax.hp = 200;
1341
1338
  snorlax.stats.hp = 400;
1342
1339
  snorlax.status = gen1.Status.init(.PAR);
1343
- try log.switched(p2.ident(3), &snorlax);
1340
+ try log.switched(.{ p2.ident(3), &snorlax });
1344
1341
  const par = 0b1000000;
1345
1342
  var expected: []const u8 = switch (endian) {
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 },
1343
+ .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
1344
+ .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
1348
1345
  };
1349
1346
  try expectLog1(expected, buf[0..9]);
1350
1347
  stream.reset();
@@ -1352,19 +1349,19 @@ test "|switch|" {
1352
1349
  snorlax.level = 100;
1353
1350
  snorlax.hp = 0;
1354
1351
  snorlax.status = 0;
1355
- try log.switched(p2.ident(3), &snorlax);
1352
+ try log.switched(.{ p2.ident(3), &snorlax });
1356
1353
  expected = switch (endian) {
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 },
1354
+ .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
1355
+ .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
1359
1356
  };
1360
1357
  try expectLog1(expected, buf[0..9]);
1361
1358
  stream.reset();
1362
1359
 
1363
1360
  snorlax.hp = 400;
1364
- try log.switched(p2.ident(3), &snorlax);
1361
+ try log.switched(.{ p2.ident(3), &snorlax });
1365
1362
  expected = switch (endian) {
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 },
1363
+ .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
1364
+ .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
1368
1365
  };
1369
1366
  try expectLog1(expected, buf[0..9]);
1370
1367
  stream.reset();
@@ -1374,7 +1371,7 @@ test "|switch|" {
1374
1371
  blissey.hp = 200;
1375
1372
  blissey.stats.hp = 400;
1376
1373
  blissey.status = gen2.Status.init(.PAR);
1377
- try log.switched(p2.ident(3), &blissey);
1374
+ try log.switched(.{ p2.ident(3), &blissey });
1378
1375
  expected = &(.{
1379
1376
  N(ArgType.Switch),
1380
1377
  0b1011,
@@ -1382,51 +1379,51 @@ test "|switch|" {
1382
1379
  N(gen2.Gender.Female),
1383
1380
  91,
1384
1381
  } ++ switch (endian) {
1385
- .Big => .{ 0, 200, 1, 144, par },
1386
- .Little => .{ 200, 0, 144, 1, par },
1382
+ .big => .{ 0, 200, 1, 144, par },
1383
+ .little => .{ 200, 0, 144, 1, par },
1387
1384
  });
1388
1385
  try expectLog2(expected, buf[0..10]);
1389
1386
  stream.reset();
1390
1387
  }
1391
1388
 
1392
1389
  test "|cant|" {
1393
- try log.cant(p2.ident(6), .Bound);
1390
+ try log.cant(.{ p2.ident(6), .Bound });
1394
1391
  try expectLog1(&.{ N(ArgType.Cant), 0b1110, N(Cant.Bound) }, buf[0..3]);
1395
1392
  stream.reset();
1396
1393
 
1397
- try log.disabled(p1.ident(2), M1.Earthquake);
1394
+ try log.cant(.{ p1.ident(2), .Disable, M1.Earthquake });
1398
1395
  try expectLog1(&.{ N(ArgType.Cant), 2, N(Cant.Disable), N(M1.Earthquake) }, buf[0..4]);
1399
1396
  stream.reset();
1400
1397
  }
1401
1398
 
1402
1399
  test "|faint|" {
1403
- try log.faint(p2.ident(2), false);
1400
+ try log.faint(.{ p2.ident(2), false });
1404
1401
  try expectLog1(&.{ N(ArgType.Faint), 0b1010 }, buf[0..2]);
1405
1402
  stream.reset();
1406
1403
 
1407
- try log.faint(p2.ident(2), true);
1404
+ try log.faint(.{ p2.ident(2), true });
1408
1405
  try expectLog1(&.{ N(ArgType.Faint), 0b1010, N(ArgType.None) }, buf[0..3]);
1409
1406
  stream.reset();
1410
1407
  }
1411
1408
 
1412
1409
  test "|turn|" {
1413
- try log.turn(42);
1414
- var expected = switch (endian) {
1415
- .Big => &.{ N(ArgType.Turn), 0, 42, N(ArgType.None) },
1416
- .Little => &.{ N(ArgType.Turn), 42, 0, N(ArgType.None) },
1410
+ try log.turn(.{42});
1411
+ const expected = switch (endian) {
1412
+ .big => &.{ N(ArgType.Turn), 0, 42, N(ArgType.None) },
1413
+ .little => &.{ N(ArgType.Turn), 42, 0, N(ArgType.None) },
1417
1414
  };
1418
1415
  try expectLog1(expected, buf[0..4]);
1419
1416
  stream.reset();
1420
1417
  }
1421
1418
 
1422
1419
  test "|win|" {
1423
- try log.win(.P2);
1420
+ try log.win(.{.P2});
1424
1421
  try expectLog1(&.{ N(ArgType.Win), 1, N(ArgType.None) }, buf[0..3]);
1425
1422
  stream.reset();
1426
1423
  }
1427
1424
 
1428
1425
  test "|tie|" {
1429
- try log.tie();
1426
+ try log.tie(.{});
1430
1427
  try expectLog1(&.{ N(ArgType.Tie), N(ArgType.None) }, buf[0..2]);
1431
1428
  stream.reset();
1432
1429
  }
@@ -1435,10 +1432,10 @@ test "|-damage|" {
1435
1432
  var chansey = gen1.helpers.Pokemon.init(.{ .species = .Chansey, .moves = &.{.Splash} });
1436
1433
  chansey.hp = 612;
1437
1434
  chansey.status = gen1.Status.slp(1);
1438
- try log.damage(p2.ident(2), &chansey, .None);
1435
+ try log.damage(.{ p2.ident(2), &chansey, .None });
1439
1436
  var expected: []const u8 = switch (endian) {
1440
- .Big => &.{ N(ArgType.Damage), 0b1010, 2, 100, 2, 191, 1, N(Damage.None) },
1441
- .Little => &.{ N(ArgType.Damage), 0b1010, 100, 2, 191, 2, 1, N(Damage.None) },
1437
+ .big => &.{ N(ArgType.Damage), 0b1010, 2, 100, 2, 191, 1, N(Damage.None) },
1438
+ .little => &.{ N(ArgType.Damage), 0b1010, 100, 2, 191, 2, 1, N(Damage.None) },
1442
1439
  };
1443
1440
  try expectLog1(expected, buf[0..8]);
1444
1441
  stream.reset();
@@ -1446,19 +1443,19 @@ test "|-damage|" {
1446
1443
  chansey.hp = 100;
1447
1444
  chansey.stats.hp = 256;
1448
1445
  chansey.status = 0;
1449
- try log.damage(p2.ident(2), &chansey, .Confusion);
1446
+ try log.damage(.{ p2.ident(2), &chansey, .Confusion });
1450
1447
  expected = switch (endian) {
1451
- .Big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0, N(Damage.Confusion) },
1452
- .Little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0, N(Damage.Confusion) },
1448
+ .big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0, N(Damage.Confusion) },
1449
+ .little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0, N(Damage.Confusion) },
1453
1450
  };
1454
1451
  try expectLog1(expected, buf[0..8]);
1455
1452
  stream.reset();
1456
1453
 
1457
1454
  chansey.status = gen1.Status.init(.PSN);
1458
- try log.damageOf(p2.ident(2), &chansey, .RecoilOf, p1.ident(1));
1455
+ try log.damage(.{ p2.ident(2), &chansey, .RecoilOf, p1.ident(1) });
1459
1456
  expected = switch (endian) {
1460
- .Big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0b1000, N(Damage.RecoilOf), 1 },
1461
- .Little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0b1000, N(Damage.RecoilOf), 1 },
1457
+ .big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0b1000, N(Damage.RecoilOf), 1 },
1458
+ .little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0b1000, N(Damage.RecoilOf), 1 },
1462
1459
  };
1463
1460
  try expectLog1(expected, buf[0..9]);
1464
1461
  stream.reset();
@@ -1468,10 +1465,10 @@ test "|-heal|" {
1468
1465
  var chansey = gen1.helpers.Pokemon.init(.{ .species = .Chansey, .moves = &.{.Splash} });
1469
1466
  chansey.hp = 612;
1470
1467
  chansey.status = gen1.Status.slp(1);
1471
- try log.heal(p2.ident(2), &chansey, .None);
1468
+ try log.heal(.{ p2.ident(2), &chansey, .None });
1472
1469
  var expected: []const u8 = switch (endian) {
1473
- .Big => &.{ N(ArgType.Heal), 0b1010, 2, 100, 2, 191, 1, N(Heal.None) },
1474
- .Little => &.{ N(ArgType.Heal), 0b1010, 100, 2, 191, 2, 1, N(Heal.None) },
1470
+ .big => &.{ N(ArgType.Heal), 0b1010, 2, 100, 2, 191, 1, N(Heal.None) },
1471
+ .little => &.{ N(ArgType.Heal), 0b1010, 100, 2, 191, 2, 1, N(Heal.None) },
1475
1472
  };
1476
1473
  try expectLog1(expected, buf[0..8]);
1477
1474
  stream.reset();
@@ -1479,33 +1476,33 @@ test "|-heal|" {
1479
1476
  chansey.hp = 100;
1480
1477
  chansey.stats.hp = 256;
1481
1478
  chansey.status = 0;
1482
- try log.heal(p2.ident(2), &chansey, .Silent);
1479
+ try log.heal(.{ p2.ident(2), &chansey, .Silent });
1483
1480
  expected = switch (endian) {
1484
- .Big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Silent) },
1485
- .Little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Silent) },
1481
+ .big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Silent) },
1482
+ .little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Silent) },
1486
1483
  };
1487
1484
  try expectLog1(expected, buf[0..8]);
1488
1485
  stream.reset();
1489
1486
 
1490
- try log.drain(p2.ident(2), &chansey, p1.ident(1));
1487
+ try log.heal(.{ p2.ident(2), &chansey, .Drain, p1.ident(1) });
1491
1488
  expected = switch (endian) {
1492
- .Big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Drain), 1 },
1493
- .Little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Drain), 1 },
1489
+ .big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Drain), 1 },
1490
+ .little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Drain), 1 },
1494
1491
  };
1495
1492
  try expectLog1(expected, buf[0..9]);
1496
1493
  stream.reset();
1497
1494
  }
1498
1495
 
1499
1496
  test "|-status|" {
1500
- try log.status(p2.ident(6), gen1.Status.init(.BRN), .None);
1497
+ try log.status(.{ p2.ident(6), gen1.Status.init(.BRN), .None });
1501
1498
  try expectLog1(&.{ N(ArgType.Status), 0b1110, 0b10000, N(Status.None) }, buf[0..4]);
1502
1499
  stream.reset();
1503
1500
 
1504
- try log.status(p2.ident(2), gen1.Status.init(.PSN), .Silent);
1501
+ try log.status(.{ p2.ident(2), gen1.Status.init(.PSN), .Silent });
1505
1502
  try expectLog1(&.{ N(ArgType.Status), 0b1010, 0b1000, N(Status.Silent) }, buf[0..4]);
1506
1503
  stream.reset();
1507
1504
 
1508
- try log.statusFrom(p1.ident(1), gen1.Status.init(.PAR), M1.BodySlam);
1505
+ try log.status(.{ p1.ident(1), gen1.Status.init(.PAR), .From, M1.BodySlam });
1509
1506
  try expectLog1(
1510
1507
  &.{ N(ArgType.Status), 0b0001, 0b1000000, N(Status.From), N(M1.BodySlam) },
1511
1508
  buf[0..5],
@@ -1514,11 +1511,11 @@ test "|-status|" {
1514
1511
  }
1515
1512
 
1516
1513
  test "|-curestatus|" {
1517
- try log.curestatus(p2.ident(6), gen1.Status.slp(7), .Message);
1514
+ try log.curestatus(.{ p2.ident(6), gen1.Status.slp(7), .Message });
1518
1515
  try expectLog1(&.{ N(ArgType.CureStatus), 0b1110, 0b111, N(CureStatus.Message) }, buf[0..4]);
1519
1516
  stream.reset();
1520
1517
 
1521
- try log.curestatus(p1.ident(2), gen1.Status.TOX, .Silent);
1518
+ try log.curestatus(.{ p1.ident(2), gen1.Status.TOX, .Silent });
1522
1519
  try expectLog1(&.{
1523
1520
  N(ArgType.CureStatus),
1524
1521
  0b0010,
@@ -1529,168 +1526,191 @@ test "|-curestatus|" {
1529
1526
  }
1530
1527
 
1531
1528
  test "|-boost|" {
1532
- try log.boost(p2.ident(6), .Speed, 2);
1529
+ try log.boost(.{ p2.ident(6), .Speed, 2 });
1533
1530
  try expectLog1(&.{ N(ArgType.Boost), 0b1110, N(Boost.Speed), 8 }, buf[0..4]);
1534
1531
  stream.reset();
1535
1532
 
1536
- try log.boost(p1.ident(2), .Rage, 1);
1533
+ try log.boost(.{ p1.ident(2), .Rage, 1 });
1537
1534
  try expectLog1(&.{ N(ArgType.Boost), 0b0010, N(Boost.Rage), 7 }, buf[0..4]);
1538
1535
  stream.reset();
1539
1536
 
1540
- try log.boost(p2.ident(3), .Defense, -2);
1537
+ try log.boost(.{ p2.ident(3), .Defense, -2 });
1541
1538
  try expectLog1(&.{ N(ArgType.Boost), 0b1011, N(Boost.Defense), 4 }, buf[0..4]);
1542
1539
  stream.reset();
1543
1540
  }
1544
1541
 
1545
1542
  test "|-clearallboost|" {
1546
- try log.clearallboost();
1543
+ try log.clearallboost(.{});
1547
1544
  try expectLog1(&.{N(ArgType.ClearAllBoost)}, buf[0..1]);
1548
1545
  stream.reset();
1549
1546
  }
1550
1547
 
1551
1548
  test "|-fail|" {
1552
- try log.fail(p2.ident(6), .None);
1549
+ try log.fail(.{ p2.ident(6), .None });
1553
1550
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.None) }, buf[0..3]);
1554
1551
  stream.reset();
1555
1552
 
1556
- try log.fail(p2.ident(6), .Sleep);
1553
+ try log.fail(.{ p2.ident(6), .Sleep });
1557
1554
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Sleep) }, buf[0..3]);
1558
1555
  stream.reset();
1559
1556
 
1560
- try log.fail(p2.ident(6), .Substitute);
1557
+ try log.fail(.{ p2.ident(6), .Substitute });
1561
1558
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Substitute) }, buf[0..3]);
1562
1559
  stream.reset();
1563
1560
 
1564
- try log.fail(p2.ident(6), .Weak);
1561
+ try log.fail(.{ p2.ident(6), .Weak });
1565
1562
  try expectLog1(&.{ N(ArgType.Fail), 0b1110, N(Fail.Weak) }, buf[0..3]);
1566
1563
  stream.reset();
1567
1564
  }
1568
1565
 
1569
1566
  test "|-miss|" {
1570
- try log.miss(p2.ident(4));
1567
+ try log.miss(.{p2.ident(4)});
1571
1568
  try expectLog1(&.{ N(ArgType.Miss), 0b1100 }, buf[0..2]);
1572
1569
  stream.reset();
1573
1570
  }
1574
1571
  test "|-hitcount|" {
1575
- try log.hitcount(p2.ident(1), 5);
1572
+ try log.hitcount(.{ p2.ident(1), 5 });
1576
1573
  try expectLog1(&.{ N(ArgType.HitCount), 0b1001, 5 }, buf[0..3]);
1577
1574
  stream.reset();
1578
1575
  }
1579
1576
 
1580
1577
  test "|-prepare|" {
1581
- try log.prepare(p2.ident(2), M1.Dig);
1578
+ try log.prepare(.{ p2.ident(2), M1.Dig });
1582
1579
  try expectLog1(&.{ N(ArgType.Prepare), 0b1010, N(M1.Dig) }, buf[0..3]);
1583
1580
  stream.reset();
1584
1581
  }
1585
1582
 
1586
1583
  test "|-mustrecharge|" {
1587
- try log.mustrecharge(p1.ident(6));
1584
+ try log.mustrecharge(.{p1.ident(6)});
1588
1585
  try expectLog1(&.{ N(ArgType.MustRecharge), 0b0110 }, buf[0..2]);
1589
1586
  stream.reset();
1590
1587
  }
1591
1588
 
1592
1589
  test "|-activate|" {
1593
- try log.activate(p1.ident(2), .Struggle);
1590
+ try log.activate(.{ p1.ident(2), .Struggle });
1594
1591
  try expectLog1(&.{ N(ArgType.Activate), 0b0010, N(Activate.Struggle) }, buf[0..3]);
1595
1592
  stream.reset();
1596
1593
 
1597
- try log.activate(p2.ident(4), .Mist);
1594
+ try log.activate(.{ p2.ident(4), .Mist });
1598
1595
  try expectLog1(&.{ N(ArgType.Activate), 0b1100, N(Activate.Mist) }, buf[0..3]);
1599
1596
  stream.reset();
1600
1597
 
1601
- try log.activate(p2.ident(6), .Substitute);
1598
+ try log.activate(.{ p2.ident(6), .Substitute });
1602
1599
  try expectLog1(&.{ N(ArgType.Activate), 0b1110, N(Activate.Substitute) }, buf[0..3]);
1603
1600
  stream.reset();
1604
1601
 
1605
- try log.activate(p1.ident(2), .Splash);
1602
+ try log.activate(.{ p1.ident(2), .Splash });
1606
1603
  try expectLog1(&.{ N(ArgType.Activate), 0b0010, N(Activate.Splash) }, buf[0..3]);
1607
1604
  stream.reset();
1605
+
1606
+ try log.activate(.{ p1.ident(4), .SubstituteBlock, M2.Spite });
1607
+ try expectLog1(&.{
1608
+ N(ArgType.Activate),
1609
+ 0b0100,
1610
+ N(Activate.SubstituteBlock),
1611
+ N(M2.Spite),
1612
+ }, buf[0..4]);
1613
+ stream.reset();
1614
+
1615
+ try log.activate(.{ p1.ident(3), .Magnitude, 5 });
1616
+ try expectLog1(&.{ N(ArgType.Activate), 0b0011, N(Activate.Magnitude), 5 }, buf[0..4]);
1617
+ stream.reset();
1608
1618
  }
1609
1619
 
1610
1620
  test "|-fieldactivate|" {
1611
- try log.fieldactivate();
1621
+ try log.fieldactivate(.{});
1612
1622
  try expectLog1(&.{N(ArgType.FieldActivate)}, buf[0..1]);
1613
1623
  stream.reset();
1614
1624
  }
1615
1625
 
1616
1626
  test "|-start|" {
1617
- try log.start(p2.ident(6), .Bide);
1627
+ try log.start(.{ p2.ident(6), .Bide });
1618
1628
  try expectLog1(&.{ N(ArgType.Start), 0b1110, N(Start.Bide) }, buf[0..3]);
1619
1629
  stream.reset();
1620
1630
 
1621
- try log.start(p1.ident(2), .ConfusionSilent);
1631
+ try log.start(.{ p1.ident(2), .ConfusionSilent });
1622
1632
  try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.ConfusionSilent) }, buf[0..3]);
1623
1633
  stream.reset();
1624
1634
 
1625
- try log.typechange(p2.ident(6), gen1.Types{ .type1 = .Fire, .type2 = .Fire }, p2.ident(5));
1635
+ try log.start(.{
1636
+ p2.ident(6),
1637
+ .TypeChange,
1638
+ gen1.Types{ .type1 = .Fire, .type2 = .Fire },
1639
+ p2.ident(5),
1640
+ });
1626
1641
  try expectLog1(
1627
1642
  &.{ N(ArgType.Start), 0b1110, N(Start.TypeChange), 0b1000_1000, 0b1101 },
1628
1643
  buf[0..5],
1629
1644
  );
1630
1645
  stream.reset();
1631
1646
 
1632
- try log.typechange(p1.ident(2), gen1.Types{ .type1 = .Bug, .type2 = .Poison }, p2.ident(4));
1647
+ try log.start(.{
1648
+ p1.ident(2),
1649
+ .TypeChange,
1650
+ gen1.Types{ .type1 = .Bug, .type2 = .Poison },
1651
+ p2.ident(4),
1652
+ });
1633
1653
  try expectLog1(
1634
1654
  &.{ N(ArgType.Start), 0b0010, N(Start.TypeChange), 0b0011_0110, 0b1100 },
1635
1655
  buf[0..5],
1636
1656
  );
1637
1657
  stream.reset();
1638
1658
 
1639
- try log.startEffect(p1.ident(2), .Disable, M1.Surf);
1659
+ try log.start(.{ p1.ident(2), .Disable, M1.Surf });
1640
1660
  try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Disable), N(M1.Surf) }, buf[0..4]);
1641
1661
  stream.reset();
1642
1662
 
1643
- try log.startEffect(p1.ident(2), .Mimic, M1.Surf);
1663
+ try log.start(.{ p1.ident(2), .Mimic, M1.Surf });
1644
1664
  try expectLog1(&.{ N(ArgType.Start), 0b0010, N(Start.Mimic), N(M1.Surf) }, buf[0..4]);
1645
1665
  stream.reset();
1646
1666
  }
1647
1667
 
1648
1668
  test "|-end|" {
1649
- try log.end(p2.ident(6), .Bide);
1669
+ try log.end(.{ p2.ident(6), .Bide });
1650
1670
  try expectLog1(&.{ N(ArgType.End), 0b1110, N(End.Bide) }, buf[0..3]);
1651
1671
  stream.reset();
1652
1672
 
1653
- try log.end(p1.ident(2), .ConfusionSilent);
1673
+ try log.end(.{ p1.ident(2), .ConfusionSilent });
1654
1674
  try expectLog1(&.{ N(ArgType.End), 0b0010, N(End.ConfusionSilent) }, buf[0..3]);
1655
1675
  stream.reset();
1656
1676
  }
1657
1677
 
1658
1678
  test "|-ohko|" {
1659
- try log.ohko();
1679
+ try log.ohko(.{});
1660
1680
  try expectLog1(&.{N(ArgType.OHKO)}, buf[0..1]);
1661
1681
  stream.reset();
1662
1682
  }
1663
1683
 
1664
1684
  test "|-crit|" {
1665
- try log.crit(p2.ident(5));
1685
+ try log.crit(.{p2.ident(5)});
1666
1686
  try expectLog1(&.{ N(ArgType.Crit), 0b1101 }, buf[0..2]);
1667
1687
  stream.reset();
1668
1688
  }
1669
1689
 
1670
1690
  test "|-supereffective|" {
1671
- try log.supereffective(p1.ident(1));
1691
+ try log.supereffective(.{p1.ident(1)});
1672
1692
  try expectLog1(&.{ N(ArgType.SuperEffective), 0b0001 }, buf[0..2]);
1673
1693
  stream.reset();
1674
1694
  }
1675
1695
 
1676
1696
  test "|-resisted|" {
1677
- try log.resisted(p2.ident(2));
1697
+ try log.resisted(.{p2.ident(2)});
1678
1698
  try expectLog1(&.{ N(ArgType.Resisted), 0b1010 }, buf[0..2]);
1679
1699
  stream.reset();
1680
1700
  }
1681
1701
 
1682
1702
  test "|-immune|" {
1683
- try log.immune(p1.ident(3), .None);
1703
+ try log.immune(.{ p1.ident(3), .None });
1684
1704
  try expectLog1(&.{ N(ArgType.Immune), 0b0011, N(Immune.None) }, buf[0..3]);
1685
1705
  stream.reset();
1686
1706
 
1687
- try log.immune(p2.ident(2), .OHKO);
1707
+ try log.immune(.{ p2.ident(2), .OHKO });
1688
1708
  try expectLog1(&.{ N(ArgType.Immune), 0b1010, N(Immune.OHKO) }, buf[0..3]);
1689
1709
  stream.reset();
1690
1710
  }
1691
1711
 
1692
1712
  test "|-transform|" {
1693
- try log.transform(p2.ident(4), p1.ident(5));
1713
+ try log.transform(.{ p2.ident(4), p1.ident(5) });
1694
1714
  try expectLog1(&.{ N(ArgType.Transform), 0b1100, 0b0101 }, buf[0..3]);
1695
1715
  stream.reset();
1696
1716
  }
@@ -1701,7 +1721,7 @@ test "|drag|" {
1701
1721
  blissey.hp = 200;
1702
1722
  blissey.stats.hp = 400;
1703
1723
  blissey.status = gen2.Status.init(.PAR);
1704
- try log.drag(p2.ident(3), &blissey);
1724
+ try log.drag(.{ p2.ident(3), &blissey });
1705
1725
  const par = 0b1000000;
1706
1726
  const expected = &(.{
1707
1727
  N(ArgType.Drag),
@@ -1710,31 +1730,31 @@ test "|drag|" {
1710
1730
  N(gen2.Gender.Female),
1711
1731
  91,
1712
1732
  } ++ switch (endian) {
1713
- .Big => .{ 0, 200, 1, 144, par },
1714
- .Little => .{ 200, 0, 144, 1, par },
1733
+ .big => .{ 0, 200, 1, 144, par },
1734
+ .little => .{ 200, 0, 144, 1, par },
1715
1735
  });
1716
1736
  try expectLog2(expected, buf[0..10]);
1717
1737
  stream.reset();
1718
1738
  }
1719
1739
 
1720
1740
  test "|-item|" {
1721
- try log.item(p2.ident(2), I2.GoldBerry, p1.ident(4));
1741
+ try log.item(.{ p2.ident(2), I2.GoldBerry, p1.ident(4) });
1722
1742
  try expectLog2(&.{ N(ArgType.Item), 0b1010, N(I2.GoldBerry), 0b0100 }, buf[0..4]);
1723
1743
  stream.reset();
1724
1744
  }
1725
1745
 
1726
1746
  test "|-enditem|" {
1727
- try log.enditem(p1.ident(1), I2.BerserkGene, .None);
1747
+ try log.enditem(.{ p1.ident(1), I2.BerserkGene, .None });
1728
1748
  try expectLog2(&.{ N(ArgType.EndItem), 0b0001, N(I2.BerserkGene), N(EndItem.None) }, buf[0..4]);
1729
1749
  stream.reset();
1730
1750
 
1731
- try log.enditem(p2.ident(4), I2.PRZCureBerry, .Eat);
1751
+ try log.enditem(.{ p2.ident(4), I2.PRZCureBerry, .Eat });
1732
1752
  try expectLog2(&.{ N(ArgType.EndItem), 0b1100, N(I2.PRZCureBerry), N(EndItem.Eat) }, buf[0..4]);
1733
1753
  stream.reset();
1734
1754
  }
1735
1755
 
1736
1756
  test "|-cureteam|" {
1737
- try log.cureteam(p2.ident(5));
1757
+ try log.cureteam(.{p2.ident(5)});
1738
1758
  try expectLog2(&.{ N(ArgType.CureTeam), 0b1101 }, buf[0..2]);
1739
1759
  stream.reset();
1740
1760
  }
@@ -1742,71 +1762,70 @@ test "|-cureteam|" {
1742
1762
  test "|-sethp|" {
1743
1763
  var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.PainSplit} });
1744
1764
  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) },
1765
+ try log.sethp(.{ p2.ident(2), &blissey, .Silent });
1766
+ const expected: []const u8 = switch (endian) {
1767
+ .big => &.{ N(ArgType.SetHP), 0b1010, 2, 100, 2, 201, 0, N(SetHP.Silent) },
1768
+ .little => &.{ N(ArgType.SetHP), 0b1010, 100, 2, 201, 2, 0, N(SetHP.Silent) },
1749
1769
  };
1750
1770
  try expectLog2(expected, buf[0..8]);
1751
1771
  stream.reset();
1752
1772
  }
1753
1773
 
1754
1774
  test "|-setboost|" {
1755
- try log.setboost(p2.ident(6), 6);
1775
+ try log.setboost(.{ p2.ident(6), 6 });
1756
1776
  try expectLog2(&.{ N(ArgType.SetBoost), 0b1110, 12 }, buf[0..3]);
1757
1777
  stream.reset();
1758
1778
 
1759
- try log.setboost(p2.ident(3), 2);
1779
+ try log.setboost(.{ p2.ident(3), 2 });
1760
1780
  try expectLog2(&.{ N(ArgType.SetBoost), 0b1011, 8 }, buf[0..3]);
1761
1781
  stream.reset();
1762
1782
  }
1763
1783
 
1764
1784
  test "|-copyboost|" {
1765
- try log.copyboost(p2.ident(3), p1.ident(6));
1785
+ try log.copyboost(.{ p2.ident(3), p1.ident(6) });
1766
1786
  try expectLog2(&.{ N(ArgType.CopyBoost), 0b1011, 0b0110 }, buf[0..3]);
1767
1787
  stream.reset();
1768
1788
  }
1769
1789
 
1770
1790
  test "|-sidestart|" {
1771
- try log.sidestart(.P2, .Reflect);
1791
+ try log.sidestart(.{ .P2, .Reflect });
1772
1792
  try expectLog2(&.{ N(ArgType.SideStart), 1, N(Side.Reflect) }, buf[0..3]);
1773
1793
  stream.reset();
1774
1794
  }
1775
1795
 
1776
1796
  test "|-sideend|" {
1777
- try log.sideend(.P2, .LightScreen);
1797
+ try log.sideend(.{ .P2, .LightScreen });
1778
1798
  try expectLog2(&.{ N(ArgType.SideEnd), 1, N(Side.LightScreen) }, buf[0..3]);
1779
1799
  stream.reset();
1780
1800
 
1781
- try log.spikesend(.P1, M2.RapidSpin, p1.ident(3));
1801
+ try log.sideend(.{ .P1, .Spikes, p1.ident(3) });
1782
1802
  try expectLog2(&.{
1783
1803
  N(ArgType.SideEnd),
1784
1804
  0,
1785
1805
  N(Side.Spikes),
1786
- N(M2.RapidSpin),
1787
1806
  0b0011,
1788
- }, buf[0..5]);
1807
+ }, buf[0..4]);
1789
1808
  stream.reset();
1790
1809
  }
1791
1810
 
1792
1811
  test "|-singlemove|" {
1793
- try log.singlemove(p2.ident(2), M2.DestinyBond);
1812
+ try log.singlemove(.{ p2.ident(2), M2.DestinyBond });
1794
1813
  try expectLog2(&.{ N(ArgType.SingleMove), 0b1010, N(M2.DestinyBond) }, buf[0..3]);
1795
1814
  stream.reset();
1796
1815
  }
1797
1816
 
1798
1817
  test "|-singleturn|" {
1799
- try log.singleturn(p1.ident(3), M2.Protect);
1818
+ try log.singleturn(.{ p1.ident(3), M2.Protect });
1800
1819
  try expectLog2(&.{ N(ArgType.SingleTurn), 0b0011, N(M2.Protect) }, buf[0..3]);
1801
1820
  stream.reset();
1802
1821
  }
1803
1822
 
1804
1823
  test "|-weather|" {
1805
- try log.weather(W2.Rain, .Upkeep);
1824
+ try log.weather(.{ W2.Rain, .Upkeep });
1806
1825
  try expectLog2(&.{ N(ArgType.Weather), N(W2.Rain), N(Weather.Upkeep) }, buf[0..3]);
1807
1826
  stream.reset();
1808
1827
 
1809
- try log.weather(W2.None, .None);
1828
+ try log.weather(.{ W2.None, .None });
1810
1829
  try expectLog2(&.{ N(ArgType.Weather), N(W2.None), N(Weather.None) }, buf[0..3]);
1811
1830
  stream.reset();
1812
1831
  }