@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.
- package/LICENSE +1 -3
- package/README.md +97 -59
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +43 -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 +96 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon.d.ts +2 -0
- package/build/pkg/addon.js +35 -57
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/ids.json +12 -12
- package/build/pkg/data/layout.json +26 -4
- package/build/pkg/data/protocol.json +69 -12
- package/build/pkg/data.d.ts +27 -5
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +16 -19
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +24 -10
- package/build/pkg/index.js +15 -10
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +20 -1
- package/build/pkg/protocol.js +123 -102
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +36 -68
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +128 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +132 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +349 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +18 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +286 -131
- package/package.json +73 -31
- package/src/bin/install-pkmn-engine +39 -24
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/data.zig +19 -31
- package/src/lib/common/debug.zig +30 -16
- package/src/lib/common/js.zig +120 -0
- package/src/lib/common/optional.zig +71 -0
- package/src/lib/common/options.zig +13 -0
- package/src/lib/common/protocol.zig +911 -367
- package/src/lib/common/rational.zig +447 -0
- package/src/lib/common/rng.zig +31 -22
- package/src/lib/common/util.zig +61 -0
- package/src/lib/gen1/calc.zig +950 -0
- package/src/lib/gen1/chance.zig +1169 -0
- package/src/lib/gen1/data/moves.zig +202 -190
- package/src/lib/gen1/data/species.zig +5 -5
- package/src/lib/gen1/data/types.zig +10 -10
- package/src/lib/gen1/data.zig +92 -79
- package/src/lib/gen1/helpers.zig +141 -28
- package/src/lib/gen1/mechanics.zig +1118 -773
- package/src/lib/gen2/calc.zig +161 -0
- package/src/lib/gen2/chance.zig +902 -0
- package/src/lib/gen2/data/items.zig +14 -20
- package/src/lib/gen2/data/moves.zig +664 -570
- package/src/lib/gen2/data/species.zig +2 -2
- package/src/lib/gen2/data/types.zig +137 -34
- package/src/lib/gen2/data.zig +125 -86
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +54 -32
- package/src/lib/gen2/mechanics.zig +3564 -15
- package/src/lib/node.zig +131 -0
- package/src/lib/pkmn.zig +81 -5
- package/src/lib/wasm.zig +13 -0
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +351 -0
- package/build/test/display.js +0 -400
- 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 -812
- package/src/lib/gen2/README.md +0 -309
- package/src/test/display/pkmn.html.tmpl +0 -368
package/src/lib/gen2/helpers.zig
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
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))
|
|
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
|
-
|
|
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
|
-
};
|
|
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 = @
|
|
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 = @
|
|
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))
|
|
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 = @
|
|
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(
|
|
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),
|