@pkmn/engine 0.1.0-dev.3de821b9 → 0.1.0-dev.3f3af84c

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 (79) 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 +47 -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 +100 -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 +15 -18
  19. package/build/pkg/gen1.js +11 -12
  20. package/build/pkg/gen1.js.map +1 -1
  21. package/build/pkg/index.d.ts +40 -90
  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 +33 -0
  36. package/build/tools/display/util.js.map +1 -0
  37. package/build.zig +330 -85
  38. package/package.json +53 -134
  39. package/src/bin/install-pkmn-engine +10 -7
  40. package/src/bin/pkmn-debug +1 -1
  41. package/src/lib/bindings/c.zig +255 -0
  42. package/src/lib/bindings/node.zig +121 -0
  43. package/src/lib/bindings/wasm.zig +59 -0
  44. package/src/lib/common/array.zig +77 -0
  45. package/src/lib/common/data.zig +8 -8
  46. package/src/lib/common/debug.zig +39 -8
  47. package/src/lib/common/js.zig +4 -2
  48. package/src/lib/common/optional.zig +13 -9
  49. package/src/lib/common/options.zig +4 -0
  50. package/src/lib/common/protocol.zig +44 -43
  51. package/src/lib/common/rational.zig +53 -51
  52. package/src/lib/common/rng.zig +5 -7
  53. package/src/lib/common/util.zig +50 -1
  54. package/src/lib/gen1/calc.zig +250 -111
  55. package/src/lib/gen1/chance.zig +130 -121
  56. package/src/lib/gen1/data/moves.zig +2 -4
  57. package/src/lib/gen1/data/species.zig +1 -3
  58. package/src/lib/gen1/data/types.zig +1 -2
  59. package/src/lib/gen1/data.zig +35 -38
  60. package/src/lib/gen1/helpers.zig +15 -27
  61. package/src/lib/gen1/mechanics.zig +118 -95
  62. package/src/lib/gen2/calc.zig +37 -27
  63. package/src/lib/gen2/chance.zig +86 -66
  64. package/src/lib/gen2/data/items.zig +1 -3
  65. package/src/lib/gen2/data/moves.zig +2 -4
  66. package/src/lib/gen2/data/species.zig +1 -3
  67. package/src/lib/gen2/data/types.zig +1 -2
  68. package/src/lib/gen2/data.zig +26 -29
  69. package/src/lib/gen2/generated.zig +18 -23
  70. package/src/lib/gen2/helpers.zig +9 -18
  71. package/src/lib/gen2/mechanics.zig +81 -81
  72. package/src/lib/node.zig +3 -116
  73. package/src/lib/pkmn.zig +14 -7
  74. package/src/lib/wasm.zig +13 -9
  75. package/src/tools/display/dom.ts +96 -0
  76. package/src/tools/display/ui.css +354 -0
  77. package/build/test/display.js +0 -405
  78. package/build/test/display.js.map +0 -1
  79. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -8,9 +8,9 @@ const expectEqual = std.testing.expectEqual;
8
8
 
9
9
  const options = @import("../common/options.zig");
10
10
  const rational = @import("../common/rational.zig");
11
- const rng = @import("../common/rng.zig");
12
11
  const util = @import("../common/util.zig");
13
12
 
13
+ const Array = @import("../common/array.zig").Array;
14
14
  const Player = @import("../common/data.zig").Player;
15
15
  const Optional = @import("../common/optional.zig").Optional;
16
16
 
@@ -19,13 +19,18 @@ const data = @import("data.zig");
19
19
  const enabled = options.chance;
20
20
  const showdown = options.showdown;
21
21
 
22
- const Gen12 = rng.Gen12;
22
+ const PointerType = util.PointerType;
23
+ const isPointerTo = util.isPointerTo;
23
24
 
24
25
  const Move = data.Move;
25
26
  const Type = data.Type;
26
27
  const Effectiveness = data.Effectiveness;
