@pkmn/engine 0.1.0-dev.f3aaee39 → 0.1.0-dev.f4ba6ebd

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 (56) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +46 -19
  3. package/build/pkg/addon.js +6 -7
  4. package/build/pkg/addon.js.map +1 -1
  5. package/build/pkg/data/ids.json +12 -12
  6. package/build/pkg/data/layout.json +2 -2
  7. package/build/pkg/data/protocol.json +69 -12
  8. package/build/pkg/data.d.ts +4 -4
  9. package/build/pkg/data.js.map +1 -1
  10. package/build/pkg/gen1.js +2 -2
  11. package/build/pkg/gen1.js.map +1 -1
  12. package/build/pkg/index.d.ts +3 -2
  13. package/build/pkg/index.js.map +1 -1
  14. package/build/pkg/protocol.js +61 -42
  15. package/build/pkg/protocol.js.map +1 -1
  16. package/build/test/display.js +8 -3
  17. package/build/test/display.js.map +1 -1
  18. package/build/tools/debug.js +5 -4
  19. package/build/tools/debug.js.map +1 -1
  20. package/build.zig +227 -96
  21. package/package.json +46 -23
  22. package/src/bin/install-pkmn-engine +29 -19
  23. package/src/lib/common/array.zig +77 -0
  24. package/src/lib/common/data.zig +12 -24
  25. package/src/lib/common/debug.zig +2 -2
  26. package/src/lib/common/js.zig +4 -2
  27. package/src/lib/common/optional.zig +21 -10
  28. package/src/lib/common/options.zig +2 -0
  29. package/src/lib/common/protocol.zig +807 -327
  30. package/src/lib/common/rational.zig +125 -31
  31. package/src/lib/common/rng.zig +22 -13
  32. package/src/lib/common/util.zig +50 -1
  33. package/src/lib/gen1/calc.zig +514 -135
  34. package/src/lib/gen1/chance.zig +407 -284
  35. package/src/lib/gen1/data/moves.zig +192 -180
  36. package/src/lib/gen1/data/species.zig +3 -3
  37. package/src/lib/gen1/data/types.zig +7 -7
  38. package/src/lib/gen1/data.zig +46 -57
  39. package/src/lib/gen1/helpers.zig +95 -550
  40. package/src/lib/gen1/mechanics.zig +571 -516
  41. package/src/lib/gen2/calc.zig +161 -0
  42. package/src/lib/gen2/chance.zig +905 -0
  43. package/src/lib/gen2/data/items.zig +12 -18
  44. package/src/lib/gen2/data/moves.zig +663 -569
  45. package/src/lib/gen2/data/species.zig +1 -1
  46. package/src/lib/gen2/data/types.zig +134 -31
  47. package/src/lib/gen2/data.zig +107 -79
  48. package/src/lib/gen2/generated.zig +806 -0
  49. package/src/lib/gen2/helpers.zig +49 -21
  50. package/src/lib/gen2/mechanics.zig +3563 -9
  51. package/src/lib/{binding/node.zig → node.zig} +10 -13
  52. package/src/lib/pkmn.zig +32 -15
  53. package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
  54. package/src/test/display/pkmn.html.tmpl +5 -5
  55. package/src/lib/gen1/README.md +0 -892
  56. package/src/lib/gen2/README.md +0 -308
@@ -27,6 +27,8 @@ const Species = data.Species;
27
27
  const Stats = data.Stats;
28
28
  const Status = data.Status;
29
29
 
30
+ const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
31
+
30
32
  pub const Options = struct {
31
33
  cleric: bool = showdown,
32
34
  };
