@pkmn/engine 0.1.0-dev.683fba11 → 0.1.0-dev.6b383c80

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 (61) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +22 -16
  3. package/build/pkg/addon/browser.js +6 -3
  4. package/build/pkg/addon/browser.js.map +1 -1
  5. package/build/pkg/addon/node.js +23 -10
  6. package/build/pkg/addon/node.js.map +1 -1
  7. package/build/pkg/addon/wasm.js +23 -14
  8. package/build/pkg/addon/wasm.js.map +1 -1
  9. package/build/pkg/addon.d.ts +5 -5
  10. package/build/pkg/addon.js.map +1 -1
  11. package/build/pkg/data.js.map +1 -1
  12. package/build/pkg/gen1.d.ts +2 -1
  13. package/build/pkg/gen1.js +22 -9
  14. package/build/pkg/gen1.js.map +1 -1
  15. package/build/pkg/index.d.ts +2 -0
  16. package/build/pkg/index.js +17 -7
  17. package/build/pkg/index.js.map +1 -1
  18. package/build/pkg/protocol.d.ts +11 -2
  19. package/build/pkg/protocol.js.map +1 -1
  20. package/build/tools/debug.js +54 -11
  21. package/build/tools/debug.js.map +1 -1
  22. package/build/tools/display/debug.jsx +19 -94
  23. package/build/tools/display/debug.jsx.map +1 -1
  24. package/build/tools/display/index.js +18 -7
  25. package/build/tools/display/index.js.map +1 -1
  26. package/build/tools/display/ui.jsx +20 -9
  27. package/build/tools/display/ui.jsx.map +1 -1
  28. package/build/tools/display/util.js +140 -1
  29. package/build/tools/display/util.js.map +1 -1
  30. package/build.zig +255 -313
  31. package/package.json +29 -131
  32. package/src/bin/install-pkmn-engine +24 -22
  33. package/src/lib/bindings/c.zig +201 -0
  34. package/src/lib/bindings/node.zig +117 -0
  35. package/src/lib/bindings/wasm.zig +51 -0
  36. package/src/lib/common/array.zig +9 -16
  37. package/src/lib/common/data.zig +8 -8
  38. package/src/lib/common/debug.zig +46 -61
  39. package/src/lib/common/js.zig +3 -9
  40. package/src/lib/common/optional.zig +20 -25
  41. package/src/lib/common/protocol.zig +224 -189
  42. package/src/lib/common/rational.zig +275 -284
  43. package/src/lib/common/rng.zig +4 -4
  44. package/src/lib/common/util.zig +34 -31
  45. package/src/lib/gen1/calc.zig +141 -119
  46. package/src/lib/gen1/chance.zig +162 -101
  47. package/src/lib/gen1/data/types.zig +2 -2
  48. package/src/lib/gen1/data.zig +27 -24
  49. package/src/lib/gen1/helpers.zig +36 -26
  50. package/src/lib/gen1/mechanics.zig +45 -49
  51. package/src/lib/gen2/calc.zig +3 -6
  52. package/src/lib/gen2/chance.zig +55 -43
  53. package/src/lib/gen2/data/types.zig +6 -3
  54. package/src/lib/gen2/data.zig +20 -16
  55. package/src/lib/gen2/helpers.zig +27 -19
  56. package/src/lib/gen2/mechanics.zig +17 -17
  57. package/src/lib/napi.h +2 -0
  58. package/src/lib/node.zig +3 -118
  59. package/src/lib/pkmn.zig +94 -19
  60. package/src/lib/wasm.zig +9 -44
  61. package/src/tools/display/dom.ts +43 -31
@@ -27,10 +27,6 @@ const Type = data.Type;
27
27
  const Effectiveness = data.Effectiveness;
28
28
  const TriAttack = data.TriAttack;
29
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
-
34
30
  /// Actions taken by a hypothetical "chance player" that convey information about which RNG events
35
31
  /// were observed during a Generation II battle `update`. This can additionally be provided as input
36
32
  /// to the `update` call to override the normal behavior of the RNG in order to force specific
