@pkmn/engine 0.1.0-dev.7963b917 → 0.1.0-dev.79957401

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 (85) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +70 -28
  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 +39 -71
  14. package/build/pkg/addon.js.map +1 -1
  15. package/build/pkg/data/ids.json +12 -12
  16. package/build/pkg/data/layout.json +17 -4
  17. package/build/pkg/data/protocol.json +84 -13
  18. package/build/pkg/data.d.ts +27 -5
  19. package/build/pkg/data.js.map +1 -1
  20. package/build/pkg/gen1.d.ts +15 -18
  21. package/build/pkg/gen1.js +30 -21
  22. package/build/pkg/gen1.js.map +1 -1
  23. package/build/pkg/index.d.ts +42 -91
  24. package/build/pkg/index.js +23 -70
  25. package/build/pkg/index.js.map +1 -1
  26. package/build/pkg/protocol.d.ts +29 -1
  27. package/build/pkg/protocol.js +123 -102
  28. package/build/pkg/protocol.js.map +1 -1
  29. package/build/tools/debug.js +84 -73
  30. package/build/tools/debug.js.map +1 -1
  31. package/build/tools/display/debug.jsx +66 -0
  32. package/build/tools/display/debug.jsx.map +1 -0
  33. package/build/tools/display/index.js +152 -0
  34. package/build/tools/display/index.js.map +1 -0
  35. package/build/tools/display/ui.jsx +360 -0
  36. package/build/tools/display/ui.jsx.map +1 -0
  37. package/build/tools/display/util.js +157 -0
  38. package/build/tools/display/util.js.map +1 -0
  39. package/build.zig +397 -149
  40. package/package.json +62 -123
  41. package/src/bin/install-pkmn-engine +43 -22
  42. package/src/bin/pkmn-debug +1 -1
  43. package/src/lib/bindings/c.zig +201 -0
  44. package/src/lib/{binding → bindings}/node.zig +15 -32
  45. package/src/lib/bindings/wasm.zig +51 -0
  46. package/src/lib/common/array.zig +70 -0
  47. package/src/lib/common/data.zig +12 -24
  48. package/src/lib/common/debug.zig +46 -30
  49. package/src/lib/common/js.zig +3 -7
  50. package/src/lib/common/optional.zig +30 -24
  51. package/src/lib/common/options.zig +6 -0
  52. package/src/lib/common/protocol.zig +961 -450
  53. package/src/lib/common/rational.zig +341 -254
  54. package/src/lib/common/rng.zig +26 -19
  55. package/src/lib/common/util.zig +53 -1
  56. package/src/lib/gen1/calc.zig +726 -178
  57. package/src/lib/gen1/chance.zig +526 -324
  58. package/src/lib/gen1/data/moves.zig +193 -183
  59. package/src/lib/gen1/data/species.zig +4 -6
  60. package/src/lib/gen1/data/types.zig +9 -10
  61. package/src/lib/gen1/data.zig +78 -90
  62. package/src/lib/gen1/helpers.zig +114 -422
  63. package/src/lib/gen1/mechanics.zig +699 -615
  64. package/src/lib/gen2/calc.zig +150 -0
  65. package/src/lib/gen2/chance.zig +914 -0
  66. package/src/lib/gen2/data/items.zig +13 -21
  67. package/src/lib/gen2/data/moves.zig +664 -572
  68. package/src/lib/gen2/data/species.zig +2 -4
  69. package/src/lib/gen2/data/types.zig +139 -34
  70. package/src/lib/gen2/data.zig +131 -103
  71. package/src/lib/gen2/generated.zig +801 -0
  72. package/src/lib/gen2/helpers.zig +76 -51
  73. package/src/lib/gen2/mechanics.zig +3569 -29
  74. package/src/lib/napi.h +2 -0
  75. package/src/lib/node.zig +14 -0
  76. package/src/lib/pkmn.zig +125 -29
  77. package/src/lib/wasm.zig +13 -0
  78. package/src/tools/display/dom.ts +108 -0
  79. package/src/tools/display/ui.css +354 -0
  80. package/build/test/display.js +0 -400
  81. package/build/test/display.js.map +0 -1
  82. package/src/lib/binding/wasm.zig +0 -12
  83. package/src/lib/gen1/README.md +0 -812
  84. package/src/lib/gen2/README.md +0 -308
  85. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,21 +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 rng = @import("../common/rng.zig");
