@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.
- package/LICENSE +1 -3
- package/README.md +141 -76
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +47 -0
- package/build/pkg/addon/browser.js.map +1 -0
- package/build/pkg/addon/node.d.ts +3 -0
- package/build/pkg/addon/node.js +110 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon/wasm.d.ts +2 -0
- package/build/pkg/addon/wasm.js +53 -0
- package/build/pkg/addon/wasm.js.map +1 -0
- package/build/pkg/addon.d.ts +28 -6
- package/build/pkg/addon.js +42 -73
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/ids.json +12 -12
- package/build/pkg/data/layout.json +40 -5
- package/build/pkg/data/protocol.json +84 -13
- package/build/pkg/data.d.ts +27 -5
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +18 -20
- package/build/pkg/gen1.js +76 -51
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +57 -103
- package/build/pkg/index.js +23 -70
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +24 -3
- package/build/pkg/protocol.js +127 -104
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +69 -74
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +152 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +152 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +359 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +33 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +336 -166
- package/package.json +71 -120
- package/src/bin/install-pkmn-engine +57 -26
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/bindings/c.zig +200 -0
- package/src/lib/bindings/node.zig +117 -0
- package/src/lib/bindings/wasm.zig +50 -0
- package/src/lib/common/array.zig +70 -0
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/data.zig +19 -31
- package/src/lib/common/debug.zig +51 -20
- package/src/lib/common/js.zig +114 -0
- package/src/lib/common/optional.zig +61 -0
- package/src/lib/common/options.zig +18 -3
- package/src/lib/common/protocol.zig +1050 -497
- package/src/lib/common/rational.zig +440 -0
- package/src/lib/common/rng.zig +31 -24
- package/src/lib/common/util.zig +44 -0
- package/src/lib/gen1/calc.zig +956 -0
- package/src/lib/gen1/chance.zig +1170 -0
- package/src/lib/gen1/data/moves.zig +203 -193
- package/src/lib/gen1/data/species.zig +6 -8
- package/src/lib/gen1/data/types.zig +12 -13
- package/src/lib/gen1/data.zig +104 -94
- package/src/lib/gen1/helpers.zig +138 -51
- package/src/lib/gen1/mechanics.zig +2720 -2351
- package/src/lib/gen2/calc.zig +150 -0
- package/src/lib/gen2/chance.zig +896 -0
- package/src/lib/gen2/data/items.zig +15 -23
- package/src/lib/gen2/data/moves.zig +665 -573
- package/src/lib/gen2/data/species.zig +3 -5
- package/src/lib/gen2/data/types.zig +141 -36
- package/src/lib/gen2/data.zig +140 -104
- package/src/lib/gen2/generated.zig +801 -0
- package/src/lib/gen2/helpers.zig +58 -45
- package/src/lib/gen2/mechanics.zig +3582 -30
- package/src/lib/napi.h +2 -0
- package/src/lib/node.zig +14 -0
- package/src/lib/pkmn.zig +177 -22
- package/src/lib/wasm.zig +13 -0
- package/src/tools/display/dom.ts +93 -0
- package/src/tools/display/ui.css +354 -0
- package/build/test/display.js +0 -382
- package/build/test/display.js.map +0 -1
- package/src/lib/binding/node.zig +0 -229
- package/src/lib/binding/wasm.zig +0 -10
- package/src/lib/gen1/README.md +0 -791
- package/src/lib/gen2/README.md +0 -309
- package/src/test/display/pkmn.html.tmpl +0 -368
package/src/lib/gen2/helpers.zig
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
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)).
|
|
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
|
-
|
|
142
|
-
|
|
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 = @
|
|
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 = @
|
|
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)).
|
|
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
|
|
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 = @
|
|
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(
|
|
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),
|