@@ -57,15 +53,28 @@ pub const Actions = extern struct {
57
53
  /// same shape if they have the same fields set (though those fields need not necessarily be
58
54
  /// set to the same value).
59
55
  pub fn matches(a: Actions, b: Actions) bool {
60
- inline for (@field(@typeInfo(Actions), @tagName(Struct)).fields) |player| {
61
- inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
62
- const a_val = @field(@field(a, player.name), field.name);
63
- const b_val = @field(@field(b, player.name), field.name);
56
+ inline for (if (@hasField(@TypeOf(@typeInfo(Actions).@"struct"), "fields"))
57
+ @typeInfo(Actions).@"struct".fields
58
+ else
59
+ @typeInfo(Actions).@"struct".field_names) |player|
60
+ {
61
+ const player_name = if (@hasField(@TypeOf(player), "name"))
62
+ player.name
63
+ else
64
+ player;
65
+ inline for (if (@hasField(@TypeOf(@typeInfo(Action).@"struct"), "fields"))
66
+ @typeInfo(Action).@"struct".fields
67
+ else
68
+ @typeInfo(Action).@"struct".field_names) |field|
69
+ {
70
+ const field_name = if (@hasField(@TypeOf(field), "name")) field.name else field;
71
+ const a_val = @field(@field(a, player_name), field_name);
72
+ const b_val = @field(@field(b, player_name), field_name);
64
73
 
65
74
  switch (@typeInfo(@TypeOf(a_val))) {
66
- Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
75
+ .@"enum" => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
67
76
  return false,
68
- Int => if ((a_val > 0) != (b_val > 0)) return false,
77
+ .int => if ((a_val > 0) != (b_val > 0)) return false,
69
78
  else => unreachable,
70
79
  }
71
80
  }
@@ -73,7 +82,7 @@ pub const Actions = extern struct {
73
82
  return true;
74
83
  }
75
84
 
76
- pub fn fmt(self: Actions, writer: anytype, shape: bool) !void {
85
+ pub fn fmt(self: Actions, writer: *std.Io.Writer, shape: bool) !void {
77
86
  try writer.writeAll("<P1 = ");
78
87
  try self.p1.fmt(writer, shape);
79
88
  try writer.writeAll(", P2 = ");
@@ -81,8 +90,7 @@ pub const Actions = extern struct {
81
90
  try writer.writeAll(">");
82
91
  }
83
92
 
84
- pub fn format(a: Actions, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
85
- _ = .{ f, o };
93
+ pub fn format(a: Actions, w: *std.Io.Writer) !void {
86
94
  try fmt(a, w, false);
87
95
  }
88
96
  };
@@ -186,37 +194,41 @@ pub const Action = packed struct(u128) {
186
194
 
187
195
  pub const Field = std.meta.FieldEnum(Action);
188
196
 
189
- pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
190
- _ = .{ f, o };
197
+ pub fn format(a: Action, w: *std.Io.Writer) !void {
191
198
  try fmt(a, w, false);
192
199
  }
193
200
 
194
- pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
201
+ pub fn fmt(self: Action, writer: *std.Io.Writer, shape: bool) !void {
195
202
  try writer.writeByte('(');
196
203
  var printed = false;
197
- inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
198
- const val = @field(self, field.name);
204
+ inline for (if (@hasField(@TypeOf(@typeInfo(Action).@"struct"), "fields"))
205
+ @typeInfo(Action).@"struct".fields
206
+ else
207
+ @typeInfo(Action).@"struct".field_names) |field|
208
+ {
209
+ const field_name = if (@hasField(@TypeOf(field), "name")) field.name else field;
210
+ const val = @field(self, field_name);
199
211
  switch (@typeInfo(@TypeOf(val))) {
200
- Enum => if (val != .None) {
212
+ .@"enum" => if (val != .None) {
201
213
  if (printed) try writer.writeAll(", ");
202
214
  if (shape) {
203
- try writer.print("{s}:?", .{field.name});
215
+ try writer.print("{s}:?", .{field_name});
204
216
  } else if (@TypeOf(val) == Optional(bool)) {
205
217
  try writer.print("{s}{s}", .{
206
218
  if (val == .false) "!" else "",
207
- field.name,
219
+ field_name,
208
220
  });
209
221
  } else {
210
- try writer.print("{s}:{s}", .{ field.name, @tagName(val) });
222
+ try writer.print("{s}:{s}", .{ field_name, @tagName(val) });
211
223
  }
212
224
  printed = true;
213
225
  },
214
- Int => if (val != 0) {
226
+ .int => if (val != 0) {
215
227
  if (printed) try writer.writeAll(", ");
216
228
  if (shape) {
217
- try writer.print("{s}:?", .{field.name});
229
+ try writer.print("{s}:?", .{field_name});
218
230
  } else {
219
- try writer.print("{s}:{d}", .{ field.name, val });
231
+ try writer.print("{s}:{d}", .{ field_name, val });
220
232
  }
221
233
  printed = true;
222
234
  },
@@ -509,7 +521,7 @@ test "Chance.damage" {
509
521
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
510
522
 
511
523
  try chance.damage(.P1, 0, 219);
512
- try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
524
+ try expectValue(219, Damages.get(chance.actions.p1.damages, 0));
513
525
  try expectProbability(&chance.probability, 1, 39);
514
526
  }
515
527
 
@@ -634,7 +646,7 @@ test "Chance.present" {
634
646
  } else {
635
647
  try expectProbability(&chance.probability, 25, 256);
636
648
  }
637
- try expectValue(@as(u3, 4), chance.actions.p2.present);
649
+ try expectValue(4, chance.actions.p2.present);
638
650
 
639
651
  chance.reset();
640
652
 
@@ -644,7 +656,7 @@ test "Chance.present" {
644
656
  } else {
645
657
  try expectProbability(&chance.probability, 51, 256);
646
658
  }
647
- try expectValue(@as(u3, 1), chance.actions.p1.present);
659
+ try expectValue(1, chance.actions.p1.present);
648
660
  }
649
661
 
650
662
  test "Chance.magnitude" {
@@ -656,7 +668,7 @@ test "Chance.magnitude" {
656
668
  } else {
657
669
  try expectProbability(&chance.probability, 13, 256);
658
670
  }
659
- try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
671
+ try expectValue(7, chance.actions.p2.magnitude);
660
672
 
661
673
  chance.reset();
662
674
 
@@ -666,7 +678,7 @@ test "Chance.magnitude" {
666
678
  } else {
667
679
  try expectProbability(&chance.probability, 51, 256);
668
680
  }
669
- try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
681
+ try expectValue(5, chance.actions.p1.magnitude);
670
682
  }
671
683
 
672
684
  test "Chance.tripleKick" {
@@ -674,7 +686,7 @@ test "Chance.tripleKick" {
674
686
 
675
687
  try chance.tripleKick(.P1, 2);
676
688
  try expectProbability(&chance.probability, 1, 3);
677
- try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
689
+ try expectValue(2, chance.actions.p1.triple_kick);
678
690
  }
679
691
 
680
692
  test "Chance.spite" {
@@ -682,7 +694,7 @@ test "Chance.spite" {
682
694
 
683
695
  try chance.spite(.P1, 3);
684
696
  try expectProbability(&chance.probability, 1, 4);
685
- try expectValue(@as(u3, 3), chance.actions.p1.spite);
697
+ try expectValue(3, chance.actions.p1.spite);
686
698
  }
687
699
 
688
700
  test "Chance.conversion2" {
@@ -709,7 +721,7 @@ test "Chance.psywave" {
709
721
 
710
722
  try chance.psywave(.P2, 100, 150);
711
723
  try expectProbability(&chance.probability, 1, 150);
712
- try expectValue(@as(u8, 100), chance.actions.p2.psywave);
724
+ try expectValue(100, chance.actions.p2.psywave);
713
725
  }
714
726
 
715
727
  test "Chance.metronome" {
@@ -725,19 +737,19 @@ test "Chance.moveSlot" {
725
737
 
726
738
  try chance.moveSlot(.P2, 2, 2);
727
739
  try expectProbability(&chance.probability, 1, 2);
728
- try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
740
+ try expectValue(2, chance.actions.p2.move_slot);
729
741
 
730
742
  chance.reset();
731
743
 
732
744
  try chance.moveSlot(.P1, 1, 3);
733
745
  try expectProbability(&chance.probability, 1, 3);
734
- try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
746
+ try expectValue(1, chance.actions.p1.move_slot);
735
747
 
736
748
  chance.reset();
737
749
 
738
750
  try chance.moveSlot(.P1, 4, 1);
739
751
  try expectProbability(&chance.probability, 1, 1);
740
- try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
752
+ try expectValue(4, chance.actions.p1.move_slot);
741
753
  }
742
754
 
743
755
  test "Chance.forceSwitch" {
@@ -745,19 +757,19 @@ test "Chance.forceSwitch" {
745
757
 
746
758
  try chance.forceSwitch(.P2, 2, 2);
747
759
  try expectProbability(&chance.probability, 1, 2);
748
- try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
760
+ try expectValue(2, chance.actions.p2.force_switch);
749
761
 
750
762
  chance.reset();
751
763
 
752
764
  try chance.forceSwitch(.P1, 1, 3);
753
765
  try expectProbability(&chance.probability, 1, 3);
754
- try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
766
+ try expectValue(1, chance.actions.p1.force_switch);
755
767
 
756
768
  chance.reset();
757
769
 
758
770
  try chance.forceSwitch(.P1, 4, 1);
759
771
  try expectProbability(&chance.probability, 1, 1);
760
- try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
772
+ try expectValue(4, chance.actions.p1.force_switch);
761
773
  }
762
774
 
763
775
  test "Chance.multiHit" {
@@ -765,20 +777,20 @@ test "Chance.multiHit" {
765
777
 
766
778
  try chance.multiHit(.P1, 3);
767
779
  try expectProbability(&chance.probability, 3, 8);
768
- try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
780
+ try expectValue(3, chance.actions.p1.multi_hit);
769
781
 
770
782
  chance.reset();
771
783
 
772
784
  try chance.multiHit(.P2, 5);
773
785
  try expectProbability(&chance.probability, 1, 8);
774
- try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
786
+ try expectValue(5, chance.actions.p2.multi_hit);
775
787
  }
776
788
 
777
789
  test "Chance.duration" {
778
790
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
779
791
 
780
792
  chance.duration(.P1, 2);
781
- try expectValue(@as(u3, 2), chance.actions.p1.duration);
793
+ try expectValue(2, chance.actions.p1.duration);
782
794
  }
783
795
 
784
796
  pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
@@ -786,7 +798,7 @@ pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
786
798
 
787
799
  r.reduce();
788
800
  if (r.p != p or r.q != q) {
789
- print("expected {d}/{d}, found {}\n", .{ p, q, r });
801
+ print("expected {d}/{d}, found {f}\n", .{ p, q, r });
790
802
  return error.TestExpectedEqual;
791
803
  }
792
804
  }
@@ -172,9 +172,12 @@ pub const Type = enum(u8) {
172
172
  return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
173
173
  }
174
174
 
175
- /// The precedence order of Type `type`.
176
- pub fn precedence(self: Type) u8 {
177
- 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)];
178
181
  }
179
182
 
180
183
  /// The internal index of this Type used by Present.
@@ -23,11 +23,14 @@ const expect = std.testing.expect;
23
23
  pub const MAX_CHOICES: usize = 9; // move 1..4, switch 2..6
24
24
  pub const MAX_LOGS: usize = 180; // TODO
25
25
 
26
- 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)
27
30
  MAX_CHOICES
28
31
  else
29
32
  std.math.ceilPowerOfTwo(usize, MAX_CHOICES) catch unreachable;
30
- pub const LOGS_SIZE = if (builtin.mode == .ReleaseSmall)
33
+ pub const LOGS_SIZE = if (builtin.mode == ReleaseSmall)
31
34
  MAX_LOGS
32
35
  else
33
36
  std.math.ceilPowerOfTwo(usize, MAX_LOGS) catch unreachable;
@@ -57,7 +60,7 @@ pub fn Battle(comptime RNG: anytype) type {
57
60
  turn: u16 = 0,
58
61
  field: Field = .{},
59
62
 
60
- _: [padding]u8 = .{0} ** padding,
63
+ _: [padding]u8 = @splat(0),
61
64
 
62
65
  pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
63
66
  assert(isPointerTo(self, Self));
@@ -100,13 +103,13 @@ pub const Weather = enum(u4) {
100
103
  };
101
104
 
102
105
  pub const Side = extern struct {
103
- pokemon: [6]Pokemon = [_]Pokemon{.{}} ** 6,
106
+ pokemon: [6]Pokemon = @splat(.{}),
104
107
  active: ActivePokemon align(8) = .{},
105
108
  conditions: Conditions = .{},
106
109
  // NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
107
110
  last_used_move: Move = .None,
108
111
 
109
- _: [7]u8 = .{0} ** 7,
112
+ _: [7]u8 = @splat(0),
110
113
 
111
114
  const Conditions = packed struct(u32) {
112
115
  Spikes: bool = false,
@@ -161,7 +164,7 @@ pub const Side = extern struct {
161
164
  pub const ActivePokemon = extern struct {
162
165
  volatiles: Volatiles align(4) = .{},
163
166
  stats: Stats(u16) = .{},
164
- moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
167
+ moves: [4]MoveSlot = @splat(.{}),
165
168
  boosts: Boosts = .{},
166
169
  types: Types = .{},
167
170
  species: Species = .None,
@@ -182,7 +185,7 @@ pub const ActivePokemon = extern struct {
182
185
 
183
186
  pub const Pokemon = extern struct {
184
187
  stats: Stats(u16) = .{},
185
- moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
188
+ moves: [4]MoveSlot = @splat(.{}),
186
189
  types: Types = .{},
187
190
  dvs: DVs = .{},
188
191
  hp: u16 = 0,
@@ -245,12 +248,12 @@ test DVs {
245
248
  var dvs = DVs.from(.Mewtwo, .{ .def = 13 });
246
249
  try expectEqual(Gender.Unknown, dvs.gender);
247
250
  try expectEqual(Type.Ice, dvs.type);
248
- try expectEqual(@as(u8, 70), dvs.power());
251
+ try expectEqual(70, dvs.power());
249
252
 
250
253
  dvs = DVs.from(.Pikachu, .{ .spc = 14 });
251
254
  try expectEqual(Gender.Male, dvs.gender);
252
255
  try expectEqual(Type.Dark, dvs.type);
253
- try expectEqual(@as(u8, 69), dvs.power());
256
+ try expectEqual(69, dvs.power());
254
257
 
255
258
  dvs = DVs.from(.Cyndaquil, .{ .atk = 1, .def = 3, .spe = 10, .spc = 9 });
256
259
  try expectEqual(Gender.Female, dvs.gender);
@@ -377,9 +380,9 @@ test Stats {
377
380
  try expectEqual(0, stats.def);
378
381
 
379
382
  var base = Species.get(.Gyarados).stats;
380
- 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));
381
384
  base = Species.get(.Pidgeot).stats;
382
- 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));
383
386
  }
384
387
 
385
388
  pub const Boosts = packed struct(u32) {
@@ -425,8 +428,8 @@ test Move {
425
428
  try expectEqual(Move.Effect.ConfusionChance, move.effect);
426
429
  try expectEqual(rng.Gen12.percent(50), move.accuracy);
427
430
  try expectEqual(rng.Gen12.percent(100), move.chance);
428
- try expectEqual(@as(u8, 5), Move.pp(.DynamicPunch));
429
- try expectEqual(@as(i8, -1), Move.get(.Counter).priority);
431
+ try expectEqual(5, Move.pp(.DynamicPunch));
432
+ try expectEqual(-1, Move.get(.Counter).priority);
430
433
  try expect(!move.effect.isHighCritical());
431
434
  try expect(Move.get(.KarateChop).effect.isHighCritical());
432
435
  try expect(Move.get(.RazorWind).effect.isHighCritical());
@@ -436,7 +439,7 @@ pub const Species = species.Species;
436
439
 
437
440
  test Species {
438
441
  try expectEqual(152, @intFromEnum(Species.Chikorita));
439
- try expectEqual(@as(u8, 100), Species.get(.Celebi).stats.spd);
442
+ try expectEqual(100, Species.get(.Celebi).stats.spd);
440
443
  }
441
444
 
442
445
  pub const Type = types.Type;
@@ -449,8 +452,9 @@ test Types {
449
452
  try expect(!Type.Steel.special());
450
453
  try expect(Type.Dark.special());
451
454
 
452
- try expectEqual(@as(u8, 3), Type.Water.precedence());
453
- 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));
454
458
 
455
459
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
456
460
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Water, .Fire));
@@ -16,8 +16,6 @@ const showdown = options.showdown;
16
16
  const Species = data.Species;
17
17
  const Stats = data.Stats;
18
18
 
19
- const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
20
-
21
19
  pub const Options = struct {
22
20
  cleric: bool = showdown,
23
21
  };
@@ -74,7 +72,7 @@ pub fn prng(rand: *PSRNG) data.PRNG {
74
72
  var carry: u8 = 0;
75
73
  var div: u8 = 0;
76
74
 
77
- var i: u8 = 0;
75
+ var i: usize = 0;
78
76
  while (i < seed.len) {
79
77
  div = @intCast(timer >> 8);
80
78
  // This is effectively @addWithOverflow but with three operands
@@ -142,15 +140,20 @@ pub const Pokemon = struct {
142
140
  var pokemon = data.Pokemon{};
143
141
  pokemon.species = p.species;
144
142
  const species = Species.get(p.species);
145
- inline for (@field(@typeInfo(@TypeOf(pokemon.stats)), @tagName(Struct)).fields) |field| {
146
- const hp = comptime std.mem.eql(u8, field.name, "hp");
143
+ inline for (if (@hasField(@TypeOf(@typeInfo(@TypeOf(pokemon.stats)).@"struct"), "fields"))
144
+ @typeInfo(@TypeOf(pokemon.stats)).@"struct".fields
145
+ else
146
+ @typeInfo(@TypeOf(pokemon.stats)).@"struct".field_names) |field|
147
+ {
148
+ const field_name = if (@hasField(@TypeOf(field), "name")) field.name else field;
149
+ const hp = comptime std.mem.eql(u8, field_name, "hp");
147
150
  const spc =
148
- comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
149
- @field(pokemon.stats, field.name) = Stats(u16).calc(
150
- field.name,
151
- @field(species.stats, field.name),
152
- if (hp) p.dvs.hp() else if (spc) p.dvs.spc else @field(p.dvs, field.name),
153
- @field(p.stats, field.name),
151
+ comptime std.mem.eql(u8, field_name, "spa") or std.mem.eql(u8, field_name, "spd");
152
+ @field(pokemon.stats, field_name) = Stats(u16).calc(
153
+ field_name,
154
+ @field(species.stats, field_name),
155
+ if (hp) p.dvs.hp() else if (spc) p.dvs.spc else @field(p.dvs, field_name),
156
+ @field(p.stats, field_name),
154
157
  p.level,
155
158
  );
156
159
  }
@@ -183,19 +186,24 @@ pub const Pokemon = struct {
183
186
 
184
187
  var stats: Stats(u16) = .{};
185
188
  const dvs = gen1.DVs.random(rand);
186
- inline for (@field(@typeInfo(@TypeOf(stats)), @tagName(Struct)).fields) |field| {
187
- const hp = std.mem.eql(u8, field.name, "hp");
188
- const spc = std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
189
- @field(stats, field.name) = Stats(u16).calc(
190
- field.name,
191
- @field(species.stats, field.name),
192
- if (hp) dvs.hp() else if (spc) dvs.spc else @field(dvs, field.name),
189
+ inline for (if (@hasField(@TypeOf(@typeInfo(@TypeOf(stats)).@"struct"), "fields"))
190
+ @typeInfo(@TypeOf(stats)).@"struct".fields
191
+ else
192
+ @typeInfo(@TypeOf(stats)).@"struct".field_names) |field|
193
+ {
194
+ const field_name = if (@hasField(@TypeOf(field), "name")) field.name else field;
195
+ const hp = std.mem.eql(u8, field_name, "hp");
196
+ const spc = std.mem.eql(u8, field_name, "spa") or std.mem.eql(u8, field_name, "spd");
197
+ @field(stats, field_name) = Stats(u16).calc(
198
+ field_name,
199
+ @field(species.stats, field_name),
200
+ if (hp) dvs.hp() else if (spc) dvs.spc else @field(dvs, field_name),
193
201
  if (rand.chance(u8, 1, 20)) rand.range(u8, 0, 255 + 1) else 255,
194
202
  lvl,
195
203
  );
196
204
  }
197
205
 
198
- var ms = [_]MoveSlot{.{}} ** 4;
206
+ var ms: [4]MoveSlot = @splat(.{});
199
207
  const n = if (rand.chance(u8, 1, 100)) rand.range(u4, 1, 3 + 1) else 4;
200
208
  for (0..n) |i| {
201
209
  var m: Move = .None;
@@ -129,11 +129,11 @@ fn start(battle: anytype, options: anytype) !Result {
129
129
 
130
130
  const p1_slot = findFirstAlive(p1);
131
131
  assert(!showdown or p1_slot == 1);
132
- if (p1_slot == 0) return if (findFirstAlive(p2) == 0) Result.Tie else Result.Lose;
132
+ if (p1_slot == 0) return if (findFirstAlive(p2) == 0) .Tie else .Lose;
133
133
 
134
134
  const p2_slot = findFirstAlive(p2);
135
135
  assert(!showdown or p2_slot == 1);
136
- if (p2_slot == 0) return Result.Win;
136
+ if (p2_slot == 0) return .Win;
137
137
 
138
138
  try switchIn(battle, .P1, p1_slot, .Initial, options);
139
139
  try switchIn(battle, .P2, p2_slot, .Initial, options);
@@ -681,7 +681,7 @@ pub fn adjustDamage(battle: anytype, player: Player, state: *State, _: anytype)
681
681
 
682
682
  // Type effectiveness matchup precedence only matters with (NVE, SE)
683
683
  if (!showdown and (eff1 + eff2) == Effectiveness.mismatch and
684
- types.type1.precedence() > types.type2.precedence())
684
+ Type.precedence(state.type, types.type1) > Type.precedence(state.type, types.type2))
685
685
  {
686
686
  assert(eff2 != neutral);
687
687
  d = d *% eff2 / 10;
@@ -818,13 +818,13 @@ fn checkFaint(
818
818
 
819
819
  if (player_out and foe_out) {
820
820
  try options.log.tie(.{});
821
- return Result.Tie;
821
+ return .Tie;
822
822
  } else if (player_out) {
823
823
  try options.log.win(.{player.foe()});
824
- return if (player == .P1) Result.Lose else Result.Win;
824
+ return if (player == .P1) .Lose else .Win;
825
825
  } else if (foe_out) {
826
826
  try options.log.win(.{player});
827
- return if (player == .P1) Result.Win else Result.Lose;
827
+ return if (player == .P1) .Win else .Lose;
828
828
  }
829
829
 
830
830
  const foe_choice: Choice.Type = if (foe_fainted) .Switch else .Pass;
@@ -1194,14 +1194,14 @@ fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result
1194
1194
 
1195
1195
  if (pkmn.options.mod and battle.turn >= 1000) {
1196
1196
  try options.log.tie(.{});
1197
- return Result.Tie;
1197
+ return .Tie;
1198
1198
  } else if (battle.turn >= 65535) {
1199
- return Result.Error;
1199
+ return .Error;
1200
1200
  }
1201
1201
 
1202
1202
  try options.log.turn(.{battle.turn});
1203
1203
 
1204
- return Result.Default;
1204
+ return .Default;
1205
1205
  }
1206
1206
 
1207
1207
  pub fn buildRage(battle: anytype, player: Player, state: *State, options: anytype) !void {
@@ -1553,7 +1553,7 @@ pub const Effects = struct {
1553
1553
  const last = battle.foe(player).lastMove(true);
1554
1554
  const failed = volatiles.Encore or
1555
1555
  (last == .None or last == .Struggle or
1556
- last == .Encore or .last == .MirrorMove);
1556
+ last == .Encore or .last == .MirrorMove);
1557
1557
  if (failed) return options.log.fail(.{ foe_ident, .None });
1558
1558
 
1559
1559
  var slot: u3 = 0;
@@ -3070,7 +3070,7 @@ pub const Rolls = struct {
3070
3070
  }
3071
3071
 
3072
3072
  // Conversion 2 can at most choose between 7 types (vs. a Grass-type attack)
3073
- var CONVERSION_2: [7]Type = [_]Type{.@"???"} ** 7;
3073
+ var CONVERSION_2: [7]Type = @splat(.@"???");
3074
3074
 
3075
3075
  fn conversion2(battle: anytype, player: Player, mtype: Type, options: anytype) !Type {
3076
3076
  var i: u8 = 0;
@@ -3495,11 +3495,11 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3495
3495
  },
3496
3496
  .Switch => {
3497
3497
  const side = battle.side(player);
3498
- var slot: u4 = 2;
3498
+ var slot: usize = 2;
3499
3499
  while (slot <= 6) : (slot += 1) {
3500
3500
  const id = side.order[slot - 1];
3501
3501
  if (id == 0 or side.pokemon[id - 1].hp == 0) continue;
3502
- out[n] = .{ .type = .Switch, .data = slot };
3502
+ out[n] = .{ .type = .Switch, .data = @intCast(slot) };
3503
3503
  n += 1;
3504
3504
  }
3505
3505
  if (n == 0) {
@@ -3529,11 +3529,11 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3529
3529
  return n;
3530
3530
  }
3531
3531
 
3532
- var slot: u4 = 2;
3532
+ var slot: usize = 2;
3533
3533
  while (!active.volatiles.Trapped and slot <= 6) : (slot += 1) {
3534
3534
  const id = side.order[slot - 1];
3535
3535
  if (id == 0 or side.pokemon[id - 1].hp == 0) continue;
3536
- out[n] = .{ .type = .Switch, .data = slot };
3536
+ out[n] = .{ .type = .Switch, .data = @intCast(slot) };
3537
3537
  n += 1;
3538
3538
  }
3539
3539
 
@@ -3566,7 +3566,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3566
3566
  const struggle =
3567
3567
  m.id == .Bide and (m.pp == 0 or active.volatiles.disable.move == slot);
3568
3568
  const s = if (struggle) 0 else slot;
3569
- out[n] = .{ .type = .Move, .data = s };
3569
+ out[n] = .{ .type = .Move, .data = @intCast(s) };
3570
3570
  n += 1;
3571
3571
  return n;
3572
3572
  }
@@ -3580,7 +3580,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3580
3580
  if (m.id == .None) break;
3581
3581
  if (m.pp == 0) continue;
3582
3582
  if (active.volatiles.disable.move == slot) continue;
3583
- out[n] = .{ .type = .Move, .data = slot };
3583
+ out[n] = .{ .type = .Move, .data = @intCast(slot) };
3584
3584
  n += 1;
3585
3585
  }
3586
3586
  // Struggle (Pokémon Showdown would use 'move 1' here)
package/src/lib/napi.h ADDED
@@ -0,0 +1,2 @@
1
+ #define NAPI_VERSION 8
2
+ #include <node_api.h>