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

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 +54 -6
  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 +25 -3
  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 +52 -76
  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 +331 -85
  39. package/package.json +56 -136
  40. package/src/bin/install-pkmn-engine +10 -7
  41. package/src/bin/pkmn-debug +1 -1
  42. package/src/lib/bindings/c.zig +255 -0
  43. package/src/lib/bindings/node.zig +117 -0
  44. package/src/lib/bindings/wasm.zig +59 -0
  45. package/src/lib/common/array.zig +77 -0
  46. package/src/lib/common/data.zig +8 -8
  47. package/src/lib/common/debug.zig +39 -8
  48. package/src/lib/common/js.zig +4 -6
  49. package/src/lib/common/napi.zig +4 -0
  50. package/src/lib/common/optional.zig +13 -9
  51. package/src/lib/common/options.zig +4 -0
  52. package/src/lib/common/protocol.zig +44 -43
  53. package/src/lib/common/rational.zig +317 -304
  54. package/src/lib/common/rng.zig +5 -7
  55. package/src/lib/common/util.zig +65 -1
  56. package/src/lib/gen1/calc.zig +266 -135
  57. package/src/lib/gen1/chance.zig +469 -110
  58. package/src/lib/gen1/data/moves.zig +2 -4
  59. package/src/lib/gen1/data/species.zig +1 -3
  60. package/src/lib/gen1/data/types.zig +2 -3
  61. package/src/lib/gen1/data.zig +35 -38
  62. package/src/lib/gen1/helpers.zig +17 -27
  63. package/src/lib/gen1/mechanics.zig +213 -160
  64. package/src/lib/gen2/calc.zig +37 -27
  65. package/src/lib/gen2/chance.zig +87 -67
  66. package/src/lib/gen2/data/items.zig +1 -3
  67. package/src/lib/gen2/data/moves.zig +2 -4
  68. package/src/lib/gen2/data/species.zig +1 -3
  69. package/src/lib/gen2/data/types.zig +7 -5
  70. package/src/lib/gen2/data.zig +28 -30
  71. package/src/lib/gen2/generated.zig +18 -23
  72. package/src/lib/gen2/helpers.zig +9 -18
  73. package/src/lib/gen2/mechanics.zig +82 -82
  74. package/src/lib/node.zig +4 -121
  75. package/src/lib/pkmn.zig +14 -7
  76. package/src/lib/wasm.zig +13 -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,50 +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
- const util = @import("../common/util.zig");
10
2
 
3
+ const builtin = @import("builtin");
4
+ const common = @import("../common/data.zig");
11
5
  const data = @import("data.zig");
12
6
  const generated = @import("generated.zig");
13
-
14
- const assert = std.debug.assert;
15
-
16
- const expectEqual = std.testing.expectEqual;
17
- const expectEqualSlices = std.testing.expectEqualSlices;
18
- const expectEqualStrings = std.testing.expectEqualStrings;
19
-
20
- const showdown = pkmn.options.showdown;
21
-
22
- const Choice = common.Choice;
23
- const ID = common.ID;
24
- const Player = common.Player;
25
- 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");
26
11
 
27
12
  const Activate = protocol.Activate;
13
+ const ActivePokemon = data.ActivePokemon;
14
+ const assert = std.debug.assert;
28
15
  const Boost = protocol.Boost;
16
+ const Boosts = data.Boosts;
17
+ const Choice = common.Choice;
29
18
  const Damage = protocol.Damage;
19
+ const Effectiveness = data.Effectiveness;
30
20
  const End = protocol.End;
21
+ const expectEqual = std.testing.expectEqual;
22
+ const expectEqualSlices = std.testing.expectEqualSlices;
23
+ const expectEqualStrings = std.testing.expectEqualStrings;
31
24
  const Fail = protocol.Fail;
32
- const Heal = protocol.Heal;
33
- const Start = protocol.Start;
34
-
35
25
  const Gen12 = rng.Gen12;
36
-
37
- const PointerType = util.PointerType;
38
-
39
- const ActivePokemon = data.ActivePokemon;
40
- const Boosts = data.Boosts;
41
- const Effectiveness = data.Effectiveness;
26
+ const Heal = protocol.Heal;
27
+ const ID = common.ID;
42
28
  const Item = data.Item;
43
29
  const Move = data.Move;
44
- const MoveSlot = data.MoveSlot;
45
- const Pokemon = data.Pokemon;
30
+ const Player = common.Player;
31
+ const Result = common.Result;
32
+ const showdown = pkmn.options.showdown;
46
33
  const Side = data.Side;
47
- const Species = data.Species;
34
+ const Start = protocol.Start;
48
35
  const Stats = data.Stats;
