@pkmn/engine 0.1.0-dev.942dbfa4 → 0.1.0-dev.954f650d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -102,6 +102,9 @@ pub const ArgType = enum(u8) {
102
102
  // Gen 8
103
103
  CanDynamax,
104
104
  SwapSideConditions,
105
+
106
+ // Gen 9
107
+ Terastallize,
105
108
  };
106
109
 
107
110
  pub const Move = enum(u8) {
@@ -133,6 +136,8 @@ pub const Damage = enum(u8) {
133
136
  Confusion,
134
137
  LeechSeed,
135
138
  RecoilOf,
139
+
140
+ Spikes,
136
141
  };
137
142
 
138
143
  pub const Status = enum(u8) {
@@ -219,8 +224,12 @@ pub const Immune = enum(u8) {
219
224
  OHKO,
220
225
  };
221
226
 
227
+ /// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
228
+ /// Ignores anything sent to it, though protocol logging should additionally be turned off
229
+ /// entirely with `options.log`.
222
230
  pub const NULL = Log(@TypeOf(std.io.null_writer)){ .writer = std.io.null_writer };
223
231
 
232
+ /// Logs protocol information to its `Writer` during a battle update when `options.log` is enabled.
224
233
  pub fn Log(comptime Writer: type) type {
225
234
  return struct {
226
235
  const Self = @This();
@@ -231,12 +240,13 @@ pub fn Log(comptime Writer: type) type {
231
240
 
232
241
  pub fn move(self: Self, source: ID, m: anytype, target: ID, from: anytype) Error!void {
233
242
  if (!enabled) return;
243
+
234
244
  assert(m != .None);
235
245
  try self.writer.writeAll(&.{
236
246
  @intFromEnum(ArgType.Move),
237
- @bitCast(u8, source),
247
+ @as(u8, @bitCast(source)),
238
248
  @intFromEnum(m),
239
- @bitCast(u8, target),
249
+ @as(u8, @bitCast(target)),
240
250
  });
241
251
  const none = &[_]u8{@intFromEnum(Move.None)};
242
252
  try self.writer.writeAll(switch (@typeInfo(@TypeOf(from))) {
@@ -254,8 +264,17 @@ pub fn Log(comptime Writer: type) type {
254
264
 
255
265
  pub fn switched(self: Self, ident: ID, pokemon: anytype) Error!void {
256
266
  if (!enabled) return;
257
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @bitCast(u8, ident) });
258
- try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
267
+
268
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @as(u8, @bitCast(ident)) });
269
+ if (@hasField(@TypeOf(pokemon.*), "dvs")) {
270
+ try self.writer.writeAll(&.{
271
+ @intFromEnum(pokemon.species),
272
+ @intFromEnum(pokemon.dvs.gender),
273
+ pokemon.level,
274
+ });
275
+ } else {
276
+ try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
277
+ }
259
278
  try self.writer.writeIntNative(u16, pokemon.hp);
260
279
  try self.writer.writeIntNative(u16, pokemon.stats.hp);
261
280
  try self.writer.writeAll(&.{pokemon.status});
@@ -263,19 +282,21 @@ pub fn Log(comptime Writer: type) type {
263
282
 
264
283
  pub fn cant(self: Self, ident: ID, reason: Cant) Error!void {
265
284
  if (!enabled) return;
285
+
266
286
  assert(reason != .Disable);
267
287
  try self.writer.writeAll(&.{
268
288
  @intFromEnum(ArgType.Cant),
269
- @bitCast(u8, ident),
289
+ @as(u8, @bitCast(ident)),
270
290
  @intFromEnum(reason),
271
291
  });
272
292
  }
273
293
 
274
294
  pub fn disabled(self: Self, ident: ID, m: anytype) Error!void {
275
295
  if (!enabled) return;
296
+
276
297
  try self.writer.writeAll(&.{
277
298
  @intFromEnum(ArgType.Cant),
278
- @bitCast(u8, ident),
299
+ @as(u8, @bitCast(ident)),
279
300
  @intFromEnum(Cant.Disable),
280
301
  @intFromEnum(m),
281
302
  });
@@ -283,12 +304,14 @@ pub fn Log(comptime Writer: type) type {
283
304
 
284
305
  pub fn faint(self: Self, ident: ID, done: bool) Error!void {
285
306
  if (!enabled) return;
286
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @bitCast(u8, ident) });
307
+
308
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @as(u8, @bitCast(ident)) });
287
309
  if (done) try self.writer.writeByte(@intFromEnum(ArgType.None));
288
310
  }
289
311
 
290
312
  pub fn turn(self: Self, num: u16) Error!void {
291
313
  if (!enabled) return;
314
+
292
315
  try self.writer.writeByte(@intFromEnum(ArgType.Turn));
293
316
  try self.writer.writeIntNative(u16, num);
294
317
  try self.writer.writeByte(@intFromEnum(ArgType.None));
@@ -296,6 +319,7 @@ pub fn Log(comptime Writer: type) type {
296
319
 
297
320
  pub fn win(self: Self, player: Player) Error!void {
298
321
  if (!enabled) return;
322
+
299
323
  try self.writer.writeAll(&.{
300
324
  @intFromEnum(ArgType.Win),
301
325
  @intFromEnum(player),
@@ -305,13 +329,15 @@ pub fn Log(comptime Writer: type) type {
305
329
 
306
330
  pub fn tie(self: Self) Error!void {
307
331
  if (!enabled) return;
332
+
308
333
  try self.writer.writeAll(&.{ @intFromEnum(ArgType.Tie), @intFromEnum(ArgType.None) });
309
334
  }
310
335
 
311
336
  pub fn damage(self: Self, ident: ID, pokemon: anytype, reason: Damage) Error!void {
312
337
  if (!enabled) return;
338
+
313
339
  assert(@intFromEnum(reason) <= @intFromEnum(Damage.LeechSeed));
314
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @bitCast(u8, ident) });
340
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
315
341
  try self.writer.writeIntNative(u16, pokemon.hp);
316
342
  try self.writer.writeIntNative(u16, pokemon.stats.hp);
317
343
  try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
@@ -325,21 +351,23 @@ pub fn Log(comptime Writer: type) type {
325
351
  source: ID,
326
352
  ) Error!void {
327
353
  if (!enabled) return;
354
+
328
355
  assert(@intFromEnum(reason) == @intFromEnum(Damage.RecoilOf));
329
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @bitCast(u8, ident) });
356
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
330
357
  try self.writer.writeIntNative(u16, pokemon.hp);
331
358
  try self.writer.writeIntNative(u16, pokemon.stats.hp);
332
359
  try self.writer.writeAll(&.{
333
360
  pokemon.status,
334
361
  @intFromEnum(reason),
335
- @bitCast(u8, source),
362
+ @as(u8, @bitCast(source)),
336
363
  });
337
364
  }
338
365
 
339
366
  pub fn heal(self: Self, ident: ID, pokemon: anytype, reason: Heal) Error!void {
340
367
  if (!enabled) return;
368
+
341
369
  assert(reason != .Drain);
342
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @bitCast(u8, ident) });
370
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(ident)) });
343
371
  try self.writer.writeIntNative(u16, pokemon.hp);
344
372
  try self.writer.writeIntNative(u16, pokemon.stats.hp);
345
373
  try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
@@ -347,22 +375,24 @@ pub fn Log(comptime Writer: type) type {
347
375
 
348
376
  pub fn drain(self: Self, source: ID, pokemon: anytype, target: ID) Error!void {
349
377
  if (!enabled) return;
350
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @bitCast(u8, source) });
378
+
379
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(source)) });
351
380
  try self.writer.writeIntNative(u16, pokemon.hp);
352
381
  try self.writer.writeIntNative(u16, pokemon.stats.hp);
353
382
  try self.writer.writeAll(&.{
354
383
  pokemon.status,
355
384
  @intFromEnum(Heal.Drain),
356
- @bitCast(u8, target),
385
+ @as(u8, @bitCast(target)),
357
386
  });
358
387
  }