9
- const util = @import("../common/util.zig");
10
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");
11
8
  const items = @import("data/items.zig");
9
+ const mechanics = @import("mechanics.zig");
12
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");
13
14
  const species = @import("data/species.zig");
15
+ const std = @import("std");
14
16
  const types = @import("data/types.zig");
15
-
16
- const gen1 = @import("../gen1/data.zig");
17
-
18
- const mechanics = @import("mechanics.zig");
17
+ const util = @import("../common/util.zig");
19
18
 
20
19
  const assert = std.debug.assert;
21
20
  const expectEqual = std.testing.expectEqual;
@@ -24,27 +23,35 @@ const expect = std.testing.expect;
24
23
  pub const MAX_CHOICES: usize = 9; // move 1..4, switch 2..6
25
24
  pub const MAX_LOGS: usize = 180; // TODO
26
25
 
27
- pub const CHOICES_SIZE = if (builtin.mode == .ReleaseSmall)
26
+ const ReleaseSmall: std.builtin.OptimizeMode =
27
+ if (@hasDecl(std.builtin.OptimizeMode, "ReleaseSmall")) .small else .ReleaseSmall;
28
+
29
+ pub const CHOICES_SIZE = if (builtin.mode == ReleaseSmall)
28
30
  MAX_CHOICES
29
31
  else
30
32
  std.math.ceilPowerOfTwo(usize, MAX_CHOICES) catch unreachable;
31
- pub const LOGS_SIZE = if (builtin.mode == .ReleaseSmall)
33
+ pub const LOGS_SIZE = if (builtin.mode == ReleaseSmall)
32
34
  MAX_LOGS
33
35
  else
34
36
  std.math.ceilPowerOfTwo(usize, MAX_LOGS) catch unreachable;
35
37
 
38
+ /// Null object pattern implementation of pkmn.battle.Options for Generation II.
39
+ pub const NULL = pkmn.battle.options(protocol.NULL, chance.NULL, calc.NULL);
40
+
36
41
  const Choice = data.Choice;
37
42
  const ID = data.ID;
38
43
  const Player = data.Player;
39
44
  const Result = data.Result;
40
45
 
41
46
  const PointerType = util.PointerType;
47
+ const isPointerTo = util.isPointerTo;
42
48
 
43
49
  const showdown = pkmn.options.showdown;
44
50
 
45
51
  pub const PRNG = rng.PRNG(2);
46
52
 
