@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.
@@ -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;
@@ -220,6 +220,7 @@ pub const Activate = enum(u8) {
220
220
  BeatUp, // FIXME of
221
221
 
222
222
  Magnitude,
223
+ Spite,
223
224
  };
224
225
 
225
226
  pub const Start = enum(u8) {
@@ -544,6 +545,7 @@ pub fn Log(comptime Writer: type) type {
544
545
  // ident: ID, reason: Activate
545
546
  // ident: ID, reason: .SubstituteBlock, m: <Move>
546
547
  // ident: ID, reason: .Magnitude, num: u8
548
+ // ident: ID, reason: .Spite, m: <Move>, num: u8
547
549
  pub fn activate(self: Self, args: anytype) Error!void {
548
550
  if (!enabled) return;
549
551
 
@@ -561,6 +563,9 @@ pub fn Log(comptime Writer: type) type {
561
563
  assert(reason == .Magnitude);
562
564
  try self.writer.writeByte(args[2]);
563
565
  }
566
+ } else if (args.len == 4) {
567
+ assert(reason == .Spite);
568
+ try self.writer.writeAll(&.{ @intFromEnum(args[2]), args[3] });
564
569
  }
565
570
  }
566
571
 
@@ -1202,14 +1207,11 @@ pub fn expectLog(
1202
1207
  ) !void {
1203
1208
  if (!enabled) return;
1204
1209
 
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
- }
1210
+ const color = if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR"))
1211
+ true
1212
+ else switch (std.io.tty.detectConfig(std.io.getStdErr())) {
1213
+ .escape_codes => true,
1214
+ else => false,
1213
1215
  };
1214
1216
 
1215
1217
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
@@ -1248,20 +1250,13 @@ fn N(e: anytype) u8 {
1248
1250
  const p1 = Player.P1;
1249
1251
  const p2 = Player.P2;
1250
1252
 
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
1253
  var buf: [pkmn.LOGS_SIZE]u8 = undefined;
1262
1254
  var stream: ByteStream = .{ .buffer = &buf };
1263
1255
  var log: FixedLog = .{ .writer = stream.writer() };
1264
1256
 
1257
+ const gen1 = pkmn.gen1;
1258
+ const gen2 = pkmn.gen2;
1259
+
1265
1260
  const M1 = gen1.Move;
1266
1261
  const S1 = gen1.Species;
1267
1262
 
@@ -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
- }
@@ -387,6 +387,87 @@ pub fn transitions(
387
387
  return stats;
388
388
  }
389
389
 
390
+ pub fn update(
391
+ battle: anytype,
392
+ c1: Choice,
393
+ c2: Choice,
394
+ options: anytype,
395
+ allocator: std.mem.Allocator,
396
+ writer: anytype,
397
+ transition: bool,
398
+ ) !Result {
399
+ options.chance.reset();
400
+
401
+ if (!pkmn.options.chance or !pkmn.options.calc or @TypeOf(battle.rng) != data.PRNG) {
402
+ return battle.update(c1, c2, options);
403
+ }
404
+
405
+ var copy = battle.*;
406
+ const actions = options.chance.actions;
407
+
408
+ // Perfom the actual update
409
+ const result = battle.update(c1, c2, options);
410
+
411
+ // Ensure we can encode the diffs in less than MAX_DIFFS bytes.
412
+ var buf: [helpers.MAX_DIFFS]u8 = undefined;
413
+ var stream: protocol.ByteStream = .{ .buffer = &buf };
414
+ const n = try helpers.diff(&copy, battle, stream.writer());
415
+
416
+ // Applying the diff to the battle should take us back to the original copy
417
+ // of the battle (ignoring the RNG).
418
+ var patched = battle.*;
419
+ copy.rng = patched.rng;
420
+ helpers.patch(&patched, buf[0..n]);
421
+ try expectEqual(copy, patched);
422
+
423
+ if (!pkmn.options.chance or !pkmn.options.calc) return result;
424
+
425
+ if (transition) {
426
+ // Ensure we can generate all transitions from the same original state
427
+ // (we must change the battle's RNG from a FixedRNG to a PRNG because
428
+ // the transitions function relies on RNG for discovery of states)
429
+ const stats = try transitions(unfix(copy), c1, c2, allocator, writer, .{
430
+ .actions = actions,
431
+ .cap = true,
432
+ });
433
+ DEBUG(stats);
434
+ // TODO try expect(stats.frontier < pkmn.gen1.MAX_FRONTIER_SIZE);
435
+ }
436
+
437
+ // Demonstrate that we can produce the same state by forcing the RNG to behave the
438
+ // same as we observed - note that because we do not pass in a durations override
439
+ // mask none of the durations will be extended.
440
+ var override = pkmn.battle.options(
441
+ protocol.NULL,
442
+ chance.NULL,
443
+ Calc{ .overrides = .{ .actions = actions } },
444
+ );
445
+ const overridden = copy.update(c1, c2, &override);
446
+ try expectEqual(result, overridden);
447
+
448
+ // The actual battle excluding its RNG field should match a copy updated with
449
+ // overridden RNG (the copy RNG may have advanced because of no-ops)
450
+ copy.rng = battle.rng;
451
+ try expectEqual(copy, battle.*);
452
+
453
+ return result;
454
+ }
455
+
456
+ fn unfix(actual: anytype) data.Battle(data.PRNG) {
457
+ return .{
458
+ .sides = actual.sides,
459
+ .turn = actual.turn,
460
+ .last_damage = actual.last_damage,
461
+ .last_moves = actual.last_moves,
462
+ .rng = .{ .src = .{
463
+ .seed = if (pkmn.options.showdown)
464
+ 0x12345678
465
+ else
466
+ .{ 123, 234, 56, 78, 9, 101, 112, 131, 4 },
467
+ } },
468
+ };
469
+ }
470
+
390
471
  fn matches(actions: Actions, i: usize, frontier: []Actions) bool {
391
472
  for (frontier, 0..) |f, j| {
392
473
  // TODO: is skipping this redundant check worth it?
@@ -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;
@@ -92,13 +92,14 @@ pub const Actions = extern struct {
92
92
  }
93
93
  };
94
94
 
95
+ // TODO: ziglang/zig#19730
95
96
  test Actions {
96
97
  const a: Actions = .{ .p1 = .{ .hit = .true, .critical_hit = .false, .damage = 245 } };
97
98
  const b: Actions = .{ .p1 = .{ .hit = .false, .critical_hit = .true, .damage = 246 } };
98
99
  const c: Actions = .{ .p1 = .{ .hit = .true } };
99
- const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
100
- const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
101
- const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
100
+ // const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
101
+ // const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
102
+ // const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
102
103
 
103
104
  try expect(a.eql(a));
104
105
  try expect(!a.eql(b));
@@ -111,8 +112,8 @@ test Actions {
111
112
  try expect(b.matches(a));
112
113
  try expect(!a.matches(c));
113
114
  try expect(!c.matches(a));
114
- try expect(d.matches(e));
115
- try expect(!d.matches(f));
115
+ // try expect(d.matches(e));
116
+ // try expect(!d.matches(f));
116
117
  }
117
118
 
118
119
  /// Information about the RNG that was observed during a Generation I battle `update` for a
@@ -254,6 +255,8 @@ pub const Duration = packed struct(u16) {
254
255
 
255
256
  pub const Commit = enum { hit, miss, binding };
256
257
 
258
+ const uN = if (options.miss) u8 else u9;
259
+
257
260
  /// Tracks chance actions and their associated probability during a Generation I battle update when
258
261
  /// `options.chance` is enabled.
259
262
  pub fn Chance(comptime Rational: type) type {
@@ -292,13 +295,13 @@ pub fn Chance(comptime Rational: type) type {
292
295
  // shared structure to track this information (though it needs to be cleared appropriately)
293
296
  pending: if (showdown) struct {
294
297
  hit: bool = false,
295
- hit_probablity: u8 = 0,
298
+ hit_probablity: uN = 0,
296
299
  } else struct {
297
300
  crit: bool = false,
298
301
  crit_probablity: u8 = 0,
299
302
  damage_roll: u8 = 0,
300
303
  hit: bool = false,
301
- hit_probablity: u8 = 0,
304
+ hit_probablity: uN = 0,
302
305
  binding: u8 = 0,
303
306
  } = .{},
304
307
 
@@ -397,7 +400,7 @@ pub fn Chance(comptime Rational: type) type {
397
400
  self.actions.p2.speed_tie = self.actions.p1.speed_tie;
398
401
  }
399
402
 
400
- pub fn hit(self: *Self, ok: bool, accuracy: u8) void {
403
+ pub fn hit(self: *Self, ok: bool, accuracy: uN) void {
401
404
  if (!enabled) return;
402
405
 
403
406
  const p = if (ok) accuracy else @as(u8, @intCast(256 - @as(u9, accuracy)));
@@ -706,19 +709,19 @@ test "Chance.damage" {
706
709
 
707
710
  try chance.damage(.P1, 217);
708
711
  if (showdown) {
709
- try expectValue(@as(u8, 217), chance.actions.p1.damage);
712
+ try expectValue(217, chance.actions.p1.damage);
710
713
  try expectProbability(&chance.probability, 1, 39);
711
714
  } else {
712
715
  try expectProbability(&chance.probability, 1, 1);
713
- try expectValue(@as(u8, 0), chance.actions.p1.damage);
716
+ try expectValue(0, chance.actions.p1.damage);
714
717
 
715
718
  try chance.commit(.P1, .miss);
716
719
  try expectProbability(&chance.probability, 1, 1);
717
- try expectValue(@as(u8, 0), chance.actions.p1.damage);
720
+ try expectValue(0, chance.actions.p1.damage);
718
721
 
719
722
  try chance.commit(.P1, .hit);
720
723
  try expectProbability(&chance.probability, 1, 39);
721
- try expectValue(@as(u8, 217), chance.actions.p1.damage);
724
+ try expectValue(217, chance.actions.p1.damage);
722
725
  }
723
726
  }
724
727
 
@@ -770,13 +773,13 @@ test "Chance.moveSlot" {
770
773
 
771
774
  try chance.moveSlot(.P2, 2, &ms, 2);
772
775
  try expectProbability(&chance.probability, 1, 2);
773
- try expectValue(@as(u4, 2), chance.actions.p2.move_slot);
776
+ try expectValue(2, chance.actions.p2.move_slot);
774
777
 
775
778
  chance.reset();
776
779
 
777
780
  try chance.moveSlot(.P1, 1, &ms, 0);
778
781
  try expectProbability(&chance.probability, 1, 3);
779
- try expectValue(@as(u4, 1), chance.actions.p1.move_slot);
782
+ try expectValue(1, chance.actions.p1.move_slot);
780
783
  }
781
784
 
782
785
  test "Chance.multiHit" {
@@ -784,32 +787,32 @@ test "Chance.multiHit" {
784
787
 
785
788
  try chance.multiHit(.P1, 3);
786
789
  try expectProbability(&chance.probability, 3, 8);
787
- try expectValue(@as(u4, 3), chance.actions.p1.multi_hit);
790
+ try expectValue(3, chance.actions.p1.multi_hit);
788
791
 
789
792
  chance.reset();
790
793
 
791
794
  try chance.multiHit(.P2, 5);
792
795
  try expectProbability(&chance.probability, 1, 8);
793
- try expectValue(@as(u4, 5), chance.actions.p2.multi_hit);
796
+ try expectValue(5, chance.actions.p2.multi_hit);
794
797
  }
795
798
 
796
799
  test "Chance.duration" {
797
800
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
798
801
 
799
802
  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);
803
+ try expectValue(2, chance.actions.p1.duration);
804
+ try expectValue(1, chance.actions.p2.durations.sleep);
802
805
 
803
806
  chance.reset();
804
807
 
805
808
  chance.duration(.binding, .P2, .P2, 4);
806
809
  if (!showdown) {
807
- try expectValue(@as(u4, 0), chance.actions.p2.duration);
808
- try expectValue(@as(u3, 0), chance.actions.p2.durations.binding);
810
+ try expectValue(0, chance.actions.p2.duration);
811
+ try expectValue(0, chance.actions.p2.durations.binding);
809
812
  try chance.commit(.P2, .hit);
810
813
  }
811
- try expectValue(@as(u4, 4), chance.actions.p2.duration);
812
- try expectValue(@as(u3, 1), chance.actions.p2.durations.binding);
814
+ try expectValue(4, chance.actions.p2.duration);
815
+ try expectValue(1, chance.actions.p2.durations.binding);
813
816
  }
814
817
 
815
818
  test "Chance.sleep" {
@@ -819,7 +822,7 @@ test "Chance.sleep" {
819
822
  chance.actions.p1.durations.sleep = @intCast(i);
820
823
  try chance.sleep(.P1, 0);
821
824
  try expectProbability(&chance.probability, 1, d);
822
- try expectValue(@as(u3, 0), chance.actions.p1.durations.sleep);
825
+ try expectValue(0, chance.actions.p1.durations.sleep);
823
826
 
824
827
  chance.reset();
825
828
 
@@ -842,7 +845,7 @@ test "Chance.confusion" {
842
845
  chance.actions.p2.durations.confusion = @intCast(i);
843
846
  try chance.confusion(.P2, 0);
844
847
  try expectProbability(&chance.probability, 1, d);
845
- try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
848
+ try expectValue(0, chance.actions.p2.durations.confusion);
846
849
 
847
850
  chance.reset();
848
851
  }
@@ -865,7 +868,7 @@ test "Chance.disable" {
865
868
  chance.actions.p1.durations.disable = @intCast(i);
866
869
  try chance.disable(.P1, 0);
867
870
  try expectProbability(&chance.probability, 1, d);
868
- try expectValue(@as(u4, 0), chance.actions.p1.durations.disable);
871
+ try expectValue(0, chance.actions.p1.durations.disable);
869
872
 
870
873
  chance.reset();
871
874
 
@@ -888,7 +891,7 @@ test "Chance.attacking" {
888
891
  chance.actions.p2.durations.attacking = @intCast(i);
889
892
  try chance.attacking(.P2, 0);
890
893
  try expectProbability(&chance.probability, 1, d);
891
- try expectValue(@as(u3, 0), chance.actions.p2.durations.attacking);
894
+ try expectValue(0, chance.actions.p2.durations.attacking);
892
895
 
893
896
  chance.reset();
894
897
  }
@@ -914,7 +917,7 @@ test "Chance.binding" {
914
917
  chance.actions.p1.durations.binding = @intCast(i);
915
918
  try chance.binding(.P1, 0);
916
919
  try expectProbability(&chance.probability, p, q);
917
- try expectValue(@as(u3, 0), chance.actions.p1.durations.binding);
920
+ try expectValue(0, chance.actions.p1.durations.binding);
918
921
 
919
922
  chance.reset();
920
923
 
@@ -934,7 +937,7 @@ test "Chance.psywave" {
934
937
 
935
938
  try chance.psywave(.P2, 100, 150);
936
939
  try expectProbability(&chance.probability, 1, 150);
937
- try expectValue(@as(u8, 101), chance.actions.p2.psywave);
940
+ try expectValue(101, chance.actions.p2.psywave);
938
941
  }
939
942
 
940
943
  test "Chance.metronome" {
@@ -988,7 +991,7 @@ const Null = struct {
988
991
  _ = .{ self, p1 };
989
992
  }
990
993
 
991
- pub fn hit(self: Null, ok: bool, accuracy: u8) void {
994
+ pub fn hit(self: Null, ok: bool, accuracy: uN) void {
992
995
  _ = .{ self, ok, accuracy };
993
996
  }
994
997
 
@@ -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];
@@ -22,11 +22,11 @@ const expect = std.testing.expect;
22
22
 
23
23
  /// The minimum size in bytes required to hold all Generation I choice options.
24
24
  pub const MAX_CHOICES: usize = 9; // move 1..4, switch 2..6
25
- /// The optimal size in bytes required to hold all Generation I choice options.
26
- /// At least as large as MAX_CHOICES.
25
+ /// The maximum number of bytes possibly logged by a single Generation I update.
27
26
  pub const MAX_LOGS: usize = 180;
28
27
 
29
- /// The maximum number of bytes possibly logged by a single Generation I update.
28
+ /// The optimal size in bytes required to hold all Generation I choice options.
29
+ /// At least as large as MAX_CHOICES.
30
30
  pub const CHOICES_SIZE = if (builtin.mode == .ReleaseSmall)
31
31
  MAX_CHOICES
32
32
  else
@@ -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
  }