49
36
  const Status = data.Status;
50
37
  const TriAttack = data.TriAttack;
@@ -106,6 +93,7 @@ pub const State = struct {
106
93
  type: Type, // BATTLE_VARS_MOVE_TYPE
107
94
  accuracy: u8, // wEnemyMoveStruct + MOVE_ACC
108
95
  move: Move, // wCurPlayerMove
96
+ hit: u3 = 0,
109
97
  from: Move = .None,
110
98
  mslot: u4, // wCurMoveNum
111
99
  first: bool, // wEnemyGoesFirst
@@ -644,7 +632,7 @@ pub fn checkCriticalHit(battle: anytype, player: Player, state: *State, options:
644
632
  }
645
633
  assert(stage <= 4);
646
634
 
647
- state.crit = try Rolls.criticalHit(battle, player, CRITICAL_HITS[stage], options);
635
+ state.crit = try Rolls.criticalHit(battle, player, state.hit, CRITICAL_HITS[stage], options);
648
636
  }
649
637
 
650
638
  pub fn calcDamage(
@@ -694,7 +682,7 @@ pub fn adjustDamage(battle: anytype, player: Player, state: *State, _: anytype)
694
682
 
695
683
  // Type effectiveness matchup precedence only matters with (NVE, SE)
696
684
  if (!showdown and (eff1 + eff2) == Effectiveness.mismatch and
697
- types.type1.precedence() > types.type2.precedence())
685
+ Type.precedence(state.type, types.type1) > Type.precedence(state.type, types.type2))
698
686
  {
699
687
  assert(eff2 != neutral);
700
688
  d = d *% eff2 / 10;
@@ -712,7 +700,7 @@ pub fn adjustDamage(battle: anytype, player: Player, state: *State, _: anytype)
712
700
 
713
701
  pub fn randomizeDamage(battle: anytype, player: Player, state: *State, options: anytype) !void {
714
702
  if (state.damage <= 1) return;
715
- const random = try Rolls.damage(battle, player, options);
703
+ const random = try Rolls.damage(battle, player, state.hit, options);
716
704
  options.calc.base(player.foe(), state.damage);
717
705
  state.damage = @intCast(@as(u32, state.damage) *% random / 255);
718
706
  options.calc.final(player.foe(), state.damage);
@@ -1205,7 +1193,7 @@ fn updateSideCondition(
1205
1193
  fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result {
1206
1194
  battle.turn += 1;
1207
1195
 
1208
- if (showdown and battle.turn >= 1000) {
1196
+ if (pkmn.options.mod and battle.turn >= 1000) {
1209
1197
  try options.log.tie(.{});
1210
1198
  return Result.Tie;
1211
1199
  } else if (battle.turn >= 65535) {
@@ -1439,7 +1427,8 @@ pub const Effects = struct {
1439
1427
  if (move.type.special() != (last == .MirrorCoat)) return;
1440
1428
  if (state.damage == 0) return;
1441
1429
 
1442
- state.damage *|= 2;
1430
+ // NOTE: llvm/llvm-project#58557
1431
+ state.damage = smul(state.damage, 2);
1443
1432
  state.miss = false;
1444
1433
  }
1445
1434
 
@@ -1534,15 +1523,18 @@ pub const Effects = struct {
1534
1523
 
1535
1524
  pub const double = struct {
1536
1525
  pub fn flying(battle: anytype, player: Player, state: *State, _: anytype) !void {
1537
- 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);
1538
1528
  }
1539
1529
 
1540
1530
  pub fn underground(battle: anytype, player: Player, state: *State, _: anytype) !void {
1541
- 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);
1542
1533
  }
1543
1534
 
1544
1535
  pub fn minimize(battle: anytype, player: Player, state: *State, _: anytype) !void {
1545
- 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);
1546
1538
  }
1547
1539
  };
1548
1540
 
@@ -1711,7 +1703,7 @@ pub const Effects = struct {
1711
1703
  if (!state.proc) return;
1712
1704
  if (foe.conditions.Safeguard) return;
1713
1705
  // Freeze Clause Mod
1714
- 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;
1715
1707
 
1716
1708
  foe_stored.status = Status.init(.FRZ);
1717
1709
  try options.log.status(.{ foe_ident, foe_stored.status, .None });
@@ -1740,7 +1732,7 @@ pub const Effects = struct {
1740
1732
  state.bp *= 2;
1741
1733
  assert(state.bp <= 160);
1742
1734
  } else {
1743
- state.damage *|= 2;
1735
+ state.damage = smul(state.damage, 2);
1744
1736
  }
1745
1737
  }
1746
1738
 
@@ -2211,7 +2203,7 @@ pub const Effects = struct {
2211
2203
 
2212
2204
  pub fn pursuit(battle: anytype, player: Player, state: *State, _: anytype) !void {
2213
2205
  // TODO: remove switching variable and just look at Choice saved in Battle struct?
2214
- if (battle.foe(player).active.volatiles.switching) state.damage *|= 2;
2206
+ if (battle.foe(player).active.volatiles.switching) state.damage = smul(state.damage, 2);
2215
2207
  }
2216
2208
 
2217
2209
  pub const rage = struct {
@@ -2224,7 +2216,7 @@ pub const Effects = struct {
2224
2216
  const side = battle.side(player);
2225
2217
 
2226
2218
  assert(side.active.volatiles.Rage);
2227
- state.damage *|= (side.active.volatiles.rage +| 1);
2219
+ state.damage = smul(state.damage, (side.active.volatiles.rage +| 1)); // TODO: |+
2228
2220
  }
2229
2221
  };
2230
2222
 
@@ -2319,7 +2311,7 @@ pub const Effects = struct {
2319
2311
  side.active.volatiles.attacks += 1;
2320
2312
  side.active.volatiles.Rollout = side.active.volatiles.attacks != 5;
2321
2313
 
2322
- if (side.active.volatiles.DefenseCurl) state.damage *|= 2;
2314
+ if (side.active.volatiles.DefenseCurl) state.damage = smul(state.damage, 2);
2323
2315
  }
2324
2316
  };
2325
2317
 
@@ -2389,7 +2381,7 @@ pub const Effects = struct {
2389
2381
  }
2390
2382
 
2391
2383
  // Sleep Clause Mod
2392
- if (showdown) {
2384
+ if (pkmn.options.mod) {
2393
2385
  for (foe.pokemon) |p| {
2394
2386
  if (Status.is(p.status, .SLP) and !Status.is(p.status, .EXT)) return;
2395
2387
  }
@@ -2847,9 +2839,15 @@ fn convertible(active: ActivePokemon, m: Move) bool {
2847
2839
  return t != .@"???" and !active.types.includes(t);
2848
2840
  }
2849
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
+
2850
2848
  pub const Rolls = struct {
2851
2849
  fn speedTie(battle: anytype, options: anytype) !bool {
2852
- const p1 = if (options.calc.overridden(.P1, .speed_tie)) |player|
2850
+ const p1 = if (options.calc.overridden(.P1, 0, .speed_tie)) |player|
2853
2851
  player == .P1
2854
2852
  else if (showdown)
2855
2853
  battle.rng.range(u8, 0, 2) == 0
@@ -2861,7 +2859,7 @@ pub const Rolls = struct {
2861
2859
  }
2862
2860
 
2863
2861
  fn quickClaw(battle: anytype, player: Player, options: anytype) !bool {
2864
- const qkc = if (options.calc.overridden(player, .quick_claw)) |val|
2862
+ const qkc = if (options.calc.overridden(player, 0, .quick_claw)) |val|
2865
2863
  val == .true
2866
2864
  else if (showdown)
2867
2865
  battle.rng.chance(u8, 60, 256)
@@ -2873,7 +2871,7 @@ pub const Rolls = struct {
2873
2871
  }
2874
2872
 
2875
2873
  fn hit(battle: anytype, player: Player, accuracy: u8, options: anytype) !bool {
2876
- const ok = if (options.calc.overridden(player, .hit)) |val|
2874
+ const ok = if (options.calc.overridden(player, 0, .hit)) |val|
2877
2875
  val == .true
2878
2876
  else if (showdown)
2879
2877
  battle.rng.chance(u8, accuracy, 256)
@@ -2884,20 +2882,22 @@ pub const Rolls = struct {
2884
2882
  return ok;
2885
2883
  }
2886
2884
 
2887
- fn criticalHit(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
2888
- const crit = if (options.calc.overridden(player, .critical_hit)) |val|
2885
+ fn criticalHit(battle: anytype, player: Player, i: u3, rate: u8, options: anytype) !bool {
2886
+ _ = .{ player, options };
2887
+ const crit = if (options.calc.overridden(player, i, .critical_hits)) |val|
2889
2888
  val == .true
2890
2889
  else if (showdown)
2891
2890
  battle.rng.chance(u8, rate, 256)
2892
2891
  else
2893
2892
  battle.rng.next() < rate;
2894
2893
 
2895
- try options.chance.criticalHit(player, crit, rate);
2894
+ try options.chance.criticalHit(player, i, crit, rate);
2896
2895
  return crit;
2897
2896
  }
2898
2897
 
2899
- fn damage(battle: anytype, player: Player, options: anytype) !u8 {
2900
- const roll = if (options.calc.overridden(player, .damage)) |val|
2898
+ fn damage(battle: anytype, player: Player, i: u3, options: anytype) !u8 {
2899
+ _ = .{ player, options };
2900
+ const roll = if (options.calc.overridden(player, i, .damages)) |val|
2901
2901
  val
2902
2902
  else roll: {
2903
2903
  if (showdown) break :roll battle.rng.range(u8, 217, 256);
@@ -2908,12 +2908,12 @@ pub const Rolls = struct {
2908
2908
  };
2909
2909
 
2910
2910
  assert(roll >= 217 and roll <= 255);
2911
- try options.chance.damage(player, roll);
2911
+ try options.chance.damage(player, i, roll);
2912
2912
  return roll;
2913
2913
  }
2914
2914
 
2915
2915
  fn confused(battle: anytype, player: Player, options: anytype) !bool {
2916
- const cfz = if (options.calc.overridden(player, .confused)) |val|
2916
+ const cfz = if (options.calc.overridden(player, 0, .confused)) |val|
2917
2917
  val == .true
2918
2918
  else if (showdown)
2919
2919
  !battle.rng.chance(u8, 128, 256)
@@ -2925,7 +2925,7 @@ pub const Rolls = struct {
2925
2925
  }
2926
2926
 
2927
2927
  fn attract(battle: anytype, player: Player, options: anytype) !bool {
2928
- const cant = if (options.calc.overridden(player, .attract)) |val|
2928
+ const cant = if (options.calc.overridden(player, 0, .attract)) |val|
2929
2929
  val == .true
2930
2930
  else if (showdown)
2931
2931
  battle.rng.chance(u8, 1, 2)
@@ -2937,7 +2937,7 @@ pub const Rolls = struct {
2937
2937
  }
2938
2938
 
2939
2939
  fn paralyzed(battle: anytype, player: Player, options: anytype) !bool {
2940
- const par = if (options.calc.overridden(player, .paralyzed)) |val|
2940
+ const par = if (options.calc.overridden(player, 0, .paralyzed)) |val|
2941
2941
  val == .true
2942
2942
  else if (showdown)
2943
2943
  battle.rng.chance(u8, 63, 256)
@@ -2949,7 +2949,7 @@ pub const Rolls = struct {
2949
2949
  }
2950
2950
 
2951
2951
  fn defrost(battle: anytype, player: Player, options: anytype) !bool {
2952
- const thaw = if (options.calc.overridden(player, .defrost)) |val|
2952
+ const thaw = if (options.calc.overridden(player, 0, .defrost)) |val|
2953
2953
  val == .true
2954
2954
  else if (showdown)
2955
2955
  battle.rng.chance(u8, 25, 256)
@@ -2962,7 +2962,7 @@ pub const Rolls = struct {
2962
2962
 
2963
2963
  fn secondaryChance(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
2964
2964
  // GLITCH: 100% secondary chance will still fail 1/256 of the time
2965
- const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
2965
+ const proc = if (options.calc.overridden(player, 0, .secondary_chance)) |val|
2966
2966
  val == .true
2967
2967
  else if (showdown)
2968
2968
  battle.rng.chance(u8, rate, 256)
@@ -2974,7 +2974,7 @@ pub const Rolls = struct {
2974
2974
  }
2975
2975
 
2976
2976
  fn item(battle: anytype, player: Player, options: anytype) !bool {
2977
- const proc = if (options.calc.overridden(player, .item)) |val|
2977
+ const proc = if (options.calc.overridden(player, 0, .item)) |val|
2978
2978
  val == .true
2979
2979
  else if (showdown)
2980
2980
  battle.rng.chance(u8, 30, 256)
@@ -2986,7 +2986,7 @@ pub const Rolls = struct {
2986
2986
  }
2987
2987
 
2988
2988
  fn triAttack(battle: anytype, player: Player, options: anytype) !TriAttack {
2989
- const status: TriAttack = if (options.calc.overridden(player, .tri_attack)) |val|
2989
+ const status: TriAttack = if (options.calc.overridden(player, 0, .tri_attack)) |val|
2990
2990
  @enumFromInt(@intFromEnum(val) - 1)
2991
2991
  else if (showdown)
2992
2992
  @enumFromInt(battle.rng.range(u2, 0, 2))
@@ -3002,7 +3002,7 @@ pub const Rolls = struct {
3002
3002
  }
3003
3003
 
3004
3004
  fn present(battle: anytype, player: Player, options: anytype) !u8 {
3005
- const power = if (options.calc.overridden(player, .present)) |val|
3005
+ const power = if (options.calc.overridden(player, 0, .present)) |val|
3006
3006
  (val - 1) * 40
3007
3007
  else if (showdown) power: {
3008
3008
  const r = battle.rng.range(u8, 0, 10);
@@ -3024,7 +3024,7 @@ pub const Rolls = struct {
3024
3024
  }
3025
3025
 
3026
3026
  fn magnitude(battle: anytype, player: Player, options: anytype) !u8 {
3027
- const num: u8 = if (options.calc.overridden(player, .magnitude)) |val|
3027
+ const num: u8 = if (options.calc.overridden(player, 0, .magnitude)) |val|
3028
3028
  val + 3
3029
3029
  else if (showdown) num: {
3030
3030
  const r = battle.rng.range(u8, 0, 100);
@@ -3052,7 +3052,7 @@ pub const Rolls = struct {
3052
3052
  }
3053
3053
 
3054
3054
  fn tripleKick(battle: anytype, player: Player, options: anytype) !u2 {
3055
- const hits = if (options.calc.overridden(player, .triple_kick)) |val|
3055
+ const hits = if (options.calc.overridden(player, 0, .triple_kick)) |val|
3056
3056
  val
3057
3057
  else if (showdown)
3058
3058
  battle.rng.range(u2, 1, 4)
@@ -3070,7 +3070,7 @@ pub const Rolls = struct {
3070
3070
 
3071
3071
  fn spite(battle: anytype, player: Player, options: anytype) !u3 {
3072
3072
  assert(!showdown);
3073
- const pp: u3 = if (options.calc.overridden(player, .spite)) |val|
3073
+ const pp: u3 = if (options.calc.overridden(player, 0, .spite)) |val|
3074
3074
  val + 1
3075
3075
  else
3076
3076
  @intCast((battle.rng.next() & 3) + 2);
@@ -3087,7 +3087,7 @@ pub const Rolls = struct {
3087
3087
  var i: u8 = 0;
3088
3088
  const neutral = @intFromEnum(Effectiveness.Neutral);
3089
3089
  assert(mtype != .@"???");
3090
- const ty: Type = if (options.calc.overridden(player, .conversion_2)) |val|
3090
+ const ty: Type = if (options.calc.overridden(player, 0, .conversion_2)) |val|
3091
3091
  @enumFromInt(@intFromEnum(val) - 1)
3092
3092
  else if (showdown) ty: {
3093
3093
  for (Type.SHOWDOWN) |t| {
@@ -3121,7 +3121,7 @@ pub const Rolls = struct {
3121
3121
  assert(count <= 8);
3122
3122
  const num = if (count == 8) 0 else @as(u8, 255) >> @intCast(count);
3123
3123
 
3124
- const ok = if (options.calc.overridden(player, .protect)) |val|
3124
+ const ok = if (options.calc.overridden(player, 0, .protect)) |val|
3125
3125
  val == .true
3126
3126
  else if (showdown)
3127
3127
  battle.rng.chance(u8, num, 255)
@@ -3143,7 +3143,7 @@ pub const Rolls = struct {
3143
3143
  const moves = active.moves;
3144
3144
 
3145
3145
  // TODO: consider throwing error instead of rerolling?
3146
- const overridden = if (options.calc.overridden(player, .move_slot)) |val|
3146
+ const overridden = if (options.calc.overridden(player, 0, .move_slot)) |val|
3147
3147
  if (convertible(active, moves[val - 1].id)) val else null
3148
3148
  else
3149
3149
  null;
@@ -3180,7 +3180,7 @@ pub const Rolls = struct {
3180
3180
  const moves = active.moves;
3181
3181
 
3182
3182
  // TODO: consider throwing error instead of rerolling?
3183
- const overridden = if (options.calc.overridden(player, .move_slot)) |val|
3183
+ const overridden = if (options.calc.overridden(player, 0, .move_slot)) |val|
3184
3184
  if (val != mslot and Move.get(moves[val - 1].id).extra.sleep_talk) val else null
3185
3185
  else
3186
3186
  null;
@@ -3224,7 +3224,7 @@ pub const Rolls = struct {
3224
3224
  assert(n > 0 and n <= 6);
3225
3225
 
3226
3226
  // TODO: consider throwing error instead of rerolling?
3227
- const overridden = if (options.calc.overridden(player, .force_switch)) |val| val: {
3227
+ const overridden = if (options.calc.overridden(player, 0, .force_switch)) |val| val: {
3228
3228
  for (slots) |slot| if (slot == val) break :val if (foe.get(slot).hp > 0) val else null;
3229
3229
  break :val null;
3230
3230
  } else null;
@@ -3250,7 +3250,7 @@ pub const Rolls = struct {
3250
3250
  const DISTRIBUTION = [_]u3{ 2, 2, 2, 3, 3, 3, 4, 5 };
3251
3251
 
3252
3252
  fn multiHit(battle: anytype, player: Player, options: anytype) !u3 {
3253
- const n: u3 = if (options.calc.overridden(player, .multi_hit)) |val|
3253
+ const n: u3 = if (options.calc.overridden(player, 0, .multi_hit)) |val|
3254
3254
  @intCast(val)
3255
3255
  else if (showdown)
3256
3256
  DISTRIBUTION[battle.rng.range(u3, 0, DISTRIBUTION.len)]
@@ -3265,7 +3265,7 @@ pub const Rolls = struct {
3265
3265
  }
3266
3266
 
3267
3267
  fn psywave(battle: anytype, player: Player, max: u8, options: anytype) !u8 {
3268
- const power = if (options.calc.overridden(player, .psywave)) |val|
3268
+ const power = if (options.calc.overridden(player, 0, .psywave)) |val|
3269
3269
  val
3270
3270
  else if (showdown)
3271
3271
  battle.rng.range(u8, 1, max)
@@ -3291,7 +3291,7 @@ pub const Rolls = struct {
3291
3291
  }
3292
3292
 
3293
3293
  // TODO: consider throwing error instead of rerolling?
3294
- const overridden = if (options.calc.overridden(player, .metronome)) |val| val: {
3294
+ const overridden = if (options.calc.overridden(player, 0, .metronome)) |val| val: {
3295
3295
  for (moves) |m| if (m.id == val) break :val null;
3296
3296
  break :val val;
3297
3297
  } else null;
@@ -3323,7 +3323,7 @@ pub const Rolls = struct {
3323
3323
  }
3324
3324
 
3325
3325
  fn sleepDuration(battle: anytype, player: Player, options: anytype) u3 {
3326
- const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
3326
+ const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
3327
3327
  @intCast(val)
3328
3328
  else if (showdown)
3329
3329
  battle.rng.range(u3, 1, 7)
@@ -3340,7 +3340,7 @@ pub const Rolls = struct {
3340
3340
  }
3341
3341
 
3342
3342
  fn confusionDuration(battle: anytype, player: Player, self: bool, options: anytype) u3 {
3343
- const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
3343
+ const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
3344
3344
  @intCast(val)
3345
3345
  else if (showdown)
3346
3346
  // Pokémon Showdown incorrectly uses the same duration for self-confusion
@@ -3354,11 +3354,11 @@ pub const Rolls = struct {
3354
3354
  }
3355
3355
 
3356
3356
  fn disableDuration(battle: anytype, player: Player, options: anytype) u4 {
3357
- const duration: u4 = if (options.calc.overridden(player, .duration)) |val|
3357
+ const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
3358
3358
  @intCast(val)
3359
3359
  else if (showdown)
3360
3360
  // Pokémon Showdown incorrectly inherits Generation III's Disable duration
3361
- battle.rng.range(u4, 2, 6)
3361
+ battle.rng.range(u3, 2, 6)
3362
3362
  else duration: {
3363
3363
  while (true) {
3364
3364
  const r = battle.rng.next() & 7;
@@ -3372,7 +3372,7 @@ pub const Rolls = struct {
3372
3372
  }
3373
3373
 
3374
3374
  fn attackingDuration(battle: anytype, player: Player, options: anytype) u3 {
3375
- const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
3375
+ const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
3376
3376
  @intCast(val)
3377
3377
  else if (showdown)
3378
3378
  battle.rng.range(u3, 2, 4)
@@ -3385,7 +3385,7 @@ pub const Rolls = struct {
3385
3385
  }
3386
3386
 
3387
3387
  fn bindingDuration(battle: anytype, player: Player, options: anytype) u3 {
3388
- const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
3388
+ const duration: u3 = (if (options.calc.overridden(player, 0, .duration)) |val|
3389
3389
  @intCast(val)
3390
3390
  else if (showdown)
3391
3391
  // TODO: PS does range(3, 6) here which after subtracting 1 is actually 2-4 not 2-5!
@@ -3400,7 +3400,7 @@ pub const Rolls = struct {
3400
3400
 
3401
3401
  // TODO: consider sharing implementation with bindingDuration
3402
3402
  fn encoreDuration(battle: anytype, player: Player, options: anytype) u3 {
3403
- const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
3403
+ const duration: u3 = (if (options.calc.overridden(player, 0, .duration)) |val|
3404
3404
  @intCast(val)
3405
3405
  else if (showdown)
3406
3406
  battle.rng.range(u3, 2, 6)
package/src/lib/node.zig CHANGED
@@ -1,131 +1,14 @@
1
- const std = @import("std");
2
-
3
- const pkmn = @import("pkmn.zig");
4
-
1
+ const c = @import("common/napi.zig");
5
2
  const js = @import("common/js.zig");
3
+ const node = @import("bindings/node.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
7
 
9
- const c = @cImport({
10
- @cDefine("NAPI_VERSION", "8");
11
- @cInclude("node_api.h");
12
- });
13
-
14
8
  export fn napi_register_module_v1(env: c.napi_env, exports: c.napi_value) c.napi_value {
15
9
  const properties = [_]c.napi_property_descriptor{
16
- js.Property.init("engine", .{ .value = register(env) }),
10
+ js.Property.init("engine", .{ .value = node.register(env) }),
17
11
  };
18
12
  assert(c.napi_define_properties(env, exports, properties.len, &properties) == c.napi_ok);
19
13
  return exports;
20
14
  }
21
-
22
- pub fn register(env: c.napi_env) c.napi_value {
23
- const object = js.Object.init(env);
24
- const properties = [_]c.napi_property_descriptor{
25
- js.Property.init("options", .{ .value = options(env) }),
26
- js.Property.init("bindings", .{ .value = bindings(env) }),
27
- };
28
- assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
29
- return object;
30
- }
31
-
32
- fn options(env: c.napi_env) c.napi_value {
33
- const object = js.Object.init(env);
34
- const properties = [_]c.napi_property_descriptor{
35
- js.Property.init("showdown", .{ .value = js.Boolean.init(env, pkmn.options.showdown) }),
36
- js.Property.init("log", .{ .value = js.Boolean.init(env, pkmn.options.log) }),
37
- js.Property.init("chance", .{ .value = js.Boolean.init(env, pkmn.options.chance) }),
38
- js.Property.init("calc", .{ .value = js.Boolean.init(env, pkmn.options.calc) }),
39
- };
40
- assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
41
- return object;
42
- }
43
-
44
- fn bindings(env: c.napi_env) c.napi_value {
45
- const array = js.Array.init(env, .{ .length = 1 });
46
- js.Array.set(env, array, 0, bind(env, pkmn.gen1));
47
- return array;
48
- }
49
-
50
- fn bind(env: c.napi_env, gen: anytype) c.napi_value {
51
- const choices_size: u32 = @intCast(gen.CHOICES_SIZE);
52
- const logs_size: u32 = @intCast(gen.LOGS_SIZE);
53
- const object = js.Object.init(env);
54
- const properties = [_]c.napi_property_descriptor{
55
- js.Property.init("CHOICES_SIZE", .{ .value = js.Number.init(env, choices_size) }),
56
- js.Property.init("LOGS_SIZE", .{ .value = js.Number.init(env, logs_size) }),
57
- js.Property.init("update", .{ .method = update(gen) }),
58
- js.Property.init("choices", .{ .method = choices(gen) }),
59
- };
60
- assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
61
- return object;
62
- }
63
-
64
- fn update(gen: anytype) c.napi_callback {
65
- return struct {
66
- fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
67
- var argc: usize = 4;
68
- var argv: [4]c.napi_value = undefined;
69
- assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
70
- assert(argc == 4);
71
-
72
- var data: ?*anyopaque = undefined;
73
- var len: usize = 0;
74
- assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
75
- assert(len == @sizeOf(gen.Battle(gen.PRNG)));
76
-
77
- var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
78
- const c1: pkmn.Choice = @bitCast(js.Number.get(env, argv[1], u8));
79
- const c2: pkmn.Choice = @bitCast(js.Number.get(env, argv[2], u8));
80
-
81
- var vtype: c.napi_valuetype = undefined;
82
- assert(c.napi_typeof(env, argv[3], &vtype) == c.napi_ok);
83
- const result = switch (vtype) {
84
- c.napi_undefined, c.napi_null => battle.update(c1, c2, &gen.NULL),
85
- else => result: {
86
- assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
87
- assert(len == gen.LOGS_SIZE);
88
-
89
- const buf = @as([*]u8, @ptrCast(data.?))[0..gen.LOGS_SIZE];
90
- var stream: pkmn.protocol.ByteStream = .{ .buffer = buf };
91
- // TODO: extract out
92
- var opts = pkmn.battle.options(
93
- pkmn.protocol.FixedLog{ .writer = stream.writer() },
94
- gen.chance.NULL,
95
- gen.calc.NULL,
96
- );
97
- break :result battle.update(c1, c2, &opts);
98
- },
99
- } catch unreachable;
100
-
101
- return js.Number.init(env, @as(u8, @bitCast(result)));
102
- }
103
- }.call;
104
- }
105
-
106
- fn choices(gen: anytype) c.napi_callback {
107
- return struct {
108
- fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
109
- var argc: usize = 4;
110
- var argv: [4]c.napi_value = undefined;
111
- assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
112
- assert(argc == 4);
113
-
114
- var data: ?*anyopaque = undefined;
115
- var len: usize = 0;
116
- assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
117
- assert(len == @sizeOf(gen.Battle(gen.PRNG)));
118
-
119
- var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
120
- const player: pkmn.Player = @enumFromInt(js.Number.get(env, argv[1], u8));
121
- const request: pkmn.Choice.Type = @enumFromInt(js.Number.get(env, argv[2], u8));
122
-
123
- assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
124
- assert(len == gen.CHOICES_SIZE);
125
-
126
- const out = @as([*]pkmn.Choice, @ptrCast(data.?))[0..gen.CHOICES_SIZE];
127
- const n = battle.choices(player, request, out);
128
- return js.Number.init(env, @as(u8, @bitCast(n)));
129
- }
130
- }.call;
131
- }
package/src/lib/pkmn.zig CHANGED
@@ -22,6 +22,11 @@ pub const Choice = @import("common/data.zig").Choice;
22
22
  /// considered terminal.
23
23
  pub const Result = @import("common/data.zig").Result;
24
24
 
25
+ // TODO
26
+ pub const Array = @import("common/array.zig").Array;
27
+ // TODO
28
+ pub const Optional = @import("common/optional.zig").Optional;
29
+
25
30
  /// Pokémon Showdown's RNG (backed by a Generation V & VI RNG).
26
31
  pub const PSRNG = @import("common/rng.zig").PSRNG;
27
32
 
@@ -81,8 +86,6 @@ pub const gen1 = struct {
81
86
  pub const Calc = @import("gen1/calc.zig").Calc;
82
87
  /// Namespace for types associated with supported Generation I Pokémon damage calc features.
83
88
  pub const calc = if (options.internal) @import("gen1/calc.zig") else struct {
84
- /// TODO
85
- pub const Overrides = @import("gen1/calc.zig").Overrides;
86
89
  /// Information relevant to damage calculation that occured during a Generation I
87
90
  /// battle `update`.
88
91
  pub const Summaries = @import("gen1/calc.zig").Summaries;
@@ -93,6 +96,10 @@ pub const gen1 = struct {
93
96
  /// though damage calculator support should additionally be turned off
94
97
  /// entirely via `options.calc`.
95
98
  pub const NULL = @import("gen1/calc.zig").NULL;
99
+ /// TODO
100
+ pub const MAX_FRONTIER = @import("gen1/calc.zig").MAX_FRONTIER;
101
+ /// TODO
102
+ pub const Rolls = @import("gen1/calc.zig").Rolls;
96
103
  };
97
104
  /// Provides helpers for initializing Generation I Pokémon battles.
98
105
  pub const helpers = @import("gen1/helpers.zig");
@@ -111,7 +118,6 @@ pub const gen2 = struct {
111
118
  };
112
119
  pub const Calc = @import("gen2/calc.zig").Calc;
113
120
  pub const calc = if (options.internal) @import("gen2/calc.zig") else struct {
114
- pub const Overrides = @import("gen2/calc.zig").Overrides;
115
121
  pub const Summaries = @import("gen2/calc.zig").Summaries;
116
122
  pub const Summary = @import("gen2/calc.zig").Summary;
117
123
  pub const NULL = @import("gen2/calc.zig").NULL;
@@ -121,8 +127,9 @@ pub const gen2 = struct {
121
127
 
122
128
  // Internal APIs used by other pkmn libraries, not actually part of the public API.
123
129
  // NOTE: `pub usingnamespace struct { ... }` here results in a (false?) dependency loop
124
- pub const js = if (options.internal) @import("common/js.zig") else struct {};
130
+ pub const js = if (options.internal) @import("common/js.zig") else {};
125
131
  pub const bindings = if (options.internal) struct {
126
- pub const node = @import("node.zig");
127
- pub const wasm = @import("wasm.zig");
128
- } else struct {};
132
+ pub const c = @import("bindings/c.zig");
133
+ pub const node = @import("bindings/node.zig");
134
+ pub const wasm = @import("bindings/wasm.zig");
135
+ } else {};