@pkmn/engine 0.1.0-dev.5ea92492 → 0.1.0-dev.5fbc7aef

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 (87) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +141 -76
  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 +28 -6
  13. package/build/pkg/addon.js +42 -73
  14. package/build/pkg/addon.js.map +1 -1
  15. package/build/pkg/data/ids.json +12 -12
  16. package/build/pkg/data/layout.json +40 -5
  17. package/build/pkg/data/protocol.json +84 -13
  18. package/build/pkg/data.d.ts +27 -5
  19. package/build/pkg/data.js.map +1 -1
  20. package/build/pkg/gen1.d.ts +18 -20
  21. package/build/pkg/gen1.js +76 -51
  22. package/build/pkg/gen1.js.map +1 -1
  23. package/build/pkg/index.d.ts +57 -103
  24. package/build/pkg/index.js +23 -70
  25. package/build/pkg/index.js.map +1 -1
  26. package/build/pkg/protocol.d.ts +24 -3
  27. package/build/pkg/protocol.js +127 -104
  28. package/build/pkg/protocol.js.map +1 -1
  29. package/build/tools/debug.js +69 -74
  30. package/build/tools/debug.js.map +1 -1
  31. package/build/tools/display/debug.jsx +152 -0
  32. package/build/tools/display/debug.jsx.map +1 -0
  33. package/build/tools/display/index.js +152 -0
  34. package/build/tools/display/index.js.map +1 -0
  35. package/build/tools/display/ui.jsx +359 -0
  36. package/build/tools/display/ui.jsx.map +1 -0
  37. package/build/tools/display/util.js +33 -0
  38. package/build/tools/display/util.js.map +1 -0
  39. package/build.zig +336 -166
  40. package/package.json +71 -120
  41. package/src/bin/install-pkmn-engine +57 -26
  42. package/src/bin/pkmn-debug +1 -1
  43. package/src/lib/bindings/c.zig +200 -0
  44. package/src/lib/bindings/node.zig +117 -0
  45. package/src/lib/bindings/wasm.zig +50 -0
  46. package/src/lib/common/array.zig +70 -0
  47. package/src/lib/common/battle.zig +17 -0
  48. package/src/lib/common/data.zig +19 -31
  49. package/src/lib/common/debug.zig +51 -20
  50. package/src/lib/common/js.zig +114 -0
  51. package/src/lib/common/optional.zig +61 -0
  52. package/src/lib/common/options.zig +18 -3
  53. package/src/lib/common/protocol.zig +1050 -497
  54. package/src/lib/common/rational.zig +440 -0
  55. package/src/lib/common/rng.zig +31 -24
  56. package/src/lib/common/util.zig +44 -0
  57. package/src/lib/gen1/calc.zig +956 -0
  58. package/src/lib/gen1/chance.zig +1170 -0
  59. package/src/lib/gen1/data/moves.zig +203 -193
  60. package/src/lib/gen1/data/species.zig +6 -8
  61. package/src/lib/gen1/data/types.zig +12 -13
  62. package/src/lib/gen1/data.zig +104 -94
  63. package/src/lib/gen1/helpers.zig +138 -51
  64. package/src/lib/gen1/mechanics.zig +2720 -2351
  65. package/src/lib/gen2/calc.zig +150 -0
  66. package/src/lib/gen2/chance.zig +896 -0
  67. package/src/lib/gen2/data/items.zig +15 -23
  68. package/src/lib/gen2/data/moves.zig +665 -573
  69. package/src/lib/gen2/data/species.zig +3 -5
  70. package/src/lib/gen2/data/types.zig +141 -36
  71. package/src/lib/gen2/data.zig +140 -104
  72. package/src/lib/gen2/generated.zig +801 -0
  73. package/src/lib/gen2/helpers.zig +58 -45
  74. package/src/lib/gen2/mechanics.zig +3582 -30
  75. package/src/lib/napi.h +2 -0
  76. package/src/lib/node.zig +14 -0
  77. package/src/lib/pkmn.zig +177 -22
  78. package/src/lib/wasm.zig +13 -0
  79. package/src/tools/display/dom.ts +93 -0
  80. package/src/tools/display/ui.css +354 -0
  81. package/build/test/display.js +0 -382
  82. package/build/test/display.js.map +0 -1
  83. package/src/lib/binding/node.zig +0 -229
  84. package/src/lib/binding/wasm.zig +0 -10
  85. package/src/lib/gen1/README.md +0 -791
  86. package/src/lib/gen2/README.md +0 -309
  87. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,31 +1,20 @@
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
- const protocol = @import("../common/protocol.zig");
6
5
  const rng = @import("../common/rng.zig");
7
-
8
- const gen1 = @import("../gen1/data.zig");
9
-
10
- const data = @import("data.zig");
6
+ const std = @import("std");
11
7
 
