@pkmn/engine 0.1.0-dev.30895c5a → 0.1.0-dev.3158fa12

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 (78) hide show
  1. package/README.md +9 -6
  2. package/build/pkg/addon/browser.d.ts +3 -0
  3. package/build/pkg/addon/browser.js +44 -0
  4. package/build/pkg/addon/browser.js.map +1 -0
  5. package/build/pkg/addon/node.d.ts +3 -0
  6. package/build/pkg/addon/node.js +97 -0
  7. package/build/pkg/addon/node.js.map +1 -0
  8. package/build/pkg/addon/wasm.d.ts +2 -0
  9. package/build/pkg/addon/wasm.js +53 -0
  10. package/build/pkg/addon/wasm.js.map +1 -0
  11. package/build/pkg/addon.d.ts +25 -3
  12. package/build/pkg/addon.js +34 -65
  13. package/build/pkg/addon.js.map +1 -1
  14. package/build/pkg/data/layout.json +15 -2
  15. package/build/pkg/data/protocol.json +23 -9
  16. package/build/pkg/data.d.ts +23 -1
  17. package/build/pkg/data.js.map +1 -1
  18. package/build/pkg/gen1.d.ts +13 -17
  19. package/build/pkg/gen1.js +6 -10
  20. package/build/pkg/gen1.js.map +1 -1
  21. package/build/pkg/index.d.ts +37 -89
  22. package/build/pkg/index.js +6 -63
  23. package/build/pkg/index.js.map +1 -1
  24. package/build/pkg/protocol.d.ts +20 -1
  25. package/build/pkg/protocol.js +105 -103
  26. package/build/pkg/protocol.js.map +1 -1
  27. package/build/tools/debug.js +35 -69
  28. package/build/tools/debug.js.map +1 -1
  29. package/build/tools/display/debug.jsx +141 -0
  30. package/build/tools/display/debug.jsx.map +1 -0
  31. package/build/tools/display/index.js +142 -0
  32. package/build/tools/display/index.js.map +1 -0
  33. package/build/tools/display/ui.jsx +349 -0
  34. package/build/tools/display/ui.jsx.map +1 -0
  35. package/build/tools/display/util.js +18 -0
  36. package/build/tools/display/util.js.map +1 -0
  37. package/build.zig +283 -77
  38. package/package.json +52 -134
  39. package/src/bin/install-pkmn-engine +7 -5
  40. package/src/bin/pkmn-debug +1 -1
  41. package/src/lib/bindings/node.zig +121 -0
  42. package/src/lib/bindings/wasm.zig +59 -0
  43. package/src/lib/common/array.zig +77 -0
  44. package/src/lib/common/data.zig +8 -8
  45. package/src/lib/common/debug.zig +39 -8
  46. package/src/lib/common/js.zig +4 -2
  47. package/src/lib/common/optional.zig +13 -9
  48. package/src/lib/common/options.zig +4 -0
  49. package/src/lib/common/protocol.zig +44 -43
  50. package/src/lib/common/rational.zig +45 -50
  51. package/src/lib/common/rng.zig +5 -7
  52. package/src/lib/common/util.zig +50 -1
  53. package/src/lib/gen1/calc.zig +213 -62
  54. package/src/lib/gen1/chance.zig +102 -71
  55. package/src/lib/gen1/data/moves.zig +2 -4
  56. package/src/lib/gen1/data/species.zig +1 -3
  57. package/src/lib/gen1/data/types.zig +1 -2
  58. package/src/lib/gen1/data.zig +35 -38
  59. package/src/lib/gen1/helpers.zig +15 -27
  60. package/src/lib/gen1/mechanics.zig +109 -84
  61. package/src/lib/gen2/calc.zig +36 -18
  62. package/src/lib/gen2/chance.zig +86 -66
  63. package/src/lib/gen2/data/items.zig +1 -3
  64. package/src/lib/gen2/data/moves.zig +2 -4
  65. package/src/lib/gen2/data/species.zig +1 -3
  66. package/src/lib/gen2/data/types.zig +1 -2
  67. package/src/lib/gen2/data.zig +26 -29
  68. package/src/lib/gen2/generated.zig +18 -23
  69. package/src/lib/gen2/helpers.zig +9 -18
  70. package/src/lib/gen2/mechanics.zig +81 -81
  71. package/src/lib/node.zig +3 -116
  72. package/src/lib/pkmn.zig +12 -2
  73. package/src/lib/wasm.zig +13 -9
  74. package/src/tools/display/dom.ts +96 -0
  75. package/src/tools/display/ui.css +354 -0
  76. package/build/test/display.js +0 -405
  77. package/build/test/display.js.map +0 -1
  78. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,26 +1,31 @@
