@pkmn/engine 0.1.0-dev.2c13d3ec → 0.1.0-dev.305a932f

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.
@@ -30,7 +30,7 @@ pub const Type = enum(u4) {
30
30
  Ice,
31
31
  Dragon,
32
32
 
33
- const CHART = [15][15]Effectiveness{
33
+ const CHART: [15][15]Effectiveness = .{
34
34
  [_]Effectiveness{ N, N, N, N, N, R, N, I, N, N, N, N, N, N, N }, // Normal
35
35
  [_]Effectiveness{ S, N, R, R, N, S, R, I, N, N, N, N, R, S, N }, // Fighting
36
36
  [_]Effectiveness{ N, S, N, N, N, R, S, N, N, N, S, R, N, N, N }, // Flying
@@ -99,7 +99,7 @@ pub const Type = enum(u4) {
99
99
  return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
100
100
  }
101
101
 
102
- /// The precedence order of type `t2` vs. type `t1`.
102
+ /// The precedence order of Type `t2` vs. Type `t1`.
103
103
  pub fn precedence(t1: Type, t2: Type) u8 {
104
104
  for (PRECEDENCE, 0..) |matchup, i| {
105
105
  if (matchup.type1 == t1 and matchup.type2 == t2) return @intCast(i);
@@ -65,7 +65,7 @@ pub fn Battle(comptime RNG: anytype) type {
65
65
  /// The last damage dealt by either side.
66
66
  last_damage: u16 = 0,
67
67
  /// Details about the last move selected/used by each player required to detect desyncs.
68
- last_moves: MoveDetails = .{},
68
+ last_moves: [2]MoveDetails = [_]MoveDetails{.{}} ** 2,
69
69
  /// The pseudo random number generator.
70
70
  rng: RNG,
71
71
 
@@ -86,6 +86,15 @@ pub fn Battle(comptime RNG: anytype) type {
86
86
  return player.ident(@intCast(self.side(player).order[0]));
87
87
  }
88
88
 
89
+ /// Returns the `MoveDetails` for the given `player`.
90
+ pub inline fn lastMove(
91
+ self: anytype,
92
+ player: Player,
93
+ ) PointerType(@TypeOf(self), MoveDetails) {
94
+ assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
95
+ return &self.last_moves[@intFromEnum(player)];
96
+ }
97
+
89
98
  /// Returns the result of applying Player 1's choice `c1` and Player 2's choice `c2` to the
90
99
  /// battle, optionally writing protocol message logs to `options.log` if `pkmn.options.log`
91
100
  /// is enabled.
@@ -205,7 +214,7 @@ pub const Pokemon = extern struct {
205
214
  }
206
215
  };
207
216
 
208
- /// Representation of a Generation I & II Pokémon's move slot in a battle.
217
+ /// Representation of a Generation I Pokémon's move slot in a battle.
209
218
  pub const MoveSlot = extern struct {
210
219
  /// The identifier for the move.
211
220
  id: Move = .None,
@@ -213,24 +222,16 @@ pub const MoveSlot = extern struct {
213
222
  pp: u8 = 0,
214
223
 
215
224
  comptime {
216
- assert(@sizeOf(MoveSlot) == @sizeOf(u16));
225
+ assert(@sizeOf(MoveSlot) == 2);
217
226
  }
218
227
  };
219
228
 
220
229
  /// Details required to detect desyncs based on the move last selected/executed by players.
221
- pub const MoveDetails = packed struct {
222
- /// The move slot index of the last move selected in the battle menu by Player 1
223
- p1_index: if (showdown) u8 else u4 = 0,
224
- /// Whether the last move executed by Player 1 was counterable.
225
- p1_counterable: if (showdown) u8 else u4 = 0,
226
- /// The move slot index of the last move selected in the battle menu by Player 2
227
- p2_index: if (showdown) u8 else u4 = 0,
228
- /// Whether the last move executed by Player 2 was counterable.
229
- p2_counterable: if (showdown) u8 else u4 = 0,
230
-
231
- comptime {
232
- assert(@sizeOf(MoveDetails) == if (showdown) 4 else 2);
233
- }
230
+ pub const MoveDetails = packed struct(if (showdown) u16 else u8) {
231
+ /// The move slot index of the last move selected in the battle menu.
232
+ index: if (showdown) u8 else u4 = 0,
233
+ /// Whether the last move executed was counterable.
234
+ counterable: if (showdown) u8 else u4 = 0,
234
235
  };
235
236
 
236
237
  /// Bitfield representation of a Generation I & II Pokémon's major status condition.
@@ -324,7 +325,7 @@ test Status {
324
325
  }
325
326
 
326
327
  /// Bitfield representation of volatile statuses and associated data in Generation I.
327
- pub const Volatiles = packed struct {
328
+ pub const Volatiles = packed struct(u64) {
328
329
  /// Whether the "Bide" volatile status is present.
329
330
  Bide: bool = false,
330
331
  /// Whether the "Thrashing" volatile status is present.
@@ -382,14 +383,10 @@ pub const Volatiles = packed struct {
382
383
  disabled_move: u3 = 0,
383
384
  /// The number of turns toxic damage has been accumulating.
384
385
  toxic: u5 = 0,
385
-
386
- comptime {
387
- assert(@sizeOf(Volatiles) == 8);
388
- }
389
386
  };
390
387
 
391
388
  test Volatiles {
392
- var volatiles = Volatiles{};
389
+ var volatiles: Volatiles = .{};
393
390
  volatiles.Confusion = true;
394
391
  volatiles.confusion = 2;
395
392
  volatiles.Thrashing = true;
@@ -451,7 +448,7 @@ test Stats {
451
448
  }
452
449
 
453
450
  /// Representation of a Pokémon's boosts in Generation I.
454
- pub const Boosts = packed struct {
451
+ pub const Boosts = packed struct(u32) {
455
452
  /// A Pokémon's Attack boosts.
456
453
  atk: i4 = 0,
457
454
  /// A Pokémon's Defense boosts.
@@ -466,14 +463,10 @@ pub const Boosts = packed struct {
466
463
  evasion: i4 = 0,
467
464
 
468
465
  _: u8 = 0,
469
-
470
- comptime {
471
- assert(@sizeOf(Boosts) == 4);
472
- }
473
466
  };
474
467
 
475
468
  test Boosts {
476
- const boosts = Boosts{ .spc = -6 };
469
+ const boosts: Boosts = .{ .spc = -6 };
477
470
  try expectEqual(0, boosts.atk);
478
471
  try expectEqual(-6, boosts.spc);
479
472
  }
@@ -485,7 +478,7 @@ test Move {
485
478
  try expectEqual(2, @intFromEnum(Move.KarateChop));
486
479
  const move = Move.get(.Fissure);
487
480
  try expectEqual(Move.Effect.OHKO, move.effect);
488
- try expectEqual(@as(u8, 30), move.accuracy);
481
+ try expectEqual(rng.Gen12.percent(30), move.accuracy);
489
482
  try expectEqual(Type.Ground, move.type);
490
483
 
491
484
  try expect(!Move.Effect.onBegin(.None));
@@ -623,16 +616,16 @@ pub const DVs = struct {
623
616
  };
624
617
 
625
618
  test DVs {
626
- var dvs = DVs{ .spc = 15, .spe = 15 };
619
+ var dvs: DVs = .{ .spc = 15, .spe = 15 };
627
620
  try expectEqual(@as(u4, 15), dvs.hp());
628
- dvs = DVs{
621
+ dvs = .{
629
622
  .atk = 5,
630
623
  .def = 15,
631
624
  .spe = 13,
632
625
  .spc = 13,
633
626
  };
634
627
  try expectEqual(@as(u4, 15), dvs.hp());
635
- dvs = DVs{
628
+ dvs = .{
636
629
  .def = 3,
637
630
  .spe = 10,
638
631
  .spc = 11,
@@ -350,47 +350,65 @@ pub const Rolls = struct {
350
350
  const U3_NONE = [_]u3{0};
351
351
  const U3_FORCED = [_]u3{1};
352
352
 
353
- /// Returns a slice with a range of values for sleep given the `action` state.
353
+ /// Returns a slice with a range of values for sleep given the `action` and `origin` states.
354
354
  pub inline fn sleep(action: Action, origin: Action) []const u3 {
355
- const turns = @field(action.durations, "sleep");
356
- _ = origin;
357
- return if (turns < 1 or turns >= 7) &U3_NONE else &[_]u3{ 0, turns };
355
+ const a = @field(action.durations, "sleep");
356
+ const o = @field(origin.durations, "sleep");
357
+ if (o == a) return if (o == 0) &U3_NONE else &[_]u3{o};
358
+ assert(a == 0 or a == o + 1);
359
+ return if (o >= 7) &U3_NONE else &[_]u3{ 0, o + 1 };
358
360
  }
359
361
 
360
362
  const DISABLE_NONE = [_]u4{0};
361
363
 
362
- /// Returns a slice with a range of values for disable given the `action` state
364
+ /// Returns a slice with a range of values for disable given the `action` and `origin` states
363
365
  /// and the state of the `parent` (the player's Pokémon's remaining sleep turns).
364
366
  pub inline fn disable(action: Action, origin: Action, parent: u4) []const u4 {
365
- const turns = @field(action.durations, "disable");
366
- _ = origin;
367
- return if (parent > 0 or turns < 1 or turns >= 8) &DISABLE_NONE else &[_]u4{ 0, turns };
367
+ if (parent > 0) return &DISABLE_NONE;
368
+ const a = @field(action.durations, "disable");
369
+ const o = @field(origin.durations, "disable");
370
+ if (o == a) return if (o == 0) &DISABLE_NONE else &[_]u4{o};
371
+ assert(a == 0 or a == o + 1);
372
+ return if (o >= 8) &DISABLE_NONE else &[_]u4{ 0, o + 1 };
368
373
  }
369
374
 
370
- /// Returns a slice with a range of values for confusion given the `action` state
375
+ /// Returns a slice with a range of values for confusion given the `action` and `origin` states
371
376
  /// and the state of the `parent` (the player's remaining sleep turns).
372
377
  pub inline fn confusion(action: Action, origin: Action, parent: u4) []const u3 {
373
- const turns = @field(action.durations, "confusion");
374
- _ = origin;
375
- if (parent > 0 or turns < 1 or turns >= 5) return &U3_NONE;
376
- return if (turns < 2) &U3_FORCED else &[_]u3{ 0, turns };
378
+ if (parent > 0) return &U3_NONE;
379
+ const a = @field(action.durations, "confusion");
380
+ const o = @field(origin.durations, "confusion");
381
+ if (o == a) return if (o == 0) &U3_NONE else &[_]u3{o};
382
+ assert(a == 0 or a == o + 1);
383
+ return if (o >= 5) &U3_NONE else if (o < 2)
384
+ if (a == 0) &U3_NONE else &U3_FORCED
385
+ else
386
+ &[_]u3{ 0, o + 1 };
377
387
  }
378
388
 
379
- /// Returns a slice with a range of values for attacking given the `action` state
389
+ /// Returns a slice with a range of values for attacking given the `action` and `origin` states
380
390
  /// and the state of the `parent` (whether the player's Pokémon was fully paralyzed).
381
391
  pub inline fn attacking(action: Action, origin: Action, parent: Optional(bool)) []const u3 {
382
- const turns = @field(action.durations, "attacking");
383
- _ = origin;
384
- if (parent == .true or turns < 1 or turns >= 3) return &U3_NONE;
385
- return if (turns < 2) &U3_FORCED else &[_]u3{ 0, turns };
392
+ if (parent == .true) return &U3_NONE;
393
+ const a = @field(action.durations, "attacking");
394
+ const o = @field(origin.durations, "attacking");
395
+ if (o == a) return if (o == 0) &U3_NONE else &[_]u3{o};
396
+ assert(a == 0 or a == o + 1);
397
+ return if (o >= 3) &U3_NONE else if (o < 2)
398
+ if (a == 0) &U3_NONE else &U3_FORCED
399
+ else
400
+ &[_]u3{ 0, o + 1 };
386
401
  }
387
402
 
388
- /// Returns a slice with a range of values for binding given the `action` state
403
+ /// Returns a slice with a range of values for binding given the `action` and `origin` states
389
404
  /// and the state of the `parent` (whether the player's Pokémon was fully paralyzed).
390
405
  pub inline fn binding(action: Action, origin: Action, parent: Optional(bool)) []const u3 {
391
- const turns = @field(action.durations, "binding");
392
- _ = origin;
393
- return if (parent == .true or turns < 1 or turns >= 4) &U3_NONE else &[_]u3{ 0, turns };
406
+ if (parent == .true) return &U3_NONE;
407
+ const a = @field(action.durations, "binding");
408
+ const o = @field(origin.durations, "binding");
409
+ if (o == a) return if (o == 0) &U3_NONE else &[_]u3{o};
410
+ assert(a == 0 or a == o + 1);
411
+ return if (o >= 4) &U3_NONE else &[_]u3{ 0, o + 1 };
394
412
  }
395
413
 
396
414
  const SLOT_NONE = [_]u4{0};
@@ -460,13 +478,13 @@ pub const Rolls = struct {
460
478
  };
461
479
 
462
480
  test "Rolls.speedTie" {
463
- const actions = Actions{ .p1 = .{ .speed_tie = .P2 } };
481
+ const actions: Actions = .{ .p1 = .{ .speed_tie = .P2 } };
464
482
  try expectEqualSlices(Optional(Player), &.{ .P1, .P2 }, Rolls.speedTie(actions.p1));
465
483
  try expectEqualSlices(Optional(Player), &.{.None}, Rolls.speedTie(actions.p2));
466
484
  }
467
485
 
468
486
  test "Rolls.damage" {
469
- const actions = Actions{ .p2 = .{ .damage = 221 } };
487
+ const actions: Actions = .{ .p2 = .{ .damage = 221 } };
470
488
  try expectEqual(Rolls.Range{ .min = 0, .max = 1 }, Rolls.damage(actions.p1, .None));
471
489
  try expectEqual(Rolls.Range{ .min = 217, .max = 256 }, Rolls.damage(actions.p2, .None));
472
490
  try expectEqual(Rolls.Range{ .min = 0, .max = 1 }, Rolls.damage(actions.p2, .false));
@@ -484,7 +502,7 @@ test "Rolls.coalesce" {
484
502
  }
485
503
 
486
504
  test "Rolls.hit" {
487
- const actions = Actions{ .p2 = .{ .hit = .true } };
505
+ const actions: Actions = .{ .p2 = .{ .hit = .true } };
488
506
  try expectEqualSlices(Optional(bool), &.{.None}, Rolls.hit(actions.p1, .None));
489
507
  try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.hit(actions.p2, .None));
490
508
  try expectEqualSlices(Optional(bool), &.{.None}, Rolls.hit(actions.p2, .true));
@@ -492,7 +510,7 @@ test "Rolls.hit" {
492
510
  }
493
511
 
494
512
  test "Rolls.secondaryChance" {
495
- const actions = Actions{ .p1 = .{ .secondary_chance = .true } };
513
+ const actions: Actions = .{ .p1 = .{ .secondary_chance = .true } };
496
514
  try expectEqualSlices(
497
515
  Optional(bool),
498
516
  &.{ .false, .true },
@@ -503,7 +521,7 @@ test "Rolls.secondaryChance" {
503
521
  }
504
522
 
505
523
  test "Rolls.criticalHit" {
506
- const actions = Actions{ .p1 = .{ .critical_hit = .true } };
524
+ const actions: Actions = .{ .p1 = .{ .critical_hit = .true } };
507
525
  try expectEqualSlices(
508
526
  Optional(bool),
509
527
  &.{ .false, .true },
@@ -514,14 +532,14 @@ test "Rolls.criticalHit" {
514
532
  }
515
533
 
516
534
  test "Rolls.confused" {
517
- const actions = Actions{ .p2 = .{ .confused = .true } };
535
+ const actions: Actions = .{ .p2 = .{ .confused = .true } };
518
536
  try expectEqualSlices(Optional(bool), &.{.None}, Rolls.confused(actions.p1, 1));
519
537
  try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.confused(actions.p2, 1));
520
538
  try expectEqualSlices(Optional(bool), &.{.None}, Rolls.confused(actions.p2, 0));
521
539
  }
522
540
 
523
541
  test "Rolls.paralyzed" {
524
- const actions = Actions{ .p2 = .{ .paralyzed = .true } };
542
+ const actions: Actions = .{ .p2 = .{ .paralyzed = .true } };
525
543
  try expectEqualSlices(Optional(bool), &.{.None}, Rolls.paralyzed(actions.p1, .None));
526
544
  try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.paralyzed(actions.p2, .None));
527
545
  try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.paralyzed(actions.p2, .false));
@@ -529,102 +547,237 @@ test "Rolls.paralyzed" {
529
547
  }
530
548
 
531
549
  test "Rolls.duration" {
532
- const actions = Actions{ .p2 = .{ .duration = 3 } };
550
+ const actions: Actions = .{ .p2 = .{ .duration = 3 } };
533
551
  try expectEqualSlices(u1, &.{0}, Rolls.duration(actions.p1, .None));
534
552
  try expectEqualSlices(u1, &.{1}, Rolls.duration(actions.p2, .None));
535
553
  try expectEqualSlices(u1, &.{0}, Rolls.duration(actions.p2, .false));
536
554
  }
537
555
 
538
- const FIXME: Action = .{};
539
-
540
556
  test "Rolls.sleep" {
541
- try expectEqualSlices(u3, &.{0}, Rolls.sleep(.{ .durations = .{ .sleep = 0 } }, FIXME));
542
- try expectEqualSlices(u3, &.{0}, Rolls.sleep(.{ .durations = .{ .sleep = 7 } }, FIXME));
543
- try expectEqualSlices(u3, &.{ 0, 4 }, Rolls.sleep(.{ .durations = .{ .sleep = 4 } }, FIXME));
557
+ try expectEqualSlices(u3, &.{0}, Rolls.sleep(
558
+ .{ .durations = .{ .sleep = 0 } },
559
+ .{ .durations = .{ .sleep = 0 } },
560
+ ));
561
+ try expectEqualSlices(u3, &.{ 0, 1 }, Rolls.sleep(
562
+ .{ .durations = .{ .sleep = 1 } },
563
+ .{ .durations = .{ .sleep = 0 } },
564
+ ));
565
+ try expectEqualSlices(u3, &.{ 0, 2 }, Rolls.sleep(
566
+ .{ .durations = .{ .sleep = 0 } },
567
+ .{ .durations = .{ .sleep = 1 } },
568
+ ));
569
+ try expectEqualSlices(u3, &.{1}, Rolls.sleep(
570
+ .{ .durations = .{ .sleep = 1 } },
571
+ .{ .durations = .{ .sleep = 1 } },
572
+ ));
573
+ try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.sleep(
574
+ .{ .durations = .{ .sleep = 0 } },
575
+ .{ .durations = .{ .sleep = 2 } },
576
+ ));
577
+ try expectEqualSlices(u3, &.{ 0, 7 }, Rolls.sleep(
578
+ .{ .durations = .{ .sleep = 7 } },
579
+ .{ .durations = .{ .sleep = 6 } },
580
+ ));
581
+ try expectEqualSlices(u3, &.{0}, Rolls.sleep(
582
+ .{ .durations = .{ .sleep = 0 } },
583
+ .{ .durations = .{ .sleep = 7 } },
584
+ ));
544
585
  }
545
586
 
546
587
  test "Rolls.disable" {
547
- try expectEqualSlices(u4, &.{0}, Rolls.disable(.{ .durations = .{ .disable = 0 } }, FIXME, 0));
548
- try expectEqualSlices(u4, &.{0}, Rolls.disable(.{ .durations = .{ .disable = 8 } }, FIXME, 0));
549
- try expectEqualSlices(u4, &.{0}, Rolls.disable(.{ .durations = .{ .disable = 4 } }, FIXME, 1));
550
- try expectEqualSlices(u4, &.{ 0, 4 }, Rolls.disable(.{
551
- .durations = .{ .disable = 4 },
552
- }, FIXME, 0));
588
+ try expectEqualSlices(u4, &.{0}, Rolls.disable(
589
+ .{ .durations = .{ .disable = 0 } },
590
+ .{ .durations = .{ .disable = 0 } },
591
+ 0,
592
+ ));
593
+ try expectEqualSlices(u4, &.{ 0, 1 }, Rolls.disable(
594
+ .{ .durations = .{ .disable = 1 } },
595
+ .{ .durations = .{ .disable = 0 } },
596
+ 0,
597
+ ));
598
+ try expectEqualSlices(u4, &.{ 0, 2 }, Rolls.disable(
599
+ .{ .durations = .{ .disable = 0 } },
600
+ .{ .durations = .{ .disable = 1 } },
601
+ 0,
602
+ ));
603
+ try expectEqualSlices(u4, &.{1}, Rolls.disable(
604
+ .{ .durations = .{ .disable = 1 } },
605
+ .{ .durations = .{ .disable = 1 } },
606
+ 0,
607
+ ));
608
+ try expectEqualSlices(u4, &.{ 0, 3 }, Rolls.disable(
609
+ .{ .durations = .{ .disable = 0 } },
610
+ .{ .durations = .{ .disable = 2 } },
611
+ 0,
612
+ ));
613
+ try expectEqualSlices(u4, &.{0}, Rolls.disable(
614
+ .{ .durations = .{ .disable = 0 } },
615
+ .{ .durations = .{ .disable = 2 } },
616
+ 1,
617
+ ));
618
+ try expectEqualSlices(u4, &.{ 0, 8 }, Rolls.disable(
619
+ .{ .durations = .{ .disable = 8 } },
620
+ .{ .durations = .{ .disable = 7 } },
621
+ 0,
622
+ ));
623
+ try expectEqualSlices(u4, &.{0}, Rolls.disable(
624
+ .{ .durations = .{ .disable = 0 } },
625
+ .{ .durations = .{ .disable = 8 } },
626
+ 0,
627
+ ));
553
628
  }
554
629
 
555
630
  test "Rolls.confusion" {
556
- try expectEqualSlices(u3, &.{0}, Rolls.confusion(.{
557
- .durations = .{ .confusion = 0 },
558
- }, FIXME, 0));
559
- try expectEqualSlices(u3, &.{0}, Rolls.confusion(.{
560
- .durations = .{ .confusion = 5 },
561
- }, FIXME, 0));
562
- try expectEqualSlices(u3, &.{0}, Rolls.confusion(.{
563
- .durations = .{ .confusion = 3 },
564
- }, FIXME, 1));
565
- try expectEqualSlices(u3, &.{1}, Rolls.confusion(.{
566
- .durations = .{ .confusion = 1 },
567
- }, FIXME, 0));
568
- try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.confusion(.{
569
- .durations = .{ .confusion = 3 },
570
- }, FIXME, 0));
631
+ try expectEqualSlices(u3, &.{0}, Rolls.confusion(
632
+ .{ .durations = .{ .confusion = 0 } },
633
+ .{ .durations = .{ .confusion = 0 } },
634
+ 0,
635
+ ));
636
+ try expectEqualSlices(u3, &.{1}, Rolls.confusion(
637
+ .{ .durations = .{ .confusion = 1 } },
638
+ .{ .durations = .{ .confusion = 0 } },
639
+ 0,
640
+ ));
641
+ try expectEqualSlices(u3, &.{0}, Rolls.confusion(
642
+ .{ .durations = .{ .confusion = 0 } },
643
+ .{ .durations = .{ .confusion = 1 } },
644
+ 0,
645
+ ));
646
+ try expectEqualSlices(u3, &.{1}, Rolls.confusion(
647
+ .{ .durations = .{ .confusion = 1 } },
648
+ .{ .durations = .{ .confusion = 1 } },
649
+ 0,
650
+ ));
651
+ try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.confusion(
652
+ .{ .durations = .{ .confusion = 0 } },
653
+ .{ .durations = .{ .confusion = 2 } },
654
+ 0,
655
+ ));
656
+ try expectEqualSlices(u3, &.{0}, Rolls.confusion(
657
+ .{ .durations = .{ .confusion = 0 } },
658
+ .{ .durations = .{ .confusion = 2 } },
659
+ 1,
660
+ ));
661
+ try expectEqualSlices(u3, &.{ 0, 5 }, Rolls.confusion(
662
+ .{ .durations = .{ .confusion = 5 } },
663
+ .{ .durations = .{ .confusion = 4 } },
664
+ 0,
665
+ ));
666
+ try expectEqualSlices(u3, &.{0}, Rolls.confusion(
667
+ .{ .durations = .{ .confusion = 0 } },
668
+ .{ .durations = .{ .confusion = 5 } },
669
+ 0,
670
+ ));
571
671
  }
572
672
 
573
673
  test "Rolls.attacking" {
574
- try expectEqualSlices(u3, &.{0}, Rolls.attacking(.{
575
- .durations = .{ .attacking = 0 },
576
- }, FIXME, .false));
577
- try expectEqualSlices(u3, &.{0}, Rolls.attacking(.{
578
- .durations = .{ .attacking = 3 },
579
- }, FIXME, .false));
580
- try expectEqualSlices(u3, &.{0}, Rolls.attacking(.{
581
- .durations = .{ .attacking = 2 },
582
- }, FIXME, .true));
583
- try expectEqualSlices(u3, &.{1}, Rolls.attacking(.{
584
- .durations = .{ .attacking = 1 },
585
- }, FIXME, .false));
586
- try expectEqualSlices(u3, &.{ 0, 2 }, Rolls.attacking(.{
587
- .durations = .{ .attacking = 2 },
588
- }, FIXME, .false));
674
+ try expectEqualSlices(u3, &.{0}, Rolls.attacking(
675
+ .{ .durations = .{ .attacking = 0 } },
676
+ .{ .durations = .{ .attacking = 0 } },
677
+ .false,
678
+ ));
679
+ try expectEqualSlices(u3, &.{1}, Rolls.attacking(
680
+ .{ .durations = .{ .attacking = 1 } },
681
+ .{ .durations = .{ .attacking = 0 } },
682
+ .false,
683
+ ));
684
+ try expectEqualSlices(u3, &.{0}, Rolls.attacking(
685
+ .{ .durations = .{ .attacking = 0 } },
686
+ .{ .durations = .{ .attacking = 1 } },
687
+ .false,
688
+ ));
689
+ try expectEqualSlices(u3, &.{1}, Rolls.attacking(
690
+ .{ .durations = .{ .attacking = 1 } },
691
+ .{ .durations = .{ .attacking = 1 } },
692
+ .false,
693
+ ));
694
+ try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.attacking(
695
+ .{ .durations = .{ .attacking = 0 } },
696
+ .{ .durations = .{ .attacking = 2 } },
697
+ .false,
698
+ ));
699
+ try expectEqualSlices(u3, &.{0}, Rolls.attacking(
700
+ .{ .durations = .{ .attacking = 0 } },
701
+ .{ .durations = .{ .attacking = 2 } },
702
+ .true,
703
+ ));
704
+ try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.attacking(
705
+ .{ .durations = .{ .attacking = 3 } },
706
+ .{ .durations = .{ .attacking = 2 } },
707
+ .false,
708
+ ));
709
+ try expectEqualSlices(u3, &.{0}, Rolls.attacking(
710
+ .{ .durations = .{ .attacking = 0 } },
711
+ .{ .durations = .{ .attacking = 3 } },
712
+ .false,
713
+ ));
589
714
  }
590
715
 
591
716
  test "Rolls.binding" {
592
- try expectEqualSlices(u3, &.{0}, Rolls.binding(.{
593
- .durations = .{ .binding = 0 },
594
- }, FIXME, .false));
595
- try expectEqualSlices(u3, &.{0}, Rolls.binding(.{
596
- .durations = .{ .binding = 4 },
597
- }, FIXME, .false));
598
- try expectEqualSlices(u3, &.{0}, Rolls.binding(.{
599
- .durations = .{ .binding = 2 },
600
- }, FIXME, .true));
601
- try expectEqualSlices(u3, &.{ 0, 2 }, Rolls.binding(.{
602
- .durations = .{ .binding = 2 },
603
- }, FIXME, .false));
717
+ try expectEqualSlices(u3, &.{0}, Rolls.binding(
718
+ .{ .durations = .{ .binding = 0 } },
719
+ .{ .durations = .{ .binding = 0 } },
720
+ .false,
721
+ ));
722
+ try expectEqualSlices(u3, &.{ 0, 1 }, Rolls.binding(
723
+ .{ .durations = .{ .binding = 1 } },
724
+ .{ .durations = .{ .binding = 0 } },
725
+ .false,
726
+ ));
727
+ try expectEqualSlices(u3, &.{ 0, 2 }, Rolls.binding(
728
+ .{ .durations = .{ .binding = 0 } },
729
+ .{ .durations = .{ .binding = 1 } },
730
+ .false,
731
+ ));
732
+ try expectEqualSlices(u3, &.{1}, Rolls.binding(
733
+ .{ .durations = .{ .binding = 1 } },
734
+ .{ .durations = .{ .binding = 1 } },
735
+ .false,
736
+ ));
737
+ try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.binding(
738
+ .{ .durations = .{ .binding = 0 } },
739
+ .{ .durations = .{ .binding = 2 } },
740
+ .false,
741
+ ));
742
+ try expectEqualSlices(u3, &.{0}, Rolls.binding(
743
+ .{ .durations = .{ .binding = 0 } },
744
+ .{ .durations = .{ .binding = 2 } },
745
+ .true,
746
+ ));
747
+ try expectEqualSlices(u3, &.{ 0, 4 }, Rolls.binding(
748
+ .{ .durations = .{ .binding = 4 } },
749
+ .{ .durations = .{ .binding = 3 } },
750
+ .false,
751
+ ));
752
+ try expectEqualSlices(u3, &.{0}, Rolls.binding(
753
+ .{ .durations = .{ .binding = 0 } },
754
+ .{ .durations = .{ .binding = 4 } },
755
+ .false,
756
+ ));
604
757
  }
605
758
 
606
759
  test "Rolls.moveSlot" {
607
- const actions = Actions{ .p2 = .{ .move_slot = 3 } };
760
+ const actions: Actions = .{ .p2 = .{ .move_slot = 3 } };
608
761
  try expectEqualSlices(u4, &.{0}, Rolls.moveSlot(actions.p1, .None));
609
762
  try expectEqualSlices(u4, &.{ 1, 2, 3, 4 }, Rolls.moveSlot(actions.p2, .None));
610
763
  try expectEqualSlices(u4, &.{0}, Rolls.moveSlot(actions.p2, .false));
611
764
  }
612
765
 
613
766
  test "Rolls.multiHit" {
614
- const actions = Actions{ .p2 = .{ .multi_hit = 3 } };
767
+ const actions: Actions = .{ .p2 = .{ .multi_hit = 3 } };
615
768
  try expectEqualSlices(u4, &.{0}, Rolls.multiHit(actions.p1, .None));
616
769
  try expectEqualSlices(u4, &.{ 2, 3, 4, 5 }, Rolls.multiHit(actions.p2, .None));
617
770
  try expectEqualSlices(u4, &.{0}, Rolls.multiHit(actions.p2, .false));
618
771
  }
619
772
 
620
773
  test "Rolls.metronome" {
621
- const actions = Actions{ .p2 = .{ .metronome = .Surf } };
774
+ const actions: Actions = .{ .p2 = .{ .metronome = .Surf } };
622
775
  try expectEqualSlices(Move, &.{.None}, Rolls.metronome(actions.p1));
623
776
  try expectEqual(@as(Move, @enumFromInt(24)), Rolls.metronome(actions.p2)[23]);
624
777
  }
625
778
 
626
779
  test "Rolls.psywave" {
627
- const actions = Actions{ .p2 = .{ .psywave = 79 } };
780
+ const actions: Actions = .{ .p2 = .{ .psywave = 79 } };
628
781
  var side = Side.init(&[_]Pokemon{.{
629
782
  .species = .Bulbasaur,
630
783
  .level = 100,