@pkmn/engine 0.1.0-dev.b01cb48c → 0.1.0-dev.b14f2221

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 (81) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +21 -11
  3. package/build/pkg/addon/browser.d.ts +3 -0
  4. package/build/pkg/addon/browser.js +47 -0
  5. package/build/pkg/addon/browser.js.map +1 -0
  6. package/build/pkg/addon/node.d.ts +3 -0
  7. package/build/pkg/addon/node.js +110 -0
  8. package/build/pkg/addon/node.js.map +1 -0
  9. package/build/pkg/addon/wasm.d.ts +2 -0
  10. package/build/pkg/addon/wasm.js +53 -0
  11. package/build/pkg/addon/wasm.js.map +1 -0
  12. package/build/pkg/addon.d.ts +26 -4
  13. package/build/pkg/addon.js +34 -65
  14. package/build/pkg/addon.js.map +1 -1
  15. package/build/pkg/data/layout.json +15 -2
  16. package/build/pkg/data/protocol.json +23 -9
  17. package/build/pkg/data.d.ts +23 -1
  18. package/build/pkg/data.js.map +1 -1
  19. package/build/pkg/gen1.d.ts +15 -18
  20. package/build/pkg/gen1.js +28 -19
  21. package/build/pkg/gen1.js.map +1 -1
  22. package/build/pkg/index.d.ts +40 -90
  23. package/build/pkg/index.js +23 -70
  24. package/build/pkg/index.js.map +1 -1
  25. package/build/pkg/protocol.d.ts +20 -1
  26. package/build/pkg/protocol.js +105 -103
  27. package/build/pkg/protocol.js.map +1 -1
  28. package/build/tools/debug.js +68 -74
  29. package/build/tools/debug.js.map +1 -1
  30. package/build/tools/display/debug.jsx +152 -0
  31. package/build/tools/display/debug.jsx.map +1 -0
  32. package/build/tools/display/index.js +152 -0
  33. package/build/tools/display/index.js.map +1 -0
  34. package/build/tools/display/ui.jsx +359 -0
  35. package/build/tools/display/ui.jsx.map +1 -0
  36. package/build/tools/display/util.js +33 -0
  37. package/build/tools/display/util.js.map +1 -0
  38. package/build.zig +255 -102
  39. package/package.json +59 -138
  40. package/src/bin/install-pkmn-engine +25 -7
  41. package/src/bin/pkmn-debug +1 -1
  42. package/src/lib/bindings/c.zig +200 -0
  43. package/src/lib/bindings/node.zig +117 -0
  44. package/src/lib/bindings/wasm.zig +50 -0
  45. package/src/lib/common/array.zig +70 -0
  46. package/src/lib/common/data.zig +8 -8
  47. package/src/lib/common/debug.zig +30 -9
  48. package/src/lib/common/js.zig +3 -7
  49. package/src/lib/common/optional.zig +11 -17
  50. package/src/lib/common/options.zig +4 -0
  51. package/src/lib/common/protocol.zig +195 -159
  52. package/src/lib/common/rational.zig +303 -310
  53. package/src/lib/common/rng.zig +5 -7
  54. package/src/lib/common/util.zig +33 -1
  55. package/src/lib/gen1/calc.zig +324 -180
  56. package/src/lib/gen1/chance.zig +536 -140
  57. package/src/lib/gen1/data/moves.zig +2 -4
  58. package/src/lib/gen1/data/species.zig +1 -3
  59. package/src/lib/gen1/data/types.zig +3 -4
  60. package/src/lib/gen1/data.zig +40 -43
  61. package/src/lib/gen1/helpers.zig +17 -29
  62. package/src/lib/gen1/mechanics.zig +240 -187
  63. package/src/lib/gen2/calc.zig +35 -28
  64. package/src/lib/gen2/chance.zig +88 -74
  65. package/src/lib/gen2/data/items.zig +1 -3
  66. package/src/lib/gen2/data/moves.zig +2 -4
  67. package/src/lib/gen2/data/species.zig +1 -3
  68. package/src/lib/gen2/data/types.zig +7 -5
  69. package/src/lib/gen2/data.zig +33 -35
  70. package/src/lib/gen2/generated.zig +18 -23
  71. package/src/lib/gen2/helpers.zig +9 -20
  72. package/src/lib/gen2/mechanics.zig +98 -98
  73. package/src/lib/napi.h +2 -0
  74. package/src/lib/node.zig +4 -121
  75. package/src/lib/pkmn.zig +103 -22
  76. package/src/lib/wasm.zig +9 -9
  77. package/src/tools/display/dom.ts +93 -0
  78. package/src/tools/display/ui.css +354 -0
  79. package/build/test/display.js +0 -405
  80. package/build/test/display.js.map +0 -1
  81. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,23 +1,20 @@