1
- const std = @import("std");
2
-
3
- const assert = std.debug.assert;
4
- const print = std.debug.print;
5
-
6
- const expect = std.testing.expect;
7
- const expectEqual = std.testing.expectEqual;
8
-
9
1
  const DEBUG = @import("../common/debug.zig").print;
2
+
3
+ const array = @import("../common/array.zig");
4
+ const common = @import("../common/data.zig");
5
+ const data = @import("data.zig");
6
+ const optional = @import("../common/optional.zig");
10
7
  const options = @import("../common/options.zig");
11
8
  const rational = @import("../common/rational.zig");
9
+ const std = @import("std");
12
10
  const util = @import("../common/util.zig");
13
11
 
14
- const Player = @import("../common/data.zig").Player;
15
- const Optional = @import("../common/optional.zig").Optional;
16
-
17
- const data = @import("data.zig");
18
-
12
+ const Array = array.Array;
13
+ const assert = std.debug.assert;
19
14
  const enabled = options.chance;
20
- const showdown = options.showdown;
21
-
15
+ const expect = std.testing.expect;
16
+ const expectEqual = std.testing.expectEqual;
17
+ const isPointerTo = util.isPointerTo;
22
18
  const Move = data.Move;
23
19
  const MoveSlot = data.MoveSlot;
20
+ const Optional = optional.Optional;
21
+ const Player = common.Player;
22
+ const PointerType = util.PointerType;
23
+ const print = std.debug.print;
24
+ const showdown = options.showdown;
25
+
26
+ const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
27
+ const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
28
+ const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
24
29
 
25
30
  /// Actions taken by a hypothetical "chance player" that convey information about which RNG events
26
31
  /// were observed during a Generation I battle `update`. This can additionally be provided as input
@@ -37,8 +42,8 @@ pub const Actions = extern struct {
37
42
  }
38
43
 
39
44
  /// Returns the `Action` for the given `player`.
40
- pub fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Action) {
41
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Actions);
45
+ pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Action) {
46
+ assert(isPointerTo(self, Actions));
42
47
  return if (player == .P1) &self.p1 else &self.p2;
43
48
  }
44
49
 
