@pkmn/engine 0.1.0-dev.fb5bf955 → 0.1.0-dev.fb6653d6

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