359
388
 
360
389
  pub fn status(self: Self, ident: ID, value: u8, reason: Status) Error!void {
361
390
  if (!enabled) return;
391
+
362
392
  assert(reason != .From);
363
393
  try self.writer.writeAll(&.{
364
394
  @intFromEnum(ArgType.Status),
365
- @bitCast(u8, ident),
395
+ @as(u8, @bitCast(ident)),
366
396
  value,
367
397
  @intFromEnum(reason),
368
398
  });
@@ -370,9 +400,10 @@ pub fn Log(comptime Writer: type) type {
370
400
 
371
401
  pub fn statusFrom(self: Self, ident: ID, value: u8, m: anytype) Error!void {
372
402
  if (!enabled) return;
403
+
373
404
  try self.writer.writeAll(&.{
374
405
  @intFromEnum(ArgType.Status),
375
- @bitCast(u8, ident),
406
+ @as(u8, @bitCast(ident)),
376
407
  value,
377
408
  @intFromEnum(Status.From),
378
409
  @intFromEnum(m),
@@ -381,9 +412,10 @@ pub fn Log(comptime Writer: type) type {
381
412
 
382
413
  pub fn curestatus(self: Self, ident: ID, value: u8, reason: CureStatus) Error!void {
383
414
  if (!enabled) return;
415
+
384
416
  try self.writer.writeAll(&.{
385
417
  @intFromEnum(ArgType.CureStatus),
386
- @bitCast(u8, ident),
418
+ @as(u8, @bitCast(ident)),
387
419
  value,
388
420
  @intFromEnum(reason),
389
421
  });
@@ -391,98 +423,113 @@ pub fn Log(comptime Writer: type) type {
391
423
 
392
424
  pub fn boost(self: Self, ident: ID, reason: Boost, num: i8) Error!void {
393
425
  if (!enabled) return;
426
+
394
427
  assert(num != 0 and (reason != .Rage or num > 0));
395
428
  try self.writer.writeAll(&.{
396
429
  @intFromEnum(ArgType.Boost),
397
- @bitCast(u8, ident),
430
+ @as(u8, @bitCast(ident)),
398
431
  @intFromEnum(reason),
399
- @intCast(u8, num + 6),
432
+ @as(u8, @intCast(num + 6)),
400
433
  });
401
434
  }
402
435
 
403
436
  pub fn clearallboost(self: Self) Error!void {
404
437
  if (!enabled) return;
438
+
405
439
  try self.writer.writeAll(&.{@intFromEnum(ArgType.ClearAllBoost)});
406
440
  }
407
441
 
408
442
  pub fn fail(self: Self, ident: ID, reason: Fail) Error!void {
409
443
  if (!enabled) return;
444
+
410
445
  try self.writer.writeAll(&.{
411
446
  @intFromEnum(ArgType.Fail),
412
- @bitCast(u8, ident),
447
+ @as(u8, @bitCast(ident)),
413
448
  @intFromEnum(reason),
414
449
  });
415
450
  }
416
451
 
417
452
  pub fn miss(self: Self, source: ID) Error!void {
418
453
  if (!enabled) return;
419
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @bitCast(u8, source) });
454
+
455
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @as(u8, @bitCast(source)) });
420
456
  }
421
457
 
422
458
  pub fn hitcount(self: Self, ident: ID, num: u8) Error!void {
423
459
  if (!enabled) return;
460
+
424
461
  try self.writer.writeAll(&.{
425
462
  @intFromEnum(ArgType.HitCount),
426
- @bitCast(u8, ident),
463
+ @as(u8, @bitCast(ident)),
427
464
  num,
428
465
  });
429
466
  }
430
467
 
431
468
  pub fn prepare(self: Self, source: ID, m: anytype) Error!void {
432
469
  if (!enabled) return;
470
+
433
471
  try self.writer.writeAll(&.{
434
472
  @intFromEnum(ArgType.Prepare),
435
- @bitCast(u8, source),
473
+ @as(u8, @bitCast(source)),
436
474
  @intFromEnum(m),
437
475
  });
438
476
  }
439
477
 
440
478
  pub fn mustrecharge(self: Self, ident: ID) Error!void {
441
479
  if (!enabled) return;
442
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.MustRecharge), @bitCast(u8, ident) });
480
+
481
+ try self.writer.writeAll(&.{
482
+ @intFromEnum(ArgType.MustRecharge),
483
+ @as(u8, @bitCast(ident)),
484
+ });
443
485
  }
444
486
 
445
487
  pub fn activate(self: Self, ident: ID, reason: Activate) Error!void {
446
488
  if (!enabled) return;
489
+
447
490
  try self.writer.writeAll(&.{
448
491
  @intFromEnum(ArgType.Activate),
449
- @bitCast(u8, ident),
492
+ @as(u8, @bitCast(ident)),
450
493
  @intFromEnum(reason),
451
494
  });
452
495
  }
453
496
 
454
497
  pub fn fieldactivate(self: Self) Error!void {
455
498
  if (!enabled) return;
499
+
456
500
  try self.writer.writeAll(&.{@intFromEnum(ArgType.FieldActivate)});
457
501
  }
458
502
 
459
503
  pub fn start(self: Self, ident: ID, reason: Start) Error!void {
460
504
  if (!enabled) return;
505
+
461
506
  assert(@intFromEnum(reason) < @intFromEnum(Start.TypeChange));
462
507
  try self.writer.writeAll(&.{
463
508
  @intFromEnum(ArgType.Start),
464
- @bitCast(u8, ident),
509
+ @as(u8, @bitCast(ident)),
465
510
  @intFromEnum(reason),
466
511
  });
467
512
  }
468
513
 
469
514
  pub fn typechange(self: Self, source: ID, types: anytype, target: ID) Error!void {
470
515
  if (!enabled) return;
516
+
471
517
  try self.writer.writeAll(&.{
472
518
  @intFromEnum(ArgType.Start),
473
- @bitCast(u8, source),
519
+ @as(u8, @bitCast(source)),
474
520
  @intFromEnum(Start.TypeChange),
475
- @bitCast(u8, types),
476
- @bitCast(u8, target),
521
+ @as(u8, @bitCast(types)),
522
+ @as(u8, @bitCast(target)),
477
523
  });
478
524
  }
479
525
 
480
526
  pub fn startEffect(self: Self, ident: ID, reason: Start, m: anytype) Error!void {
481
527
  if (!enabled) return;
528
+
482
529
  assert(@intFromEnum(reason) > @intFromEnum(Start.TypeChange));
483
530
  try self.writer.writeAll(&.{
484
531
  @intFromEnum(ArgType.Start),
485
- @bitCast(u8, ident),
532
+ @as(u8, @bitCast(ident)),
486
533
  @intFromEnum(reason),
487
534
  @intFromEnum(m),
488
535
  });
@@ -490,68 +537,84 @@ pub fn Log(comptime Writer: type) type {
490
537
 
491
538
  pub fn end(self: Self, ident: ID, reason: End) Error!void {
492
539
  if (!enabled) return;
540
+
493
541
  try self.writer.writeAll(&.{
494
542
  @intFromEnum(ArgType.End),
495
- @bitCast(u8, ident),
543
+ @as(u8, @bitCast(ident)),
496
544
  @intFromEnum(reason),
497
545
  });
498
546
  }
499
547
 
500
548
  pub fn ohko(self: Self) Error!void {
501
549
  if (!enabled) return;
550
+
502
551
  try self.writer.writeAll(&.{@intFromEnum(ArgType.OHKO)});
503
552
  }
504
553
 
505
554
  pub fn crit(self: Self, ident: ID) Error!void {
506
555
  if (!enabled) return;
507
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @bitCast(u8, ident) });
556
+
557
+ try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @as(u8, @bitCast(ident)) });
508
558
  }