@@ -51,15 +56,15 @@ pub const Actions = extern struct {
51
56
  /// same shape if they have the same fields set (though those fields need not necessarily be
52
57
  /// set to the same value).
53
58
  pub fn matches(a: Actions, b: Actions) bool {
54
- inline for (@typeInfo(Actions).Struct.fields) |player| {
55
- inline for (@typeInfo(Action).Struct.fields) |field| {
59
+ inline for (@field(@typeInfo(Actions), @tagName(Struct)).fields) |player| {
60
+ inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
56
61
  const a_val = @field(@field(a, player.name), field.name);
57
62
  const b_val = @field(@field(b, player.name), field.name);
58
63
 
59
64
  switch (@typeInfo(@TypeOf(a_val))) {
60
- .Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
65
+ Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
61
66
  return false,
62
- .Int => if ((a_val > 0) != (b_val > 0)) return false,
67
+ Int => if ((a_val > 0) != (b_val > 0)) return false,
63
68
  else => unreachable,
64
69
  }
65
70
  }
@@ -67,6 +72,25 @@ pub const Actions = extern struct {
67
72
  return true;
68
73
  }
69
74
 
75
+ /// TODO
76
+ pub fn matchesAny(a: Actions, bs: []Actions, i: usize) bool {
77
+ for (bs, 0..) |b, j| {
78
+ // TODO: is skipping this redundant check worth it?
79
+ if (i == j) continue;
80
+ if (b.matches(a)) return true;
81
+ }
82
+ return false;
83
+ }
84
+
85
+ /// TODO
86
+ pub fn relax(actions: Actions) Actions {
87
+ if (!options.overwrite) return actions;
88
+ var a = actions;
89
+ if (a.p1.confusion == .overwritten) a.p1.confusion = .continuing;
90
+ if (a.p2.confusion == .overwritten) a.p2.confusion = .continuing;
91
+ return a;
92
+ }
93
+
70
94
  pub fn fmt(self: Actions, writer: anytype, shape: bool) !void {
71
95
  try writer.writeAll("<P1 = ");
72
96
  try self.p1.fmt(writer, shape);
@@ -175,10 +199,10 @@ pub const Action = packed struct(u64) {
175
199
  pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
176
200
  try writer.writeByte('(');
177
201
  var printed = false;
178
- inline for (@typeInfo(Action).Struct.fields) |field| {
202
+ inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
179
203
  const val = @field(self, field.name);
180
204
  switch (@typeInfo(@TypeOf(val))) {
181
- .Enum => if (val != .None) {
205
+ Enum => if (val != .None) {
182
206
  if (printed) try writer.writeAll(", ");
183
207
  if (shape) {
184
208
  try writer.print("{s}:?", .{field.name});
@@ -199,7 +223,7 @@ pub const Action = packed struct(u64) {
199
223
  }
200
224
  printed = true;
201
225
  },
202
- .Int => if (val != 0) {
226
+ Int => if (val != 0) {
203
227
  if (printed) try writer.writeAll(", ");
204
228
  if (shape) {
205
229
  try writer.print("{s}:?", .{field.name});
@@ -216,15 +240,19 @@ pub const Action = packed struct(u64) {
216
240
  };
217
241
 
218
242
  /// TODO
219
- pub const Durations = struct {
243
+ pub const Durations = extern struct {
220
244
  /// TODO
221
245
  p1: Duration = .{},
222
246
  /// TODO
223
247
  p2: Duration = .{},
224
248
 
249
+ comptime {
250
+ assert(@sizeOf(Durations) == 8);
251
+ }
252
+
225
253
  /// TODO
226
- pub fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Duration) {
227
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Durations);
254
+ pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Duration) {
255
+ assert(isPointerTo(self, Durations));
228
256
  return if (player == .P1) &self.p1 else &self.p2;
229
257
  }
230
258
 
@@ -239,14 +267,18 @@ pub const Durations = struct {
239
267
  }
240
268
  };
241
269
 
270
+ pub const Sleeps = Array(6, u3);
271
+
242
272
  /// TODO
243
- pub const Duration = struct {
244
- sleeps: [6]u3 = .{0} ** 6,
273
+ pub const Duration = packed struct(u32) {
274
+ sleeps: Sleeps.T = 0,
245
275
  confusion: u3 = 0,
246
276
  disable: u4 = 0,
247
277
  attacking: u3 = 0,
248
278
  binding: u3 = 0,
249
279
 
280
+ _: u1 = 0,
281
+
250
282
  pub fn format(
251
283
  self: Duration,
252
284
  comptime fmt: []const u8,
@@ -256,27 +288,22 @@ pub const Duration = struct {
256
288
  _ = .{ fmt, opts };
257
289
  try writer.writeByte('(');
258
290
  var printed = false;
259
- inline for (@typeInfo(Duration).Struct.fields) |field| {
291
+ inline for (@field(@typeInfo(Duration), @tagName(Struct)).fields) |field| {
260
292
  const val = @field(self, field.name);
261
293
  switch (@typeInfo(@TypeOf(val))) {
262
- .Int => if (val != 0) {
294
+ Int => if (val != 0) {
263
295
  if (printed) try writer.writeAll(", ");
264
- try writer.print("{s}:{d}", .{ field.name, val });
265
- printed = true;
266
- },
267
- .Array => {
268
- var total: usize = 0;
269
- for (val) |v| total += v;
270
- if (total > 0) {
271
- if (printed) try writer.writeAll(", ");
296
+ if (comptime std.mem.eql(u8, field.name, "sleeps")) {
272
297
  try writer.print("{s}:[", .{field.name});
273
- for (val, 0..) |v, i| {
298
+ for (0..6) |i| {
274
299
  if (i != 0) try writer.writeByte(',');
275
- try writer.print("{d}", .{v});
300
+ try writer.print("{d}", .{Sleeps.get(val, i)});
276
301
  }
277
302
  try writer.writeAll("]");
278
- printed = true;
303
+ } else {
304
+ try writer.print("{s}:{d}", .{ field.name, val });
279
305
  }
306
+ printed = true;
280
307
  },
281
308
  else => unreachable,
282
309
  }
@@ -364,7 +391,7 @@ pub fn Chance(comptime Rational: type) type {
364
391
 
365
392
  // If the move actually lands we can commit any past critical hit / damage rolls. Note
366
393
  // we can't rely on the presence or absence of a damage roll to determine whether a
367
- // "critical hit" was spurious or not as moves that do 1 or less damage don't rol for
394
+ // "critical hit" was spurious or not as moves that do 1 or less damage don't roll for
368
395
  // damage but can still crit (instead, whether or not a roll is deemed to be a no-op is
369
396
  // passed to the critical hit helper).
370
397
  //
@@ -380,7 +407,7 @@ pub fn Chance(comptime Rational: type) type {
380
407
  action.critical_hit = if (self.pending.crit) .true else .false;
381
408
  } else assert(!self.pending.glitch);
382
409
 
383
- if (self.pending.damage_roll > 0) {
410
+ if (self.pending.damage_roll > 0 and (!self.pending.glitch or self.pending.hit)) {
384
411
  try self.probability.update(1, 39);
385
412
  action.damage = self.pending.damage_roll;
386
413
  }
@@ -407,9 +434,9 @@ pub fn Chance(comptime Rational: type) type {
407
434
 
408
435
  var d = self.durations.get(player);
409
436
 
410
- const out = d.sleeps[0];
411
- d.sleeps[0] = d.sleeps[slot - 1];
412
- d.sleeps[slot - 1] = out;
437
+ const out = Sleeps.get(d.sleeps, 0);
438
+ d.sleeps = Sleeps.set(d.sleeps, 0, Sleeps.get(d.sleeps, slot - 1));
439
+ d.sleeps = Sleeps.set(d.sleeps, slot - 1, out);
413
440
 
414
441
  d.confusion = 0;
415
442
  d.disable = 0;
@@ -542,7 +569,8 @@ pub fn Chance(comptime Rational: type) type {
542
569
  .None => {
543
570
  @field(a, @tagName(field)) = .None;
544
571
  if (field == .sleep) {
545
- self.durations.get(player).sleeps[0] = 0;
572
+ var d = self.durations.get(player);
573
+ d.sleeps = Sleeps.set(d.sleeps, 0, 0);
546
574
  } else {
547
575
  @field(self.durations.get(player), @tagName(field)) = 0;
548
576
  }
@@ -556,7 +584,8 @@ pub fn Chance(comptime Rational: type) type {
556
584
  });
557
585
  @field(a, @tagName(field)) = .started;
558
586
  if (field == .sleep) {
559
- self.durations.get(player).sleeps[0] = 1;
587
+ var d = self.durations.get(player);
588
+ d.sleeps = Sleeps.set(d.sleeps, 0, 1);
560
589
  } else {
561
590
  @field(self.durations.get(player), @tagName(field)) = 1;
562
591
  }
@@ -573,19 +602,19 @@ pub fn Chance(comptime Rational: type) type {
573
602
  a.sleep = obs;
574
603
 
575
604
  var d = self.durations.get(player);
576
- const n = d.sleeps[0];
605
+ const n = Sleeps.get(d.sleeps, 0);
577
606
 
578
607
  if (obs == .None) {
579
- d.sleeps[0] = 0;
608
+ d.sleeps = Sleeps.set(d.sleeps, 0, 0);
580
609
  } else if (obs == .ended) {
581
610
  assert(n >= 1 and n <= 7);
582
611
  if (n != 7) try self.probability.update(1, 8 - @as(u4, n));
583
- d.sleeps[0] = 0;
612
+ d.sleeps = Sleeps.set(d.sleeps, 0, 0);
584
613
  } else {
585
614
  assert(obs == .continuing);
586
615
  assert(n >= 1 and n < 7);
587
616
  try self.probability.update(8 - @as(u4, n) - 1, 8 - @as(u4, n));
588
- d.sleeps[0] += 1;
617
+ d.sleeps = Sleeps.set(d.sleeps, 0, n + 1);
589
618
  }
590
619
  }
591
620
 
@@ -643,6 +672,7 @@ pub fn Chance(comptime Rational: type) type {
643
672
  var d = self.durations.get(player);
644
673
  const n = d.attacking;
645
674
  if (obs == .ended) {
675
+ // "3-4 turns" includes the turn for the initial attack *plus* the forced attacks
646
676
  assert(n >= 2 and n <= 3);
647
677
  if (n != 3) try self.probability.update(1, 4 - @as(u4, n));
648
678
  d.attacking = 0;
@@ -669,6 +699,7 @@ pub fn Chance(comptime Rational: type) type {
669
699
  const q: u4 = if (n < 3) 8 - ((n - 1) * p) else 2;
670
700
 
671
701
  if (obs == .ended) {
702
+ // "2-5 turns" includes the turn for the initial attack *plus* the forced attacks
672
703
  assert(n >= 1 and n <= 4);
673
704
  if (n != 4) try self.probability.update(p, q);
674
705
  d.binding = 0;
@@ -802,16 +833,16 @@ test "Chance.damage" {
802
833
 
803
834
  try chance.damage(.P1, 217);
804
835
  if (showdown) {
805
- try expectValue(217, chance.actions.p1.damage);
836
+ try expectValue(@as(u8, 217), chance.actions.p1.damage);
806
837
  try expectProbability(&chance.probability, 1, 39);
807
838
  } else {
808
839
  try expectProbability(&chance.probability, 1, 1);
809
- try expectValue(0, chance.actions.p1.damage);
840
+ try expectValue(@as(u8, 0), chance.actions.p1.damage);
810
841
 
811
842
  try chance.commit(.P1, .hit);
812
843
 
813
844
  try expectProbability(&chance.probability, 1, 39);
814
- try expectValue(217, chance.actions.p1.damage);
845
+ try expectValue(@as(u8, 217), chance.actions.p1.damage);
815
846
  }
816
847
  }
817
848
 
@@ -863,13 +894,13 @@ test "Chance.moveSlot" {
863
894
 
864
895
  try chance.moveSlot(.P2, 2, &ms, 2);
865
896
  try expectProbability(&chance.probability, 1, 2);
866
- try expectValue(2, chance.actions.p2.move_slot);
897
+ try expectValue(@as(u4, 2), chance.actions.p2.move_slot);
867
898
 
868
899
  chance.reset();
869
900
 
870
901
  try chance.moveSlot(.P1, 1, &ms, 0);
871
902
  try expectProbability(&chance.probability, 1, 3);
872
- try expectValue(1, chance.actions.p1.move_slot);
903
+ try expectValue(@as(u4, 1), chance.actions.p1.move_slot);
873
904
  }
874
905
 
875
906
  test "Chance.multiHit" {
@@ -877,43 +908,43 @@ test "Chance.multiHit" {
877
908
 
878
909
  try chance.multiHit(.P1, 3);
879
910
  try expectProbability(&chance.probability, 3, 8);
880
- try expectValue(3, chance.actions.p1.multi_hit);
911
+ try expectValue(@as(u4, 3), chance.actions.p1.multi_hit);
881
912
 
882
913
  chance.reset();
883
914
 
884
915
  try chance.multiHit(.P2, 5);
885
916
  try expectProbability(&chance.probability, 1, 8);
886
- try expectValue(5, chance.actions.p2.multi_hit);
917
+ try expectValue(@as(u4, 5), chance.actions.p2.multi_hit);
887
918
  }
888
919
 
889
920
  test "Chance.duration" {
890
921
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
891
922
 
892
923
  chance.duration(.P1, 2);
893
- try expectValue(2, chance.actions.p1.duration);
924
+ try expectValue(@as(u4, 2), chance.actions.p1.duration);
894
925
 
895
926
  chance.reset();
896
927
 
897
928
  chance.duration(.P2, 4);
898
- try expectValue(4, chance.actions.p2.duration);
929
+ try expectValue(@as(u4, 4), chance.actions.p2.duration);
899
930
  }
900
931
 
901
932
  test "Chance.sleep" {
902
933
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
903
934
 
904
935
  for ([_]u8{ 7, 6, 5, 4, 3, 2, 1 }, 1..8) |d, i| {
905
- chance.durations.p1.sleeps[0] = @intCast(i);
936
+ chance.durations.p1.sleeps = Sleeps.set(chance.durations.p1.sleeps, 0, @intCast(i));
906
937
  try chance.sleep(.P1, .ended);
907
938
  try expectProbability(&chance.probability, 1, d);
908
- try expectValue(0, chance.durations.p1.sleeps[0]);
939
+ try expectValue(@as(u3, 0), Sleeps.get(chance.durations.p1.sleeps, 0));
909
940
 
910
941
  chance.reset();
911
942
 
912
943
  if (i < 7) {
913
- chance.durations.p1.sleeps[0] = @intCast(i);
944
+ chance.durations.p1.sleeps = Sleeps.set(chance.durations.p1.sleeps, 0, @intCast(i));
914
945
  try chance.sleep(.P1, .continuing);
915
946
  try expectProbability(&chance.probability, d - 1, d);
916
- try expectValue(@as(u3, @intCast(i)) + 1, chance.durations.p1.sleeps[0]);
947
+ try expectValue(@as(u3, @intCast(i)) + 1, Sleeps.get(chance.durations.p1.sleeps, 0));
917
948
 
918
949
  chance.reset();
919
950
  }
@@ -928,7 +959,7 @@ test "Chance.confusion" {
928
959
  chance.durations.p2.confusion = @intCast(i);
929
960
  try chance.confusion(.P2, .ended);
930
961
  try expectProbability(&chance.probability, 1, d);
931
- try expectValue(0, chance.durations.p2.confusion);
962
+ try expectValue(@as(u3, 0), chance.durations.p2.confusion);
932
963
 
933
964
  chance.reset();
934
965
  }
@@ -951,7 +982,7 @@ test "Chance.disable" {
951
982
  chance.durations.p1.disable = @intCast(i);
952
983
  try chance.disable(.P1, .ended);
953
984
  try expectProbability(&chance.probability, 1, d);
954
- try expectValue(0, chance.durations.p1.disable);
985
+ try expectValue(@as(u4, 0), chance.durations.p1.disable);
955
986
 
956
987
  chance.reset();
957
988
 
@@ -974,7 +1005,7 @@ test "Chance.attacking" {
974
1005
  chance.durations.p2.attacking = @intCast(i);
975
1006
  try chance.attacking(.P2, .ended);
976
1007
  try expectProbability(&chance.probability, 1, d);
977
- try expectValue(0, chance.durations.p2.attacking);
1008
+ try expectValue(@as(u3, 0), chance.durations.p2.attacking);
978
1009
 
979
1010
  chance.reset();
980
1011
  }
@@ -1000,7 +1031,7 @@ test "Chance.binding" {
1000
1031
  chance.durations.p1.binding = @intCast(i);
1001
1032
  try chance.binding(.P1, .ended);
1002
1033
  try expectProbability(&chance.probability, p, q);
1003
- try expectValue(0, chance.durations.p1.binding);
1034
+ try expectValue(@as(u3, 0), chance.durations.p1.binding);
1004
1035
 
1005
1036
  chance.reset();
1006
1037
 
@@ -1020,7 +1051,7 @@ test "Chance.psywave" {
1020
1051
 
1021
1052
  try chance.psywave(.P2, 100, 150);
1022
1053
  try expectProbability(&chance.probability, 1, 150);
1023
- try expectValue(101, chance.actions.p2.psywave);
1054
+ try expectValue(@as(u8, 101), chance.actions.p2.psywave);
1024
1055
  }
1025
1056
 
1026
1057
  test "Chance.metronome" {
@@ -1,12 +1,10 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
- const rng = @import("../../common/rng.zig");
6
3
  const gen1 = @import("../../gen1/data.zig");
4
+ const rng = @import("../../common/rng.zig");
5
+ const std = @import("std");
7
6
 
8
7
  const assert = std.debug.assert;
9
-
10
8
  const percent = rng.Gen12.percent;
11
9
  const Type = gen1.Type;
12
10
 
@@ -1,11 +1,9 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const gen1 = @import("../../gen1/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
-
9
7
  const Stats = gen1.Stats;
10
8
  const Types = gen1.Types;
11
9
 
@@ -1,8 +1,7 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const gen1 = @import("../../gen1/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
7
  const Effectiveness = gen1.Effectiveness;
@@ -1,20 +1,16 @@
1
- const std = @import("std");
2
1
  const builtin = @import("builtin");
3
-
4
- const pkmn = @import("../pkmn.zig");
5
-
2
+ const calc = @import("calc.zig");
3
+ const chance = @import("chance.zig");
6
4
  const data = @import("../common/data.zig");
5
+ const mechanics = @import("mechanics.zig");
6
+ const moves = @import("data/moves.zig");
7
+ const pkmn = @import("../pkmn.zig");
7
8
  const protocol = @import("../common/protocol.zig");
8
9
  const rng = @import("../common/rng.zig");
9
- const util = @import("../common/util.zig");
10
-
11
- const moves = @import("data/moves.zig");
12
10
  const species = @import("data/species.zig");
11
+ const std = @import("std");
13
12
  const types = @import("data/types.zig");
14
-
15
- const calc = @import("calc.zig");
16
- const chance = @import("chance.zig");
17
- const mechanics = @import("mechanics.zig");
13
+ const util = @import("../common/util.zig");
18
14
 
19
15
  const assert = std.debug.assert;
20
16
  const expectEqual = std.testing.expectEqual;
@@ -47,6 +43,7 @@ const Player = data.Player;
47
43
  const Result = data.Result;
48
44
 
49
45
  const PointerType = util.PointerType;
46
+ const isPointerTo = util.isPointerTo;
50
47
 
51
48
  const showdown = pkmn.options.showdown;
52
49
 
@@ -71,13 +68,13 @@ pub fn Battle(comptime RNG: anytype) type {
71
68
 
72
69
  /// Returns the `Side` for the given `player`.
73
70
  pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
74
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
71
+ assert(isPointerTo(self, Self));
75
72
  return &self.sides[@intFromEnum(player)];
76
73
  }
77
74
 
78
75
  /// Returns the `Side` of the opponent for the given `player`
79
76
  pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
80
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
77
+ assert(isPointerTo(self, Self));
81
78
  return &self.sides[@intFromEnum(player.foe())];
82
79
  }
83
80
 
@@ -91,7 +88,7 @@ pub fn Battle(comptime RNG: anytype) type {
91
88
  self: anytype,
92
89
  player: Player,
93
90
  ) PointerType(@TypeOf(self), MoveDetails) {
94
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
91
+ assert(isPointerTo(self, Self));
95
92
  return &self.last_moves[@intFromEnum(player)];
96
93
  }
97
94
 
@@ -142,7 +139,7 @@ pub const Side = extern struct {
142
139
 
143
140
  /// Returns the stored `Pokemon` corresponding to the one-indexed party `slot`.
144
141
  pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
145
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
142
+ assert(isPointerTo(self, Side));
146
143
  assert(slot > 0 and slot <= 6);
147
144
  const id = self.order[slot - 1];
148
145
  assert(id > 0 and id <= 6);
@@ -151,7 +148,7 @@ pub const Side = extern struct {
151
148
 
152
149
  /// Returns the stored `Pokemon` corresponding to the `active` Pokémon (slot 1).
153
150
  pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
154
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
151
+ assert(isPointerTo(self, Side));
155
152
  return self.get(1);
156
153
  }
157
154
  };
@@ -177,7 +174,7 @@ pub const ActivePokemon = extern struct {
177
174
 
178
175
  /// Returns the active Pokémon's current move slot located at the one-indexed `mslot`.
179
176
  pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
180
- assert(@typeInfo(@TypeOf(self)).Pointer.child == ActivePokemon);
177
+ assert(isPointerTo(self, ActivePokemon));
181
178
  assert(mslot > 0 and mslot <= 4);
182
179
  assert(self.moves[mslot - 1].id != .None);
183
180
  return &self.moves[mslot - 1];
@@ -207,7 +204,7 @@ pub const Pokemon = extern struct {
207
204
 
208
205
  /// Returns the Pokémon's original move slot located at the one-indexed `mslot`.
209
206
  pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
210
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
207
+ assert(isPointerTo(self, Pokemon));
211
208
  assert(mslot > 0 and mslot <= 4);
212
209
  assert(self.moves[mslot - 1].id != .None);
213
210
  return &self.moves[mslot - 1];
@@ -255,7 +252,7 @@ pub const Status = enum(u8) {
255
252
 
256
253
  pub const TOX = 0b10001000;
257
254
 
258
- const SLP = 0b111;
255
+ const SLEEP = 0b111;
259
256
 
260
257
  /// Whether or not the status `num` is the same as `status`.
261
258
  pub fn is(num: u8, status: Status) bool {
@@ -283,7 +280,7 @@ pub const Status = enum(u8) {
283
280
 
284
281
  /// Returns the duration of a sleep status.
285
282
  pub fn duration(num: u8) u3 {
286
- return @intCast(num & SLP);
283
+ return @intCast(num & SLEEP);
287
284
  }
288
285
 
289
286
  /// Returns whether `num` reflects any status.
@@ -316,12 +313,12 @@ test Status {
316
313
  try expect(Status.is(Status.slp(5), .SLP));
317
314
  try expect(!Status.is(Status.slp(5), .EXT));
318
315
  try expect(!Status.is(Status.slp(7), .PSN));
319
- try expectEqual(5, Status.duration(Status.slp(5)));
316
+ try expectEqual(@as(u3, 5), Status.duration(Status.slp(5)));
320
317
  try expect(Status.is(Status.slf(2), .SLP));
321
318
  try expect(Status.is(Status.slf(2), .EXT));
322
319
  try expect(Status.is(Status.TOX, .PSN));
323
320
  try expect(Status.is(Status.TOX, .EXT));
324
- try expectEqual(1, Status.duration(Status.slp(1)));
321
+ try expectEqual(@as(u3, 1), Status.duration(Status.slp(1)));
325
322
  }
326
323
 
327
324
  /// Bitfield representation of volatile statuses and associated data in Generation I.
@@ -405,16 +402,16 @@ test Volatiles {
405
402
  try expect(!volatiles.Transform);
406
403
  try expect(!volatiles.MultiHit);
407
404
 
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);
405
+ try expectEqual(@as(u16, 235), volatiles.state);
406
+ try expectEqual(@as(u8, 42), volatiles.substitute);
407
+ try expectEqual(@as(u4, 2), volatiles.disable_move);
408
+ try expectEqual(@as(u4, 4), volatiles.disable_duration);
409
+ try expectEqual(@as(u3, 2), volatiles.confusion);
410
+ try expectEqual(@as(u5, 4), volatiles.toxic);
411
+ try expectEqual(@as(u3, 3), volatiles.attacks);
415
412
  }
416
413
 
417
- /// Representaiton of a Pokémon's stats in Generation I.
414
+ /// Representation of a Pokémon's stats in Generation I.
418
415
  pub fn Stats(comptime T: type) type {
419
416
  return extern struct {
420
417
  hp: T = 0,
@@ -442,9 +439,9 @@ test Stats {
442
439
  try expectEqual(0, stats.def);
443
440
 
444
441
  var base = Species.get(.Gyarados).stats;
445
- try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
442
+ try expectEqual(@as(u16, 127), Stats(u16).calc("hp", base.hp, 0, 5120, 38));
446
443
  base = Species.get(.Pidgeot).stats;
447
- try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
444
+ try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
448
445
  }
449
446
 
450
447
  /// Representation of a Pokémon's boosts in Generation I.
@@ -537,7 +534,7 @@ pub const Species = species.Species;
537
534
 
538
535
  test Species {
539
536
  try expectEqual(2, @intFromEnum(Species.Ivysaur));
540
- try expectEqual(100, Species.get(.Mew).stats.def);
537
+ try expectEqual(@as(u8, 100), Species.get(.Mew).stats.def);
541
538
  }
542
539
 
543
540
  /// Representation of a Generation I type in Pokémon.
@@ -576,8 +573,8 @@ test Types {
576
573
  try expectEqual(Effectiveness.Resisted, Type.effectiveness(.Fire, .Water));
577
574
  try expectEqual(Effectiveness.Neutral, Type.effectiveness(.Normal, .Grass));
578
575
 
579
- try expectEqual(3, Type.precedence(.Water, .Water));
580
- try expectEqual(26, Type.precedence(.Bug, .Ghost));
576
+ try expectEqual(@as(u8, 3), Type.precedence(.Water, .Water));
577
+ try expectEqual(@as(u8, 26), Type.precedence(.Bug, .Ghost));
581
578
  try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
582
579
 
583
580
  const t: Types = .{ .type1 = .Rock, .type2 = .Ground };
@@ -617,18 +614,18 @@ pub const DVs = struct {
617
614
 
618
615
  test DVs {
619
616
  var dvs: DVs = .{ .spc = 15, .spe = 15 };
620
- try expectEqual(15, dvs.hp());
617
+ try expectEqual(@as(u4, 15), dvs.hp());
621
618
  dvs = .{
622
619
  .atk = 5,
623
620
  .def = 15,
624
621
  .spe = 13,
625
622
  .spc = 13,
626
623
  };
627
- try expectEqual(15, dvs.hp());
624
+ try expectEqual(@as(u4, 15), dvs.hp());
628
625
  dvs = .{
629
626
  .def = 3,
630
627
  .spe = 10,
631
628
  .spc = 11,
632
629
  };
633
- try expectEqual(13, dvs.hp());
630
+ try expectEqual(@as(u4, 13), dvs.hp());
634
631
  }