@pkmn/engine 0.1.0-dev.f918c3bd → 0.1.0-dev.fb6653d6

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