@pkmn/engine 0.1.0-dev.305a932f → 0.1.0-dev.32adfe77

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.
Files changed (45) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +37 -14
  3. package/build/pkg/addon.js.map +1 -1
  4. package/build/pkg/data/layout.json +2 -2
  5. package/build/pkg/data.d.ts +3 -2
  6. package/build/pkg/data.js.map +1 -1
  7. package/build/pkg/gen1.js +2 -2
  8. package/build/pkg/gen1.js.map +1 -1
  9. package/build/pkg/index.d.ts +2 -1
  10. package/build/pkg/index.js.map +1 -1
  11. package/build/pkg/protocol.js +1 -1
  12. package/build/pkg/protocol.js.map +1 -1
  13. package/build/test/display.js.map +1 -1
  14. package/build/tools/debug.js +3 -1
  15. package/build/tools/debug.js.map +1 -1
  16. package/build.zig +78 -68
  17. package/package.json +34 -23
  18. package/src/bin/install-pkmn-engine +14 -14
  19. package/src/lib/common/data.zig +8 -8
  20. package/src/lib/common/optional.zig +9 -2
  21. package/src/lib/common/protocol.zig +402 -383
  22. package/src/lib/common/rational.zig +11 -7
  23. package/src/lib/common/rng.zig +20 -11
  24. package/src/lib/gen1/README.md +28 -28
  25. package/src/lib/gen1/calc.zig +7 -7
  26. package/src/lib/gen1/chance.zig +70 -68
  27. package/src/lib/gen1/data/moves.zig +24 -10
  28. package/src/lib/gen1/data/species.zig +3 -3
  29. package/src/lib/gen1/data/types.zig +5 -5
  30. package/src/lib/gen1/data.zig +36 -36
  31. package/src/lib/gen1/helpers.zig +21 -36
  32. package/src/lib/gen1/mechanics.zig +333 -344
  33. package/src/lib/gen2/README.md +1 -2
  34. package/src/lib/gen2/calc.zig +143 -0
  35. package/src/lib/gen2/chance.zig +1314 -0
  36. package/src/lib/gen2/data/items.zig +3 -3
  37. package/src/lib/gen2/data/moves.zig +32 -15
  38. package/src/lib/gen2/data/species.zig +1 -1
  39. package/src/lib/gen2/data/types.zig +75 -28
  40. package/src/lib/gen2/data.zig +37 -25
  41. package/src/lib/gen2/generated.zig +806 -0
  42. package/src/lib/gen2/mechanics.zig +2612 -349
  43. package/src/lib/{binding/node.zig → node.zig} +9 -12
  44. package/src/lib/pkmn.zig +26 -3
  45. package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