27
28
  const TriAttack = data.TriAttack;
28
29
 
30
+ const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
31
+ const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
32
+ const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
33
+
29
34
  /// Actions taken by a hypothetical "chance player" that convey information about which RNG events
30
35
  /// were observed during a Generation II battle `update`. This can additionally be provided as input
31
36
  /// to the `update` call to override the normal behavior of the RNG in order to force specific
@@ -37,8 +42,8 @@ pub const Actions = extern struct {
37
42
  p2: Action = .{},
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
 
@@ -52,15 +57,15 @@ pub const Actions = extern struct {
52
57
  /// same shape if they have the same fields set (though those fields need not necessarily be
53
58
  /// set to the same value).
54
59
  pub fn matches(a: Actions, b: Actions) bool {
55
- inline for (@typeInfo(Actions).Struct.fields) |player| {
56
- inline for (@typeInfo(Action).Struct.fields) |field| {
60
+ inline for (@field(@typeInfo(Actions), @tagName(Struct)).fields) |player| {
61
+ inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
57
62
  const a_val = @field(@field(a, player.name), field.name);
58
63
  const b_val = @field(@field(b, player.name), field.name);
59
64
 
60
65
  switch (@typeInfo(@TypeOf(a_val))) {
61
- .Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
66
+ Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
62
67
  return false,
63
- .Int => if ((a_val > 0) != (b_val > 0)) return false,
68
+ Int => if ((a_val > 0) != (b_val > 0)) return false,
64
69
  else => unreachable,
65
70
  }
66
71
  }
@@ -82,10 +87,9 @@ pub const Actions = extern struct {
82
87
  }
83
88
  };
84
89
 
85
- // TODO: ziglang/zig#19730
86
90
  test Actions {
87
- const a: Actions = .{ .p1 = .{ .hit = .true, .critical_hit = .false, .damage = 245 } };
88
- const b: Actions = .{ .p1 = .{ .hit = .false, .critical_hit = .true, .damage = 246 } };
91
+ const a: Actions = .{ .p1 = .{ .hit = .true, .confused = .false, .damages = 245 } };
92
+ const b: Actions = .{ .p1 = .{ .hit = .false, .confused = .true, .damages = 246 } };
89
93
  const c: Actions = .{ .p1 = .{ .hit = .true } };
90
94
 
91
95
  try expect(a.eql(a));
@@ -101,11 +105,19 @@ test Actions {
101
105
  try expect(!c.matches(a));
102
106
  }
103
107
 
108
+ /// Observation made about a duration - whether the duration has started, been continued, or ended.
109
+ pub const Observation = enum { started, continuing, ended };
110
+
111
+ pub const Damages = Array(5, u8);
112
+ pub const Criticals = Array(5, Optional(bool));
113
+
104
114
  /// Information about the RNG that was observed during a Generation II battle `update` for a
105
115
  /// single player.
106
116
  pub const Action = packed struct(u128) {
107
- /// If not 0, the roll to be returned Rolls.damage.
108
- damage: u8 = 0,
117
+ /// TODO
118
+ damages: Damages.T = 0,
119
+ // TODO
120
+ critical_hits: Criticals.T = 0,
109
121
 
110
122
  /// If not None, the Player to be returned by Rolls.speedTie.
111
123
  speed_tie: Optional(Player) = .None,
@@ -113,50 +125,58 @@ pub const Action = packed struct(u128) {
113
125
  quick_claw: Optional(bool) = .None,
114
126
  /// If not None, the value to return for Rolls.hit.
115
127
  hit: Optional(bool) = .None,
116
- /// If not None, the value to be returned by Rolls.criticalHit.
117
- critical_hit: Optional(bool) = .None,
118
-
119
128
  /// If not None, the value to return for Rolls.confused.
120
129
  confused: Optional(bool) = .None,
130
+
121
131
  /// If not None, the value to return for Rolls.attract.
122
132
  attract: Optional(bool) = .None,
123
133
  /// If not None, the value to return for Rolls.paralyzed.
124
134
  paralyzed: Optional(bool) = .None,
125
135
  /// If not None, the value to return for Rolls.defrost.
126
136
  defrost: Optional(bool) = .None,
127
-
128
137
  /// If not None, the value to be returned for Rolls.secondaryChance.
129
138
  secondary_chance: Optional(bool) = .None,
139
+
130
140
  /// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
131
141
  item: Optional(bool) = .None,
132
142
  /// If not None, the value to be returned for Rolls.protect.
133
143
  protect: Optional(bool) = .None,
134
144
  /// If not None, the value to return for Rolls.triAttack.
135
145
  tri_attack: Optional(TriAttack) = .None,
146
+ /// If not 0, the value to return for Rolls.tripleKick.
147
+ triple_kick: u2 = 0,
136
148
 
137
149
  /// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
138
150
  present: u3 = 0,
139
151
  /// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
140
152
  magnitude: u3 = 0,
141
- /// If not 0, the value to return for Rolls.tripleKick.
142
- triple_kick: u2 = 0,
143
-
144
- /// If not 0, the amount of PP to deduct for Rolls.spite.
153
+ /// If not 0, the amount of PP to deduct for Rolls.spite.
145
154
  spite: u3 = 0,
146
- /// If not None, the value to return for Rolls.conversion2.
147
- conversion_2: Optional(Type) = .None,
148
-
149
155
  /// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
150
156
  /// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
151
- move_slot: u4 = 0,
157
+ move_slot: u3 = 0,
152
158
  /// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
153
159
  /// invalid values (eg. due to empty party slots or fainted members) will be ignored.
154
- force_switch: u4 = 0,
155
-
160
+ force_switch: u3 = 0,
156
161
  /// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
157
- multi_hit: u4 = 0,
162
+ multi_hit: u3 = 0,
163
+
164
+ sleep: Optional(Observation) = .None,
165
+ /// TODO
166
+ confusion: Optional(Observation) = .None,
167
+ /// TODO
168
+ disable: Optional(Observation) = .None,
169
+ /// TODO
170
+ attacking: Optional(Observation) = .None,
171
+ /// TODO
172
+ binding: Optional(Observation) = .None,
173
+ /// TODO
174
+ encore: Optional(Observation) = .None,
175
+
158
176
  /// If not 0, the value to by one of the Rolls.*Duration rolls.
159
- duration: u4 = 0,
177
+ duration: u3 = 0,
178
+ /// If not None, the value to return for Rolls.conversion2.
179
+ conversion_2: Optional(Type) = .None,
160
180
 
161
181
  /// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
162
182
  psywave: u8 = 0,
@@ -164,8 +184,6 @@ pub const Action = packed struct(u128) {
164
184
  /// If not None, the Move to return for Rolls.metronome.
165
185
  metronome: Move = .None,
166
186
 
167
- _: u48 = 0, // TODO
168
-
169
187
  pub const Field = std.meta.FieldEnum(Action);
170
188
 
171
189
  pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
@@ -176,10 +194,10 @@ pub const Action = packed struct(u128) {
176
194
  pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
177
195
  try writer.writeByte('(');
178
196
  var printed = false;
179
- inline for (@typeInfo(Action).Struct.fields) |field| {
197
+ inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
180
198
  const val = @field(self, field.name);
181
199
  switch (@typeInfo(@TypeOf(val))) {
182
- .Enum => if (val != .None) {
200
+ Enum => if (val != .None) {
183
201
  if (printed) try writer.writeAll(", ");
184
202
  if (shape) {
185
203
  try writer.print("{s}:?", .{field.name});
@@ -193,7 +211,7 @@ pub const Action = packed struct(u128) {
193
211
  }
194
212
  printed = true;
195
213
  },
196
- .Int => if (val != 0) {
214
+ Int => if (val != 0) {
197
215
  if (printed) try writer.writeAll(", ");
198
216
  if (shape) {
199
217
  try writer.print("{s}:?", .{field.name});
@@ -255,19 +273,21 @@ pub fn Chance(comptime Rational: type) type {
255
273
  self.actions.get(player).hit = if (ok) .true else .false;
256
274
  }
257
275
 
258
- pub fn criticalHit(self: *Self, player: Player, crit: bool, rate: u8) Error!void {
276
+ pub fn criticalHit(self: *Self, player: Player, i: u3, crit: bool, rate: u8) Error!void {
259
277
  if (!enabled) return;
260
278
 
261
279
  const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
262
280
  try self.probability.update(n, 256);
263
- self.actions.get(player).critical_hit = if (crit) .true else .false;
281
+ var a = self.actions.get(player);
282
+ a.critical_hits = Criticals.set(a.critical_hits, i, if (crit) .true else .false);
264
283
  }
265
284
 
266
- pub fn damage(self: *Self, player: Player, roll: u8) Error!void {
285
+ pub fn damage(self: *Self, player: Player, i: u3, roll: u8) Error!void {
267
286
  if (!enabled) return;
268
287
 
269
288
  try self.probability.update(1, 39);
270
- self.actions.get(player).damage = roll;
289
+ var a = self.actions.get(player);
290
+ a.damages = Damages.set(a.damages, i, roll);
271
291
  }
272
292
 
273
293
  pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
@@ -419,7 +439,7 @@ pub fn Chance(comptime Rational: type) type {
419
439
  self.actions.get(player).multi_hit = n;
420
440
  }
421
441
 
422
- pub fn duration(self: *Self, player: Player, turns: u4) void {
442
+ pub fn duration(self: *Self, player: Player, turns: u3) void {
423
443
  if (!enabled) return;
424
444
 
425
445
  self.actions.get(player).duration = if (options.key) 2 else turns;
@@ -474,22 +494,22 @@ test "Chance.hit" {
474
494
  test "Chance.criticalHit" {
475
495
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
476
496
 
477
- try chance.criticalHit(.P1, true, 17);
478
- try expectValue(Optional(bool).true, chance.actions.p1.critical_hit);
497
+ try chance.criticalHit(.P1, 0, true, 17);
498
+ try expectValue(Optional(bool).true, Criticals.get(chance.actions.p1.critical_hits, 0));
479
499
  try expectProbability(&chance.probability, 17, 256);
480
500
 
481
501
  chance.reset();
482
502
 
483
- try chance.criticalHit(.P2, false, 5);
503
+ try chance.criticalHit(.P2, 1, false, 5);
484
504
  try expectProbability(&chance.probability, 251, 256);
485
- try expectValue(Optional(bool).false, chance.actions.p2.critical_hit);
505
+ try expectValue(Optional(bool).false, Criticals.get(chance.actions.p2.critical_hits, 1));
486
506
  }
487
507
 
488
508
  test "Chance.damage" {
489
509
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
490
510
 
491
- try chance.damage(.P1, 217);
492
- try expectValue(217, chance.actions.p1.damage);
511
+ try chance.damage(.P1, 0, 219);
512
+ try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
493
513
  try expectProbability(&chance.probability, 1, 39);
494
514
  }
495
515
 
@@ -614,7 +634,7 @@ test "Chance.present" {
614
634
  } else {
615
635
  try expectProbability(&chance.probability, 25, 256);
616
636
  }
617
- try expectValue(4, chance.actions.p2.present);
637
+ try expectValue(@as(u3, 4), chance.actions.p2.present);
618
638
 
619
639
  chance.reset();
620
640
 
@@ -624,7 +644,7 @@ test "Chance.present" {
624
644
  } else {
625
645
  try expectProbability(&chance.probability, 51, 256);
626
646
  }
627
- try expectValue(1, chance.actions.p1.present);
647
+ try expectValue(@as(u3, 1), chance.actions.p1.present);
628
648
  }
629
649
 
630
650
  test "Chance.magnitude" {
@@ -636,7 +656,7 @@ test "Chance.magnitude" {
636
656
  } else {
637
657
  try expectProbability(&chance.probability, 13, 256);
638
658
  }
639
- try expectValue(7, chance.actions.p2.magnitude);
659
+ try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
640
660
 
641
661
  chance.reset();
642
662
 
@@ -646,7 +666,7 @@ test "Chance.magnitude" {
646
666
  } else {
647
667
  try expectProbability(&chance.probability, 51, 256);
648
668
  }
649
- try expectValue(5, chance.actions.p1.magnitude);
669
+ try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
650
670
  }
651
671
 
652
672
  test "Chance.tripleKick" {
@@ -654,7 +674,7 @@ test "Chance.tripleKick" {
654
674
 
655
675
  try chance.tripleKick(.P1, 2);
656
676
  try expectProbability(&chance.probability, 1, 3);
657
- try expectValue(2, chance.actions.p1.triple_kick);
677
+ try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
658
678
  }
659
679
 
660
680
  test "Chance.spite" {
@@ -662,7 +682,7 @@ test "Chance.spite" {
662
682
 
663
683
  try chance.spite(.P1, 3);
664
684
  try expectProbability(&chance.probability, 1, 4);
665
- try expectValue(3, chance.actions.p1.spite);
685
+ try expectValue(@as(u3, 3), chance.actions.p1.spite);
666
686
  }
667
687
 
668
688
  test "Chance.conversion2" {
@@ -689,7 +709,7 @@ test "Chance.psywave" {
689
709
 
690
710
  try chance.psywave(.P2, 100, 150);
691
711
  try expectProbability(&chance.probability, 1, 150);
692
- try expectValue(100, chance.actions.p2.psywave);
712
+ try expectValue(@as(u8, 100), chance.actions.p2.psywave);
693
713
  }
694
714
 
695
715
  test "Chance.metronome" {
@@ -705,19 +725,19 @@ test "Chance.moveSlot" {
705
725
 
706
726
  try chance.moveSlot(.P2, 2, 2);
707
727
  try expectProbability(&chance.probability, 1, 2);
708
- try expectValue(2, chance.actions.p2.move_slot);
728
+ try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
709
729
 
710
730
  chance.reset();
711
731
 
712
732
  try chance.moveSlot(.P1, 1, 3);
713
733
  try expectProbability(&chance.probability, 1, 3);
714
- try expectValue(1, chance.actions.p1.move_slot);
734
+ try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
715
735
 
716
736
  chance.reset();
717
737
 
718
738
  try chance.moveSlot(.P1, 4, 1);
719
739
  try expectProbability(&chance.probability, 1, 1);
720
- try expectValue(4, chance.actions.p1.move_slot);
740
+ try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
721
741
  }
722
742
 
723
743
  test "Chance.forceSwitch" {
@@ -725,19 +745,19 @@ test "Chance.forceSwitch" {
725
745
 
726
746
  try chance.forceSwitch(.P2, 2, 2);
727
747
  try expectProbability(&chance.probability, 1, 2);
728
- try expectValue(2, chance.actions.p2.force_switch);
748
+ try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
729
749
 
730
750
  chance.reset();
731
751
 
732
752
  try chance.forceSwitch(.P1, 1, 3);
733
753
  try expectProbability(&chance.probability, 1, 3);
734
- try expectValue(1, chance.actions.p1.force_switch);
754
+ try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
735
755
 
736
756
  chance.reset();
737
757
 
738
758
  try chance.forceSwitch(.P1, 4, 1);
739
759
  try expectProbability(&chance.probability, 1, 1);
740
- try expectValue(4, chance.actions.p1.force_switch);
760
+ try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
741
761
  }
742
762
 
743
763
  test "Chance.multiHit" {
@@ -745,20 +765,20 @@ test "Chance.multiHit" {
745
765
 
746
766
  try chance.multiHit(.P1, 3);
747
767
  try expectProbability(&chance.probability, 3, 8);
748
- try expectValue(3, chance.actions.p1.multi_hit);
768
+ try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
749
769
 
750
770
  chance.reset();
751
771
 
752
772
  try chance.multiHit(.P2, 5);
753
773
  try expectProbability(&chance.probability, 1, 8);
754
- try expectValue(5, chance.actions.p2.multi_hit);
774
+ try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
755
775
  }
756
776
 
757
777
  test "Chance.duration" {
758
778
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
759
779
 
760
780
  chance.duration(.P1, 2);
761
- try expectValue(2, chance.actions.p1.duration);
781
+ try expectValue(@as(u3, 2), chance.actions.p1.duration);
762
782
  }
763
783
 
764
784
  pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
@@ -800,12 +820,12 @@ const Null = struct {
800
820
  _ = .{ self, player, ok, accuracy };
801
821
  }
802
822
 
803
- pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
804
- _ = .{ self, player, crit, rate };
823
+ pub fn criticalHit(self: Null, player: Player, i: u3, crit: bool, rate: u8) Error!void {
824
+ _ = .{ self, player, i, crit, rate };
805
825
  }
806
826
 
807
- pub fn damage(self: Null, player: Player, roll: u8) Error!void {
808
- _ = .{ self, player, roll };
827
+ pub fn damage(self: Null, player: Player, i: u3, roll: u8) Error!void {
828
+ _ = .{ self, player, i, roll };
809
829
  }
810
830
 
811
831
  pub fn confused(self: Null, player: Player, ok: bool) Error!void {
@@ -876,7 +896,7 @@ const Null = struct {
876
896
  _ = .{ self, player, move, n };
877
897
  }
878
898
 
879
- pub fn duration(self: Null, player: Player, turns: u4) void {
899
+ pub fn duration(self: Null, player: Player, turns: u3) void {
880
900
  _ = .{ self, player, turns };
881
901
  }
882
902
  };
@@ -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 data = @import("../../gen2/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
-
9
7
  const Type = data.Type;
10
8
 
11
9
  /// Representation of a held item in Generation II Pokémon.
@@ -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 gen2 = @import("../../gen2/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 = gen2.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 gen2 = @import("../../gen2/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
-
9
7
  const Stats = gen2.Stats;
10
8
  const Types = gen2.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,24 +1,20 @@
1
- const std = @import("std");
2
- const builtin = @import("builtin");
3
-
4
- const pkmn = @import("../pkmn.zig");
5
-
6
- const data = @import("../common/data.zig");
7
1
  const DEBUG = @import("../common/debug.zig").print;
8
- const protocol = @import("../common/protocol.zig");
9
- const rng = @import("../common/rng.zig");
10
- const util = @import("../common/util.zig");
11
2
 
3
+ const builtin = @import("builtin");
4
+ const calc = @import("calc.zig");
5
+ const chance = @import("chance.zig");
6
+ const data = @import("../common/data.zig");
7
+ const gen1 = @import("../gen1/data.zig");
12
8
  const items = @import("data/items.zig");
9
+ const mechanics = @import("mechanics.zig");
13
10
  const moves = @import("data/moves.zig");
11
+ const pkmn = @import("../pkmn.zig");
12
+ const protocol = @import("../common/protocol.zig");
13
+ const rng = @import("../common/rng.zig");
14
14
  const species = @import("data/species.zig");
15
+ const std = @import("std");
15
16
  const types = @import("data/types.zig");
16
-
17
- const gen1 = @import("../gen1/data.zig");
18
-
19
- const calc = @import("calc.zig");
20
- const chance = @import("chance.zig");
21
- const mechanics = @import("mechanics.zig");
17
+ const util = @import("../common/util.zig");
22
18
 
23
19
  const assert = std.debug.assert;
24
20
  const expectEqual = std.testing.expectEqual;
@@ -45,6 +41,7 @@ const Player = data.Player;
45
41
  const Result = data.Result;
46
42
 
47
43
  const PointerType = util.PointerType;
44
+ const isPointerTo = util.isPointerTo;
48
45
 
49
46
  const showdown = pkmn.options.showdown;
50
47
 
@@ -63,12 +60,12 @@ pub fn Battle(comptime RNG: anytype) type {
63
60
  _: [padding]u8 = .{0} ** padding,
64
61
 
65
62
  pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
66
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
63
+ assert(isPointerTo(self, Self));
67
64
  return &self.sides[@intFromEnum(player)];
68
65
  }
69
66
 
70
67
  pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
71
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
68
+ assert(isPointerTo(self, Self));
72
69
  return &self.sides[@intFromEnum(player.foe())];
73
70
  }
74
71
 
@@ -134,7 +131,7 @@ pub const Side = extern struct {
134
131
  }
135
132
 
136
133
  pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
137
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
134
+ assert(isPointerTo(self, Side));
138
135
  assert(slot > 0 and slot <= 6);
139
136
  const id = self.pokemon[slot - 1].position;
140
137
  assert(id > 0 and id <= 6);
@@ -142,7 +139,7 @@ pub const Side = extern struct {
142
139
  }
143
140
 
144
141
  pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
145
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
142
+ assert(isPointerTo(self, Side));
146
143
  return self.get(1);
147
144
  }
148
145
 
@@ -176,7 +173,7 @@ pub const ActivePokemon = extern struct {
176
173
  }
177
174
 
178
175
  pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
179
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
176
+ assert(isPointerTo(self, Pokemon));
180
177
  assert(mslot > 0 and mslot <= 4);
181
178
  assert(self.moves[mslot - 1].id != .None);
182
179
  return &self.moves[mslot - 1];
@@ -201,7 +198,7 @@ pub const Pokemon = extern struct {
201
198
  }
202
199
 
203
200
  pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
204
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
201
+ assert(isPointerTo(self, Pokemon));
205
202
  assert(mslot > 0 and mslot <= 4);
206
203
  assert(self.moves[mslot - 1].id != .None);
207
204
  return &self.moves[mslot - 1];
@@ -248,12 +245,12 @@ test DVs {
248
245
  var dvs = DVs.from(.Mewtwo, .{ .def = 13 });
249
246
  try expectEqual(Gender.Unknown, dvs.gender);
250
247
  try expectEqual(Type.Ice, dvs.type);
251
- try expectEqual(70, dvs.power());
248
+ try expectEqual(@as(u8, 70), dvs.power());
252
249
 
253
250
  dvs = DVs.from(.Pikachu, .{ .spc = 14 });
254
251
  try expectEqual(Gender.Male, dvs.gender);
255
252
  try expectEqual(Type.Dark, dvs.type);
256
- try expectEqual(69, dvs.power());
253
+ try expectEqual(@as(u8, 69), dvs.power());
257
254
 
258
255
  dvs = DVs.from(.Cyndaquil, .{ .atk = 1, .def = 3, .spe = 10, .spc = 9 });
259
256
  try expectEqual(Gender.Female, dvs.gender);
@@ -380,9 +377,9 @@ test Stats {
380
377
  try expectEqual(0, stats.def);
381
378
 
382
379
  var base = Species.get(.Gyarados).stats;
383
- try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
380
+ try expectEqual(@as(u16, 127), Stats(u16).calc("hp", base.hp, 0, 5120, 38));
384
381
  base = Species.get(.Pidgeot).stats;
385
- try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
382
+ try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
386
383
  }
387
384
 
388
385
  pub const Boosts = packed struct(u32) {
@@ -428,8 +425,8 @@ test Move {
428
425
  try expectEqual(Move.Effect.ConfusionChance, move.effect);
429
426
  try expectEqual(rng.Gen12.percent(50), move.accuracy);
430
427
  try expectEqual(rng.Gen12.percent(100), move.chance);
431
- try expectEqual(5, Move.pp(.DynamicPunch));
432
- try expectEqual(-1, Move.get(.Counter).priority);
428
+ try expectEqual(@as(u8, 5), Move.pp(.DynamicPunch));
429
+ try expectEqual(@as(i8, -1), Move.get(.Counter).priority);
433
430
  try expect(!move.effect.isHighCritical());
434
431
  try expect(Move.get(.KarateChop).effect.isHighCritical());
435
432
  try expect(Move.get(.RazorWind).effect.isHighCritical());
@@ -439,7 +436,7 @@ pub const Species = species.Species;
439
436
 
440
437
  test Species {
441
438
  try expectEqual(152, @intFromEnum(Species.Chikorita));
442
- try expectEqual(100, Species.get(.Celebi).stats.spd);
439
+ try expectEqual(@as(u8, 100), Species.get(.Celebi).stats.spd);
443
440
  }
444
441
 
445
442
  pub const Type = types.Type;
@@ -452,7 +449,7 @@ test Types {
452
449
  try expect(!Type.Steel.special());
453
450
  try expect(Type.Dark.special());
454
451
 
455
- try expectEqual(3, Type.Water.precedence());
452
+ try expectEqual(@as(u8, 3), Type.Water.precedence());
456
453
  try expect(Type.Bug.precedence() > Type.Poison.precedence());
457
454
 
458
455
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
@@ -1,37 +1,32 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const common = @import("../common/data.zig");
6
-
7
4
  const data = @import("data.zig");
8
5
  const mechanics = @import("mechanics.zig");
6
+ const std = @import("std");
9
7
 
10
- const Player = common.Player;
11
- const Result = common.Result;
12
-
13
- const Effectiveness = data.Effectiveness;
14
- const Move = data.Move;
15
-
16
- const Effects = mechanics.Effects;
17
- const State = mechanics.State;
18
-
19
- const canMove = mechanics.canMove;
8
+ const adjustDamage = mechanics.adjustDamage;
9
+ const afterMove = mechanics.afterMove;
10
+ const applyDamage = mechanics.applyDamage;
11
+ const buildRage = mechanics.buildRage;
12
+ const calcDamage = mechanics.calcDamage;
20
13
  const canCharge = mechanics.canCharge;
14
+ const canMove = mechanics.canMove;
15
+ const checkCriticalHit = mechanics.checkCriticalHit;
16
+ const checkHit = mechanics.checkHit;
21
17
  const decrementPP = mechanics.decrementPP;
18
+ const destinyBond = mechanics.destinyBond;
22
19
  const doMove = mechanics.doMove;
23
- const checkHit = mechanics.checkHit;
24
- const checkCriticalHit = mechanics.checkCriticalHit;
25
- const calcDamage = mechanics.calcDamage;
26
- const adjustDamage = mechanics.adjustDamage;
27
- const randomizeDamage = mechanics.randomizeDamage;
28
- const applyDamage = mechanics.applyDamage;
29
- const reportOutcome = mechanics.reportOutcome;
30
20
  const effectChance = mechanics.effectChance;
31
- const afterMove = mechanics.afterMove;
32
- const buildRage = mechanics.buildRage;
21
+ const Effectiveness = data.Effectiveness;
22
+ const Effects = mechanics.Effects;
33
23
  const kingsRock = mechanics.kingsRock;
34
- const destinyBond = mechanics.destinyBond;
24
+ const Move = data.Move;
25
+ const Player = common.Player;
26
+ const randomizeDamage = mechanics.randomizeDamage;
27
+ const reportOutcome = mechanics.reportOutcome;
28
+ const Result = common.Result;
29
+ const State = mechanics.State;
35
30
 
36
31
  const SECONDARY = true;
37
32
  const KINGS = true;