@pkmn/engine 0.1.0-dev.44b2e6ec → 0.1.0-dev.47dcb76c

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.
@@ -10,7 +10,7 @@ const path = require('path');
10
10
  const {pipeline} = require('stream/promises');
11
11
  const tty = require('tty');
12
12
 
13
- const ZIG_VERSION = {major: 0, minor: 12, patch: 0, dev: 1396};
13
+ const ZIG_VERSION = {major: 0, minor: 12, patch: 0, dev: 2036};
14
14
  const DEV = ZIG_VERSION.dev ? `-dev.${ZIG_VERSION.dev}` : '';
15
15
  const VERSION = `${ZIG_VERSION.major}.${ZIG_VERSION.minor}.${ZIG_VERSION.patch}${DEV}`;
16
16
  const INDEX = 'https://ziglang.org/download/index.json';
@@ -283,19 +283,19 @@ const downloadImportLib = async () => {
283
283
  let error = false;
284
284
  for (let i = 2; i < process.argv.length; i++) {
285
285
  switch (process.argv[i]) {
286
- case "--silent": {
287
- SILENT = true;
288
- break;
289
- }
290
- case "--zig": {
291
- if (options || only) error = true;
292
- only = true;
293
- break;
294
- }
295
- default: {
296
- if (options || only || !process.argv[i].startsWith('--options=')) error = true;
297
- options = process.argv[i].slice(10).split(' ');
298
- }
286
+ case "--silent": {
287
+ SILENT = true;
288
+ break;
289
+ }
290
+ case "--zig": {
291
+ if (options || only) error = true;
292
+ only = true;
293
+ break;
294
+ }
295
+ default: {
296
+ if (options || only || !process.argv[i].startsWith('--options=')) error = true;
297
+ options = process.argv[i].slice(10).split(' ');
298
+ }
299
299
  }
300
300
  }
301
301
  if (error) {
@@ -22,8 +22,8 @@ pub const Player = enum(u1) {
22
22
 
23
23
  test Player {
24
24
  try expectEqual(Player.P2, Player.P1.foe());
25
- try expectEqual(@as(u8, 0b0001), @as(u8, @bitCast(Player.P1.ident(1))));
26
- try expectEqual(@as(u8, 0b1101), @as(u8, @bitCast(Player.P2.ident(5))));
25
+ try expectEqual(0b0001, @as(u8, @bitCast(Player.P1.ident(1))));
26
+ try expectEqual(0b1101, @as(u8, @bitCast(Player.P2.ident(5))));
27
27
  }
28
28
 
29
29
  /// An identifier for a specific Pokémon in battle.
@@ -46,8 +46,8 @@ pub const ID = packed struct(u8) {
46
46
  };
47
47
 
48
48
  test ID {
49
- try expectEqual(@as(u8, 0b0001), @as(u8, @bitCast(ID{ .player = .P1, .id = 1 })));
50
- try expectEqual(@as(u8, 0b1101), @as(u8, @bitCast(ID{ .player = .P2, .id = 5 })));
49
+ try expectEqual(0b0001, @as(u8, @bitCast(ID{ .player = .P1, .id = 1 })));
50
+ try expectEqual(0b1101, @as(u8, @bitCast(ID{ .player = .P2, .id = 5 })));
51
51
  const id: ID = .{ .player = .P2, .id = 4 };
52
52
  try expectEqual(id, ID.from(id.int()));
53
53
  }
@@ -46,7 +46,7 @@ test Optional {
46
46
  try expect(b != .true);
47
47
  try expect(b != .false);
48
48
 
49
- const Player = @import("./data.zig").Player;
49
+ const Player = @import("data.zig").Player;
50
50
  try expect(@bitSizeOf(Optional(Player)) == 2);
51
51
 
52
52
  const p: Optional(Player) = .P2;
@@ -3,8 +3,8 @@ const builtin = @import("builtin");
3
3
 
4
4
  const pkmn = @import("../pkmn.zig");
5
5
 
6
- const data = @import("./data.zig");
7
- const options = @import("./options.zig");
6
+ const data = @import("data.zig");
7
+ const options = @import("options.zig");
8
8
 
9
9
  const assert = std.debug.assert;
10
10
  const print = std.debug.print;
@@ -1202,14 +1202,11 @@ pub fn expectLog(
1202
1202
  ) !void {
1203
1203
  if (!enabled) return;
1204
1204
 
1205
- const color = color: {
1206
- if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
1207
- break :color true;
1208
- } else if (std.process.hasEnvVarConstant("NO_COLOR")) {
1209
- break :color false;
1210
- } else {
1211
- break :color std.io.getStdErr().supportsAnsiEscapeCodes();
1212
- }
1205
+ const color = if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR"))
1206
+ true
1207
+ else switch (std.io.tty.detectConfig(std.io.getStdErr())) {
1208
+ .escape_codes => true,
1209
+ else => false,
1213
1210
  };
1214
1211
 
1215
1212
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
@@ -1248,20 +1245,13 @@ fn N(e: anytype) u8 {
1248
1245
  const p1 = Player.P1;
1249
1246
  const p2 = Player.P2;
1250
1247
 
1251
- const gen1 = struct {
1252
- pub usingnamespace @import("../gen1/data.zig");
1253
- pub const helpers = @import("../gen1/helpers.zig");
1254
- };
1255
-
1256
- const gen2 = struct {
1257
- pub usingnamespace @import("../gen2/data.zig");
1258
- pub const helpers = @import("../gen2/helpers.zig");
1259
- };
1260
-
1261
1248
  var buf: [pkmn.LOGS_SIZE]u8 = undefined;
1262
1249
  var stream: ByteStream = .{ .buffer = &buf };
1263
1250
  var log: FixedLog = .{ .writer = stream.writer() };
1264
1251
 
1252
+ const gen1 = pkmn.gen1;
1253
+ const gen2 = pkmn.gen2;
1254
+
1265
1255
  const M1 = gen1.Move;
1266
1256
  const S1 = gen1.Species;
1267
1257
 
@@ -1,6 +1,6 @@
1
1
  const std = @import("std");
2
2
 
3
- const options = @import("./options.zig");
3
+ const options = @import("options.zig");
4
4
 
5
5
  const assert = std.debug.assert;
6
6
  const expectEqual = std.testing.expectEqual;
@@ -66,11 +66,15 @@ pub const PSRNG = extern struct {
66
66
  (@as(u64, self.range(u16, 0, 0x10000)) << 16) |
67
67
  (@as(u64, self.range(u16, 0, 0x10000)));
68
68
  }
69
+
70
+ pub fn Bound(comptime T: type) type {
71
+ return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
72
+ }
69
73
  };
70
74
 
71
75
  test PSRNG {
72
76
  var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
73
- try expectEqual(@as(u8, 121), psrng.range(u8, 0, 256));
77
+ try expectEqual(121, psrng.range(u8, 0, 256));
74
78
  try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
75
79
  }
76
80
 
@@ -107,9 +111,9 @@ test Gen12 {
107
111
  try expectEqual(e, rng.next());
108
112
  }
109
113
 
110
- try expectEqual(@as(u8, 16), Gen12.percent(6) + 1);
111
- try expectEqual(@as(u8, 16), Gen12.percent(7) - 1);
112
- try expectEqual(@as(u8, 128), Gen12.percent(50) + 1);
114
+ try expectEqual(16, Gen12.percent(6) + 1);
115
+ try expectEqual(16, Gen12.percent(7) - 1);
116
+ try expectEqual(128, Gen12.percent(50) + 1);
113
117
  }
114
118
 
115
119
  // https://pkmn.cc/pokeemerald/src/random.c
@@ -197,7 +201,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
197
201
  for (0..n) |_| _ = self.next();
198
202
  }
199
203
 
200
- pub fn range(self: *Self, comptime T: type, from: T, to: Bound(T)) T {
204
+ pub fn range(self: *Self, comptime T: type, from: T, to: PSRNG.Bound(T)) T {
201
205
  assert(showdown);
202
206
  return @intCast(@as(u64, self.next()) * (to - from) / divisor + from);
203
207
  }
@@ -206,7 +210,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
206
210
  self: *Self,
207
211
  comptime T: type,
208
212
  numerator: T,
209
- denominator: Bound(T),
213
+ denominator: PSRNG.Bound(T),
210
214
  ) bool {
211
215
  assert(showdown);
212
216
  assert(denominator > 0);
@@ -237,7 +241,3 @@ fn Output(comptime gen: comptime_int) type {
237
241
  else => unreachable,
238
242
  };
239
243
  }
240
-
241
- fn Bound(comptime T: type) type {
242
- return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
243
- }
@@ -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;
@@ -706,19 +706,19 @@ test "Chance.damage" {
706
706
 
707
707
  try chance.damage(.P1, 217);
708
708
  if (showdown) {
709
- try expectValue(@as(u8, 217), chance.actions.p1.damage);
709
+ try expectValue(217, chance.actions.p1.damage);
710
710
  try expectProbability(&chance.probability, 1, 39);
711
711
  } else {
712
712
  try expectProbability(&chance.probability, 1, 1);
713
- try expectValue(@as(u8, 0), chance.actions.p1.damage);
713
+ try expectValue(0, chance.actions.p1.damage);
714
714
 
715
715
  try chance.commit(.P1, .miss);
716
716
  try expectProbability(&chance.probability, 1, 1);
717
- try expectValue(@as(u8, 0), chance.actions.p1.damage);
717
+ try expectValue(0, chance.actions.p1.damage);
718
718
 
719
719
  try chance.commit(.P1, .hit);
720
720
  try expectProbability(&chance.probability, 1, 39);
721
- try expectValue(@as(u8, 217), chance.actions.p1.damage);
721
+ try expectValue(217, chance.actions.p1.damage);
722
722
  }
723
723
  }
724
724
 
@@ -770,13 +770,13 @@ test "Chance.moveSlot" {
770
770
 
771
771
  try chance.moveSlot(.P2, 2, &ms, 2);
772
772
  try expectProbability(&chance.probability, 1, 2);
773
- try expectValue(@as(u4, 2), chance.actions.p2.move_slot);
773
+ try expectValue(2, chance.actions.p2.move_slot);
774
774
 
775
775
  chance.reset();
776
776
 
777
777
  try chance.moveSlot(.P1, 1, &ms, 0);
778
778
  try expectProbability(&chance.probability, 1, 3);
779
- try expectValue(@as(u4, 1), chance.actions.p1.move_slot);
779
+ try expectValue(1, chance.actions.p1.move_slot);
780
780
  }
781
781
 
782
782
  test "Chance.multiHit" {
@@ -784,32 +784,32 @@ test "Chance.multiHit" {
784
784
 
785
785
  try chance.multiHit(.P1, 3);
786
786
  try expectProbability(&chance.probability, 3, 8);
787
- try expectValue(@as(u4, 3), chance.actions.p1.multi_hit);
787
+ try expectValue(3, chance.actions.p1.multi_hit);
788
788
 
789
789
  chance.reset();
790
790
 
791
791
  try chance.multiHit(.P2, 5);
792
792
  try expectProbability(&chance.probability, 1, 8);
793
- try expectValue(@as(u4, 5), chance.actions.p2.multi_hit);
793
+ try expectValue(5, chance.actions.p2.multi_hit);
794
794
  }
795
795
 
796
796
  test "Chance.duration" {
797
797
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
798
798
 
799
799
  chance.duration(.sleep, .P1, .P2, 2);
800
- try expectValue(@as(u4, 2), chance.actions.p1.duration);
801
- try expectValue(@as(u3, 1), chance.actions.p2.durations.sleep);
800
+ try expectValue(2, chance.actions.p1.duration);
801
+ try expectValue(1, chance.actions.p2.durations.sleep);
802
802
 
803
803
  chance.reset();
804
804
 
805
805
  chance.duration(.binding, .P2, .P2, 4);
806
806
  if (!showdown) {
807
- try expectValue(@as(u4, 0), chance.actions.p2.duration);
808
- try expectValue(@as(u3, 0), chance.actions.p2.durations.binding);
807
+ try expectValue(0, chance.actions.p2.duration);
808
+ try expectValue(0, chance.actions.p2.durations.binding);
809
809
  try chance.commit(.P2, .hit);
810
810
  }
811
- try expectValue(@as(u4, 4), chance.actions.p2.duration);
812
- try expectValue(@as(u3, 1), chance.actions.p2.durations.binding);
811
+ try expectValue(4, chance.actions.p2.duration);
812
+ try expectValue(1, chance.actions.p2.durations.binding);
813
813
  }
814
814
 
815
815
  test "Chance.sleep" {
@@ -819,7 +819,7 @@ test "Chance.sleep" {
819
819
  chance.actions.p1.durations.sleep = @intCast(i);
820
820
  try chance.sleep(.P1, 0);
821
821
  try expectProbability(&chance.probability, 1, d);
822
- try expectValue(@as(u3, 0), chance.actions.p1.durations.sleep);
822
+ try expectValue(0, chance.actions.p1.durations.sleep);
823
823
 
824
824
  chance.reset();
825
825
 
@@ -842,7 +842,7 @@ test "Chance.confusion" {
842
842
  chance.actions.p2.durations.confusion = @intCast(i);
843
843
  try chance.confusion(.P2, 0);
844
844
  try expectProbability(&chance.probability, 1, d);
845
- try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
845
+ try expectValue(0, chance.actions.p2.durations.confusion);
846
846
 
847
847
  chance.reset();
848
848
  }
@@ -865,7 +865,7 @@ test "Chance.disable" {
865
865
  chance.actions.p1.durations.disable = @intCast(i);
866
866
  try chance.disable(.P1, 0);
867
867
  try expectProbability(&chance.probability, 1, d);
868
- try expectValue(@as(u4, 0), chance.actions.p1.durations.disable);
868
+ try expectValue(0, chance.actions.p1.durations.disable);
869
869
 
870
870
  chance.reset();
871
871
 
@@ -888,7 +888,7 @@ test "Chance.attacking" {
888
888
  chance.actions.p2.durations.attacking = @intCast(i);
889
889
  try chance.attacking(.P2, 0);
890
890
  try expectProbability(&chance.probability, 1, d);
891
- try expectValue(@as(u3, 0), chance.actions.p2.durations.attacking);
891
+ try expectValue(0, chance.actions.p2.durations.attacking);
892
892
 
893
893
  chance.reset();
894
894
  }
@@ -914,7 +914,7 @@ test "Chance.binding" {
914
914
  chance.actions.p1.durations.binding = @intCast(i);
915
915
  try chance.binding(.P1, 0);
916
916
  try expectProbability(&chance.probability, p, q);
917
- try expectValue(@as(u3, 0), chance.actions.p1.durations.binding);
917
+ try expectValue(0, chance.actions.p1.durations.binding);
918
918
 
919
919
  chance.reset();
920
920
 
@@ -934,7 +934,7 @@ test "Chance.psywave" {
934
934
 
935
935
  try chance.psywave(.P2, 100, 150);
936
936
  try expectProbability(&chance.probability, 1, 150);
937
- try expectValue(@as(u8, 101), chance.actions.p2.psywave);
937
+ try expectValue(101, chance.actions.p2.psywave);
938
938
  }
939
939
 
940
940
  test "Chance.metronome" {
@@ -1091,7 +1091,7 @@ pub const Species = enum(u8) {
1091
1091
  /// The number of Pokémon species in this generation.
1092
1092
  pub const size = 151;
1093
1093
 
1094
- /// The Pokémon's critical hit rate=io out of 256.
1094
+ /// The Pokémon's critical hit ratio out of 256.
1095
1095
  pub fn chance(id: Species) u8 {
1096
1096
  assert(id != .None);
1097
1097
  return CHANCES[@intFromEnum(id) - 1];
@@ -112,7 +112,7 @@ pub fn Battle(comptime RNG: anytype) type {
112
112
  /// make (i.e. on the cartridge a soft-lock occurs).
113
113
  ///
114
114
  /// This function will always return choices > 0 if `pkmn.options.showdown` is true.
115
- pub fn choices(self: *Self, player: Player, request: Choice.Type, out: []Choice) u8 {
115
+ pub fn choices(self: *const Self, player: Player, request: Choice.Type, out: []Choice) u8 {
116
116
  return mechanics.choices(self, player, request, out);
117
117
  }
118
118
  };
@@ -316,12 +316,12 @@ test Status {
316
316
  try expect(Status.is(Status.slp(5), .SLP));
317
317
  try expect(!Status.is(Status.slp(5), .EXT));
318
318
  try expect(!Status.is(Status.slp(7), .PSN));
319
- try expectEqual(@as(u3, 5), Status.duration(Status.slp(5)));
319
+ try expectEqual(5, Status.duration(Status.slp(5)));
320
320
  try expect(Status.is(Status.slf(2), .SLP));
321
321
  try expect(Status.is(Status.slf(2), .EXT));
322
322
  try expect(Status.is(Status.TOX, .PSN));
323
323
  try expect(Status.is(Status.TOX, .EXT));
324
- try expectEqual(@as(u3, 1), Status.duration(Status.slp(1)));
324
+ try expectEqual(1, Status.duration(Status.slp(1)));
325
325
  }
326
326
 
327
327
  /// Bitfield representation of volatile statuses and associated data in Generation I.
@@ -405,13 +405,13 @@ test Volatiles {
405
405
  try expect(!volatiles.Transform);
406
406
  try expect(!volatiles.MultiHit);
407
407
 
408
- try expectEqual(@as(u16, 235), volatiles.state);
409
- try expectEqual(@as(u8, 42), volatiles.substitute);
410
- try expectEqual(@as(u4, 2), volatiles.disable_move);
411
- try expectEqual(@as(u4, 4), volatiles.disable_duration);
412
- try expectEqual(@as(u4, 2), volatiles.confusion);
413
- try expectEqual(@as(u5, 4), volatiles.toxic);
414
- try expectEqual(@as(u4, 3), volatiles.attacks);
408
+ try expectEqual(235, volatiles.state);
409
+ try expectEqual(42, volatiles.substitute);
410
+ try expectEqual(2, volatiles.disable_move);
411
+ try expectEqual(4, volatiles.disable_duration);
412
+ try expectEqual(2, volatiles.confusion);
413
+ try expectEqual(4, volatiles.toxic);
414
+ try expectEqual(3, volatiles.attacks);
415
415
  }
416
416
 
417
417
  /// Representaiton of a Pokémon's stats in Generation I.
@@ -442,9 +442,9 @@ test Stats {
442
442
  try expectEqual(0, stats.def);
443
443
 
444
444
  var base = Species.get(.Gyarados).stats;
445
- try expectEqual(@as(u16, 127), Stats(u16).calc("hp", base.hp, 0, 5120, 38));
445
+ try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
446
446
  base = Species.get(.Pidgeot).stats;
447
- try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
447
+ try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
448
448
  }
449
449
 
450
450
  /// Representation of a Pokémon's boosts in Generation I.
@@ -537,7 +537,7 @@ pub const Species = species.Species;
537
537
 
538
538
  test Species {
539
539
  try expectEqual(2, @intFromEnum(Species.Ivysaur));
540
- try expectEqual(@as(u8, 100), Species.get(.Mew).stats.def);
540
+ try expectEqual(100, Species.get(.Mew).stats.def);
541
541
  }
542
542
 
543
543
  /// Representation of a Generation I type in Pokémon.
@@ -576,8 +576,8 @@ test Types {
576
576
  try expectEqual(Effectiveness.Resisted, Type.effectiveness(.Fire, .Water));
577
577
  try expectEqual(Effectiveness.Neutral, Type.effectiveness(.Normal, .Grass));
578
578
 
579
- try expectEqual(@as(u8, 3), Type.precedence(.Water, .Water));
580
- try expectEqual(@as(u8, 26), Type.precedence(.Bug, .Ghost));
579
+ try expectEqual(3, Type.precedence(.Water, .Water));
580
+ try expectEqual(26, Type.precedence(.Bug, .Ghost));
581
581
  try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
582
582
 
583
583
  const t: Types = .{ .type1 = .Rock, .type2 = .Ground };
@@ -617,18 +617,18 @@ pub const DVs = struct {
617
617
 
618
618
  test DVs {
619
619
  var dvs: DVs = .{ .spc = 15, .spe = 15 };
620
- try expectEqual(@as(u4, 15), dvs.hp());
620
+ try expectEqual(15, dvs.hp());
621
621
  dvs = .{
622
622
  .atk = 5,
623
623
  .def = 15,
624
624
  .spe = 13,
625
625
  .spc = 13,
626
626
  };
627
- try expectEqual(@as(u4, 15), dvs.hp());
627
+ try expectEqual(15, dvs.hp());
628
628
  dvs = .{
629
629
  .def = 3,
630
630
  .spe = 10,
631
631
  .spc = 11,
632
632
  };
633
- try expectEqual(@as(u4, 13), dvs.hp());
633
+ try expectEqual(13, dvs.hp());
634
634
  }
@@ -478,12 +478,12 @@ test "Rolls.damage" {
478
478
  test "Rolls.coalesce" {
479
479
  var summaries =
480
480
  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));
481
+ try expectEqual(0, try Rolls.coalesce(.P2, 0, &summaries, false));
482
+ try expectEqual(241, try Rolls.coalesce(.P2, 238, &summaries, false));
483
+ try expectEqual(255, try Rolls.coalesce(.P2, 238, &summaries, true));
484
484
  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));
485
+ try expectEqual(217, try Rolls.coalesce(.P2, 217, &summaries, false));
486
+ try expectEqual(255, try Rolls.coalesce(.P2, 217, &summaries, true));
487
487
  }
488
488
 
489
489
  test "Rolls.hit" {
@@ -771,9 +771,9 @@ test "Rolls.psywave" {
771
771
 
772
772
  try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p1, &side, .None));
773
773
  var rolls = Rolls.psywave(actions.p2, &side, .None);
774
- try expectEqual(@as(u8, 150), rolls[rolls.len - 1]);
774
+ try expectEqual(150, rolls[rolls.len - 1]);
775
775
  side.stored().level = 81;
776
776
  rolls = Rolls.psywave(actions.p2, &side, .None);
777
- try expectEqual(@as(u8, 121), rolls[rolls.len - 1]);
777
+ try expectEqual(121, rolls[rolls.len - 1]);
778
778
  try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p2, &side, .false));
779
779
  }
@@ -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) {
@@ -2729,6 +2735,8 @@ pub const Rolls = struct {
2729
2735
  fn hit(battle: anytype, player: Player, accuracy: u8, options: anytype) bool {
2730
2736
  const ok = if (options.calc.overridden(player, .hit)) |val|
2731
2737
  val == .true
2738
+ else if (@hasDecl(@TypeOf(battle.rng), "hit"))
2739
+ battle.rng.hit(player, accuracy)
2732
2740
  else if (showdown)
2733
2741
  battle.rng.chance(u8, accuracy, 256)
2734
2742
  else
@@ -2741,6 +2749,8 @@ pub const Rolls = struct {
2741
2749
  fn confused(battle: anytype, player: Player, options: anytype) !bool {
2742
2750
  const cfz = if (options.calc.overridden(player, .confused)) |val|
2743
2751
  val == .true
2752
+ else if (@hasDecl(@TypeOf(battle.rng), "confused"))
2753
+ battle.rng.confused(player)
2744
2754
  else if (showdown)
2745
2755
  !battle.rng.chance(u8, 128, 256)
2746
2756
  else
@@ -2753,6 +2763,8 @@ pub const Rolls = struct {
2753
2763
  fn paralyzed(battle: anytype, player: Player, options: anytype) !bool {
2754
2764
  const par = if (options.calc.overridden(player, .paralyzed)) |val|
2755
2765
  val == .true
2766
+ else if (@hasDecl(@TypeOf(battle.rng), "paralyzed"))
2767
+ battle.rng.paralyzed(player)
2756
2768
  else if (showdown)
2757
2769
  battle.rng.chance(u8, 63, 256)
2758
2770
  else
@@ -2765,6 +2777,8 @@ pub const Rolls = struct {
2765
2777
  fn confusionChance(battle: anytype, player: Player, options: anytype) !bool {
2766
2778
  const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2767
2779
  val == .true
2780
+ else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
2781
+ battle.rng.secondaryChance(player, 25)
2768
2782
  else if (showdown)
2769
2783
  battle.rng.chance(u8, 25, 256)
2770
2784
  else
@@ -2779,6 +2793,8 @@ pub const Rolls = struct {
2779
2793
 
2780
2794
  const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2781
2795
  val == .true
2796
+ else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
2797
+ battle.rng.secondaryChance(player, rate)
2782
2798
  else if (showdown)
2783
2799
  battle.rng.chance(u8, rate, 256)
2784
2800
  else
@@ -2793,6 +2809,8 @@ pub const Rolls = struct {
2793
2809
 
2794
2810
  const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2795
2811
  val == .true
2812
+ else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
2813
+ battle.rng.secondaryChance(player, rate)
2796
2814
  else if (showdown)
2797
2815
  battle.rng.chance(u8, rate, 256)
2798
2816
  else
@@ -2805,6 +2823,8 @@ pub const Rolls = struct {
2805
2823
  fn unboost(battle: anytype, player: Player, options: anytype) !bool {
2806
2824
  const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2807
2825
  val == .true
2826
+ else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
2827
+ battle.rng.secondaryChance(player, 85)
2808
2828
  else if (showdown)
2809
2829
  battle.rng.chance(u8, 85, 256)
2810
2830
  else
@@ -2817,6 +2837,8 @@ pub const Rolls = struct {
2817
2837
  fn metronome(battle: anytype, player: Player, options: anytype) !Move {
2818
2838
  const move: Move = if (options.calc.overridden(player, .metronome)) |val|
2819
2839
  val
2840
+ else if (@hasDecl(@TypeOf(battle.rng), "metronome"))
2841
+ battle.rng.metronome(player)
2820
2842
  else if (showdown)
2821
2843
  Move.METRONOME[battle.rng.range(u8, 0, Move.METRONOME.len)]
2822
2844
  else move: {
@@ -2835,6 +2857,8 @@ pub const Rolls = struct {
2835
2857
  fn psywave(battle: anytype, player: Player, max: u8, options: anytype) !u8 {
2836
2858
  const power = if (options.calc.overridden(player, .psywave)) |val|
2837
2859
  val - 1
2860
+ else if (@hasDecl(@TypeOf(battle.rng), "psywave"))
2861
+ battle.rng.psywave(player)
2838
2862
  else if (showdown)
2839
2863
  battle.rng.range(u8, 0, max)
2840
2864
  else power: {
@@ -2852,6 +2876,8 @@ pub const Rolls = struct {
2852
2876
  fn sleepDuration(battle: anytype, player: Player, options: anytype) u3 {
2853
2877
  const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
2854
2878
  @intCast(val)
2879
+ else if (@hasDecl(@TypeOf(battle.rng), "sleepDuration"))
2880
+ battle.rng.sleepDuration(player)
2855
2881
  else if (showdown)
2856
2882
  battle.rng.range(u3, 1, 8)
2857
2883
  else duration: {
@@ -2869,6 +2895,8 @@ pub const Rolls = struct {
2869
2895
  fn disableDuration(battle: anytype, player: Player, options: anytype) u4 {
2870
2896
  const duration: u4 = if (options.calc.overridden(player, .duration)) |val|
2871
2897
  val
2898
+ else if (@hasDecl(@TypeOf(battle.rng), "disableDuration"))
2899
+ battle.rng.disableDuration(player)
2872
2900
  else if (showdown)
2873
2901
  battle.rng.range(u4, 1, 9)
2874
2902
  else
@@ -2882,6 +2910,8 @@ pub const Rolls = struct {
2882
2910
  fn confusionDuration(battle: anytype, player: Player, self: bool, options: anytype) u3 {
2883
2911
  const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
2884
2912
  @intCast(val)
2913
+ else if (@hasDecl(@TypeOf(battle.rng), "confusionDuration"))
2914
+ battle.rng.confusionDuration(player, self)
2885
2915
  else if (showdown)
2886
2916
  battle.rng.range(u3, 2, 6)
2887
2917
  else
@@ -2895,6 +2925,8 @@ pub const Rolls = struct {
2895
2925
  fn attackingDuration(battle: anytype, player: Player, options: anytype) u3 {
2896
2926
  const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
2897
2927
  @intCast(val)
2928
+ else if (@hasDecl(@TypeOf(battle.rng), "attackingDuration"))
2929
+ battle.rng.attackingDuration(player)
2898
2930
  else if (showdown)
2899
2931
  battle.rng.range(u3, 2, 4)
2900
2932
  else
@@ -2916,6 +2948,8 @@ pub const Rolls = struct {
2916
2948
  const roll = if (effect == .Binding) .duration else .multi_hit;
2917
2949
  const n: u3 = if (options.calc.overridden(player, roll)) |val|
2918
2950
  @intCast(val)
2951
+ else if (@hasDecl(@TypeOf(battle.rng), "distribution"))
2952
+ battle.rng.distribution(player)
2919
2953
  else if (showdown)
2920
2954
  DISTRIBUTION[battle.rng.range(u3, 0, DISTRIBUTION.len)]
2921
2955
  else n: {
@@ -2948,7 +2982,9 @@ pub const Rolls = struct {
2948
2982
  else
2949
2983
  null;
2950
2984
 
2951
- const slot: u4 = overridden orelse slot: {
2985
+ const slot: u4 = overridden orelse if (@hasDecl(@TypeOf(battle.rng), "moveSlot"))
2986
+ battle.rng.moveSlot(player, moves, check_pp)
2987
+ else slot: {
2952
2988
  if (showdown) {
2953
2989
  if (check_pp == 0) {
2954
2990
  var i: usize = moves.len;