@@ -44,7 +44,7 @@ pub fn Rational(comptime T: type) type {
44
44
  /// Both p and q must be >= 1, and if computable at comptime must have no common factors.
45
45
  pub fn update(r: *Self, p: anytype, q: anytype) Error!void {
46
46
  // FIXME
47
- // std.debug.print("({d}/{d}) * ", .{p, q});
47
+ // std.debug.print("({d}/{d}) * ", .{ p, q });
48
48
  assert(p >= 1);
49
49
  assert(q >= 1);
50
50
 
@@ -185,16 +185,16 @@ pub fn Rational(comptime T: type) type {
185
185
  try writer.print("{d}/{d}", .{ self.p, self.q });
186
186
  }
187
187
 
188
- inline fn multiplication(r: *Self, p: anytype, q: anytype) !void {
188
+ fn multiplication(r: *Self, p: anytype, q: anytype) !void {
189
189
  r.p = try std.math.mul(T, r.p, p);
190
190
  r.q = try std.math.mul(T, r.q, q);
191
191
  }
192
192
 
193
- inline fn addition(r: *Self, p: anytype, q: anytype) !void {
193
+ fn addition(r: *Self, p: anytype, q: anytype) !void {
194
194
  // (a/b) + (c/d) = (ad+bc)/(bd)
195
- var d = try std.math.mul(T, r.q, q);
196
- var n1 = try std.math.mul(T, r.p, q);
197
- var n2 = try std.math.mul(T, r.q, p);
195
+ const d = try std.math.mul(T, r.q, q);
196
+ const n1 = try std.math.mul(T, r.p, q);
197
+ const n2 = try std.math.mul(T, r.q, p);
198
198
 
199
199
  r.p = try std.math.add(T, n1, n2);
200
200
  r.q = d;
@@ -203,7 +203,7 @@ pub fn Rational(comptime T: type) type {
203
203
  }
204
204
 
205
205
  // https://en.wikipedia.org/wiki/Euclidean_algorithm
206
- inline fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
206
+ fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
207
207
  assert(p >= 1);
208
208
  assert(q >= 1);
209
209
 
@@ -234,6 +234,8 @@ test Rational {
234
234
  var r: Rational(t) = .{};
235
235
 
236
236
  var c: t = 128;
237
+ _ = &c;
238
+
237
239
  try r.update(c, 256);
238
240
  try doTurn(&r);
239
241
 
@@ -320,6 +322,8 @@ test BigRational {
320
322
  try r.reset();
321
323
 
322
324
  var c: u8 = 128;
325
+ _ = &c;
326
+
323
327
  try r.update(c, 256);
324
328
  try doTurn(&r);
325
329
 
@@ -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;
@@ -25,6 +25,11 @@ pub fn PRNG(comptime gen: comptime_int) type {
25
25
  pub fn next(self: *Self) Output(gen) {
26
26
  return self.src.next();
27
27
  }
28
+
29
+ pub fn advance(self: *Self, n: usize) void {
30
+ if (!options.advance) return;
31
+ for (0..n) |_| self.src.advance();
32
+ }
28
33
  };
29
34
  }
30
35
 
@@ -61,11 +66,15 @@ pub const PSRNG = extern struct {
61
66
  (@as(u64, self.range(u16, 0, 0x10000)) << 16) |
62
67
  (@as(u64, self.range(u16, 0, 0x10000)));
63
68
  }
69
+
70
+ pub fn Bound(comptime T: type) type {
71
+ return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
72
+ }
64
73
  };
65
74
 
66
75
  test PSRNG {
67
76
  var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
68
- try expectEqual(@as(u8, 121), psrng.range(u8, 0, 256));
77
+ try expectEqual(121, psrng.range(u8, 0, 256));
69
78
  try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
70
79
  }
71
80
 
@@ -89,6 +98,10 @@ pub const Gen12 = extern struct {
89
98
  self.index = (self.index + 1) % 9;
90
99
  return val;
91
100
  }
101
+
102
+ pub fn advance(self: *Gen12) void {
103
+ _ = self.next();
104
+ }
92
105
  };
93
106
 
94
107
  test Gen12 {
@@ -98,9 +111,9 @@ test Gen12 {
98
111
  try expectEqual(e, rng.next());
99
112
  }
100
113
 
101
- try expectEqual(@as(u8, 16), Gen12.percent(6) + 1);
102
- try expectEqual(@as(u8, 16), Gen12.percent(7) - 1);
103
- 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);
104
117
  }
105
118
 
106
119
  // https://pkmn.cc/pokeemerald/src/random.c
@@ -188,7 +201,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
188
201
  for (0..n) |_| _ = self.next();
189
202
  }
190
203
 
191
- 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 {
192
205
  assert(showdown);
193
206
  return @intCast(@as(u64, self.next()) * (to - from) / divisor + from);
194
207
  }
@@ -197,7 +210,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
197
210
  self: *Self,
198
211
  comptime T: type,
199
212
  numerator: T,
200
- denominator: Bound(T),
213
+ denominator: PSRNG.Bound(T),
201
214
  ) bool {
202
215
  assert(showdown);
203
216
  assert(denominator > 0);
@@ -228,7 +241,3 @@ fn Output(comptime gen: comptime_int) type {
228
241
  else => unreachable,
229
242
  };
230
243
  }
231
-
232
- fn Bound(comptime T: type) type {
233
- return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
234
- }
@@ -427,34 +427,34 @@ data in the browser for ease of debugging.
427
427
 
428
428
  > **NOTE:** The offsets in the following table represent *bits* and **not** bytes.
429
429
 
430
- | Start | End | Data | Description |
431
- | ----- | --- | ------------------- | ----------------------------------------------------------- |
432
- | 0 | 1 | `Bide` | Whether the "Bide" volatile status is present |
433
- | 1 | 2 | `Thrashing` | Whether the "Thrashing" volatile status is present |
434
- | 2 | 3 | `MultiHit` | Whether the "MultiHit" volatile status is present |
435
- | 3 | 4 | `Flinch` | Whether the "Flinch" volatile status is present |
436
- | 4 | 5 | `Charging` | Whether the "Charging" volatile status is present |
437
- | 5 | 6 | `Binding` | Whether the "Binding" volatile status is present |
438
- | 6 | 7 | `Invulnerable` | Whether the "Invulnerable" volatile status is present |
439
- | 7 | 8 | `Confusion` | Whether the "Confusion" volatile status is present |
440
- | 8 | 9 | `Mist` | Whether the "Mist" volatile status is present |
441
- | 9 | 10 | `FocusEnergy` | Whether the "FocusEnergy" volatile status is present |
442
- | 10 | 11 | `Substitute` | Whether the "Substitute" volatile status is present |
443
- | 11 | 12 | `Recharging` | Whether the "Recharging" volatile status is present |
444
- | 12 | 13 | `Rage` | Whether the "Rage" volatile status is present |
445
- | 13 | 14 | `LeechSeed` | Whether the "LeechSeed" volatile status is present |
446
- | 14 | 15 | `Toxic` | Whether the "Toxic" volatile status is present |
447
- | 15 | 16 | `LightScreen` | Whether the "LightScreen" volatile status is present |
448
- | 16 | 17 | `Reflect` | Whether the "Reflect" volatile status is present |
449
- | 17 | 18 | `Transform` | Whether the "Transform" volatile status is present |
450
- | 18 | 21 | `confusion` | The remaining turns of confusion |
451
- | 21 | 24 | `attacks` | The number of attacks remaining |
452
- | 24 | 40 | `state` | A union of either: <ul><li>the total accumulated damage from Bide</li><li>the overwritten accuracy of certain moves</li></ul> |
453
- | 40 | 48 | `substitute` | The remaining HP of the Substitute |
454
- | 48 | 52 | `transform` | The identity of whom the active Pokémon is transformed into |
455
- | 52 | 56 | `disabled_duration` | The remaining turns the move is disabled |
456
- | 56 | 59 | `disabled_move` | The move slot (1-4) that's disabled |
457
- | 59 | 64 | `toxic` | The number of turns toxic damage has been accumulating |
430
+ | Start | End | Data | Description |
431
+ | ----- | --- | -------------------| ----------------------------------------------------------- |
432
+ | 0 | 1 | `Bide` | Whether the "Bide" volatile status is present |
433
+ | 1 | 2 | `Thrashing` | Whether the "Thrashing" volatile status is present |
434
+ | 2 | 3 | `MultiHit` | Whether the "MultiHit" volatile status is present |
435
+ | 3 | 4 | `Flinch` | Whether the "Flinch" volatile status is present |
436
+ | 4 | 5 | `Charging` | Whether the "Charging" volatile status is present |
437
+ | 5 | 6 | `Binding` | Whether the "Binding" volatile status is present |
438
+ | 6 | 7 | `Invulnerable` | Whether the "Invulnerable" volatile status is present |
439
+ | 7 | 8 | `Confusion` | Whether the "Confusion" volatile status is present |
440
+ | 8 | 9 | `Mist` | Whether the "Mist" volatile status is present |
441
+ | 9 | 10 | `FocusEnergy` | Whether the "FocusEnergy" volatile status is present |
442
+ | 10 | 11 | `Substitute` | Whether the "Substitute" volatile status is present |
443
+ | 11 | 12 | `Recharging` | Whether the "Recharging" volatile status is present |
444
+ | 12 | 13 | `Rage` | Whether the "Rage" volatile status is present |
445
+ | 13 | 14 | `LeechSeed` | Whether the "LeechSeed" volatile status is present |
446
+ | 14 | 15 | `Toxic` | Whether the "Toxic" volatile status is present |
447
+ | 15 | 16 | `LightScreen` | Whether the "LightScreen" volatile status is present |
448
+ | 16 | 17 | `Reflect` | Whether the "Reflect" volatile status is present |
449
+ | 17 | 18 | `Transform` | Whether the "Transform" volatile status is present |
450
+ | 18 | 21 | `confusion` | The remaining turns of confusion |
451
+ | 21 | 24 | `attacks` | The number of attacks remaining |
452
+ | 24 | 40 | `state` | A union of either: <ul><li>the total accumulated damage from Bide</li><li>the overwritten accuracy of certain moves</li></ul> |
453
+ | 40 | 48 | `substitute` | The remaining HP of the Substitute |
454
+ | 48 | 52 | `transform` | The identity of whom the active Pokémon is transformed into |
455
+ | 52 | 56 | `disable_duration` | The remaining turns the move is disabled |
456
+ | 56 | 59 | `disable_move` | The move slot (1-4) that's disabled |
457
+ | 59 | 64 | `toxic` | The number of turns toxic damage has been accumulating |
458
458
 
459
459
  ### `Pokemon`
460
460
 
@@ -50,7 +50,7 @@ pub const Summaries = extern struct {
50
50
  }
51
51
 
52
52
  /// Returns the `Summary` for the given `player`.
53
- pub inline fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Summary) {
53
+ pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Summary) {
54
54
  assert(@typeInfo(@TypeOf(self)).Pointer.child == Summaries);
55
55
  return if (player == .P1) &self.p1 else &self.p2;
56
56
  }