@@ -48,7 +50,7 @@ pub const Battle = struct {
48
50
  comptime rolls: anytype,
49
51
  p1: []const Pokemon,
50
52
  p2: []const Pokemon,
51
- ) data.Battle(rng.FixedRNG(1, rolls.len)) {
53
+ ) data.Battle(rng.FixedRNG(2, rolls.len)) {
52
54
  return .{
53
55
  .rng = .{ .rolls = rolls },
54
56
  .sides = .{ Side.init(p1), Side.init(p2) },
@@ -65,17 +67,47 @@ pub const Battle = struct {
65
67
  };
66
68
 
67
69
  pub fn prng(rand: *PSRNG) data.PRNG {
68
- // FIXME: what is max range in gen2?
69
70
  return .{
70
71
  .src = .{
71
72
  .seed = if (showdown)
72
73
  rand.newSeed()
73
- else
74
- .{
75
- rand.range(u8, 0, 256), rand.range(u8, 0, 256), rand.range(u8, 0, 256),
76
- rand.range(u8, 0, 256), rand.range(u8, 0, 256), rand.range(u8, 0, 256),
77
- rand.range(u8, 0, 256), rand.range(u8, 0, 256), rand.range(u8, 0, 256),
78
- },
74
+ else seed: {
75
+ // GLITCH: The initial RNG seed in Gen II link battles is heavily constrained
76
+ // https://www.smogon.com/forums/threads/rng-in-rby-link-battles.3746779
77
+ var seed = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
78
+
79
+ // Bytes in seed can only range from 0-252, not 0-255
80
+ const max: u8 = 253;
81
+ // Instructions take multiples of 4 cycles to execute
82
+ var timer: u16 = 4 * rand.range(u16, 0, 16384);
83
+ var add: u8 = rand.range(u8, 0, 256);
84
+ var sub: u8 = rand.range(u8, 0, 256);
85
+ var carry: u8 = 0;
86
+ var div: u8 = 0;
87
+
88
+ var i: u8 = 0;
89
+ while (i < seed.len) {
90
+ div = @intCast(timer >> 8);
91
+ // This is effectively @addWithOverflow but with three operands
92
+ const result = @as(u16, add) + @as(u16, div) + @as(u16, carry);
93
+ add = @intCast(result & 255);
94
+ carry = @intFromBool(result > 255);
95
+ timer +%= 44;
96
+ div = @intCast(timer >> 8);
97
+ sub -%= div +% carry;
98
+
99
+ if (sub < max) {
100
+ seed[i] = sub;
101
+ i += 1;
102
+ timer +%= 152;
103
+ carry = 1;
104
+ } else {
105
+ timer +%= 132;
106
+ carry = 0;
107
+ }
108
+ }
109
+ break :seed seed;
110
+ },
79
111
  },
80
112
  };
81
113
  }
@@ -87,7 +119,7 @@ pub const Side = struct {
87
119
 
88
120
  for (0..ps.len) |i| {
89
121
  side.pokemon[i] = Pokemon.init(ps[i]);
90
- // FIXME side.order[i] = i + 1;
122
+ side.pokemon[i].position = @as(u4, @intCast(i)) + 1;
91
123
  }
92
124
  return side;
93
125
  }
@@ -98,7 +130,7 @@ pub const Side = struct {
98
130
 
99
131
  for (0..n) |i| {
100
132
  side.pokemon[i] = Pokemon.random(rand, opt);
101
- side.pokemon[i].position = i + 1;
133
+ side.pokemon[i].position = @as(u4, @intCast(i)) + 1;
102
134
  }
103
135
 
104
136
  return side;
@@ -121,7 +153,7 @@ pub const Pokemon = struct {
121
153
  var pokemon = data.Pokemon{};
122
154
  pokemon.species = p.species;
123
155
  const species = Species.get(p.species);
124
- inline for (@typeInfo(@TypeOf(pokemon.stats)).Struct.fields) |field| {
156
+ inline for (@field(@typeInfo(@TypeOf(pokemon.stats)), @tagName(Struct)).fields) |field| {
125
157
  const hp = comptime std.mem.eql(u8, field.name, "hp");
126
158
  const spc =
127
159
  comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
@@ -135,12 +167,9 @@ pub const Pokemon = struct {
135
167
  }
136
168
  assert(p.moves.len > 0 and p.moves.len <= 4);
137
169
  for (p.moves, 0..) |m, j| {
138
- pokemon.moves[j] = .{
139
- .id = m,
140
- .pp_ups = 3,
141
- // NB: PP can be at most 61 legally (though can overflow to 63)
142
- .pp = @intCast(@min(Move.pp(m) / 5 * 8, 61)),
143
- };
170
+ pokemon.moves[j].id = m;
171
+ // NB: PP can be at most 61 legally (though can overflow to 63)
172
+ pokemon.moves[j].pp = @intCast(@min(Move.pp(m) / 5 * 8, 61));
144
173
  }
145
174
  pokemon.item = p.item;
146
175
  if (p.hp) |hp| {
@@ -151,7 +180,7 @@ pub const Pokemon = struct {
151
180
  pokemon.status = p.status;
152
181
  pokemon.types = species.types;
153
182
  pokemon.level = p.level;
154
- pokemon.dvs = DVs.from(p.dvs);
183
+ pokemon.dvs = DVs.from(p.species, p.dvs);
155
184
  return pokemon;
156
185
  }
157
186
 
@@ -165,7 +194,7 @@ pub const Pokemon = struct {
165
194
 
166
195
  var stats: Stats(u16) = .{};
167
196
  const dvs = gen1.DVs.random(rand);
168
- inline for (@typeInfo(@TypeOf(stats)).Struct.fields) |field| {
197
+ inline for (@field(@typeInfo(@TypeOf(stats)), @tagName(Struct)).fields) |field| {
169
198
  const hp = std.mem.eql(u8, field.name, "hp");
170
199
  const spc = std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
171
200
  @field(stats, field.name) = Stats(u16).calc(
@@ -192,14 +221,13 @@ pub const Pokemon = struct {
192
221
  const max_pp: u8 = @intCast(Move.pp(m) + pp_ups * @min(Move.pp(m) / 5, 7));
193
222
  ms[i] = .{
194
223
  .id = m,
195
- .pp_ups = pp_ups,
196
224
  .pp = if (opt.cleric) max_pp else rand.range(u8, 0, max_pp + 1),
197
225
  };
198
226
  }
199
227
  return .{
200
228
  .species = s,
201
229
  .types = species.types,
202
- .dvs = DVs.from(dvs),
230
+ .dvs = DVs.from(s, dvs),
203
231
  .level = lvl,
204
232
  .stats = stats,
205
233
  .hp = if (opt.cleric) stats.hp else rand.range(u16, 0, stats.hp + 1),