47
53
  pub fn Battle(comptime RNG: anytype) type {
54
+ const padding = if (!showdown) 3 else 5;
48
55
  return extern struct {
49
56
  const Self = @This();
50
57
 
@@ -53,17 +60,19 @@ pub fn Battle(comptime RNG: anytype) type {
53
60
  turn: u16 = 0,
54
61
  field: Field = .{},
55
62
 
56
- pub inline fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
57
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
63
+ _: [padding]u8 = @splat(0),
64
+
65
+ pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
66
+ assert(isPointerTo(self, Self));
58
67
  return &self.sides[@intFromEnum(player)];
59
68
  }
60
69
 
61
- pub inline fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
62
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
70
+ pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
71
+ assert(isPointerTo(self, Self));
63
72
  return &self.sides[@intFromEnum(player.foe())];
64
73
  }
65
74
 
66
- pub inline fn active(self: *const Self, player: Player) ID {
75
+ pub fn active(self: *const Self, player: Player) ID {
67
76
  return player.ident(@intCast(self.side(player).pokemon[0].position));
68
77
  }
69
78
 
@@ -77,35 +86,32 @@ pub fn Battle(comptime RNG: anytype) type {
77
86
  };
78
87
  }
79
88
 
80
- // TODO
81
89
  test Battle {
82
- try expectEqual(496, @sizeOf(Battle(PRNG)));
90
+ try expectEqual(512, @sizeOf(Battle(PRNG)));
83
91
  }
84
92
 
85
- const Field = packed struct {
93
+ pub const Field = packed struct(u8) {
86
94
  weather: Weather = .None,
87
95
  weather_duration: u4 = 0,
88
-
89
- comptime {
90
- assert(@sizeOf(Field) == 1);
91
- }
92
96
  };
93
97
 
94
- const Weather = enum(u4) {
98
+ pub const Weather = enum(u4) {
95
99
  None,
96
100
  Rain,
97
101
  Sun,
98
102
  Sandstorm,
99
103
  };
100
104
 
101
- const Side = extern struct {
102
- pokemon: [6]Pokemon = [_]Pokemon{.{}} ** 6,
103
- active: ActivePokemon = .{},
104
- conditions: Conditions,
105
+ pub const Side = extern struct {
106
+ pokemon: [6]Pokemon = @splat(.{}),
107
+ active: ActivePokemon align(8) = .{},
108
+ conditions: Conditions = .{},
109
+ // NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
105
110
  last_used_move: Move = .None,
106
- _: u8 = 0,
107
111
 
108
- const Conditions = packed struct {
112
+ _: [7]u8 = @splat(0),
113
+
114
+ const Conditions = packed struct(u32) {
109
115
  Spikes: bool = false,
110
116
  Safeguard: bool = false,
111
117
  LightScreen: bool = false,
@@ -115,55 +121,71 @@ const Side = extern struct {
115
121
  light_screen: u4 = 0,
116
122
  reflect: u4 = 0,
117
123
 
118
- comptime {
119
- assert(@sizeOf(Conditions) == 2);
120
- }
124
+ future_sight: FutureSight = .{},
125
+
126
+ const FutureSight = packed struct(u16) {
127
+ damage: u12 = 0,
128
+ count: u4 = 0,
129
+ };
121
130
  };
122
131
 
123
132
  comptime {
124
- assert(@sizeOf(Side) == 240);
133
+ assert(@sizeOf(Side) == 248);
125
134
  }
126
135
 
127
- pub inline fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
128
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
136
+ pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
137
+ assert(isPointerTo(self, Side));
129
138
  assert(slot > 0 and slot <= 6);
130
139
  const id = self.pokemon[slot - 1].position;
131
140
  assert(id > 0 and id <= 6);
132
141
  return &self.pokemon[id - 1];
133
142
  }
134
143
 
135
- pub inline fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
136
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
144
+ pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
145
+ assert(isPointerTo(self, Side));
137
146
  return self.get(1);
138
147
  }
148
+
149
+ pub fn lastMove(self: anytype, encore: bool) Move {
150
+ assert(self.last_used_move != .None or !self.active.volatiles.dirty);
151
+ if (encore) return self.last_used_move;
152
+ return if (self.active.volatiles.dirty) .None else self.last_used_move;
153
+ }
154
+
155
+ // TODO
156
+ // pub fn useMove(self: anytype) void {
157
+ // assert(side.last_selected_move != .None);
158
+ // self.last_used_move = side.last_selected_move;
159
+ // self.active.volatiles.dirty = false;
160
+ // }
139
161
  };
140
162
 
141
163
  // NOTE: DVs (Gender & Hidden Power) and Happiness are stored only in Pokemon
142
- const ActivePokemon = extern struct {
143
- volatiles: Volatile align(4) = .{},
164
+ pub const ActivePokemon = extern struct {
165
+ volatiles: Volatiles align(4) = .{},
144
166
  stats: Stats(u16) = .{},
145
- moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
167
+ moves: [4]MoveSlot = @splat(.{}),
146
168
  boosts: Boosts = .{},
169
+ types: Types = .{},
147
170
  species: Species = .None,
148
- item: Item = .None,
149
- last_move: Move = .None,
171
+
150
172
  _: u8 = 0,
151
173
 
152
174
  comptime {
153
175
  assert(@sizeOf(ActivePokemon) == 44);
154
176
  }
155
177
 
156
- pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
157
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
178
+ pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
179
+ assert(isPointerTo(self, Pokemon));
158
180
  assert(mslot > 0 and mslot <= 4);
159
181
  assert(self.moves[mslot - 1].id != .None);
160
182
  return &self.moves[mslot - 1];
161
183
  }
162
184
  };
163
185
 
164
- const Pokemon = extern struct {
186
+ pub const Pokemon = extern struct {
165
187
  stats: Stats(u16) = .{},
166
- moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
188
+ moves: [4]MoveSlot = @splat(.{}),
167
189
  types: Types = .{},
168
190
  dvs: DVs = .{},
169
191
  hp: u16 = 0,
@@ -178,8 +200,8 @@ const Pokemon = extern struct {
178
200
  assert(@sizeOf(Pokemon) == 32);
179
201
  }
180
202
 
181
- pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
182
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
203
+ pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
204
+ assert(isPointerTo(self, Pokemon));
183
205
  assert(mslot > 0 and mslot <= 4);
184
206
  assert(self.moves[mslot - 1].id != .None);
185
207
  return &self.moves[mslot - 1];
@@ -192,7 +214,7 @@ pub const Gender = enum(u2) {
192
214
  Unknown,
193
215
  };
194
216
 
195
- const DVs = packed struct {
217
+ pub const DVs = packed struct(u16) {
196
218
  gender: Gender = .Male,
197
219
  pow: u6 = 40,
198
220
  type: Type = .Dark,
@@ -200,10 +222,10 @@ const DVs = packed struct {
200
222
  pub fn init(g: Gender, p: u6, t: Type) DVs {
201
223
  assert(p >= 1 and p <= 40);
202
224
  assert(t != .Normal and t != .@"???");
203
- return DVs{ .gender = g, .pow = p, .type = t };
225
+ return .{ .gender = g, .pow = p, .type = t };
204
226
  }
205
227
 
206
- pub inline fn power(dvs: DVs) u8 {
228
+ pub fn power(dvs: DVs) u8 {
207
229
  return @as(u8, dvs.pow) + 30;
208
230
  }
209
231
 
@@ -217,13 +239,8 @@ const DVs = packed struct {
217
239
  };
218
240
  const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
219
241
  ((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
220
- var t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2) + 1;
221
- if (t >= @intFromEnum(Type.@"???")) t = t + 1;
222
- return DVs{ .gender = g, .pow = p, .type = @enumFromInt(t) };
223
- }
224
-
225
- comptime {
226
- assert(@sizeOf(DVs) == 2);
242
+ const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
243
+ return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
227
244
  }
228
245
  };
229
246
 
@@ -231,12 +248,12 @@ test DVs {
231
248
  var dvs = DVs.from(.Mewtwo, .{ .def = 13 });
232
249
  try expectEqual(Gender.Unknown, dvs.gender);
233
250
  try expectEqual(Type.Ice, dvs.type);
234
- try expectEqual(@as(u8, 70), dvs.power());
251
+ try expectEqual(70, dvs.power());
235
252
 
236
253
  dvs = DVs.from(.Pikachu, .{ .spc = 14 });
237
254
  try expectEqual(Gender.Male, dvs.gender);
238
255
  try expectEqual(Type.Dark, dvs.type);
239
- try expectEqual(@as(u8, 69), dvs.power());
256
+ try expectEqual(69, dvs.power());
240
257
 
241
258
  dvs = DVs.from(.Cyndaquil, .{ .atk = 1, .def = 3, .spe = 10, .spc = 9 });
242
259
  try expectEqual(Gender.Female, dvs.gender);
@@ -248,10 +265,12 @@ test DVs {
248
265
  try expectEqual(Gender.Female, dvs.gender);
249
266
  }
250
267
 
251
- const MoveSlot = packed struct {
268
+ /// Representation of a Generation II Pokémon's move slot in a battle.
269
+ pub const MoveSlot = extern struct {
270
+ /// The identifier for the move.
252
271
  id: Move = .None,
253
- pp_ups: u2 = 3,
254
- pp: u6 = 0,
272
+ /// The remaining PP of the move.
273
+ pp: u8 = 0,
255
274
 
256
275
  comptime {
257
276
  assert(@sizeOf(MoveSlot) == 2);
@@ -260,14 +279,19 @@ const MoveSlot = packed struct {
260
279
 
261
280
  pub const Status = gen1.Status;
262
281
 
263
- const Volatile = packed struct {
282
+ /// TODO
283
+ pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
284
+
285
+ pub const Volatiles = packed struct(u128) {
264
286
  Bide: bool = false,
265
287
  Thrashing: bool = false,
288
+ BeatUp: bool = false,
266
289
  Flinch: bool = false,
267
290
  Charging: bool = false,
268
291
  Underground: bool = false,
269
292
  Flying: bool = false,
270
293
  Confusion: bool = false,
294
+
271
295
  Mist: bool = false,
272
296
  FocusEnergy: bool = false,
273
297
  Substitute: bool = false,
@@ -278,52 +302,55 @@ const Volatile = packed struct {
278
302
  Transform: bool = false,
279
303
 
280
304
  Nightmare: bool = false,
281
- Cure: bool = false,
305
+ Curse: bool = false,
282
306
  Protect: bool = false,
283
307
  Foresight: bool = false,
284
308
  PerishSong: bool = false,
285
309
  Endure: bool = false,
286
310
  Rollout: bool = false,
287
311
  Attract: bool = false,
312
+
288
313
  DefenseCurl: bool = false,
289
314
  Encore: bool = false,
290
315
  LockOn: bool = false,
291
316
  DestinyBond: bool = false,
292
- BeatUp: bool = false,
317
+ Trapped: bool = false,
293
318
 
294
- trapped: bool = false,
295
319
  switched: bool = false,
320
+ // TODO: replace with simply looking at Choice on Battle
296
321
  switching: bool = false,
322
+ // TODO: simply store both last moves on side
323
+ dirty: bool = false,
297
324
 
298
- _: u5 = 0,
325
+ frozen: bool = false,
326
+ minimized: bool = false,
327
+ _: u10 = 0,
328
+ // TODO: is this needed for unmodified stats?
329
+ transform: u4 = 0,
299
330
 
300
- bind: u4 = 0,
301
- future_sight: FutureSight = .{},
302
331
  bide: u16 = 0,
303
- disabled: Disabled = .{},
332
+ bind: Bind = .{},
333
+ disable: Disable = .{},
304
334
  rage: u8 = 0,
305
335
  substitute: u8 = 0,
306
336
  toxic: u8 = 0,
307
337
  confusion: u4 = 0,
308
338
  encore: u4 = 0,
339
+ // TODO merge with attacks (ie rollout/thrashing)? need to be zeroed at same time
309
340
  fury_cutter: u4 = 0,
310
341
  perish_song: u4 = 0,
311
342
  protect: u4 = 0,
312
- rollout: u4 = 0,
343
+ attacks: u4 = 0, // bide/thrashing/rollout turns
313
344
 
314
- const Disabled = packed struct {
315
- move: u4 = 0,
345
+ const Bind = packed struct(u8) {
316
346
  duration: u4 = 0,
347
+ reason: u4 = 0,
317
348
  };
318
349
 
319
- const FutureSight = packed struct {
320
- damage: u12 = 0,
321
- count: u4 = 0,
350
+ const Disable = packed struct(u8) {
351
+ move: u4 = 0,
352
+ duration: u4 = 0,
322
353
  };
323
-
324
- comptime {
325
- assert(@sizeOf(Volatile) == 16);
326
- }
327
354
  };
328
355
 
329
356
  pub fn Stats(comptime T: type) type {
@@ -353,12 +380,12 @@ test Stats {
353
380
  try expectEqual(0, stats.def);
354
381
 
355
382
  var base = Species.get(.Gyarados).stats;
356
- try expectEqual(@as(u16, 127), Stats(u16).calc("hp", base.hp, 0, 5120, 38));
383
+ try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
357
384
  base = Species.get(.Pidgeot).stats;
358
- try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
385
+ try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
359
386
  }
360
387
 
361
- pub const Boosts = packed struct {
388
+ pub const Boosts = packed struct(u32) {
362
389
  atk: i4 = 0,
363
390
  def: i4 = 0,
364
391
  spe: i4 = 0,
@@ -374,7 +401,7 @@ pub const Boosts = packed struct {
374
401
  };
375
402
 
376
403
  test Boosts {
377
- const boosts = Boosts{ .spd = -6 };
404
+ const boosts: Boosts = .{ .spd = -6 };
378
405
  try expectEqual(0, boosts.atk);
379
406
  try expectEqual(-6, boosts.spd);
380
407
  }
@@ -387,15 +414,10 @@ test Item {
387
414
  try expectEqual(Type.Normal, Item.boost(.PolkadotBow).?);
388
415
  try expectEqual(Type.Dark, Item.boost(.BlackGlasses).?);
389
416
 
390
- try expect(!Item.mail(.UpGrade));
391
- try expect(Item.mail(.FlowerMail));
392
- try expect(Item.mail(.MirageMail));
393
- try expect(!Item.mail(.TownMap));
394
-
395
- try expect(!Item.berry(.LightBall));
396
- try expect(Item.berry(.PSNCureBerry));
397
- try expect(Item.berry(.GoldBerry));
398
- try expect(!Item.berry(.MasterBall));
417
+ try expect(!Item.isMail(.UpGrade));
418
+ try expect(Item.isMail(.FlowerMail));
419
+ try expect(Item.isMail(.MirageMail));
420
+ try expect(!Item.isMail(.TownMap));
399
421
  }
400
422
 
401
423
  pub const Move = moves.Move;
@@ -404,15 +426,20 @@ test Move {
404
426
  try expectEqual(251, @intFromEnum(Move.BeatUp));
405
427
  const move = Move.get(.DynamicPunch);
406
428
  try expectEqual(Move.Effect.ConfusionChance, move.effect);
407
- try expectEqual(@as(u8, 50), move.accuracy);
408
- try expectEqual(@as(u8, 5), move.pp);
429
+ try expectEqual(rng.Gen12.percent(50), move.accuracy);
430
+ try expectEqual(rng.Gen12.percent(100), move.chance);
431
+ try expectEqual(5, Move.pp(.DynamicPunch));
432
+ try expectEqual(-1, Move.get(.Counter).priority);
433
+ try expect(!move.effect.isHighCritical());
434
+ try expect(Move.get(.KarateChop).effect.isHighCritical());
435
+ try expect(Move.get(.RazorWind).effect.isHighCritical());
409
436
  }
410
437
 
411
438
  pub const Species = species.Species;
412
439
 
413
440
  test Species {
414
441
  try expectEqual(152, @intFromEnum(Species.Chikorita));
415
- try expectEqual(@as(u8, 100), Species.get(.Celebi).stats.spd);
442
+ try expectEqual(100, Species.get(.Celebi).stats.spd);
416
443
  }
417
444
 
418
445
  pub const Type = types.Type;
@@ -425,8 +452,9 @@ test Types {
425
452
  try expect(!Type.Steel.special());
426
453
  try expect(Type.Dark.special());
427
454
 
428
- try expectEqual(@as(u8, 3), Type.Water.precedence());
429
- try expect(Type.Bug.precedence() > Type.Poison.precedence());
455
+ try expectEqual(3, Type.precedence(.Water, .Water));
456
+ try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
457
+ try expect(Type.precedence(.Ice, .Fire) > Type.precedence(.Ice, .Water));
430
458
 
431
459
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
432
460
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Water, .Fire));