@pkmn/engine 0.1.0-dev.44b2e6ec → 0.1.0-dev.44c4a618

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.
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const builtin = @import("builtin");
2
3
 
3
4
  const common = @import("../common/data.zig");
4
5
  const optional = @import("../common/optional.zig");
@@ -35,6 +36,8 @@ const Status = data.Status;
35
36
  const Action = chance.Action;
36
37
  const Actions = chance.Actions;
37
38
 
39
+ const endian = builtin.cpu.arch.endian();
40
+
38
41
  /// Configuration options controlling the domain of valid Pokémon that can be generated by the
39
42
  /// random generator helpers.
40
43
  pub const Options = struct {
@@ -43,6 +46,8 @@ pub const Options = struct {
43
46
  /// Whether to generate Pokémon with moves that contain bugs on Pokémon Showdown that are
44
47
  /// unimplementable in the engine.
45
48
  block: bool = showdown,
49
+ // FIXME: remove once durations work with -Dchance
50
+ durations: bool = false,
46
51
  };
47
52
 
48
53
  /// Helpers to simplify initialization of a Generation I battle.
@@ -86,18 +91,38 @@ pub const Battle = struct {
86
91
  };
87
92
 
88
93
  fn prng(rand: *PSRNG) data.PRNG {
89
- // GLITCH: initial bytes in seed can only range from 0-252, not 0-255
90
- const max: u8 = 253;
91
94
  return .{
92
95
  .src = .{
93
96
  .seed = if (showdown)
94
97
  rand.newSeed()
95
- else
96
- .{
97
- rand.range(u8, 0, max), rand.range(u8, 0, max), rand.range(u8, 0, max),
98
- rand.range(u8, 0, max), rand.range(u8, 0, max), rand.range(u8, 0, max),
99
- rand.range(u8, 0, max), rand.range(u8, 0, max), rand.range(u8, 0, max),
100
- },
98
+ else seed: {
99
+ // GLITCH: The initial RNG seed in Gen I link battles is heavily constrained
100
+ // https://www.smogon.com/forums/threads/rng-in-rby-link-battles.3746779
101
+ var seed = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
102
+
103
+ // Bytes in seed can only range from 0-252, not 0-255
104
+ const max: u8 = 253;
105
+ // Instructions take multiples of 4 cycles to execute
106
+ var timer: u16 = 4 * rand.range(u16, 0, 16384);
107
+ var add: u8 = rand.range(u8, 0, 256);
108
+ var carry: u8 = 0;
109
+
110
+ var i: u8 = 0;
111
+ while (i < seed.len) {
112
+ const div: u8 = @intCast(timer >> 8);
113
+ add +%= div +% carry;
114
+ if (add < max) {
115
+ seed[i] = add;
116
+ i += 1;
117
+ timer +%= 472;
118
+ carry = 1;
119
+ } else {
120
+ timer +%= 452;
121
+ carry = 0;
122
+ }
123
+ }
124
+ break :seed seed;
125
+ },
101
126
  },
102
127
  };
103
128
  }
@@ -210,6 +235,7 @@ pub const Pokemon = struct {
210
235
  var m: Move = .None;
211
236
  sample: while (true) {
212
237
  m = @enumFromInt(rand.range(u8, 1, Move.size - 1 + 1));
238
+ if (opt.durations and durations(m)) continue :sample;
213
239
  if (opt.block and blocked(m)) continue :sample;
214
240
  for (0..i) |j| if (ms[j].id == m) continue :sample;
215
241
  break;
@@ -247,6 +273,23 @@ fn blocked(m: Move) bool {
247
273
  };
248
274
  }
249
275
 
276
+ fn durations(m: Move) bool {
277
+ // Any moves that have effects that result in duration tracking with -Dchance
278
+ return switch (Move.get(m).effect) {
279
+ .Confusion,
280
+ .Bide,
281
+ .Sleep,
282
+ .Rage,
283
+ .Binding,
284
+ .Thrashing,
285
+ .ConfusionChance,
286
+ .Disable,
287
+ .Metronome,
288
+ => true,
289
+ else => false,
290
+ };
291
+ }
292
+
250
293
  /// Convenience helper to create a move-type choice for the provided move slot.
251
294
  pub fn move(slot: u4) Choice {
252
295
  return .{ .type = .Move, .data = slot };
@@ -478,12 +521,12 @@ test "Rolls.damage" {
478
521
  test "Rolls.coalesce" {
479
522
  var summaries =
480
523
  calc.Summaries{ .p1 = .{ .damage = .{ .base = 74, .final = 69, .capped = true } } };
481
- try expectEqual(@as(u8, 0), try Rolls.coalesce(.P2, 0, &summaries, false));
482
- try expectEqual(@as(u8, 241), try Rolls.coalesce(.P2, 238, &summaries, false));
483
- try expectEqual(@as(u8, 255), try Rolls.coalesce(.P2, 238, &summaries, true));
524
+ try expectEqual(0, try Rolls.coalesce(.P2, 0, &summaries, false));
525
+ try expectEqual(241, try Rolls.coalesce(.P2, 238, &summaries, false));
526
+ try expectEqual(255, try Rolls.coalesce(.P2, 238, &summaries, true));
484
527
  summaries.p1.damage.final = 74;
485
- try expectEqual(@as(u8, 217), try Rolls.coalesce(.P2, 217, &summaries, false));
486
- try expectEqual(@as(u8, 255), try Rolls.coalesce(.P2, 217, &summaries, true));
528
+ try expectEqual(217, try Rolls.coalesce(.P2, 217, &summaries, false));
529
+ try expectEqual(255, try Rolls.coalesce(.P2, 217, &summaries, true));
487
530
  }
488
531
 
489
532
  test "Rolls.hit" {
@@ -771,9 +814,53 @@ test "Rolls.psywave" {
771
814
 
772
815
  try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p1, &side, .None));
773
816
  var rolls = Rolls.psywave(actions.p2, &side, .None);
774
- try expectEqual(@as(u8, 150), rolls[rolls.len - 1]);
817
+ try expectEqual(150, rolls[rolls.len - 1]);
775
818
  side.stored().level = 81;
776
819
  rolls = Rolls.psywave(actions.p2, &side, .None);
777
- try expectEqual(@as(u8, 121), rolls[rolls.len - 1]);
820
+ try expectEqual(121, rolls[rolls.len - 1]);
778
821
  try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p2, &side, .false));
779
822
  }
823
+
824
+ /// Empirically determined maximum number of bytes possibly required to store the diff between two
825
+ /// Generation I battles.
826
+ pub const MAX_DIFFS: usize = 117;
827
+
828
+ /// The optimal size in bytes required to hold the diff between two Generation I battles.
829
+ /// At least as large as MAX_DIFFS.
830
+ pub const DIFFS_SIZE = if (builtin.mode == .ReleaseSmall)
831
+ MAX_DIFFS
832
+ else
833
+ std.math.ceilPowerOfTwo(usize, MAX_DIFFS) catch unreachable;
834
+
835
+ /// TODO
836
+ pub fn diff(
837
+ a: *const data.Battle(data.PRNG),
838
+ b: *const data.Battle(data.PRNG),
839
+ w: protocol.ByteStream.Writer,
840
+ ) !usize {
841
+ const pos = w.stream.pos;
842
+ const size = @sizeOf(data.Battle(data.PRNG)) - @sizeOf(data.PRNG);
843
+ assert(size % 2 == 0);
844
+ assert(size / 2 < 255);
845
+
846
+ var i: usize = 0;
847
+ while (i < size) : (i += 2) {
848
+ const val = std.mem.bytesAsValue(u16, std.mem.asBytes(a)[i .. i + 2]).*;
849
+ if (val != std.mem.bytesAsValue(u16, std.mem.asBytes(b)[i .. i + 2]).*) {
850
+ try w.writeByte(@intCast(i / 2));
851
+ try w.writeInt(u16, val, endian);
852
+ }
853
+ }
854
+
855
+ return w.stream.pos - pos;
856
+ }
857
+
858
+ /// TODO
859
+ pub fn patch(battle: *data.Battle(data.PRNG), buf: []u8) void {
860
+ var i: usize = 0;
861
+ while (i < buf.len) : (i += 3) {
862
+ const off = @as(u16, @intCast(buf[i])) * 2;
863
+ const val = std.mem.readInt(u16, @ptrCast(buf[i + 1 .. i + 3]), endian);
864
+ std.mem.writeInt(u16, @ptrCast(std.mem.asBytes(battle)[off .. off + 2]), val, endian);
865
+ }
866
+ }
@@ -1053,7 +1053,7 @@ fn checkCriticalHit(battle: anytype, player: Player, move: Move.Data, options: a
1053
1053
  const side = battle.side(player);
1054
1054
 
1055
1055
  // Base speed is used for the critical hit calculation, even when Transform-ed
1056
- var rate = @as(u16, Species.chance(side.stored().species));
1056
+ var rate: u16 = Species.chance(side.stored().species);
1057
1057
  // GLITCH: Focus Energy reduces critical hit rate instead of increasing it
1058
1058
  rate = if (side.active.volatiles.FocusEnergy) rate / 2 else @min(rate * 2, 255);
1059
1059
  rate = if (move.effect == .HighCritical) @min(rate * 4, 255) else rate / 2;
@@ -1110,9 +1110,9 @@ fn calcDamage(
1110
1110
  def = @max((def / 4) & 255, if (showdown) 1 else 0);
1111
1111
  }
1112
1112
 
1113
- const lvl = @as(u32, side.stored().level * @as(u2, if (crit) 2 else 1));
1113
+ const lvl: u32 = side.stored().level * @as(u2, if (crit) 2 else 1);
1114
1114
 
1115
- def = @as(u32, if (move.effect == .Explode) @max(def / 2, 1) else def);
1115
+ def = if (move.effect == .Explode) @max(def / 2, 1) else def;
1116
1116
 
1117
1117
  if (def == 0) return false;
1118
1118
 
@@ -1395,7 +1395,7 @@ fn moveHit(
1395
1395
  const overwritten = overwrite and state > 0;
1396
1396
  assert(!overwritten or (0 < state and state <= 255 and !side.active.volatiles.Bide));
1397
1397
 
1398
- var accuracy = if (overwritten) state else @as(u16, move.accuracy);
1398
+ var accuracy: u16 = if (overwritten) state else move.accuracy;
1399
1399
  var boost = BOOSTS[@as(u4, @intCast(@as(i8, side.active.boosts.accuracy) + 6))];
1400
1400
  accuracy = accuracy * boost[0] / boost[1];
1401
1401
  boost = BOOSTS[@as(u4, @intCast(@as(i8, -foe.active.boosts.evasion) + 6))];
@@ -2689,6 +2689,8 @@ pub const Rolls = struct {
2689
2689
  fn speedTie(battle: anytype, options: anytype) !bool {
2690
2690
  const p1 = if (options.calc.overridden(.P1, .speed_tie)) |player|
2691
2691
  player == .P1
2692
+ else if (@hasDecl(@TypeOf(battle.rng), "speedTie"))
2693
+ battle.rng.speedTie()
2692
2694
  else if (showdown)
2693
2695
  battle.rng.range(u8, 0, 2) == 0
2694
2696
  else
@@ -2701,6 +2703,8 @@ pub const Rolls = struct {
2701
2703
  fn criticalHit(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
2702
2704
  const crit = if (options.calc.overridden(player, .critical_hit)) |val|
2703
2705
  val == .true
2706
+ else if (@hasDecl(@TypeOf(battle.rng), "criticalHit"))
2707
+ battle.rng.criticalHit(player, rate)
2704
2708
  else if (showdown)
2705
2709
  battle.rng.chance(u8, rate, 256)
2706
2710
  else
@@ -2713,6 +2717,8 @@ pub const Rolls = struct {
2713
2717
  fn damage(battle: anytype, player: Player, options: anytype) !u8 {
2714
2718
  const roll = if (options.calc.overridden(player, .damage)) |val|
2715
2719
  val
2720
+ else if (@hasDecl(@TypeOf(battle.rng), "damage"))
2721
+ battle.rng.damage(player)
2716
2722
  else roll: {
2717
2723
  if (showdown) break :roll battle.rng.range(u8, 217, 256);
2718
2724
  while (true) {
@@ -2726,21 +2732,27 @@ pub const Rolls = struct {
2726
2732
  return roll;
2727
2733
  }
2728
2734
 
2735
+ const uN = if (pkmn.options.miss) u8 else u9;
2729
2736
  fn hit(battle: anytype, player: Player, accuracy: u8, options: anytype) bool {
2737
+ const acc: uN = if (pkmn.options.miss) accuracy else @as(uN, accuracy) + 1;
2730
2738
  const ok = if (options.calc.overridden(player, .hit)) |val|
2731
2739
  val == .true
2740
+ else if (@hasDecl(@TypeOf(battle.rng), "hit"))
2741
+ battle.rng.hit(player, acc)
2732
2742
  else if (showdown)
2733
- battle.rng.chance(u8, accuracy, 256)
2743
+ battle.rng.chance(uN, acc, 256)
2734
2744
  else
2735
- battle.rng.next() < accuracy;
2745
+ battle.rng.next() < acc;
2736
2746
 
2737
- options.chance.hit(ok, accuracy);
2747
+ options.chance.hit(ok, acc);
2738
2748
  return ok;
2739
2749
  }
2740
2750
 
2741
2751
  fn confused(battle: anytype, player: Player, options: anytype) !bool {
2742
2752
  const cfz = if (options.calc.overridden(player, .confused)) |val|
2743
2753
  val == .true
2754
+ else if (@hasDecl(@TypeOf(battle.rng), "confused"))
2755
+ battle.rng.confused(player)
2744
2756
  else if (showdown)
2745
2757
  !battle.rng.chance(u8, 128, 256)
2746
2758
  else
@@ -2753,6 +2765,8 @@ pub const Rolls = struct {
2753
2765
  fn paralyzed(battle: anytype, player: Player, options: anytype) !bool {
2754
2766
  const par = if (options.calc.overridden(player, .paralyzed)) |val|
2755
2767
  val == .true
2768
+ else if (@hasDecl(@TypeOf(battle.rng), "paralyzed"))
2769
+ battle.rng.paralyzed(player)
2756
2770
  else if (showdown)
2757
2771
  battle.rng.chance(u8, 63, 256)
2758
2772
  else
@@ -2765,6 +2779,8 @@ pub const Rolls = struct {
2765
2779
  fn confusionChance(battle: anytype, player: Player, options: anytype) !bool {
2766
2780
  const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2767
2781
  val == .true
2782
+ else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
2783
+ battle.rng.secondaryChance(player, 25)
2768
2784
  else if (showdown)
2769
2785
  battle.rng.chance(u8, 25, 256)
2770
2786
  else
@@ -2779,6 +2795,8 @@ pub const Rolls = struct {
2779
2795
 
2780
2796
  const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2781
2797
  val == .true
2798
+ else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
2799
+ battle.rng.secondaryChance(player, rate)
2782
2800
  else if (showdown)
2783
2801
  battle.rng.chance(u8, rate, 256)
2784
2802
  else
@@ -2793,6 +2811,8 @@ pub const Rolls = struct {
2793
2811
 
2794
2812
  const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2795
2813
  val == .true
2814
+ else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
2815
+ battle.rng.secondaryChance(player, rate)
2796
2816
  else if (showdown)
2797
2817
  battle.rng.chance(u8, rate, 256)
2798
2818
  else
@@ -2805,6 +2825,8 @@ pub const Rolls = struct {
2805
2825
  fn unboost(battle: anytype, player: Player, options: anytype) !bool {
2806
2826
  const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2807
2827
  val == .true
2828
+ else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
2829
+ battle.rng.secondaryChance(player, 85)
2808
2830
  else if (showdown)
2809
2831
  battle.rng.chance(u8, 85, 256)
2810
2832
  else
@@ -2817,6 +2839,8 @@ pub const Rolls = struct {
2817
2839
  fn metronome(battle: anytype, player: Player, options: anytype) !Move {
2818
2840
  const move: Move = if (options.calc.overridden(player, .metronome)) |val|
2819
2841
  val
2842
+ else if (@hasDecl(@TypeOf(battle.rng), "metronome"))
2843
+ battle.rng.metronome(player)
2820
2844
  else if (showdown)
2821
2845
  Move.METRONOME[battle.rng.range(u8, 0, Move.METRONOME.len)]
2822
2846
  else move: {
@@ -2835,6 +2859,8 @@ pub const Rolls = struct {
2835
2859
  fn psywave(battle: anytype, player: Player, max: u8, options: anytype) !u8 {
2836
2860
  const power = if (options.calc.overridden(player, .psywave)) |val|
2837
2861
  val - 1
2862
+ else if (@hasDecl(@TypeOf(battle.rng), "psywave"))
2863
+ battle.rng.psywave(player)
2838
2864
  else if (showdown)
2839
2865
  battle.rng.range(u8, 0, max)
2840
2866
  else power: {
@@ -2852,6 +2878,8 @@ pub const Rolls = struct {
2852
2878
  fn sleepDuration(battle: anytype, player: Player, options: anytype) u3 {
2853
2879
  const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
2854
2880
  @intCast(val)
2881
+ else if (@hasDecl(@TypeOf(battle.rng), "sleepDuration"))
2882
+ battle.rng.sleepDuration(player)
2855
2883
  else if (showdown)
2856
2884
  battle.rng.range(u3, 1, 8)
2857
2885
  else duration: {
@@ -2869,6 +2897,8 @@ pub const Rolls = struct {
2869
2897
  fn disableDuration(battle: anytype, player: Player, options: anytype) u4 {
2870
2898
  const duration: u4 = if (options.calc.overridden(player, .duration)) |val|
2871
2899
  val
2900
+ else if (@hasDecl(@TypeOf(battle.rng), "disableDuration"))
2901
+ battle.rng.disableDuration(player)
2872
2902
  else if (showdown)
2873
2903
  battle.rng.range(u4, 1, 9)
2874
2904
  else
@@ -2882,6 +2912,8 @@ pub const Rolls = struct {
2882
2912
  fn confusionDuration(battle: anytype, player: Player, self: bool, options: anytype) u3 {
2883
2913
  const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
2884
2914
  @intCast(val)
2915
+ else if (@hasDecl(@TypeOf(battle.rng), "confusionDuration"))
2916
+ battle.rng.confusionDuration(player, self)
2885
2917
  else if (showdown)
2886
2918
  battle.rng.range(u3, 2, 6)
2887
2919
  else
@@ -2895,6 +2927,8 @@ pub const Rolls = struct {
2895
2927
  fn attackingDuration(battle: anytype, player: Player, options: anytype) u3 {
2896
2928
  const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
2897
2929
  @intCast(val)
2930
+ else if (@hasDecl(@TypeOf(battle.rng), "attackingDuration"))
2931
+ battle.rng.attackingDuration(player)
2898
2932
  else if (showdown)
2899
2933
  battle.rng.range(u3, 2, 4)
2900
2934
  else
@@ -2916,6 +2950,8 @@ pub const Rolls = struct {
2916
2950
  const roll = if (effect == .Binding) .duration else .multi_hit;
2917
2951
  const n: u3 = if (options.calc.overridden(player, roll)) |val|
2918
2952
  @intCast(val)
2953
+ else if (@hasDecl(@TypeOf(battle.rng), "distribution"))
2954
+ battle.rng.distribution(player)
2919
2955
  else if (showdown)
2920
2956
  DISTRIBUTION[battle.rng.range(u3, 0, DISTRIBUTION.len)]
2921
2957
  else n: {
@@ -2948,7 +2984,9 @@ pub const Rolls = struct {
2948
2984
  else
2949
2985
  null;
2950
2986
 
2951
- const slot: u4 = overridden orelse slot: {
2987
+ const slot: u4 = overridden orelse if (@hasDecl(@TypeOf(battle.rng), "moveSlot"))
2988
+ battle.rng.moveSlot(player, moves, check_pp)
2989
+ else slot: {
2952
2990
  if (showdown) {
2953
2991
  if (check_pp == 0) {
2954
2992
  var i: usize = moves.len;
@@ -14,7 +14,7 @@ const util = @import("../common/util.zig");
14
14
  const Player = @import("../common/data.zig").Player;
15
15
  const Optional = @import("../common/optional.zig").Optional;
16
16
 
17
- const data = @import("./data.zig");
17
+ const data = @import("data.zig");
18
18
 
19
19
  const enabled = options.chance;
20
20
  const showdown = options.showdown;
@@ -97,16 +97,17 @@ pub const Actions = extern struct {
97
97
  }
98
98
  };
99
99
 
100
+ // TODO: ziglang/zig#19730
100
101
  test Actions {
101
102
  const a: Actions = .{ .p1 = .{ .hit = .true, .critical_hit = .false, .damage = 245 } };
102
103
  const b: Actions = .{ .p1 = .{ .hit = .false, .critical_hit = .true, .damage = 246 } };
103
104
  const c: Actions = .{ .p1 = .{ .hit = .true } };
104
- const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
105
- const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
106
- const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
107
- const g: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1 } } };
108
- const h: Actions =
109
- .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1, .thrash = true } } };
105
+ // const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
106
+ // const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
107
+ // const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
108
+ // const g: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1 } } };
109
+ // const h: Actions =
110
+ // .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1, .thrash = true } } };
110
111
 
111
112
  try expect(a.eql(a));
112
113
  try expect(!a.eql(b));
@@ -119,10 +120,10 @@ test Actions {
119
120
  try expect(b.matches(a));
120
121
  try expect(!a.matches(c));
121
122
  try expect(!c.matches(a));
122
- try expect(d.matches(e));
123
- try expect(!d.matches(f));
124
- try expect(!g.matches(h));
125
- try expect(h.matches(h));
123
+ // try expect(d.matches(e));
124
+ // try expect(!d.matches(f));
125
+ // try expect(!g.matches(h));
126
+ // try expect(h.matches(h));
126
127
  }
127
128
 
128
129
  /// Information about the RNG that was observed during a Generation II battle `update` for a
@@ -699,7 +700,7 @@ test "Chance.damage" {
699
700
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
700
701
 
701
702
  try chance.damage(.P1, 217);
702
- try expectValue(@as(u8, 217), chance.actions.p1.damage);
703
+ try expectValue(217, chance.actions.p1.damage);
703
704
  try expectProbability(&chance.probability, 1, 39);
704
705
  }
705
706
 
@@ -824,7 +825,7 @@ test "Chance.present" {
824
825
  } else {
825
826
  try expectProbability(&chance.probability, 25, 256);
826
827
  }
827
- try expectValue(@as(u3, 4), chance.actions.p2.present);
828
+ try expectValue(4, chance.actions.p2.present);
828
829
 
829
830
  chance.reset();
830
831
 
@@ -834,7 +835,7 @@ test "Chance.present" {
834
835
  } else {
835
836
  try expectProbability(&chance.probability, 51, 256);
836
837
  }
837
- try expectValue(@as(u3, 1), chance.actions.p1.present);
838
+ try expectValue(1, chance.actions.p1.present);
838
839
  }
839
840
 
840
841
  test "Chance.magnitude" {
@@ -846,7 +847,7 @@ test "Chance.magnitude" {
846
847
  } else {
847
848
  try expectProbability(&chance.probability, 13, 256);
848
849
  }
849
- try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
850
+ try expectValue(7, chance.actions.p2.magnitude);
850
851
 
851
852
  chance.reset();
852
853
 
@@ -856,7 +857,7 @@ test "Chance.magnitude" {
856
857
  } else {
857
858
  try expectProbability(&chance.probability, 51, 256);
858
859
  }
859
- try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
860
+ try expectValue(5, chance.actions.p1.magnitude);
860
861
  }
861
862
 
862
863
  test "Chance.tripleKick" {
@@ -864,7 +865,7 @@ test "Chance.tripleKick" {
864
865
 
865
866
  try chance.tripleKick(.P1, 2);
866
867
  try expectProbability(&chance.probability, 1, 3);
867
- try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
868
+ try expectValue(2, chance.actions.p1.triple_kick);
868
869
  }
869
870
 
870
871
  test "Chance.spite" {
@@ -872,7 +873,7 @@ test "Chance.spite" {
872
873
 
873
874
  try chance.spite(.P1, 3);
874
875
  try expectProbability(&chance.probability, 1, 4);
875
- try expectValue(@as(u3, 3), chance.actions.p1.spite);
876
+ try expectValue(3, chance.actions.p1.spite);
876
877
  }
877
878
 
878
879
  test "Chance.conversion2" {
@@ -899,7 +900,7 @@ test "Chance.psywave" {
899
900
 
900
901
  try chance.psywave(.P2, 100, 150);
901
902
  try expectProbability(&chance.probability, 1, 150);
902
- try expectValue(@as(u8, 100), chance.actions.p2.psywave);
903
+ try expectValue(100, chance.actions.p2.psywave);
903
904
  }
904
905
 
905
906
  test "Chance.metronome" {
@@ -915,19 +916,19 @@ test "Chance.moveSlot" {
915
916
 
916
917
  try chance.moveSlot(.P2, 2, 2);
917
918
  try expectProbability(&chance.probability, 1, 2);
918
- try expectValue(@as(u4, 2), chance.actions.p2.move_slot);
919
+ try expectValue(2, chance.actions.p2.move_slot);
919
920
 
920
921
  chance.reset();
921
922
 
922
923
  try chance.moveSlot(.P1, 1, 3);
923
924
  try expectProbability(&chance.probability, 1, 3);
924
- try expectValue(@as(u4, 1), chance.actions.p1.move_slot);
925
+ try expectValue(1, chance.actions.p1.move_slot);
925
926
 
926
927
  chance.reset();
927
928
 
928
929
  try chance.moveSlot(.P1, 4, 1);
929
930
  try expectProbability(&chance.probability, 1, 1);
930
- try expectValue(@as(u4, 4), chance.actions.p1.move_slot);
931
+ try expectValue(4, chance.actions.p1.move_slot);
931
932
  }
932
933
 
933
934
  test "Chance.forceSwitch" {
@@ -935,19 +936,19 @@ test "Chance.forceSwitch" {
935
936
 
936
937
  try chance.forceSwitch(.P2, 2, 2);
937
938
  try expectProbability(&chance.probability, 1, 2);
938
- try expectValue(@as(u4, 2), chance.actions.p2.force_switch);
939
+ try expectValue(2, chance.actions.p2.force_switch);
939
940
 
940
941
  chance.reset();
941
942
 
942
943
  try chance.forceSwitch(.P1, 1, 3);
943
944
  try expectProbability(&chance.probability, 1, 3);
944
- try expectValue(@as(u4, 1), chance.actions.p1.force_switch);
945
+ try expectValue(1, chance.actions.p1.force_switch);
945
946
 
946
947
  chance.reset();
947
948
 
948
949
  try chance.forceSwitch(.P1, 4, 1);
949
950
  try expectProbability(&chance.probability, 1, 1);
950
- try expectValue(@as(u4, 4), chance.actions.p1.force_switch);
951
+ try expectValue(4, chance.actions.p1.force_switch);
951
952
  }
952
953
 
953
954
  test "Chance.multiHit" {
@@ -955,21 +956,21 @@ test "Chance.multiHit" {
955
956
 
956
957
  try chance.multiHit(.P1, 3);
957
958
  try expectProbability(&chance.probability, 3, 8);
958
- try expectValue(@as(u4, 3), chance.actions.p1.multi_hit);
959
+ try expectValue(3, chance.actions.p1.multi_hit);
959
960
 
960
961
  chance.reset();
961
962
 
962
963
  try chance.multiHit(.P2, 5);
963
964
  try expectProbability(&chance.probability, 1, 8);
964
- try expectValue(@as(u4, 5), chance.actions.p2.multi_hit);
965
+ try expectValue(5, chance.actions.p2.multi_hit);
965
966
  }
966
967
 
967
968
  test "Chance.duration" {
968
969
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
969
970
 
970
971
  chance.duration(.sleep, .P1, .P2, 2);
971
- try expectValue(@as(u4, 2), chance.actions.p1.duration);
972
- try expectValue(@as(u3, 1), chance.actions.p2.durations.sleep);
972
+ try expectValue(2, chance.actions.p1.duration);
973
+ try expectValue(1, chance.actions.p2.durations.sleep);
973
974
  }
974
975
 
975
976
  test "Chance.sleep" {
@@ -979,7 +980,7 @@ test "Chance.sleep" {
979
980
  chance.actions.p1.durations.sleep = @intCast(i);
980
981
  try chance.sleep(.P1, 0);
981
982
  try expectProbability(&chance.probability, 1, d);
982
- try expectValue(@as(u3, 0), chance.actions.p1.durations.sleep);
983
+ try expectValue(0, chance.actions.p1.durations.sleep);
983
984
 
984
985
  chance.reset();
985
986
 
@@ -1003,7 +1004,7 @@ test "Chance.confusion" {
1003
1004
  chance.actions.p2.durations.confusion = @intCast(i);
1004
1005
  try chance.confusion(.P2, 0);
1005
1006
  try expectProbability(&chance.probability, 1, d);
1006
- try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
1007
+ try expectValue(0, chance.actions.p2.durations.confusion);
1007
1008
  try expectValue(false, chance.actions.p2.durations.thrash);
1008
1009
 
1009
1010
  chance.reset();
@@ -1028,7 +1029,7 @@ test "Chance.confusion" {
1028
1029
  chance.actions.p2.durations.confusion = @intCast(i);
1029
1030
  try chance.confusion(.P2, 0);
1030
1031
  try expectProbability(&chance.probability, 1, d);
1031
- try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
1032
+ try expectValue(0, chance.actions.p2.durations.confusion);
1032
1033
  try expectValue(true, chance.actions.p2.durations.thrash);
1033
1034
 
1034
1035
  chance.reset();
@@ -1054,7 +1055,7 @@ test "Chance.disable" {
1054
1055
  chance.actions.p2.durations.disable = @intCast(i);
1055
1056
  try chance.disable(.P2, 0);
1056
1057
  try expectProbability(&chance.probability, 1, d);
1057
- try expectValue(@as(u4, 0), chance.actions.p2.durations.disable);
1058
+ try expectValue(0, chance.actions.p2.durations.disable);
1058
1059
 
1059
1060
  chance.reset();
1060
1061
  }
@@ -1074,7 +1075,7 @@ test "Chance.disable" {
1074
1075
  chance.actions.p2.durations.disable = @intCast(i);
1075
1076
  try chance.disable(.P2, 0);
1076
1077
  try expectProbability(&chance.probability, 1, d);
1077
- try expectValue(@as(u4, 0), chance.actions.p2.durations.disable);
1078
+ try expectValue(0, chance.actions.p2.durations.disable);
1078
1079
 
1079
1080
  chance.reset();
1080
1081
  }
@@ -1099,7 +1100,7 @@ test "Chance.attacking" {
1099
1100
  chance.actions.p2.durations.attacking = @intCast(i);
1100
1101
  try chance.attacking(.P2, 0);
1101
1102
  try expectProbability(&chance.probability, 1, d);
1102
- try expectValue(@as(u3, 0), chance.actions.p2.durations.attacking);
1103
+ try expectValue(0, chance.actions.p2.durations.attacking);
1103
1104
 
1104
1105
  chance.reset();
1105
1106
  }
@@ -1123,7 +1124,7 @@ test "Chance.binding" {
1123
1124
  chance.actions.p2.durations.binding = @intCast(i);
1124
1125
  try chance.binding(.P2, 0);
1125
1126
  try expectProbability(&chance.probability, 1, d);
1126
- try expectValue(@as(u3, 0), chance.actions.p2.durations.binding);
1127
+ try expectValue(0, chance.actions.p2.durations.binding);
1127
1128
 
1128
1129
  chance.reset();
1129
1130
  }
@@ -1147,7 +1148,7 @@ test "Chance.encore" {
1147
1148
  chance.actions.p2.durations.encore = @intCast(i);
1148
1149
  try chance.encore(.P2, 0);
1149
1150
  try expectProbability(&chance.probability, 1, d);
1150
- try expectValue(@as(u3, 0), chance.actions.p2.durations.encore);
1151
+ try expectValue(0, chance.actions.p2.durations.encore);
1151
1152
 
1152
1153
  chance.reset();
1153
1154
  }