1
- const std = @import("std");
2
-
3
- const pkmn = @import("../pkmn.zig");
4
-
1
+ const chance = @import("chance.zig");
5
2
  const common = @import("../common/data.zig");
3
+ const Optional = @import("../common/optional.zig").Optional;
4
+ const pkmn = @import("../pkmn.zig");
5
+ const std = @import("std");
6
6
  const util = @import("../common/util.zig");
7
7
 
8
- const chance = @import("chance.zig");
9
-
8
+ const Action = chance.Action;
9
+ const Actions = chance.Actions;
10
10
  const assert = std.debug.assert;
11
-
11
+ const Criticals = chance.Criticals;
12
+ const Damages = chance.Damages;
12
13
  const enabled = pkmn.options.calc;
13
-
14
+ const isPointerTo = util.isPointerTo;
14
15
  const Player = common.Player;
15
-
16
16
  const PointerType = util.PointerType;
17
17
 
18
- const Actions = chance.Actions;
19
- const Action = chance.Action;
20
-
21
18
  /// Information relevant to damage calculation that occured during a Generation II battle `update`.
22
19
  pub const Summaries = extern struct {
23
20
  /// Relevant information for Player 1.
@@ -31,7 +28,7 @@ pub const Summaries = extern struct {
31
28
 
32
29
  /// Returns the `Summary` for the given `player`.
33
30
  pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Summary) {
34
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Summaries);
31
+ assert(isPointerTo(self, Summaries));
35
32
  return if (player == .P1) &self.p1 else &self.p2;
36
33
  }
37
34
  };
@@ -65,33 +62,34 @@ pub const Summary = extern struct {
65
62
  }
66
63
  };
67
64
 
68
- /// TODO
69
- pub const Overrides = extern struct {
70
- /// TODO
71
- actions: Actions = .{},
72
- };
73
-
74
65
  /// Allows for forcing the value of specific RNG events during a Generation II battle `update` via
75
66
  /// `overrides` and tracks `summaries` of information relevant to damage calculation.
