@pkmn/engine 0.1.0-dev.d716e940 → 0.1.0-dev.d952b7c9

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