509
559
 
510
560
  pub fn supereffective(self: Self, ident: ID) Error!void {
511
561
  if (!enabled) return;
562
+
512
563
  try self.writer.writeAll(&.{
513
564
  @intFromEnum(ArgType.SuperEffective),
514
- @bitCast(u8, ident),
565
+ @as(u8, @bitCast(ident)),
515
566
  });
516
567
  }
517
568
 
518
569
  pub fn resisted(self: Self, ident: ID) Error!void {
519
570
  if (!enabled) return;
520
- try self.writer.writeAll(&.{ @intFromEnum(ArgType.Resisted), @bitCast(u8, ident) });
571
+
572
+ try self.writer.writeAll(&.{
573
+ @intFromEnum(ArgType.Resisted),
574
+ @as(u8, @bitCast(ident)),
575
+ });
521
576
  }
522
577
 
523
578
  pub fn immune(self: Self, ident: ID, reason: Immune) Error!void {
524
579
  if (!enabled) return;
580
+
525
581
  try self.writer.writeAll(&.{
526
582
  @intFromEnum(ArgType.Immune),
527
- @bitCast(u8, ident),
583
+ @as(u8, @bitCast(ident)),
528
584
  @intFromEnum(reason),
529
585
  });
530
586
  }
531
587
 