76
67
  pub const Calc = struct {
77
68
  /// Overrides the normal behavior of the RNG during an `update` to force specific outcomes.
78
- overrides: Overrides = .{},
69
+ overrides: Actions = .{},
79
70
  /// Information relevant to damage calculation.
80
71
  summaries: Summaries = .{},
81
72
 
82
73
  pub fn overridden(
83
74
  self: Calc,
84
75
  player: Player,
76
+ hit: u3,
85
77
  comptime field: Action.Field,
86
- ) ?std.meta.FieldType(Action, field) {
78
+ ) ReturnType(field) {
87
79
  if (!enabled) return null;
88
80
 
89
- const overrides =
90
- if (player == .P1) self.overrides.actions.p1 else self.overrides.actions.p2;
91
- const val = @field(overrides, @tagName(field));
81
+ const val = switch (field) {
82
+ .damages => Damages.get(self.overrides.get(player).damages, hit),
83
+ .critical_hits => Criticals.get(self.overrides.get(player).critical_hits, hit),
84
+ else => val: {
85
+ assert(hit == 0);
86
+ break :val @field(self.overrides.get(player), @tagName(field));
87
+ },
88
+ };
89
+
92
90
  return if (switch (@typeInfo(@TypeOf(val))) {
93
- .Enum => val != .None,
94
- .Int => val != 0,
91
+ .@"enum" => val != .None,
92
+ .int => val != 0,
95
93
  else => unreachable,
96
94
  }) val else null;
97
95
  }
@@ -123,9 +121,10 @@ const Null = struct {
123
121
  pub fn overridden(
124
122
  self: Null,
125
123
  player: Player,
124
+ hit: u3,
126
125
  comptime field: Action.Field,
127
- ) ?std.meta.FieldType(Action, field) {
128
- _ = .{ self, player };
126
+ ) ReturnType(field) {
127
+ _ = .{ self, player, hit };
129
128
  return null;
130
129
  }
131
130
 
@@ -141,3 +140,11 @@ const Null = struct {
141
140
  _ = .{ self, player };
142
141
  }
143
142
  };
143
+
144
+ fn ReturnType(comptime field: Action.Field) type {
145
+ return ?(switch (field) {
146
+ .damages => u8,
147
+ .critical_hits => Optional(bool),
148
+ else => @FieldType(Action, @tagName(field)),
149
+ });
150
+ }
@@ -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,7 +19,8 @@ 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;
@@ -37,8 +38,8 @@ pub const Actions = extern struct {
37
38
  p2: Action = .{},
38
39
 
39
40
  /// 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);
41
+ pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Action) {
42
+ assert(isPointerTo(self, Actions));
42
43
  return if (player == .P1) &self.p1 else &self.p2;
43
44
  }
44
45
 
@@ -52,15 +53,15 @@ pub const Actions = extern struct {
52
53
  /// same shape if they have the same fields set (though those fields need not necessarily be
53
54
  /// set to the same value).
54
55
  pub fn matches(a: Actions, b: Actions) bool {
55
- inline for (@typeInfo(Actions).Struct.fields) |player| {
56
- inline for (@typeInfo(Action).Struct.fields) |field| {
56
+ inline for (@typeInfo(Actions).@"struct".fields) |player| {
57
+ inline for (@typeInfo(Action).@"struct".fields) |field| {
57
58
  const a_val = @field(@field(a, player.name), field.name);
58
59
  const b_val = @field(@field(b, player.name), field.name);
59
60
 
60
61
  switch (@typeInfo(@TypeOf(a_val))) {
61
- .Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
62
+ .@"enum" => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
62
63
  return false,
63
- .Int => if ((a_val > 0) != (b_val > 0)) return false,
64
+ .int => if ((a_val > 0) != (b_val > 0)) return false,
64
65
  else => unreachable,
65
66
  }
66
67
  }
@@ -68,7 +69,7 @@ pub const Actions = extern struct {
68
69
  return true;
69
70
  }
70
71
 
71
- pub fn fmt(self: Actions, writer: anytype, shape: bool) !void {
72
+ pub fn fmt(self: Actions, writer: *std.Io.Writer, shape: bool) !void {
72
73
  try writer.writeAll("<P1 = ");
73
74
  try self.p1.fmt(writer, shape);
74
75
  try writer.writeAll(", P2 = ");
@@ -76,16 +77,14 @@ pub const Actions = extern struct {
76
77
  try writer.writeAll(">");
77
78
  }
78
79
 
79
- pub fn format(a: Actions, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
80
- _ = .{ f, o };
80
+ pub fn format(a: Actions, w: *std.Io.Writer) !void {
81
81
  try fmt(a, w, false);
82
82
  }
83
83
  };
84
84
 
85
- // TODO: ziglang/zig#19730
86
85
  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 } };
86
+ const a: Actions = .{ .p1 = .{ .hit = .true, .confused = .false, .damages = 245 } };
87
+ const b: Actions = .{ .p1 = .{ .hit = .false, .confused = .true, .damages = 246 } };
89
88
  const c: Actions = .{ .p1 = .{ .hit = .true } };
90
89
 
91
90
  try expect(a.eql(a));
@@ -101,11 +100,19 @@ test Actions {
101
100
  try expect(!c.matches(a));
102
101
  }
103
102
 
103
+ /// Observation made about a duration - whether the duration has started, been continued, or ended.
104
+ pub const Observation = enum { started, continuing, ended };
105
+
106
+ pub const Damages = Array(5, u8);
107
+ pub const Criticals = Array(5, Optional(bool));
108
+
104
109
  /// Information about the RNG that was observed during a Generation II battle `update` for a
105
110
  /// single player.
106
111
  pub const Action = packed struct(u128) {
107
- /// If not 0, the roll to be returned Rolls.damage.
108
- damage: u8 = 0,
112
+ /// TODO
113
+ damages: Damages.T = 0,
114
+ // TODO
115
+ critical_hits: Criticals.T = 0,
109
116
 
110
117
  /// If not None, the Player to be returned by Rolls.speedTie.
111
118
  speed_tie: Optional(Player) = .None,
@@ -113,50 +120,58 @@ pub const Action = packed struct(u128) {
113
120
  quick_claw: Optional(bool) = .None,
114
121
  /// If not None, the value to return for Rolls.hit.
115
122
  hit: Optional(bool) = .None,
116
- /// If not None, the value to be returned by Rolls.criticalHit.
117
- critical_hit: Optional(bool) = .None,
118
-
119
123
  /// If not None, the value to return for Rolls.confused.
120
124
  confused: Optional(bool) = .None,
125
+
121
126
  /// If not None, the value to return for Rolls.attract.
122
127
  attract: Optional(bool) = .None,
123
128
  /// If not None, the value to return for Rolls.paralyzed.
124
129
  paralyzed: Optional(bool) = .None,
125
130
  /// If not None, the value to return for Rolls.defrost.
126
131
  defrost: Optional(bool) = .None,
127
-
128
132
  /// If not None, the value to be returned for Rolls.secondaryChance.
129
133
  secondary_chance: Optional(bool) = .None,
134
+
130
135
  /// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
131
136
  item: Optional(bool) = .None,
132
137
  /// If not None, the value to be returned for Rolls.protect.
133
138
  protect: Optional(bool) = .None,
134
139
  /// If not None, the value to return for Rolls.triAttack.
135
140
  tri_attack: Optional(TriAttack) = .None,
141
+ /// If not 0, the value to return for Rolls.tripleKick.
142
+ triple_kick: u2 = 0,
136
143
 
137
144
  /// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
138
145
  present: u3 = 0,
139
146
  /// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
140
147
  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.
148
+ /// If not 0, the amount of PP to deduct for Rolls.spite.
145
149
  spite: u3 = 0,
146
- /// If not None, the value to return for Rolls.conversion2.
147
- conversion_2: Optional(Type) = .None,
148
-
149
150
  /// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
150
151
  /// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
151
- move_slot: u4 = 0,
152
+ move_slot: u3 = 0,
152
153
  /// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
153
154
  /// invalid values (eg. due to empty party slots or fainted members) will be ignored.
154
- force_switch: u4 = 0,
155
-
155
+ force_switch: u3 = 0,
156
156
  /// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
157
- multi_hit: u4 = 0,
157
+ multi_hit: u3 = 0,
158
+
159
+ sleep: Optional(Observation) = .None,
160
+ /// TODO
161
+ confusion: Optional(Observation) = .None,
162
+ /// TODO
163
+ disable: Optional(Observation) = .None,
164
+ /// TODO
165
+ attacking: Optional(Observation) = .None,
166
+ /// TODO
167
+ binding: Optional(Observation) = .None,
168
+ /// TODO
169
+ encore: Optional(Observation) = .None,
170
+
158
171
  /// If not 0, the value to by one of the Rolls.*Duration rolls.
159
- duration: u4 = 0,
172
+ duration: u3 = 0,
173
+ /// If not None, the value to return for Rolls.conversion2.
174
+ conversion_2: Optional(Type) = .None,
160
175
 
161
176
  /// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
162
177
  psywave: u8 = 0,
@@ -164,22 +179,19 @@ pub const Action = packed struct(u128) {
164
179
  /// If not None, the Move to return for Rolls.metronome.
165
180
  metronome: Move = .None,
166
181
 
167
- _: u48 = 0, // TODO
168
-
169
182
  pub const Field = std.meta.FieldEnum(Action);
170
183
 
171
- pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
172
- _ = .{ f, o };
184
+ pub fn format(a: Action, w: *std.Io.Writer) !void {
173
185
  try fmt(a, w, false);
174
186
  }
175
187
 
176
- pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
188
+ pub fn fmt(self: Action, writer: *std.Io.Writer, shape: bool) !void {
177
189
  try writer.writeByte('(');
178
190
  var printed = false;
179
- inline for (@typeInfo(Action).Struct.fields) |field| {
191
+ inline for (@typeInfo(Action).@"struct".fields) |field| {
180
192
  const val = @field(self, field.name);
181
193
  switch (@typeInfo(@TypeOf(val))) {
182
- .Enum => if (val != .None) {
194
+ .@"enum" => if (val != .None) {
183
195
  if (printed) try writer.writeAll(", ");
184
196
  if (shape) {
185
197
  try writer.print("{s}:?", .{field.name});
@@ -193,7 +205,7 @@ pub const Action = packed struct(u128) {
193
205
  }
194
206
  printed = true;
195
207
  },
196
- .Int => if (val != 0) {
208
+ .int => if (val != 0) {
197
209
  if (printed) try writer.writeAll(", ");
198
210
  if (shape) {
199
211
  try writer.print("{s}:?", .{field.name});
@@ -255,19 +267,21 @@ pub fn Chance(comptime Rational: type) type {
255
267
  self.actions.get(player).hit = if (ok) .true else .false;
256
268
  }
257
269
 
258
- pub fn criticalHit(self: *Self, player: Player, crit: bool, rate: u8) Error!void {
270
+ pub fn criticalHit(self: *Self, player: Player, i: u3, crit: bool, rate: u8) Error!void {
259
271
  if (!enabled) return;
260
272
 
261
273
  const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
262
274
  try self.probability.update(n, 256);
263
- self.actions.get(player).critical_hit = if (crit) .true else .false;
275
+ var a = self.actions.get(player);
276
+ a.critical_hits = Criticals.set(a.critical_hits, i, if (crit) .true else .false);
264
277
  }
265
278
 
266
- pub fn damage(self: *Self, player: Player, roll: u8) Error!void {
279
+ pub fn damage(self: *Self, player: Player, i: u3, roll: u8) Error!void {
267
280
  if (!enabled) return;
268
281
 
269
282
  try self.probability.update(1, 39);
270
- self.actions.get(player).damage = roll;
283
+ var a = self.actions.get(player);
284
+ a.damages = Damages.set(a.damages, i, roll);
271
285
  }
272
286
 
273
287
  pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
@@ -419,10 +433,10 @@ pub fn Chance(comptime Rational: type) type {
419
433
  self.actions.get(player).multi_hit = n;
420
434
  }
421
435
 
422
- pub fn duration(self: *Self, player: Player, turns: u4) void {
436
+ pub fn duration(self: *Self, player: Player, turns: u3) void {
423
437
  if (!enabled) return;
424
438
 
425
- self.actions.get(player).duration = if (options.key) 1 else turns;
439
+ self.actions.get(player).duration = if (options.key) 2 else turns;
426
440
  }
427
441
  };
428
442
  }
@@ -474,22 +488,22 @@ test "Chance.hit" {
474
488
  test "Chance.criticalHit" {
475
489
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
476
490
 
477
- try chance.criticalHit(.P1, true, 17);
478
- try expectValue(Optional(bool).true, chance.actions.p1.critical_hit);
491
+ try chance.criticalHit(.P1, 0, true, 17);
492
+ try expectValue(Optional(bool).true, Criticals.get(chance.actions.p1.critical_hits, 0));
479
493
  try expectProbability(&chance.probability, 17, 256);
480
494
 
481
495
  chance.reset();
482
496
 
483
- try chance.criticalHit(.P2, false, 5);
497
+ try chance.criticalHit(.P2, 1, false, 5);
484
498
  try expectProbability(&chance.probability, 251, 256);
485
- try expectValue(Optional(bool).false, chance.actions.p2.critical_hit);
499
+ try expectValue(Optional(bool).false, Criticals.get(chance.actions.p2.critical_hits, 1));
486
500
  }
487
501
 
488
502
  test "Chance.damage" {
489
503
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
490
504
 
491
- try chance.damage(.P1, 217);
492
- try expectValue(217, chance.actions.p1.damage);
505
+ try chance.damage(.P1, 0, 219);
506
+ try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
493
507
  try expectProbability(&chance.probability, 1, 39);
494
508
  }
495
509
 
@@ -614,7 +628,7 @@ test "Chance.present" {
614
628
  } else {
615
629
  try expectProbability(&chance.probability, 25, 256);
616
630
  }
617
- try expectValue(4, chance.actions.p2.present);
631
+ try expectValue(@as(u3, 4), chance.actions.p2.present);
618
632
 
619
633
  chance.reset();
620
634
 
@@ -624,7 +638,7 @@ test "Chance.present" {
624
638
  } else {
625
639
  try expectProbability(&chance.probability, 51, 256);
626
640
  }
627
- try expectValue(1, chance.actions.p1.present);
641
+ try expectValue(@as(u3, 1), chance.actions.p1.present);
628
642
  }
629
643
 
630
644
  test "Chance.magnitude" {
@@ -636,7 +650,7 @@ test "Chance.magnitude" {
636
650
  } else {
637
651
  try expectProbability(&chance.probability, 13, 256);
638
652
  }
639
- try expectValue(7, chance.actions.p2.magnitude);
653
+ try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
640
654
 
641
655
  chance.reset();
642
656
 
@@ -646,7 +660,7 @@ test "Chance.magnitude" {
646
660
  } else {
647
661
  try expectProbability(&chance.probability, 51, 256);
648
662
  }
649
- try expectValue(5, chance.actions.p1.magnitude);
663
+ try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
650
664
  }
651
665
 
652
666
  test "Chance.tripleKick" {
@@ -654,7 +668,7 @@ test "Chance.tripleKick" {
654
668
 
655
669
  try chance.tripleKick(.P1, 2);
656
670
  try expectProbability(&chance.probability, 1, 3);
657
- try expectValue(2, chance.actions.p1.triple_kick);
671
+ try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
658
672
  }
659
673
 
660
674
  test "Chance.spite" {
@@ -662,7 +676,7 @@ test "Chance.spite" {
662
676
 
663
677
  try chance.spite(.P1, 3);
664
678
  try expectProbability(&chance.probability, 1, 4);
665
- try expectValue(3, chance.actions.p1.spite);
679
+ try expectValue(@as(u3, 3), chance.actions.p1.spite);
666
680
  }
667
681
 
668
682
  test "Chance.conversion2" {
@@ -689,7 +703,7 @@ test "Chance.psywave" {
689
703
 
690
704
  try chance.psywave(.P2, 100, 150);
691
705
  try expectProbability(&chance.probability, 1, 150);
692
- try expectValue(100, chance.actions.p2.psywave);
706
+ try expectValue(@as(u8, 100), chance.actions.p2.psywave);
693
707
  }
694
708
 
695
709
  test "Chance.metronome" {
@@ -705,19 +719,19 @@ test "Chance.moveSlot" {
705
719
 
706
720
  try chance.moveSlot(.P2, 2, 2);
707
721
  try expectProbability(&chance.probability, 1, 2);
708
- try expectValue(2, chance.actions.p2.move_slot);
722
+ try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
709
723
 
710
724
  chance.reset();
711
725
 
712
726
  try chance.moveSlot(.P1, 1, 3);
713
727
  try expectProbability(&chance.probability, 1, 3);
714
- try expectValue(1, chance.actions.p1.move_slot);
728
+ try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
715
729
 
716
730
  chance.reset();
717
731
 
718
732
  try chance.moveSlot(.P1, 4, 1);
719
733
  try expectProbability(&chance.probability, 1, 1);
720
- try expectValue(4, chance.actions.p1.move_slot);
734
+ try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
721
735
  }
722
736
 
723
737
  test "Chance.forceSwitch" {
@@ -725,19 +739,19 @@ test "Chance.forceSwitch" {
725
739
 
726
740
  try chance.forceSwitch(.P2, 2, 2);
727
741
  try expectProbability(&chance.probability, 1, 2);
728
- try expectValue(2, chance.actions.p2.force_switch);
742
+ try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
729
743
 
730
744
  chance.reset();
731
745
 
732
746
  try chance.forceSwitch(.P1, 1, 3);
733
747
  try expectProbability(&chance.probability, 1, 3);
734
- try expectValue(1, chance.actions.p1.force_switch);
748
+ try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
735
749
 
736
750
  chance.reset();
737
751
 
738
752
  try chance.forceSwitch(.P1, 4, 1);
739
753
  try expectProbability(&chance.probability, 1, 1);
740
- try expectValue(4, chance.actions.p1.force_switch);
754
+ try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
741
755
  }
742
756
 
743
757
  test "Chance.multiHit" {
@@ -745,20 +759,20 @@ test "Chance.multiHit" {
745
759
 
746
760
  try chance.multiHit(.P1, 3);
747
761
  try expectProbability(&chance.probability, 3, 8);
748
- try expectValue(3, chance.actions.p1.multi_hit);
762
+ try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
749
763
 
750
764
  chance.reset();
751
765
 
752
766
  try chance.multiHit(.P2, 5);
753
767
  try expectProbability(&chance.probability, 1, 8);
754
- try expectValue(5, chance.actions.p2.multi_hit);
768
+ try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
755
769
  }
756
770
 
757
771
  test "Chance.duration" {
758
772
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
759
773
 
760
774
  chance.duration(.P1, 2);
761
- try expectValue(2, chance.actions.p1.duration);
775
+ try expectValue(@as(u3, 2), chance.actions.p1.duration);
762
776
  }
763
777
 
764
778
  pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
@@ -766,7 +780,7 @@ pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
766
780
 
767
781
  r.reduce();
768
782
  if (r.p != p or r.q != q) {
769
- print("expected {d}/{d}, found {}\n", .{ p, q, r });
783
+ print("expected {d}/{d}, found {f}\n", .{ p, q, r });
770
784
  return error.TestExpectedEqual;
771
785
  }
772
786
  }
@@ -800,12 +814,12 @@ const Null = struct {
800
814
  _ = .{ self, player, ok, accuracy };
801
815
  }
802
816
 
803
- pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
804
- _ = .{ self, player, crit, rate };
817
+ pub fn criticalHit(self: Null, player: Player, i: u3, crit: bool, rate: u8) Error!void {
818
+ _ = .{ self, player, i, crit, rate };
805
819
  }
806
820
 
807
- pub fn damage(self: Null, player: Player, roll: u8) Error!void {
808
- _ = .{ self, player, roll };
821
+ pub fn damage(self: Null, player: Player, i: u3, roll: u8) Error!void {
822
+ _ = .{ self, player, i, roll };
809
823
  }
810
824
 
811
825
  pub fn confused(self: Null, player: Player, ok: bool) Error!void {
@@ -876,7 +890,7 @@ const Null = struct {
876
890
  _ = .{ self, player, move, n };
877
891
  }
878
892
 
879
- pub fn duration(self: Null, player: Player, turns: u4) void {
893
+ pub fn duration(self: Null, player: Player, turns: u3) void {
880
894
  _ = .{ self, player, turns };
881
895
  }
882
896
  };
@@ -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;
@@ -173,9 +172,12 @@ pub const Type = enum(u8) {
173
172
  return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
174
173
  }
175
174
 
176
- /// The precedence order of Type `type`.
177
- pub fn precedence(self: Type) u8 {
178
- return PRECEDENCE[@intFromEnum(self)];
175
+ /// The precedence order of Type `t1` vs. Type `t2`.
176
+ pub fn precedence(t1: Type, t2: Type) u8 {
177
+ // The Ice vs. Fire matchup is out of order - return a higher
178
+ // number than anything else so that it sorts last correctly
179
+ if (t1 == .Ice and t2 == .Fire) return 18;
180
+ return PRECEDENCE[@intFromEnum(t2)];
179
181
  }
180
182
 
181
183
  /// The internal index of this Type used by Present.