12
8
  const assert = std.debug.assert;
13
-
14
- const expectEqual = std.testing.expectEqual;
15
-
16
9
  const Choice = common.Choice;
17
-
18
- const showdown = options.showdown;
19
-
20
- const PSRNG = rng.PSRNG;
21
-
22
10
  const DVs = data.DVs;
23
11
  const Item = data.Item;
24
12
  const Move = data.Move;
25
13
  const MoveSlot = data.MoveSlot;
14
+ const PSRNG = rng.PSRNG;
15
+ const showdown = options.showdown;
26
16
  const Species = data.Species;
27
17
  const Stats = data.Stats;
28
- const Status = data.Status;
29
18
 
30
19
  pub const Options = struct {
31
20
  cleric: bool = showdown,
@@ -48,7 +37,7 @@ pub const Battle = struct {
48
37
  comptime rolls: anytype,
49
38
  p1: []const Pokemon,
50
39
  p2: []const Pokemon,
51
- ) data.Battle(rng.FixedRNG(1, rolls.len)) {
40
+ ) data.Battle(rng.FixedRNG(2, rolls.len)) {
52
41
  return .{
53
42
  .rng = .{ .rolls = rolls },
54
43
  .sides = .{ Side.init(p1), Side.init(p2) },
@@ -65,19 +54,47 @@ pub const Battle = struct {
65
54
  };
66
55
 
67
56
  pub fn prng(rand: *PSRNG) data.PRNG {
68
- // FIXME: what is max range in gen2?
69
57
  return .{
70
58
  .src = .{
71
59
  .seed = if (showdown)
72
60
  rand.newSeed()
73
- else
74
- .{
75
- rand.range(u8, 0, 256), rand.range(u8, 0, 256),
76
- rand.range(u8, 0, 256), rand.range(u8, 0, 256),
77
- rand.range(u8, 0, 256), rand.range(u8, 0, 256),
78
- rand.range(u8, 0, 256), rand.range(u8, 0, 256),
79
- rand.range(u8, 0, 256), rand.range(u8, 0, 256),
80
- },
61
+ else seed: {
62
+ // GLITCH: The initial RNG seed in Gen II link battles is heavily constrained
63
+ // https://www.smogon.com/forums/threads/rng-in-rby-link-battles.3746779
64
+ var seed = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
65
+
66
+ // Bytes in seed can only range from 0-252, not 0-255
67
+ const max: u8 = 253;
68
+ // Instructions take multiples of 4 cycles to execute
69
+ var timer: u16 = 4 * rand.range(u16, 0, 16384);
70
+ var add: u8 = rand.range(u8, 0, 256);
71
+ var sub: u8 = rand.range(u8, 0, 256);
72
+ var carry: u8 = 0;
73
+ var div: u8 = 0;
74
+
75
+ var i: usize = 0;
76
+ while (i < seed.len) {
77
+ div = @intCast(timer >> 8);
78
+ // This is effectively @addWithOverflow but with three operands
79
+ const result = @as(u16, add) + @as(u16, div) + @as(u16, carry);
80
+ add = @intCast(result & 255);
81
+ carry = @intFromBool(result > 255);
82
+ timer +%= 44;
83
+ div = @intCast(timer >> 8);
84
+ sub -%= div +% carry;
85
+
86
+ if (sub < max) {
87
+ seed[i] = sub;
88
+ i += 1;
89
+ timer +%= 152;
90
+ carry = 1;
91
+ } else {
92
+ timer +%= 132;
93
+ carry = 0;
94
+ }
95
+ }
96
+ break :seed seed;
97
+ },
81
98
  },
82
99
  };
83
100
  }
@@ -89,7 +106,7 @@ pub const Side = struct {
89
106
 
90
107
  for (0..ps.len) |i| {
91
108
  side.pokemon[i] = Pokemon.init(ps[i]);
92
- // FIXME side.order[i] = i + 1;
109
+ side.pokemon[i].position = @as(u4, @intCast(i)) + 1;
93
110
  }
94
111
  return side;
95
112
  }
@@ -100,7 +117,7 @@ pub const Side = struct {
100
117
 
101
118
  for (0..n) |i| {
102
119
  side.pokemon[i] = Pokemon.random(rand, opt);
103
- side.pokemon[i].position = i + 1;
120
+ side.pokemon[i].position = @as(u4, @intCast(i)) + 1;
104
121
  }
105
122
 
106
123
  return side;
@@ -123,7 +140,7 @@ pub const Pokemon = struct {
123
140
  var pokemon = data.Pokemon{};
124
141
  pokemon.species = p.species;
125
142
  const species = Species.get(p.species);
126
- inline for (@typeInfo(@TypeOf(pokemon.stats)).Struct.fields) |field| {
143
+ inline for (@typeInfo(@TypeOf(pokemon.stats)).@"struct".fields) |field| {
127
144
  const hp = comptime std.mem.eql(u8, field.name, "hp");
128
145
  const spc =
129
146
  comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
@@ -137,12 +154,9 @@ pub const Pokemon = struct {
137
154
  }
138
155
  assert(p.moves.len > 0 and p.moves.len <= 4);
139
156
  for (p.moves, 0..) |m, j| {
140
- pokemon.moves[j] = .{
141
- .id = m,
142
- .pp_ups = 3,
143
- // NB: PP can be at most 61 legally (though can overflow to 63)
144
- .pp = @intCast(u8, @min(Move.pp(m) / 5 * 8, 61)),
145
- };
157
+ pokemon.moves[j].id = m;
158
+ // NB: PP can be at most 61 legally (though can overflow to 63)
159
+ pokemon.moves[j].pp = @intCast(@min(Move.pp(m) / 5 * 8, 61));
146
160
  }
147
161
  pokemon.item = p.item;
148
162
  if (p.hp) |hp| {
@@ -153,21 +167,21 @@ pub const Pokemon = struct {
153
167
  pokemon.status = p.status;
154
168
  pokemon.types = species.types;
155
169
  pokemon.level = p.level;
156
- pokemon.dvs = DVs.from(p.dvs);
170
+ pokemon.dvs = DVs.from(p.species, p.dvs);
157
171
  return pokemon;
158
172
  }
159
173
 
160
174
  pub fn random(rand: *PSRNG, opt: Options) data.Pokemon {
161
- const s = @intToEnum(Species, rand.range(u8, 1, Species.size + 1));
175
+ const s: Species = @enumFromInt(rand.range(u8, 1, Species.size + 1));
162
176
  const species = Species.get(s);
163
177
  const lvl = if (rand.chance(u8, 1, 20)) rand.range(u8, 1, 99 + 1) else 100;
164
178
  // Pokémon Showdown does not support most items without in-battle held item effects
165
- const max_item = @enumToInt(if (showdown) Item.FlowerMail else Item.TM50);
179
+ const max_item = @intFromEnum(if (showdown) Item.FlowerMail else Item.TM50);
166
180
  const item = if (rand.chance(u8, 1, 10)) 0 else rand.range(u8, 1, max_item + 1);
167
181
 
168
182
  var stats: Stats(u16) = .{};
169
183
  const dvs = gen1.DVs.random(rand);
170
- inline for (@typeInfo(@TypeOf(stats)).Struct.fields) |field| {
184
+ inline for (@typeInfo(@TypeOf(stats)).@"struct".fields) |field| {
171
185
  const hp = std.mem.eql(u8, field.name, "hp");
172
186
  const spc = std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
173
187
  @field(stats, field.name) = Stats(u16).calc(
@@ -179,29 +193,28 @@ pub const Pokemon = struct {
179
193
  );
180
194
  }
181
195
 
182
- var ms = [_]MoveSlot{.{}} ** 4;
196
+ var ms: [4]MoveSlot = @splat(.{});
183
197
  const n = if (rand.chance(u8, 1, 100)) rand.range(u4, 1, 3 + 1) else 4;
184
198
  for (0..n) |i| {
185
199
  var m: Move = .None;
186
200
  sample: while (true) {
187
- m = @intToEnum(Move, rand.range(u8, 1, 164 + 1));
201
+ m = @enumFromInt(rand.range(u8, 1, 164 + 1));
188
202
  for (0..i) |j| if (ms[j].id == m) continue :sample;
189
203
  break;
190
204
  }
191
- const pp_ups =
205
+ const pp_ups: u8 =
192
206
  if (!opt.cleric and rand.chance(u8, 1, 10)) rand.range(u2, 0, 2 + 1) else 3;
193
207
  // NB: PP can be at most 61 legally (though can overflow to 63)
194
- const max_pp = @intCast(u8, Move.pp(m) + @as(u8, pp_ups) * @min(Move.pp(m) / 5, 7));
208
+ const max_pp: u8 = @intCast(Move.pp(m) + pp_ups * @min(Move.pp(m) / 5, 7));
195
209
  ms[i] = .{
196
210
  .id = m,
197
- .pp_ups = pp_ups,
198
211
  .pp = if (opt.cleric) max_pp else rand.range(u8, 0, max_pp + 1),
199
212
  };
200
213
  }
201
214
  return .{
202
215
  .species = s,
203
216
  .types = species.types,
204
- .dvs = DVs.from(dvs),
217
+ .dvs = DVs.from(s, dvs),
205
218
  .level = lvl,
206
219
  .stats = stats,
207
220
  .hp = if (opt.cleric) stats.hp else rand.range(u16, 0, stats.hp + 1),