532
588
  pub fn transform(self: Self, source: ID, target: ID) Error!void {
533
589
  if (!enabled) return;
590
+
534
591
  try self.writer.writeAll(&.{
535
592
  @intFromEnum(ArgType.Transform),
536
- @bitCast(u8, source),
537
- @bitCast(u8, target),
593
+ @as(u8, @bitCast(source)),
594
+ @as(u8, @bitCast(target)),
538
595
  });
539
596
  }
540
597
 
541
598
  pub fn laststill(self: Self) Error!void {
542
599
  if (!enabled) return;
600
+
543
601
  try self.writer.writeAll(&.{@intFromEnum(ArgType.LastStill)});
544
602
  }
545
603
 
546
604
  pub fn lastmiss(self: Self) Error!void {
547
605
  if (!enabled) return;
606
+
548
607
  try self.writer.writeAll(&.{@intFromEnum(ArgType.LastMiss)});
549
608
  }
550
609
  };
551
610
  }
552
611
 
612
+ /// `Log` type backed by the optimized `ByteStream.Writer`.
553
613
  pub const FixedLog = Log(ByteStream.Writer);
554
614
 
615
+ /// Stripped down version of `std.io.FixedBufferStream` optimized for efficiently writing the
616
+ /// individual protocol bytes. Note that the `ByteStream.Writer` is **not** a `std.io.Writer` and
617
+ /// should not be used for general purpose writing.
555
618
  pub const ByteStream = struct {
556
619
  buffer: []u8,
557
620
  pos: usize = 0,
@@ -593,14 +656,18 @@ pub const ByteStream = struct {
593
656
  };
594
657
 
595
658
  pub const Kind = enum { Move, Species, Type, Status };
596
- pub const Formatter = fn (Kind, u8) []const u8;
597
659
 
598
- pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, color: bool) void {
660
+ pub fn format(
661
+ comptime gen: anytype,
662
+ a: []const u8,
663
+ b: ?[]const u8,
664
+ color: bool,
665
+ ) void {
599
666
  print("\n", .{});
600
667
 
601
668
  var i: usize = 0;
602
669
  while (i < a.len) {
603
- const arg = @enumFromInt(ArgType, a[i]);
670
+ const arg: ArgType = @enumFromInt(a[i]);
604
671
  const name = switch (arg) {
605
672
  .None => if (color) "\x1b[2m-\x1b[0m" else "-",
606
673
  .LastStill => "|[still]",
@@ -646,19 +713,29 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
646
713
  .OHKO,
647
714
  => {},
648
715
  .Move => {
649
- const source = ID.from(@intCast(u4, a[i]));
716
+ const source = ID.from(@intCast(a[i]));
650
717
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
651
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
652
- const target = ID.from(@intCast(u4, a[i]));
718
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
719
+ const target = ID.from(@intCast(a[i]));
653
720
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
654
- const reason = @enumFromInt(Move, a[i]);
721
+ const reason: Move = @enumFromInt(a[i]);
655
722
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
656
- if (reason == .From) printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
723
+ if (reason == .From) {
724
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
725
+ }
657
726
  },
658
727
  .Switch => {
659
- const id = ID.from(@intCast(u4, a[i]));
728
+ const id = ID.from(@intCast(a[i]));
660
729
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
661
- printc(" {s}", .{formatter(.Species, a[i])}, a, b, &i, 1, color);
730
+ printc(" {s}", .{formatter(gen, .Species, a[i])}, a, b, &i, 1, color);
731
+ if (@hasDecl(gen, "Gender")) {
732
+ if (a[i] == N(gen.Gender.Unknown)) {
733
+ i += 1;
734
+ } else {
735
+ var gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
736
+ printc(", {s}", .{gender}, a, b, &i, 1, color);
737
+ }
738
+ }
662
739
  printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
663
740
  switch (endian) {
664
741
  .Big => {
@@ -674,15 +751,15 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
674
751
  printc("/{d}", .{hp}, a, b, &i, 2, color);
675
752
  },
676
753
  }
677
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
754
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
678
755
  },
679
756
  .Cant => {
680
- const id = ID.from(@intCast(u4, a[i]));
757
+ const id = ID.from(@intCast(a[i]));
681
758
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
682
- const reason = @enumFromInt(Cant, a[i]);
759
+ const reason: Cant = @enumFromInt(a[i]);
683
760
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
684
761
  if (reason == .Disable) {
685
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
762
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
686
763
  }
687
764
  },
688
765
  .Faint,
@@ -692,7 +769,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
692
769
  .SuperEffective,
693
770
  .Resisted,
694
771
  => {
695
- const id = ID.from(@intCast(u4, a[i]));
772
+ const id = ID.from(@intCast(a[i]));
696
773
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
697
774
  },
698
775
  .Turn => {
@@ -702,9 +779,11 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
702
779
  };
703
780
  printc(" {d}", .{turn}, a, b, &i, 2, color);
704
781
  },
705
- .Win => printc(" {s}", .{@tagName(@enumFromInt(Player, a[i]))}, a, b, &i, 1, color),
782
+ .Win => {
783
+ printc(" {s}", .{@tagName(@as(Player, @enumFromInt(a[i])))}, a, b, &i, 1, color);
784
+ },
706
785
  .Damage, .Heal => {
707
- var id = ID.from(@intCast(u4, a[i]));
786
+ var id = ID.from(@intCast(a[i]));
708
787
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
709
788
  switch (endian) {
710
789
  .Big => {
@@ -720,93 +799,96 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
720
799
  printc("/{d}", .{hp}, a, b, &i, 2, color);
721
800
  },
722
801
  }
723
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
802
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
724
803
  if (arg == .Damage) {
725
- const reason = a[i];
726
- printc(" {s}", .{@tagName(@enumFromInt(Damage, reason))}, a, b, &i, 1, color);
727
- if (reason == @intFromEnum(Damage.RecoilOf)) {
728
- id = ID.from(@intCast(u4, a[i]));
804
+ const reason: Damage = @enumFromInt(a[i]);
805
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
806
+ if (reason == .RecoilOf) {
807
+ id = ID.from(@intCast(a[i]));
729
808
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
730
809
  }
731
810
  } else {
732
- const reason = @enumFromInt(Heal, a[i]);
811
+ const reason: Heal = @enumFromInt(a[i]);
733
812
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
734
813
  if (reason == .Drain) {
735
- id = ID.from(@intCast(u4, a[i]));
814
+ id = ID.from(@intCast(a[i]));
736
815
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
737
816
  }
738
817
  }
739
818
  },
740
819
  .Status => {
741
- const id = ID.from(@intCast(u4, a[i]));
820
+ const id = ID.from(@intCast(a[i]));
742
821
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
743
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
744
- const reason = @enumFromInt(Status, a[i]);
822
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
823
+ const reason: Status = @enumFromInt(a[i]);
745
824
  printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
746
- if (reason == .From) printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
825
+ if (reason == .From) {
826
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
827
+ }
747
828
  },
748
829
  .CureStatus => {
749
- const id = ID.from(@intCast(u4, a[i]));
830
+ const id = ID.from(@intCast(a[i]));
750
831
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
751
- printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
752
- printc(" {s}", .{@tagName(@enumFromInt(CureStatus, a[i]))}, a, b, &i, 1, color);
832
+ printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
833
+ const reason: CureStatus = @enumFromInt(a[i]);
834
+ printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
753
835
  },
754
836
  .Boost => {
755
- const id = ID.from(@intCast(u4, a[i]));
837
+ const id = ID.from(@intCast(a[i]));
756
838
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
757
- printc(" {s}", .{@tagName(@enumFromInt(Boost, a[i]))}, a, b, &i, 1, color);
839
+ printc(" {s}", .{@tagName(@as(Boost, @enumFromInt(a[i])))}, a, b, &i, 1, color);
758
840
  printc(" {d}", .{a[i]}, a, b, &i, 1, color);
759
841
  },
760
842
  .Fail => {
761
- const id = ID.from(@intCast(u4, a[i]));
843
+ const id = ID.from(@intCast(a[i]));
762
844
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
763
- printc(" {s}", .{@tagName(@enumFromInt(Fail, a[i]))}, a, b, &i, 1, color);
845
+ printc(" {s}", .{@tagName(@as(Fail, @enumFromInt(a[i])))}, a, b, &i, 1, color);
764
846
  },
765
847
  .HitCount => {
766
- const id = ID.from(@intCast(u4, a[i]));
848
+ const id = ID.from(@intCast(a[i]));
767
849
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
768
850
  printc(" {d}", .{a[i]}, a, b, &i, 1, color);
769
851
  },
770
852
  .Prepare => {
771
- const id = ID.from(@intCast(u4, a[i]));
853
+ const id = ID.from(@intCast(a[i]));
772
854
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
773
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
855
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
774
856
  },
775
857
  .Activate => {
776
- const id = ID.from(@intCast(u4, a[i]));
858
+ const id = ID.from(@intCast(a[i]));
777
859
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
778
- printc(" {s}", .{@tagName(@enumFromInt(Activate, a[i]))}, a, b, &i, 1, color);
860
+ printc(" {s}", .{@tagName(@as(Activate, @enumFromInt(a[i])))}, a, b, &i, 1, color);
779
861
  },
780
862
  .Start => {
781
- const id = ID.from(@intCast(u4, a[i]));
863
+ const id = ID.from(@intCast(a[i]));
782
864
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
783
865
  const reason = a[i];
784
- printc(" {s}", .{@tagName(@enumFromInt(Start, reason))}, a, b, &i, 1, color);
785
- if (@enumFromInt(Start, reason) == .TypeChange) {
786
- const types = @bitCast(gen1.Types, a[i]);
866
+ printc(" {s}", .{@tagName(@as(Start, @enumFromInt(reason)))}, a, b, &i, 1, color);
867
+ if (@as(Start, @enumFromInt(reason)) == .TypeChange) {
868
+ const types = @as(gen1.Types, @bitCast(a[i]));
787
869
  const args = .{
788
- formatter(.Type, @intFromEnum(types.type1)),
789
- formatter(.Type, @intFromEnum(types.type2)),
870
+ formatter(gen, .Type, @intFromEnum(types.type1)),
871
+ formatter(gen, .Type, @intFromEnum(types.type2)),
790
872
  };
791
873
  printc(" {s}/{s}", args, a, b, &i, 1, color);
792
874
  } else if (reason >= @intFromEnum(Start.Disable)) {
793
- printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
875
+ printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
794
876
  }
795
877
  },
796
878
  .End => {
797
- const id = ID.from(@intCast(u4, a[i]));
879
+ const id = ID.from(@intCast(a[i]));
798
880
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
799
- printc(" {s}", .{@tagName(@enumFromInt(End, a[i]))}, a, b, &i, 1, color);
881
+ printc(" {s}", .{@tagName(@as(End, @enumFromInt(a[i])))}, a, b, &i, 1, color);
800
882
  },
801
883
  .Immune => {
802
- const id = ID.from(@intCast(u4, a[i]));
884
+ const id = ID.from(@intCast(a[i]));
803
885
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
804
- printc(" {s}", .{@tagName(@enumFromInt(Immune, a[i]))}, a, b, &i, 1, color);
886
+ printc(" {s}", .{@tagName(@as(Immune, @enumFromInt(a[i])))}, a, b, &i, 1, color);
805
887
  },
806
888
  .Transform => {
807
- const source = ID.from(@intCast(u4, a[i]));
889
+ const source = ID.from(@intCast(a[i]));
808
890
  printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
809
- const target = ID.from(@intCast(u4, a[i]));
891
+ const target = ID.from(@intCast(a[i]));
810
892
  printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
811
893
  },
812
894
  else => unreachable,
@@ -840,12 +922,13 @@ fn printc(
840
922
  }
841
923
 
842
924
  pub fn expectLog(
843
- comptime formatter: Formatter,
925
+ comptime gen: anytype,
844
926
  expected: []const u8,
845
927
  actual: []const u8,
846
928
  offset: usize,
847
929
  ) !void {
848
930
  if (!enabled) return;
931
+
849
932
  const color = color: {
850
933
  if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
851
934
  break :color true;
@@ -858,8 +941,8 @@ pub fn expectLog(
858
941
 
859
942
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
860
943
  error.TestExpectedEqual => {
861
- format(formatter, expected, null, color);
862
- format(formatter, actual, expected, color);
944
+ format(gen, expected, null, color);
945
+ format(gen, actual, expected, color);
863
946
  return err;
864
947
  },
865
948
  else => return err,
@@ -899,6 +982,11 @@ const gen1 = struct {
899
982
  pub const helpers = @import("../gen1/helpers.zig");
900
983
  };
901
984
 
985
+ const gen2 = struct {
986
+ pub usingnamespace @import("../gen2/data.zig");
987
+ pub const helpers = @import("../gen2/helpers.zig");
988
+ };
989
+
902
990
  var buf: [gen1.LOGS_SIZE]u8 = undefined;
903
991
  var stream = ByteStream{ .buffer = &buf };
904
992
  var log: FixedLog = .{ .writer = stream.writer() };
@@ -907,15 +995,19 @@ const M = gen1.Move;
907
995
  const S = gen1.Species;
908
996
 
909
997
  fn expectLog1(expected: []const u8, actual: []const u8) !void {
910
- return expectLog(gen1Formatter, expected, actual, 0);
998
+ return expectLog(gen1, expected, actual, 0);
911
999
  }
912
1000
 
913
- fn gen1Formatter(kind: Kind, byte: u8) []const u8 {
1001
+ fn expectLog2(expected: []const u8, actual: []const u8) !void {
1002
+ return expectLog(gen2, expected, actual, 0);
1003
+ }
1004
+
1005
+ fn formatter(comptime gen: anytype, kind: Kind, byte: u8) []const u8 {
914
1006
  return switch (kind) {
915
- .Move => @tagName(@enumFromInt(M, byte)),
916
- .Species => @tagName(@enumFromInt(S, byte)),
917
- .Type => @tagName(@enumFromInt(gen1.Type, byte)),
918
- .Status => gen1.Status.name(byte),
1007
+ .Move => @tagName(@as(gen.Move, @enumFromInt(byte))),
1008
+ .Species => @tagName(@as(gen.Species, @enumFromInt(byte))),
1009
+ .Type => @tagName(@as(gen.Type, @enumFromInt(byte))),
1010
+ .Status => gen.Status.name(byte),
919
1011
  };
920
1012
  }
921
1013
 
@@ -1000,6 +1092,25 @@ test "|switch|" {
1000
1092
  };
1001
1093
  try expectLog1(expected, buf[0..9]);
1002
1094
  stream.reset();
1095
+
1096
+ var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.Splash} });
1097
+ blissey.level = 91;
1098
+ blissey.hp = 200;
1099
+ blissey.stats.hp = 400;
1100
+ blissey.status = gen2.Status.init(.PAR);
1101
+ try log.switched(p2.ident(3), &blissey);
1102
+ expected = &(.{
1103
+ N(ArgType.Switch),
1104
+ 0b1011,
1105
+ N(gen2.Species.Blissey),
1106
+ N(gen2.Gender.Female),
1107
+ 91,
1108
+ } ++ switch (endian) {
1109
+ .Big => .{ 0, 200, 1, 144, par },
1110
+ .Little => .{ 200, 0, 144, 1, par },
1111
+ });
1112
+ try expectLog2(expected, buf[0..10]);
1113
+ stream.reset();
1003
1114
  }
1004
1115
 
1005
1116
  test "|cant|" {