@pkmn/engine 0.1.0-dev.f3aab252 → 0.1.0-dev.f3b63b86

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 (80) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +35 -8
  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 +39 -89
  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 +235 -213
  39. package/package.json +59 -141
  40. package/src/bin/install-pkmn-engine +25 -9
  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 +5 -12
  46. package/src/lib/common/debug.zig +30 -9
  47. package/src/lib/common/js.zig +3 -9
  48. package/src/lib/common/optional.zig +11 -21
  49. package/src/lib/common/options.zig +4 -0
  50. package/src/lib/common/protocol.zig +180 -171
  51. package/src/lib/common/rational.zig +278 -285
  52. package/src/lib/common/rng.zig +1 -3
  53. package/src/lib/common/util.zig +14 -31
  54. package/src/lib/gen1/calc.zig +258 -106
  55. package/src/lib/gen1/chance.zig +57 -54
  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 +3 -4
  59. package/src/lib/gen1/data.zig +12 -16
  60. package/src/lib/gen1/helpers.zig +13 -28
  61. package/src/lib/gen1/mechanics.zig +131 -101
  62. package/src/lib/gen2/calc.zig +12 -23
  63. package/src/lib/gen2/chance.zig +12 -18
  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 +7 -5
  68. package/src/lib/gen2/data.zig +19 -22
  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 +50 -47
  72. package/src/lib/napi.h +2 -0
  73. package/src/lib/node.zig +4 -121
  74. package/src/lib/pkmn.zig +98 -19
  75. package/src/lib/wasm.zig +9 -9
  76. package/src/tools/display/dom.ts +93 -0
  77. package/src/tools/display/ui.css +354 -0
  78. package/build/test/display.js +0 -405
  79. package/build/test/display.js.map +0 -1
  80. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -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,15 @@ 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| {
56
+ inline for (@typeInfo(Actions).@"struct".fields) |player| {
57
+ inline for (@typeInfo(Action).@"struct".fields) |field| {
62
58
  const a_val = @field(@field(a, player.name), field.name);
63
59
  const b_val = @field(@field(b, player.name), field.name);
64
60
 
65
61
  switch (@typeInfo(@TypeOf(a_val))) {
66
- Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
62
+ .@"enum" => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
67
63
  return false,
68
- Int => if ((a_val > 0) != (b_val > 0)) return false,
64
+ .int => if ((a_val > 0) != (b_val > 0)) return false,
69
65
  else => unreachable,
70
66
  }
71
67
  }
@@ -73,7 +69,7 @@ pub const Actions = extern struct {
73
69
  return true;
74
70
  }
75
71
 
76
- pub fn fmt(self: Actions, writer: anytype, shape: bool) !void {
72
+ pub fn fmt(self: Actions, writer: *std.Io.Writer, shape: bool) !void {
77
73
  try writer.writeAll("<P1 = ");
78
74
  try self.p1.fmt(writer, shape);
79
75
  try writer.writeAll(", P2 = ");
@@ -81,8 +77,7 @@ pub const Actions = extern struct {
81
77
  try writer.writeAll(">");
82
78
  }
83
79
 
84
- pub fn format(a: Actions, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
85
- _ = .{ f, o };
80
+ pub fn format(a: Actions, w: *std.Io.Writer) !void {
86
81
  try fmt(a, w, false);
87
82
  }
88
83
  };
@@ -186,18 +181,17 @@ pub const Action = packed struct(u128) {
186
181
 
187
182
  pub const Field = std.meta.FieldEnum(Action);
188
183
 
189
- pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
190
- _ = .{ f, o };
184
+ pub fn format(a: Action, w: *std.Io.Writer) !void {
191
185
  try fmt(a, w, false);
192
186
  }
193
187
 
194
- pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
188
+ pub fn fmt(self: Action, writer: *std.Io.Writer, shape: bool) !void {
195
189
  try writer.writeByte('(');
196
190
  var printed = false;
197
- inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
191
+ inline for (@typeInfo(Action).@"struct".fields) |field| {
198
192
  const val = @field(self, field.name);
199
193
  switch (@typeInfo(@TypeOf(val))) {
200
- Enum => if (val != .None) {
194
+ .@"enum" => if (val != .None) {
201
195
  if (printed) try writer.writeAll(", ");
202
196
  if (shape) {
203
197
  try writer.print("{s}:?", .{field.name});
@@ -211,7 +205,7 @@ pub const Action = packed struct(u128) {
211
205
  }
212
206
  printed = true;
213
207
  },
214
- Int => if (val != 0) {
208
+ .int => if (val != 0) {
215
209
  if (printed) try writer.writeAll(", ");
216
210
  if (shape) {
217
211
  try writer.print("{s}:?", .{field.name});
@@ -786,7 +780,7 @@ pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
786
780
 
787
781
  r.reduce();
788
782
  if (r.p != p or r.q != q) {
789
- print("expected {d}/{d}, found {}\n", .{ p, q, r });
783
+ print("expected {d}/{d}, found {f}\n", .{ p, q, r });
790
784
  return error.TestExpectedEqual;
791
785
  }
792
786
  }
@@ -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.
@@ -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;
@@ -61,7 +57,7 @@ pub fn Battle(comptime RNG: anytype) type {
61
57
  turn: u16 = 0,
62
58
  field: Field = .{},
63
59
 
64
- _: [padding]u8 = .{0} ** padding,
60
+ _: [padding]u8 = @splat(0),
65
61
 
66
62
  pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
67
63
  assert(isPointerTo(self, Self));
@@ -104,13 +100,13 @@ pub const Weather = enum(u4) {
104
100
  };
105
101
 
106
102
  pub const Side = extern struct {
107
- pokemon: [6]Pokemon = [_]Pokemon{.{}} ** 6,
103
+ pokemon: [6]Pokemon = @splat(.{}),
108
104
  active: ActivePokemon align(8) = .{},
109
105
  conditions: Conditions = .{},
110
106
  // NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
111
107
  last_used_move: Move = .None,
112
108
 
113
- _: [7]u8 = .{0} ** 7,
109
+ _: [7]u8 = @splat(0),
114
110
 
115
111
  const Conditions = packed struct(u32) {
116
112
  Spikes: bool = false,
@@ -165,7 +161,7 @@ pub const Side = extern struct {
165
161
  pub const ActivePokemon = extern struct {
166
162
  volatiles: Volatiles align(4) = .{},
167
163
  stats: Stats(u16) = .{},
168
- moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
164
+ moves: [4]MoveSlot = @splat(.{}),
169
165
  boosts: Boosts = .{},
170
166
  types: Types = .{},
171
167
  species: Species = .None,
@@ -186,7 +182,7 @@ pub const ActivePokemon = extern struct {
186
182
 
187
183
  pub const Pokemon = extern struct {
188
184
  stats: Stats(u16) = .{},
189
- moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
185
+ moves: [4]MoveSlot = @splat(.{}),
190
186
  types: Types = .{},
191
187
  dvs: DVs = .{},
192
188
  hp: u16 = 0,
@@ -453,8 +449,9 @@ test Types {
453
449
  try expect(!Type.Steel.special());
454
450
  try expect(Type.Dark.special());
455
451
 
456
- try expectEqual(@as(u8, 3), Type.Water.precedence());
457
- try expect(Type.Bug.precedence() > Type.Poison.precedence());
452
+ try expectEqual(@as(u8, 3), Type.precedence(.Water, .Water));
453
+ try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
454
+ try expect(Type.precedence(.Ice, .Fire) > Type.precedence(.Ice, .Water));
458
455
 
459
456
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
460
457
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Water, .Fire));
@@ -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;
@@ -1,30 +1,21 @@
1
- const std = @import("std");
2
-
3
1
  const common = @import("../common/data.zig");
2
+ const data = @import("data.zig");
3
+ const gen1 = @import("../gen1/data.zig");
4
4
  const options = @import("../common/options.zig");
5
5
  const rng = @import("../common/rng.zig");
6
-
7
- const gen1 = @import("../gen1/data.zig");
8
-
9
- const data = @import("data.zig");
6
+ const std = @import("std");
10
7
 
11
8
  const assert = std.debug.assert;
12
-
13
9
  const Choice = common.Choice;
14
-
15
- const showdown = options.showdown;
16
-
17
- const PSRNG = rng.PSRNG;
18
-
19
10
  const DVs = data.DVs;
20
11
  const Item = data.Item;
21
12
  const Move = data.Move;
22
13
  const MoveSlot = data.MoveSlot;
14
+ const PSRNG = rng.PSRNG;
15
+ const showdown = options.showdown;
23
16
  const Species = data.Species;
24
17
  const Stats = data.Stats;
25
18
 
26
- const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
27
-
28
19
  pub const Options = struct {
29
20
  cleric: bool = showdown,
30
21
  };
@@ -81,7 +72,7 @@ pub fn prng(rand: *PSRNG) data.PRNG {
81
72
  var carry: u8 = 0;
82
73
  var div: u8 = 0;
83
74
 
84
- var i: u8 = 0;
75
+ var i: usize = 0;
85
76
  while (i < seed.len) {
86
77
  div = @intCast(timer >> 8);
87
78
  // This is effectively @addWithOverflow but with three operands
@@ -149,7 +140,7 @@ pub const Pokemon = struct {
149
140
  var pokemon = data.Pokemon{};
150
141
  pokemon.species = p.species;
151
142
  const species = Species.get(p.species);
152
- inline for (@field(@typeInfo(@TypeOf(pokemon.stats)), @tagName(Struct)).fields) |field| {
143
+ inline for (@typeInfo(@TypeOf(pokemon.stats)).@"struct".fields) |field| {
153
144
  const hp = comptime std.mem.eql(u8, field.name, "hp");
154
145
  const spc =
155
146
  comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
@@ -190,7 +181,7 @@ pub const Pokemon = struct {
190
181
 
191
182
  var stats: Stats(u16) = .{};
192
183
  const dvs = gen1.DVs.random(rand);
193
- inline for (@field(@typeInfo(@TypeOf(stats)), @tagName(Struct)).fields) |field| {
184
+ inline for (@typeInfo(@TypeOf(stats)).@"struct".fields) |field| {
194
185
  const hp = std.mem.eql(u8, field.name, "hp");
195
186
  const spc = std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
196
187
  @field(stats, field.name) = Stats(u16).calc(
@@ -202,7 +193,7 @@ pub const Pokemon = struct {
202
193
  );
203
194
  }
204
195
 
205
- var ms = [_]MoveSlot{.{}} ** 4;
196
+ var ms: [4]MoveSlot = @splat(.{});
206
197
  const n = if (rand.chance(u8, 1, 100)) rand.range(u4, 1, 3 + 1) else 4;
207
198
  for (0..n) |i| {
208
199
  var m: Move = .None;
@@ -1,44 +1,37 @@
1
- const std = @import("std");
2
-
3
- const pkmn = @import("../pkmn.zig");
4
-
5
- const common = @import("../common/data.zig");
6
1
  const DEBUG = @import("../common/debug.zig").print;
7
- const protocol = @import("../common/protocol.zig");
8
- const rng = @import("../common/rng.zig");
9
2
 
3
+ const builtin = @import("builtin");
4
+ const common = @import("../common/data.zig");
10
5
  const data = @import("data.zig");
11
6
  const generated = @import("generated.zig");
12
-
13
- const assert = std.debug.assert;
14
-
15
- const expectEqual = std.testing.expectEqual;
16
- const expectEqualSlices = std.testing.expectEqualSlices;
17
- const expectEqualStrings = std.testing.expectEqualStrings;
18
-
19
- const showdown = pkmn.options.showdown;
20
-
21
- const Choice = common.Choice;
22
- const ID = common.ID;
23
- const Player = common.Player;
24
- const Result = common.Result;
7
+ const pkmn = @import("../pkmn.zig");
8
+ const protocol = @import("../common/protocol.zig");
9
+ const rng = @import("../common/rng.zig");
10
+ const std = @import("std");
25
11
 
26
12
  const Activate = protocol.Activate;
13
+ const ActivePokemon = data.ActivePokemon;
14
+ const assert = std.debug.assert;
27
15
  const Boost = protocol.Boost;
16
+ const Boosts = data.Boosts;
17
+ const Choice = common.Choice;
28
18
  const Damage = protocol.Damage;
19
+ const Effectiveness = data.Effectiveness;
29
20
  const End = protocol.End;
21
+ const expectEqual = std.testing.expectEqual;
22
+ const expectEqualSlices = std.testing.expectEqualSlices;
23
+ const expectEqualStrings = std.testing.expectEqualStrings;
30
24
  const Fail = protocol.Fail;
31
- const Heal = protocol.Heal;
32
- const Start = protocol.Start;
33
-
34
25
  const Gen12 = rng.Gen12;
35
-
36
- const ActivePokemon = data.ActivePokemon;
37
- const Boosts = data.Boosts;
38
- const Effectiveness = data.Effectiveness;
26
+ const Heal = protocol.Heal;
27
+ const ID = common.ID;
39
28
  const Item = data.Item;
40
29
  const Move = data.Move;
30
+ const Player = common.Player;
31
+ const Result = common.Result;
32
+ const showdown = pkmn.options.showdown;
41
33
  const Side = data.Side;
34
+ const Start = protocol.Start;
42
35
  const Stats = data.Stats;
43
36
  const Status = data.Status;
44
37
  const TriAttack = data.TriAttack;
@@ -689,7 +682,7 @@ pub fn adjustDamage(battle: anytype, player: Player, state: *State, _: anytype)
689
682
 
690
683
  // Type effectiveness matchup precedence only matters with (NVE, SE)
691
684
  if (!showdown and (eff1 + eff2) == Effectiveness.mismatch and
692
- types.type1.precedence() > types.type2.precedence())
685
+ Type.precedence(state.type, types.type1) > Type.precedence(state.type, types.type2))
693
686
  {
694
687
  assert(eff2 != neutral);
695
688
  d = d *% eff2 / 10;
@@ -1200,7 +1193,7 @@ fn updateSideCondition(
1200
1193
  fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result {
1201
1194
  battle.turn += 1;
1202
1195
 
1203
- if (showdown and battle.turn >= 1000) {
1196
+ if (pkmn.options.mod and battle.turn >= 1000) {
1204
1197
  try options.log.tie(.{});
1205
1198
  return Result.Tie;
1206
1199
  } else if (battle.turn >= 65535) {
@@ -1434,7 +1427,8 @@ pub const Effects = struct {
1434
1427
  if (move.type.special() != (last == .MirrorCoat)) return;
1435
1428
  if (state.damage == 0) return;
1436
1429
 
1437
- state.damage *|= 2;
1430
+ // NOTE: llvm/llvm-project#58557
1431
+ state.damage = smul(state.damage, 2);
1438
1432
  state.miss = false;
1439
1433
  }
1440
1434
 
@@ -1529,15 +1523,18 @@ pub const Effects = struct {
1529
1523
 
1530
1524
  pub const double = struct {
1531
1525
  pub fn flying(battle: anytype, player: Player, state: *State, _: anytype) !void {
1532
- if (battle.foe(player).active.volatiles.Flying) state.damage *|= 2;
1526
+ if (!battle.foe(player).active.volatiles.Flying) return;
1527
+ state.damage = smul(state.damage, 2);
1533
1528
  }
1534
1529
 
1535
1530
  pub fn underground(battle: anytype, player: Player, state: *State, _: anytype) !void {
1536
- if (battle.foe(player).active.volatiles.Underground) state.damage *|= 2;
1531
+ if (!battle.foe(player).active.volatiles.Underground) return;
1532
+ state.damage = smul(state.damage, 2);
1537
1533
  }
1538
1534
 
1539
1535
  pub fn minimize(battle: anytype, player: Player, state: *State, _: anytype) !void {
1540
- if (battle.foe(player).active.volatiles.minimized) state.damage *|= 2;
1536
+ if (!battle.foe(player).active.volatiles.minimized) return;
1537
+ state.damage = smul(state.damage, 2);
1541
1538
  }
1542
1539
  };
1543
1540
 
@@ -1561,7 +1558,7 @@ pub const Effects = struct {
1561
1558
  const last = battle.foe(player).lastMove(true);
1562
1559
  const failed = volatiles.Encore or
1563
1560
  (last == .None or last == .Struggle or
1564
- last == .Encore or .last == .MirrorMove);
1561
+ last == .Encore or .last == .MirrorMove);
1565
1562
  if (failed) return options.log.fail(.{ foe_ident, .None });
1566
1563
 
1567
1564
  var slot: u3 = 0;
@@ -1706,7 +1703,7 @@ pub const Effects = struct {
1706
1703
  if (!state.proc) return;
1707
1704
  if (foe.conditions.Safeguard) return;
1708
1705
  // Freeze Clause Mod
1709
- if (showdown) for (foe.pokemon) |p| if (Status.is(p.status, .FRZ)) return;
1706
+ if (pkmn.options.mod) for (foe.pokemon) |p| if (Status.is(p.status, .FRZ)) return;
1710
1707
 
1711
1708
  foe_stored.status = Status.init(.FRZ);
1712
1709
  try options.log.status(.{ foe_ident, foe_stored.status, .None });
@@ -1735,7 +1732,7 @@ pub const Effects = struct {
1735
1732
  state.bp *= 2;
1736
1733
  assert(state.bp <= 160);
1737
1734
  } else {
1738
- state.damage *|= 2;
1735
+ state.damage = smul(state.damage, 2);
1739
1736
  }
1740
1737
  }
1741
1738
 
@@ -2206,7 +2203,7 @@ pub const Effects = struct {
2206
2203
 
2207
2204
  pub fn pursuit(battle: anytype, player: Player, state: *State, _: anytype) !void {
2208
2205
  // TODO: remove switching variable and just look at Choice saved in Battle struct?
2209
- if (battle.foe(player).active.volatiles.switching) state.damage *|= 2;
2206
+ if (battle.foe(player).active.volatiles.switching) state.damage = smul(state.damage, 2);
2210
2207
  }
2211
2208
 
2212
2209
  pub const rage = struct {
@@ -2219,7 +2216,7 @@ pub const Effects = struct {
2219
2216
  const side = battle.side(player);
2220
2217
 
2221
2218
  assert(side.active.volatiles.Rage);
2222
- state.damage *|= (side.active.volatiles.rage +| 1);
2219
+ state.damage = smul(state.damage, (side.active.volatiles.rage +| 1)); // TODO: |+
2223
2220
  }
2224
2221
  };
2225
2222
 
@@ -2314,7 +2311,7 @@ pub const Effects = struct {
2314
2311
  side.active.volatiles.attacks += 1;
2315
2312
  side.active.volatiles.Rollout = side.active.volatiles.attacks != 5;
2316
2313
 
2317
- if (side.active.volatiles.DefenseCurl) state.damage *|= 2;
2314
+ if (side.active.volatiles.DefenseCurl) state.damage = smul(state.damage, 2);
2318
2315
  }
2319
2316
  };
2320
2317
 
@@ -2384,7 +2381,7 @@ pub const Effects = struct {
2384
2381
  }
2385
2382
 
2386
2383
  // Sleep Clause Mod
2387
- if (showdown) {
2384
+ if (pkmn.options.mod) {
2388
2385
  for (foe.pokemon) |p| {
2389
2386
  if (Status.is(p.status, .SLP) and !Status.is(p.status, .EXT)) return;
2390
2387
  }
@@ -2842,6 +2839,12 @@ fn convertible(active: ActivePokemon, m: Move) bool {
2842
2839
  return t != .@"???" and !active.types.includes(t);
2843
2840
  }
2844
2841
 
2842
+ // NOTE: llvm/llvm-project#58557
2843
+ fn smul(a: anytype, b: @TypeOf(a)) @TypeOf(a) {
2844
+ if (!comptime builtin.target.cpu.arch.isWasm()) return a *| b;
2845
+ return @max(a *% b, std.math.maxInt(@TypeOf(a)));
2846
+ }
2847
+
2845
2848
  pub const Rolls = struct {
2846
2849
  fn speedTie(battle: anytype, options: anytype) !bool {
2847
2850
  const p1 = if (options.calc.overridden(.P1, 0, .speed_tie)) |player|
@@ -3078,7 +3081,7 @@ pub const Rolls = struct {
3078
3081
  }
3079
3082
 
3080
3083
  // Conversion 2 can at most choose between 7 types (vs. a Grass-type attack)
3081
- var CONVERSION_2: [7]Type = [_]Type{.@"???"} ** 7;
3084
+ var CONVERSION_2: [7]Type = @splat(.@"???");
3082
3085
 
3083
3086
  fn conversion2(battle: anytype, player: Player, mtype: Type, options: anytype) !Type {
3084
3087
  var i: u8 = 0;
@@ -3503,11 +3506,11 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3503
3506
  },
3504
3507
  .Switch => {
3505
3508
  const side = battle.side(player);
3506
- var slot: u4 = 2;
3509
+ var slot: usize = 2;
3507
3510
  while (slot <= 6) : (slot += 1) {
3508
3511
  const id = side.order[slot - 1];
3509
3512
  if (id == 0 or side.pokemon[id - 1].hp == 0) continue;
3510
- out[n] = .{ .type = .Switch, .data = slot };
3513
+ out[n] = .{ .type = .Switch, .data = @intCast(slot) };
3511
3514
  n += 1;
3512
3515
  }
3513
3516
  if (n == 0) {
@@ -3537,11 +3540,11 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3537
3540
  return n;
3538
3541
  }
3539
3542
 
3540
- var slot: u4 = 2;
3543
+ var slot: usize = 2;
3541
3544
  while (!active.volatiles.Trapped and slot <= 6) : (slot += 1) {
3542
3545
  const id = side.order[slot - 1];
3543
3546
  if (id == 0 or side.pokemon[id - 1].hp == 0) continue;
3544
- out[n] = .{ .type = .Switch, .data = slot };
3547
+ out[n] = .{ .type = .Switch, .data = @intCast(slot) };
3545
3548
  n += 1;
3546
3549
  }
3547
3550
 
@@ -3574,7 +3577,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3574
3577
  const struggle =
3575
3578
  m.id == .Bide and (m.pp == 0 or active.volatiles.disable.move == slot);
3576
3579
  const s = if (struggle) 0 else slot;
3577
- out[n] = .{ .type = .Move, .data = s };
3580
+ out[n] = .{ .type = .Move, .data = @intCast(s) };
3578
3581
  n += 1;
3579
3582
  return n;
3580
3583
  }
@@ -3588,7 +3591,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3588
3591
  if (m.id == .None) break;
3589
3592
  if (m.pp == 0) continue;
3590
3593
  if (active.volatiles.disable.move == slot) continue;
3591
- out[n] = .{ .type = .Move, .data = slot };
3594
+ out[n] = .{ .type = .Move, .data = @intCast(slot) };
3592
3595
  n += 1;
3593
3596
  }
3594
3597
  // 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>