@@ -211,8 +211,8 @@ pub fn transitions(
211
211
  ) !?Stats {
212
212
  var stats: Stats = .{};
213
213
 
214
- var actions = options.actions;
215
- var cap = options.cap;
214
+ const actions = options.actions;
215
+ const cap = options.cap;
216
216
 
217
217
  var seen = std.AutoHashMap(Actions, void).init(allocator);
218
218
  defer seen.deinit();
@@ -232,8 +232,8 @@ pub fn transitions(
232
232
  _ = try b.update(c1, c2, &opts);
233
233
  stats.updates += 1;
234
234
 
235
- var p1 = b.side(.P1);
236
- var p2 = b.side(.P2);
235
+ const p1 = b.side(.P1);
236
+ const p2 = b.side(.P2);
237
237
 
238
238
  var p: Rational(u128) = .{ .p = 0, .q = 1 };
239
239
  try frontier.append(opts.chance.actions);
@@ -247,7 +247,7 @@ pub fn transitions(
247
247
  var i: usize = 0;
248
248
  assert(frontier.items.len == 1);
249
249
  while (i < frontier.items.len) : (i += 1) {
250
- var template = frontier.items[i];
250
+ const template = frontier.items[i];
251
251
  opts.calc.overrides.durations = .{
252
252
  .p1 = template.p1.durations,
253
253
  .p2 = template.p2.durations,
@@ -387,7 +387,7 @@ pub fn transitions(
387
387
  return stats;
388
388
  }
389
389
 
390
- inline fn matches(actions: Actions, i: usize, frontier: []Actions) bool {
390
+ fn matches(actions: Actions, i: usize, frontier: []Actions) bool {
391
391
  for (frontier, 0..) |f, j| {
392
392
  // TODO: is skipping this redundant check worth it?
393
393
  if (i == j) continue;
@@ -14,12 +14,14 @@ 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 Move = @import("data.zig").Move;
18
- const MoveSlot = @import("data.zig").MoveSlot;
17
+ const data = @import("data.zig");
19
18
 
20
19
  const enabled = options.chance;
21
20
  const showdown = options.showdown;
22
21
 
22
+ const Move = data.Move;
23
+ const MoveSlot = data.MoveSlot;
24
+
23
25
  /// Actions taken by a hypothetical "chance player" that convey information about which RNG events
24
26
  /// were observed during a Generation I battle `update`. This can additionally be provided as input
25
27
  /// to the `update` call to override the normal behavior of the RNG in order to force specific
@@ -35,19 +37,19 @@ pub const Actions = extern struct {
35
37
  }
36
38
 
37
39
  /// Returns the `Action` for the given `player`.
38
- pub inline fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Action) {
40
+ pub fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Action) {
39
41
  assert(@typeInfo(@TypeOf(self)).Pointer.child == Actions);
40
42
  return if (player == .P1) &self.p1 else &self.p2;
41
43
  }
42
44
 
43
45
  /// Perform a reset by clearing fields which should not persist across updates.
44
- pub inline fn reset(self: *Actions) void {
46
+ pub fn reset(self: *Actions) void {
45
47
  self.p1.reset();
46
48
  self.p2.reset();
47
49
  }
48
50
 
49
51
  /// Returns true if `a` is equal to `b`.
50
- pub inline fn eql(a: Actions, b: Actions) bool {
52
+ pub fn eql(a: Actions, b: Actions) bool {
51
53
  return @as(u128, @bitCast(a)) == @as(u128, @bitCast(b));
52
54
  }
53
55
 
@@ -157,7 +159,7 @@ pub const Action = packed struct(u64) {
157
159
  pub const Field = std.meta.FieldEnum(Action);
158
160
 
159
161
  /// Perform a reset by clearing fields which should not persist across updates.
160
- pub inline fn reset(self: *Action) void {
162
+ pub fn reset(self: *Action) void {
161
163
  self.* = @bitCast(@as(u64, @bitCast(self.*)) & DURATIONS);
162
164
  }
163
165
 
@@ -514,22 +516,6 @@ pub fn Chance(comptime Rational: type) type {
514
516
  }
515
517
  }
516
518
 
517
- pub fn disable(self: *Self, player: Player, turns: u4) Error!void {
518
- if (!enabled) return;
519
-
520
- var durations = &self.actions.get(player).durations;
521
- const n = durations.disable;
522
- if (turns == 0) {
523
- assert(n >= 1 and n <= 8);
524
- if (n != 8) try self.probability.update(1, 9 - @as(u4, n));
525
- durations.disable = 0;
526
- } else {
527
- assert(n >= 1 and n < 8);
528
- try self.probability.update(9 - @as(u4, n) - 1, 9 - @as(u4, n));
529
- durations.disable += 1;
530
- }
531
- }
532
-
533
519
  pub fn confusion(self: *Self, player: Player, turns: u4) Error!void {
534
520
  if (!enabled) return;
535
521
 
@@ -546,6 +532,22 @@ pub fn Chance(comptime Rational: type) type {
546
532
  }
547
533
  }
548
534
 
535
+ pub fn disable(self: *Self, player: Player, turns: u4) Error!void {
536
+ if (!enabled) return;
537
+
538
+ var durations = &self.actions.get(player).durations;
539
+ const n = durations.disable;
540
+ if (turns == 0) {
541
+ assert(n >= 1 and n <= 8);
542
+ if (n != 8) try self.probability.update(1, 9 - @as(u4, n));
543
+ durations.disable = 0;
544
+ } else {
545
+ assert(n >= 1 and n < 8);
546
+ try self.probability.update(9 - @as(u4, n) - 1, 9 - @as(u4, n));
547
+ durations.disable += 1;
548
+ }
549
+ }
550
+
549
551
  pub fn attacking(self: *Self, player: Player, turns: u4) Error!void {
550
552
  if (!enabled) return;
551
553
 
@@ -593,7 +595,7 @@ pub fn Chance(comptime Rational: type) type {
593
595
  pub fn metronome(self: *Self, player: Player, move: Move) Error!void {
594
596
  if (!enabled) return;
595
597
 
596
- try self.probability.update(1, Move.size - 2);
598
+ try self.probability.update(1, Move.METRONOME.len);
597
599
  self.actions.get(player).metronome = move;
598
600
  }
599
601
  };
@@ -704,19 +706,19 @@ test "Chance.damage" {
704
706
 
705
707
  try chance.damage(.P1, 217);
706
708
  if (showdown) {
707
- try expectValue(@as(u8, 217), chance.actions.p1.damage);
709
+ try expectValue(217, chance.actions.p1.damage);
708
710
  try expectProbability(&chance.probability, 1, 39);
709
711
  } else {
710
712
  try expectProbability(&chance.probability, 1, 1);
711
- try expectValue(@as(u8, 0), chance.actions.p1.damage);
713
+ try expectValue(0, chance.actions.p1.damage);
712
714
 
713
715
  try chance.commit(.P1, .miss);
714
716
  try expectProbability(&chance.probability, 1, 1);
715
- try expectValue(@as(u8, 0), chance.actions.p1.damage);
717
+ try expectValue(0, chance.actions.p1.damage);
716
718
 
717
719
  try chance.commit(.P1, .hit);
718
720
  try expectProbability(&chance.probability, 1, 39);
719
- try expectValue(@as(u8, 217), chance.actions.p1.damage);
721
+ try expectValue(217, chance.actions.p1.damage);
720
722
  }
721
723
  }
722
724
 
@@ -768,13 +770,13 @@ test "Chance.moveSlot" {
768
770
 
769
771
  try chance.moveSlot(.P2, 2, &ms, 2);
770
772
  try expectProbability(&chance.probability, 1, 2);
771
- try expectValue(@as(u4, 2), chance.actions.p2.move_slot);
773
+ try expectValue(2, chance.actions.p2.move_slot);
772
774
 
773
775
  chance.reset();
774
776
 
775
777
  try chance.moveSlot(.P1, 1, &ms, 0);
776
778
  try expectProbability(&chance.probability, 1, 3);
777
- try expectValue(@as(u4, 1), chance.actions.p1.move_slot);
779
+ try expectValue(1, chance.actions.p1.move_slot);
778
780
  }
779
781
 
780
782
  test "Chance.multiHit" {
@@ -782,32 +784,32 @@ test "Chance.multiHit" {
782
784
 
783
785
  try chance.multiHit(.P1, 3);
784
786
  try expectProbability(&chance.probability, 3, 8);
785
- try expectValue(@as(u4, 3), chance.actions.p1.multi_hit);
787
+ try expectValue(3, chance.actions.p1.multi_hit);
786
788
 
787
789
  chance.reset();
788
790
 
789
791
  try chance.multiHit(.P2, 5);
790
792
  try expectProbability(&chance.probability, 1, 8);
791
- try expectValue(@as(u4, 5), chance.actions.p2.multi_hit);
793
+ try expectValue(5, chance.actions.p2.multi_hit);
792
794
  }
793
795
 
794
796
  test "Chance.duration" {
795
797
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
796
798
 
797
799
  chance.duration(.sleep, .P1, .P2, 2);
798
- try expectValue(@as(u4, 2), chance.actions.p1.duration);
799
- 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);
800
802
 
801
803
  chance.reset();
802
804
 
803
805
  chance.duration(.binding, .P2, .P2, 4);
804
806
  if (!showdown) {
805
- try expectValue(@as(u4, 0), chance.actions.p2.duration);
806
- 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);
807
809
  try chance.commit(.P2, .hit);
808
810
  }
809
- try expectValue(@as(u4, 4), chance.actions.p2.duration);
810
- 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);
811
813
  }
812
814
 
813
815
  test "Chance.sleep" {
@@ -817,7 +819,7 @@ test "Chance.sleep" {
817
819
  chance.actions.p1.durations.sleep = @intCast(i);
818
820
  try chance.sleep(.P1, 0);
819
821
  try expectProbability(&chance.probability, 1, d);
820
- try expectValue(@as(u3, 0), chance.actions.p1.durations.sleep);
822
+ try expectValue(0, chance.actions.p1.durations.sleep);
821
823
 
822
824
  chance.reset();
823
825
 
@@ -832,28 +834,6 @@ test "Chance.sleep" {
832
834
  }
833
835
  }
834
836
 
835
- test "Chance.disable" {
836
- var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
837
-
838
- for ([_]u8{ 8, 7, 6, 5, 4, 3, 2, 1 }, 1..9) |d, i| {
839
- chance.actions.p1.durations.disable = @intCast(i);
840
- try chance.disable(.P1, 0);
841
- try expectProbability(&chance.probability, 1, d);
842
- try expectValue(@as(u4, 0), chance.actions.p1.durations.disable);
843
-
844
- chance.reset();
845
-
846
- if (i < 8) {
847
- chance.actions.p1.durations.disable = @intCast(i);
848
- try chance.disable(.P1, 1);
849
- try expectProbability(&chance.probability, d - 1, d);
850
- try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p1.durations.disable);
851
-
852
- chance.reset();
853
- }
854
- }
855
- }
856
-
857
837
  test "Chance.confusion" {
858
838
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
859
839
 
@@ -862,7 +842,7 @@ test "Chance.confusion" {
862
842
  chance.actions.p2.durations.confusion = @intCast(i);
863
843
  try chance.confusion(.P2, 0);
864
844
  try expectProbability(&chance.probability, 1, d);
865
- try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
845
+ try expectValue(0, chance.actions.p2.durations.confusion);
866
846
 
867
847
  chance.reset();
868
848
  }
@@ -878,6 +858,28 @@ test "Chance.confusion" {
878
858
  }
879
859
  }
880
860
 
861
+ test "Chance.disable" {
862
+ var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
863
+
864
+ for ([_]u8{ 8, 7, 6, 5, 4, 3, 2, 1 }, 1..9) |d, i| {
865
+ chance.actions.p1.durations.disable = @intCast(i);
866
+ try chance.disable(.P1, 0);
867
+ try expectProbability(&chance.probability, 1, d);
868
+ try expectValue(0, chance.actions.p1.durations.disable);
869
+
870
+ chance.reset();
871
+
872
+ if (i < 8) {
873
+ chance.actions.p1.durations.disable = @intCast(i);
874
+ try chance.disable(.P1, 1);
875
+ try expectProbability(&chance.probability, d - 1, d);
876
+ try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p1.durations.disable);
877
+
878
+ chance.reset();
879
+ }
880
+ }
881
+ }
882
+
881
883
  test "Chance.attacking" {
882
884
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
883
885
 
@@ -886,7 +888,7 @@ test "Chance.attacking" {
886
888
  chance.actions.p2.durations.attacking = @intCast(i);
887
889
  try chance.attacking(.P2, 0);
888
890
  try expectProbability(&chance.probability, 1, d);
889
- try expectValue(@as(u3, 0), chance.actions.p2.durations.attacking);
891
+ try expectValue(0, chance.actions.p2.durations.attacking);
890
892
 
891
893
  chance.reset();
892
894
  }
@@ -912,7 +914,7 @@ test "Chance.binding" {
912
914
  chance.actions.p1.durations.binding = @intCast(i);
913
915
  try chance.binding(.P1, 0);
914
916
  try expectProbability(&chance.probability, p, q);
915
- try expectValue(@as(u3, 0), chance.actions.p1.durations.binding);
917
+ try expectValue(0, chance.actions.p1.durations.binding);
916
918
 
917
919
  chance.reset();
918
920
 
@@ -932,7 +934,7 @@ test "Chance.psywave" {
932
934
 
933
935
  try chance.psywave(.P2, 100, 150);
934
936
  try expectProbability(&chance.probability, 1, 150);
935
- try expectValue(@as(u8, 101), chance.actions.p2.psywave);
937
+ try expectValue(101, chance.actions.p2.psywave);
936
938
  }
937
939
 
938
940
  test "Chance.metronome" {
@@ -998,10 +1000,6 @@ const Null = struct {
998
1000
  _ = .{ self, player, roll };
999
1001
  }
1000
1002
 
1001
- pub fn secondaryChance(self: Null, player: Player, proc: bool, rate: u8) Error!void {
1002
- _ = .{ self, player, proc, rate };
1003
- }
1004
-
1005
1003
  pub fn confused(self: Null, player: Player, ok: bool) Error!void {
1006
1004
  _ = .{ self, player, ok };
1007
1005
  }
@@ -1010,6 +1008,10 @@ const Null = struct {
1010
1008
  _ = .{ self, player, ok };
1011
1009
  }
1012
1010
 
1011
+ pub fn secondaryChance(self: Null, player: Player, proc: bool, rate: u8) Error!void {
1012
+ _ = .{ self, player, proc, rate };
1013
+ }
1014
+
1013
1015
  pub fn moveSlot(self: Null, player: Player, slot: u4, ms: []const MoveSlot, n: u4) Error!void {
1014
1016
  _ = .{ self, player, slot, ms, n };
1015
1017
  }
@@ -1,4 +1,4 @@
1
- //! Code generated by `tools/generate` - manual edits will be overwritten
1
+ //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
3
  const std = @import("std");
4
4
 
@@ -1599,43 +1599,43 @@ pub const Move = enum(u8) {
1599
1599
  }
1600
1600
 
1601
1601
  /// Whether this effect activates during the "begin" step of move execution.
1602
- pub inline fn onBegin(effect: Effect) bool {
1602
+ pub fn onBegin(effect: Effect) bool {
1603
1603
  return @intFromEnum(effect) > 0 and @intFromEnum(effect) <= 16;
1604
1604
  }
1605
1605
 
1606
1606
  /// Whether this effect lowers stats.
1607
- pub inline fn isStatDown(effect: Effect) bool {
1607
+ pub fn isStatDown(effect: Effect) bool {
1608
1608
  return @intFromEnum(effect) > 16 and @intFromEnum(effect) <= 21;
1609
1609
  }
1610
1610
 
1611
1611
  /// Whether this effect activates during the "end" step of move execution.
1612
- pub inline fn onEnd(effect: Effect) bool {
1612
+ pub fn onEnd(effect: Effect) bool {
1613
1613
  return @intFromEnum(effect) > 16 and @intFromEnum(effect) <= 31;
1614
1614
  }
1615
1615
 
1616
1616
  /// Whether this effect is considered to "always happen".
1617
- pub inline fn alwaysHappens(effect: Effect) bool {
1617
+ pub fn alwaysHappens(effect: Effect) bool {
1618
1618
  return @intFromEnum(effect) > 31 and @intFromEnum(effect) <= 38;
1619
1619
  }
1620
1620
 
1621
1621
  /// Whether this effect is handled specially by the engine.
1622
- pub inline fn isSpecial(effect: Effect) bool {
1622
+ pub fn isSpecial(effect: Effect) bool {
1623
1623
  // NB: isSpecial includes isMulti up to Twineedle
1624
1624
  return @intFromEnum(effect) > 31 and @intFromEnum(effect) <= 46;
1625
1625
  }
1626
1626
 
1627
1627
  /// Whether this effect is a multi-hit effect.
1628
- pub inline fn isMulti(effect: Effect) bool {
1628
+ pub fn isMulti(effect: Effect) bool {
1629
1629
  return @intFromEnum(effect) > 44 and @intFromEnum(effect) <= 47;
1630
1630
  }
1631
1631
 
1632
1632
  /// Whether this effect is has chance of lowering stats.
1633
- pub inline fn isStatDownChance(effect: Effect) bool {
1633
+ pub fn isStatDownChance(effect: Effect) bool {
1634
1634
  return @intFromEnum(effect) > 47 and @intFromEnum(effect) <= 51;
1635
1635
  }
1636
1636
 
1637
1637
  /// Whether this effect has a secondary chance.
1638
- pub inline fn isSecondaryChance(effect: Effect) bool {
1638
+ pub fn isSecondaryChance(effect: Effect) bool {
1639
1639
  // NB: isSecondaryChance includes isStatDownChance as well as Twineedle
1640
1640
  return (@intFromEnum(effect) > 46 and @intFromEnum(effect) <= 61);
1641
1641
  }
@@ -1838,8 +1838,22 @@ pub const Move = enum(u8) {
1838
1838
  /// The number of Pokémon moves in this generation.
1839
1839
  pub const size = 165;
1840
1840
 
1841
+ /// Pokémon moves that can be called by Metronome in this generation.
1842
+ pub const METRONOME = init: {
1843
+ var num = 0;
1844
+ var moves: [163]Move = undefined;
1845
+ for (1..Move.size) |i| {
1846
+ if (i != @intFromEnum(Move.Metronome)) {
1847
+ moves[num] = @enumFromInt(i);
1848
+ num += 1;
1849
+ }
1850
+ }
1851
+ assert(num == moves.len);
1852
+ break :init moves;
1853
+ };
1854
+
1841
1855
  /// Returns the `Data` corresponding to the move.
1842
- pub inline fn get(id: Move) Data {
1856
+ pub fn get(id: Move) Data {
1843
1857
  assert(id != .None and id != .SKIP_TURN);
1844
1858
  return DATA[@intFromEnum(id) - 1];
1845
1859
  }
@@ -1,4 +1,4 @@
1
- //! Code generated by `tools/generate` - manual edits will be overwritten
1
+ //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
3
  const std = @import("std");
4
4
 
@@ -1091,8 +1091,8 @@ 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.
1095
- pub inline fn chance(id: Species) u8 {
1094
+ /// The Pokémon's critical hit ratio out of 256.
1095
+ pub fn chance(id: Species) u8 {
1096
1096
  assert(id != .None);
1097
1097
  return CHANCES[@intFromEnum(id) - 1];
1098
1098
  }