@pkmn/engine 0.1.0-dev.dc33f678 → 0.1.0-dev.dfd46bbb
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/build.zig +19 -13
- package/package.json +5 -2
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/protocol.zig +24 -7
- package/src/lib/common/rational.zig +4 -4
- package/src/lib/common/rng.zig +9 -0
- package/src/lib/gen1/calc.zig +2 -2
- package/src/lib/gen1/chance.zig +4 -4
- package/src/lib/gen1/data/moves.zig +10 -10
- package/src/lib/gen1/data/species.zig +2 -2
- package/src/lib/gen1/data/types.zig +5 -5
- package/src/lib/gen1/data.zig +14 -14
- package/src/lib/gen1/helpers.zig +13 -13
- package/src/lib/gen1/mechanics.zig +44 -50
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1314 -0
- package/src/lib/gen2/data/items.zig +3 -3
- package/src/lib/gen2/data/moves.zig +5 -5
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +10 -10
- package/src/lib/gen2/data.zig +17 -27
- package/src/lib/gen2/generated.zig +814 -0
- package/src/lib/gen2/mechanics.zig +1221 -351
package/build.zig
CHANGED
|
@@ -224,30 +224,32 @@ pub fn build(b: *std.Build) !void {
|
|
|
224
224
|
var benchmark_config = tools;
|
|
225
225
|
benchmark_config.general.optimize = .ReleaseFast;
|
|
226
226
|
benchmark_config.general.strip = true;
|
|
227
|
-
const benchmark = tool(b, "src/test/benchmark.zig", benchmark_config);
|
|
227
|
+
const benchmark = try tool(b, "src/test/benchmark.zig", benchmark_config);
|
|
228
228
|
|
|
229
229
|
var fuzz_config = tools;
|
|
230
230
|
fuzz_config.general.strip = false;
|
|
231
231
|
fuzz_config.tool.name = "fuzz";
|
|
232
|
-
const fuzz = tool(b, "src/test/fuzz.zig", fuzz_config);
|
|
232
|
+
const fuzz = try tool(b, "src/test/fuzz.zig", fuzz_config);
|
|
233
233
|
|
|
234
|
-
const analyze = tool(b, "src/tools/analyze.zig", tools);
|
|
235
|
-
const dump = tool(b, "src/tools/dump.zig", tools);
|
|
236
|
-
const transitions = tool(b, "src/tools/transitions.zig", tools);
|
|
234
|
+
const analyze = try tool(b, "src/tools/analyze.zig", tools);
|
|
235
|
+
const dump = try tool(b, "src/tools/dump.zig", tools);
|
|
236
|
+
const transitions = try tool(b, "src/tools/transitions.zig", tools);
|
|
237
237
|
|
|
238
238
|
// FIXME: serde randomly fails to build in some release configurations
|
|
239
239
|
var hack = tools;
|
|
240
240
|
if (optimize != .Debug) hack.tool.tests = null;
|
|
241
|
-
const serde = tool(b, "src/tools/serde.zig", hack);
|
|
241
|
+
const serde = try tool(b, "src/tools/serde.zig", hack);
|
|
242
242
|
|
|
243
|
-
b.step("analyze", "Run LLVM analysis tool").dependOn(&
|
|
244
|
-
b.step("benchmark", "Run benchmark code").dependOn(&
|
|
245
|
-
b.step("dump", "Run protocol dump tool").dependOn(&
|
|
246
|
-
b.step("fuzz", "Run fuzz tester").dependOn(&
|
|
247
|
-
b.step("serde", "Run serialization/deserialization tool").dependOn(&
|
|
243
|
+
if (analyze) |t| b.step("analyze", "Run LLVM analysis tool").dependOn(&t.step);
|
|
244
|
+
if (benchmark) |t| b.step("benchmark", "Run benchmark code").dependOn(&t.step);
|
|
245
|
+
if (dump) |t| b.step("dump", "Run protocol dump tool").dependOn(&t.step);
|
|
246
|
+
if (fuzz) |t| b.step("fuzz", "Run fuzz tester").dependOn(&t.step);
|
|
247
|
+
if (serde) |t| b.step("serde", "Run serialization/deserialization tool").dependOn(&t.step);
|
|
248
248
|
b.step("test", "Run all tests").dependOn(&tests.step);
|
|
249
249
|
b.step("tools", "Install tools").dependOn(&ToolsStep.create(b, &exes).step);
|
|
250
|
-
|
|
250
|
+
if (transitions) |t| {
|
|
251
|
+
b.step("transitions", "Visualize transitions algorithm search").dependOn(&t.step);
|
|
252
|
+
}
|
|
251
253
|
}
|
|
252
254
|
|
|
253
255
|
fn maybeStrip(
|
|
@@ -326,7 +328,11 @@ const ToolConfig = struct {
|
|
|
326
328
|
},
|
|
327
329
|
};
|
|
328
330
|
|
|
329
|
-
fn tool(b: *std.Build, path: []const u8, config: ToolConfig)
|
|
331
|
+
fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.RunStep {
|
|
332
|
+
std.fs.cwd().access(path, .{}) catch |err| switch (err) {
|
|
333
|
+
error.FileNotFound => return null,
|
|
334
|
+
else => |e| return e,
|
|
335
|
+
};
|
|
330
336
|
var name = config.tool.name orelse std.fs.path.basename(path);
|
|
331
337
|
const index = std.mem.lastIndexOfScalar(u8, name, '.');
|
|
332
338
|
if (index) |i| name = name[0..i];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pkmn/engine",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.dfd46bbb",
|
|
4
4
|
"description": "A minimal, complete, Pokémon battle simulation engine optimized for performance",
|
|
5
5
|
"repository": "github:pkmn/engine",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,11 +52,14 @@
|
|
|
52
52
|
"src/lib/gen1/data/types.zig",
|
|
53
53
|
"src/lib/gen1/helpers.zig",
|
|
54
54
|
"src/lib/gen1/mechanics.zig",
|
|
55
|
+
"src/lib/gen2/calc.zig",
|
|
56
|
+
"src/lib/gen2/chance.zig",
|
|
55
57
|
"src/lib/gen2/data.zig",
|
|
56
58
|
"src/lib/gen2/data/items.zig",
|
|
57
59
|
"src/lib/gen2/data/moves.zig",
|
|
58
60
|
"src/lib/gen2/data/species.zig",
|
|
59
61
|
"src/lib/gen2/data/types.zig",
|
|
62
|
+
"src/lib/gen2/generated.zig",
|
|
60
63
|
"src/lib/gen2/helpers.zig",
|
|
61
64
|
"src/lib/gen2/mechanics.zig",
|
|
62
65
|
"src/lib/pkmn.zig",
|
|
@@ -90,7 +93,7 @@
|
|
|
90
93
|
"binaryen": "^114.0.0",
|
|
91
94
|
"eslint": "^8.51.0",
|
|
92
95
|
"html-minifier": "^4.0.0",
|
|
93
|
-
"json-stringify-pretty-compact": "
|
|
96
|
+
"json-stringify-pretty-compact": "3.0.0",
|
|
94
97
|
"minimist": "^1.2.8",
|
|
95
98
|
"mustache": "^4.2.0",
|
|
96
99
|
"source-map-support": "^0.5.21",
|
package/src/lib/common/data.zig
CHANGED
|
@@ -9,12 +9,12 @@ pub const Player = enum(u1) {
|
|
|
9
9
|
P2,
|
|
10
10
|
|
|
11
11
|
/// Returns a player's opponent.
|
|
12
|
-
pub
|
|
12
|
+
pub fn foe(self: Player) Player {
|
|
13
13
|
return @enumFromInt(~@intFromEnum(self));
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/// Return's an identifier for the player's Pokémon at the one-indexed `id`.
|
|
17
|
-
pub
|
|
17
|
+
pub fn ident(self: Player, id: u3) ID {
|
|
18
18
|
assert(id > 0 and id <= 6);
|
|
19
19
|
return .{ .id = id, .player = self };
|
|
20
20
|
}
|
|
@@ -35,12 +35,12 @@ pub const ID = packed struct(u8) {
|
|
|
35
35
|
_: u4 = 0,
|
|
36
36
|
|
|
37
37
|
/// Converts the identifier into a number.
|
|
38
|
-
pub
|
|
38
|
+
pub fn int(self: ID) u4 {
|
|
39
39
|
return @intCast(@as(u8, @bitCast(self)));
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/// Decodes the identifier from a number.
|
|
43
|
-
pub
|
|
43
|
+
pub fn from(id: u4) ID {
|
|
44
44
|
return @bitCast(@as(u8, id));
|
|
45
45
|
}
|
|
46
46
|
};
|
|
@@ -196,7 +196,7 @@ pub const Activate = enum(u8) {
|
|
|
196
196
|
Haze,
|
|
197
197
|
Mist,
|
|
198
198
|
Struggle,
|
|
199
|
-
Substitute,
|
|
199
|
+
Substitute, // FIXME SubstituteDamage
|
|
200
200
|
Splash,
|
|
201
201
|
|
|
202
202
|
Rage, // TODO
|
|
@@ -208,6 +208,9 @@ pub const Activate = enum(u8) {
|
|
|
208
208
|
FireSpin,
|
|
209
209
|
Clamp,
|
|
210
210
|
Whirlpool,
|
|
211
|
+
SubstituteBlock,
|
|
212
|
+
|
|
213
|
+
DestinyBond,
|
|
211
214
|
|
|
212
215
|
BeatUp, // FIXME of
|
|
213
216
|
};
|
|
@@ -254,6 +257,7 @@ pub const End = enum(u8) {
|
|
|
254
257
|
Encore,
|
|
255
258
|
FutureSight,
|
|
256
259
|
LeechSeed,
|
|
260
|
+
|
|
257
261
|
Bind,
|
|
258
262
|
Wrap,
|
|
259
263
|
FireSpin,
|
|
@@ -269,6 +273,8 @@ pub const End = enum(u8) {
|
|
|
269
273
|
LightScreenSilent,
|
|
270
274
|
ReflectSilent,
|
|
271
275
|
BideSilent,
|
|
276
|
+
|
|
277
|
+
LeechSeedFrom,
|
|
272
278
|
};
|
|
273
279
|
|
|
274
280
|
pub const Immune = enum(u8) {
|
|
@@ -570,6 +576,7 @@ pub fn Log(comptime Writer: type) type {
|
|
|
570
576
|
pub fn activate(self: Self, ident: ID, reason: Activate) Error!void {
|
|
571
577
|
if (!enabled) return;
|
|
572
578
|
|
|
579
|
+
assert(reason != .SubstituteBlock); // TODO
|
|
573
580
|
try self.writer.writeAll(&.{
|
|
574
581
|
@intFromEnum(ArgType.Activate),
|
|
575
582
|
@as(u8, @bitCast(ident)),
|
|
@@ -577,6 +584,18 @@ pub fn Log(comptime Writer: type) type {
|
|
|
577
584
|
});
|
|
578
585
|
}
|
|
579
586
|
|
|
587
|
+
pub fn activateMove(self: Self, ident: ID, reason: Activate, m: anytype) Error!void {
|
|
588
|
+
if (!enabled) return;
|
|
589
|
+
|
|
590
|
+
assert(reason == .SubstituteBlock); // TODO
|
|
591
|
+
try self.writer.writeAll(&.{
|
|
592
|
+
@intFromEnum(ArgType.Activate),
|
|
593
|
+
@as(u8, @bitCast(ident)),
|
|
594
|
+
@intFromEnum(reason),
|
|
595
|
+
@intFromEnum(m),
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
580
599
|
pub fn fieldactivate(self: Self) Error!void {
|
|
581
600
|
if (!enabled) return;
|
|
582
601
|
|
|
@@ -764,14 +783,13 @@ pub fn Log(comptime Writer: type) type {
|
|
|
764
783
|
});
|
|
765
784
|
}
|
|
766
785
|
|
|
767
|
-
pub fn spikesend(self: Self,
|
|
786
|
+
pub fn spikesend(self: Self, source: ID) Error!void {
|
|
768
787
|
if (!enabled) return;
|
|
769
788
|
|
|
770
789
|
try self.writer.writeAll(&.{
|
|
771
790
|
@intFromEnum(ArgType.SideEnd),
|
|
772
|
-
@intFromEnum(player),
|
|
791
|
+
@intFromEnum(source.player),
|
|
773
792
|
@intFromEnum(Side.Spikes),
|
|
774
|
-
@intFromEnum(m),
|
|
775
793
|
@as(u8, @bitCast(source)),
|
|
776
794
|
});
|
|
777
795
|
}
|
|
@@ -1789,14 +1807,13 @@ test "|-sideend|" {
|
|
|
1789
1807
|
try expectLog2(&.{ N(ArgType.SideEnd), 1, N(Side.LightScreen) }, buf[0..3]);
|
|
1790
1808
|
stream.reset();
|
|
1791
1809
|
|
|
1792
|
-
try log.spikesend(
|
|
1810
|
+
try log.spikesend(p1.ident(3));
|
|
1793
1811
|
try expectLog2(&.{
|
|
1794
1812
|
N(ArgType.SideEnd),
|
|
1795
1813
|
0,
|
|
1796
1814
|
N(Side.Spikes),
|
|
1797
|
-
N(M2.RapidSpin),
|
|
1798
1815
|
0b0011,
|
|
1799
|
-
}, buf[0..
|
|
1816
|
+
}, buf[0..4]);
|
|
1800
1817
|
stream.reset();
|
|
1801
1818
|
}
|
|
1802
1819
|
|
|
@@ -44,7 +44,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
44
44
|
/// Both p and q must be >= 1, and if computable at comptime must have no common factors.
|
|
45
45
|
pub fn update(r: *Self, p: anytype, q: anytype) Error!void {
|
|
46
46
|
// FIXME
|
|
47
|
-
// std.debug.print("({d}/{d}) * ", .{p, q});
|
|
47
|
+
// std.debug.print("({d}/{d}) * ", .{ p, q });
|
|
48
48
|
assert(p >= 1);
|
|
49
49
|
assert(q >= 1);
|
|
50
50
|
|
|
@@ -185,12 +185,12 @@ pub fn Rational(comptime T: type) type {
|
|
|
185
185
|
try writer.print("{d}/{d}", .{ self.p, self.q });
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
fn multiplication(r: *Self, p: anytype, q: anytype) !void {
|
|
189
189
|
r.p = try std.math.mul(T, r.p, p);
|
|
190
190
|
r.q = try std.math.mul(T, r.q, q);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
fn addition(r: *Self, p: anytype, q: anytype) !void {
|
|
194
194
|
// (a/b) + (c/d) = (ad+bc)/(bd)
|
|
195
195
|
var d = try std.math.mul(T, r.q, q);
|
|
196
196
|
var n1 = try std.math.mul(T, r.p, q);
|
|
@@ -203,7 +203,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
// https://en.wikipedia.org/wiki/Euclidean_algorithm
|
|
206
|
-
|
|
206
|
+
fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
|
|
207
207
|
assert(p >= 1);
|
|
208
208
|
assert(q >= 1);
|
|
209
209
|
|
package/src/lib/common/rng.zig
CHANGED
|
@@ -25,6 +25,11 @@ pub fn PRNG(comptime gen: comptime_int) type {
|
|
|
25
25
|
pub fn next(self: *Self) Output(gen) {
|
|
26
26
|
return self.src.next();
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
pub fn advance(self: *Self, n: usize) void {
|
|
30
|
+
if (!options.advance) return;
|
|
31
|
+
for (0..n) |_| self.src.advance();
|
|
32
|
+
}
|
|
28
33
|
};
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -89,6 +94,10 @@ pub const Gen12 = extern struct {
|
|
|
89
94
|
self.index = (self.index + 1) % 9;
|
|
90
95
|
return val;
|
|
91
96
|
}
|
|
97
|
+
|
|
98
|
+
pub fn advance(self: *Gen12) void {
|
|
99
|
+
_ = self.next();
|
|
100
|
+
}
|
|
92
101
|
};
|
|
93
102
|
|
|
94
103
|
test Gen12 {
|
package/src/lib/gen1/calc.zig
CHANGED
|
@@ -50,7 +50,7 @@ pub const Summaries = extern struct {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/// Returns the `Summary` for the given `player`.
|
|
53
|
-
pub
|
|
53
|
+
pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Summary) {
|
|
54
54
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Summaries);
|
|
55
55
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
56
56
|
}
|
|
@@ -387,7 +387,7 @@ pub fn transitions(
|
|
|
387
387
|
return stats;
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
-
|
|
390
|
+
fn matches(actions: Actions, i: usize, frontier: []Actions) bool {
|
|
391
391
|
for (frontier, 0..) |f, j| {
|
|
392
392
|
// TODO: is skipping this redundant check worth it?
|
|
393
393
|
if (i == j) continue;
|
package/src/lib/gen1/chance.zig
CHANGED
|
@@ -37,19 +37,19 @@ pub const Actions = extern struct {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/// Returns the `Action` for the given `player`.
|
|
40
|
-
pub
|
|
40
|
+
pub fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Action) {
|
|
41
41
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Actions);
|
|
42
42
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/// Perform a reset by clearing fields which should not persist across updates.
|
|
46
|
-
pub
|
|
46
|
+
pub fn reset(self: *Actions) void {
|
|
47
47
|
self.p1.reset();
|
|
48
48
|
self.p2.reset();
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/// Returns true if `a` is equal to `b`.
|
|
52
|
-
pub
|
|
52
|
+
pub fn eql(a: Actions, b: Actions) bool {
|
|
53
53
|
return @as(u128, @bitCast(a)) == @as(u128, @bitCast(b));
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -159,7 +159,7 @@ pub const Action = packed struct(u64) {
|
|
|
159
159
|
pub const Field = std.meta.FieldEnum(Action);
|
|
160
160
|
|
|
161
161
|
/// Perform a reset by clearing fields which should not persist across updates.
|
|
162
|
-
pub
|
|
162
|
+
pub fn reset(self: *Action) void {
|
|
163
163
|
self.* = @bitCast(@as(u64, @bitCast(self.*)) & DURATIONS);
|
|
164
164
|
}
|
|
165
165
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//! Code generated by `tools/generate` - manual edits will be overwritten
|
|
1
|
+
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
3
|
const std = @import("std");
|
|
4
4
|
|
|
@@ -1599,43 +1599,43 @@ pub const Move = enum(u8) {
|
|
|
1599
1599
|
}
|
|
1600
1600
|
|
|
1601
1601
|
/// Whether this effect activates during the "begin" step of move execution.
|
|
1602
|
-
pub
|
|
1602
|
+
pub fn onBegin(effect: Effect) bool {
|
|
1603
1603
|
return @intFromEnum(effect) > 0 and @intFromEnum(effect) <= 16;
|
|
1604
1604
|
}
|
|
1605
1605
|
|
|
1606
1606
|
/// Whether this effect lowers stats.
|
|
1607
|
-
pub
|
|
1607
|
+
pub fn isStatDown(effect: Effect) bool {
|
|
1608
1608
|
return @intFromEnum(effect) > 16 and @intFromEnum(effect) <= 21;
|
|
1609
1609
|
}
|
|
1610
1610
|
|
|
1611
1611
|
/// Whether this effect activates during the "end" step of move execution.
|
|
1612
|
-
pub
|
|
1612
|
+
pub fn onEnd(effect: Effect) bool {
|
|
1613
1613
|
return @intFromEnum(effect) > 16 and @intFromEnum(effect) <= 31;
|
|
1614
1614
|
}
|
|
1615
1615
|
|
|
1616
1616
|
/// Whether this effect is considered to "always happen".
|
|
1617
|
-
pub
|
|
1617
|
+
pub fn alwaysHappens(effect: Effect) bool {
|
|
1618
1618
|
return @intFromEnum(effect) > 31 and @intFromEnum(effect) <= 38;
|
|
1619
1619
|
}
|
|
1620
1620
|
|
|
1621
1621
|
/// Whether this effect is handled specially by the engine.
|
|
1622
|
-
pub
|
|
1622
|
+
pub fn isSpecial(effect: Effect) bool {
|
|
1623
1623
|
// NB: isSpecial includes isMulti up to Twineedle
|
|
1624
1624
|
return @intFromEnum(effect) > 31 and @intFromEnum(effect) <= 46;
|
|
1625
1625
|
}
|
|
1626
1626
|
|
|
1627
1627
|
/// Whether this effect is a multi-hit effect.
|
|
1628
|
-
pub
|
|
1628
|
+
pub fn isMulti(effect: Effect) bool {
|
|
1629
1629
|
return @intFromEnum(effect) > 44 and @intFromEnum(effect) <= 47;
|
|
1630
1630
|
}
|
|
1631
1631
|
|
|
1632
1632
|
/// Whether this effect is has chance of lowering stats.
|
|
1633
|
-
pub
|
|
1633
|
+
pub fn isStatDownChance(effect: Effect) bool {
|
|
1634
1634
|
return @intFromEnum(effect) > 47 and @intFromEnum(effect) <= 51;
|
|
1635
1635
|
}
|
|
1636
1636
|
|
|
1637
1637
|
/// Whether this effect has a secondary chance.
|
|
1638
|
-
pub
|
|
1638
|
+
pub fn isSecondaryChance(effect: Effect) bool {
|
|
1639
1639
|
// NB: isSecondaryChance includes isStatDownChance as well as Twineedle
|
|
1640
1640
|
return (@intFromEnum(effect) > 46 and @intFromEnum(effect) <= 61);
|
|
1641
1641
|
}
|
|
@@ -1853,7 +1853,7 @@ pub const Move = enum(u8) {
|
|
|
1853
1853
|
};
|
|
1854
1854
|
|
|
1855
1855
|
/// Returns the `Data` corresponding to the move.
|
|
1856
|
-
pub
|
|
1856
|
+
pub fn get(id: Move) Data {
|
|
1857
1857
|
assert(id != .None and id != .SKIP_TURN);
|
|
1858
1858
|
return DATA[@intFromEnum(id) - 1];
|
|
1859
1859
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//! Code generated by `tools/generate` - manual edits will be overwritten
|
|
1
|
+
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
3
|
const std = @import("std");
|
|
4
4
|
|
|
@@ -1092,7 +1092,7 @@ pub const Species = enum(u8) {
|
|
|
1092
1092
|
pub const size = 151;
|
|
1093
1093
|
|
|
1094
1094
|
/// The Pokémon's critical hit rate=io out of 256.
|
|
1095
|
-
pub
|
|
1095
|
+
pub fn chance(id: Species) u8 {
|
|
1096
1096
|
assert(id != .None);
|
|
1097
1097
|
return CHANCES[@intFromEnum(id) - 1];
|
|
1098
1098
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//! Code generated by `tools/generate` - manual edits will be overwritten
|
|
1
|
+
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
3
|
const std = @import("std");
|
|
4
4
|
|
|
@@ -90,12 +90,12 @@ pub const Type = enum(u4) {
|
|
|
90
90
|
pub const size = 15;
|
|
91
91
|
|
|
92
92
|
/// Whether or not this type is considered to be special as opposed to physical.
|
|
93
|
-
pub
|
|
93
|
+
pub fn special(self: Type) bool {
|
|
94
94
|
return @intFromEnum(self) >= @intFromEnum(Type.Fire);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/// The `Effectiveness` of type `t2` vs. type `t1`.
|
|
98
|
-
pub
|
|
98
|
+
pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
|
|
99
99
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -120,12 +120,12 @@ pub const Types = packed struct {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/// Whether this typing is immune to type `t`.
|
|
123
|
-
pub
|
|
123
|
+
pub fn immune(self: Types, t: Type) bool {
|
|
124
124
|
return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/// Whether this typing includes type `t`.
|
|
128
|
-
pub
|
|
128
|
+
pub fn includes(self: Types, t: Type) bool {
|
|
129
129
|
return self.type1 == t or self.type2 == t;
|
|
130
130
|
}
|
|
131
131
|
};
|
package/src/lib/gen1/data.zig
CHANGED
|
@@ -70,24 +70,24 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
70
70
|
rng: RNG,
|
|
71
71
|
|
|
72
72
|
/// Returns the `Side` for the given `player`.
|
|
73
|
-
pub
|
|
73
|
+
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
74
74
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
75
75
|
return &self.sides[@intFromEnum(player)];
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/// Returns the `Side` of the opponent for the given `player`
|
|
79
|
-
pub
|
|
79
|
+
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
80
80
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
81
81
|
return &self.sides[@intFromEnum(player.foe())];
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/// Returns an identifier for the active Pokémon of `player`.
|
|
85
|
-
pub
|
|
85
|
+
pub fn active(self: *const Self, player: Player) ID {
|
|
86
86
|
return player.ident(@intCast(self.side(player).order[0]));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/// Returns the `MoveDetails` for the given `player`.
|
|
90
|
-
pub
|
|
90
|
+
pub fn lastMove(
|
|
91
91
|
self: anytype,
|
|
92
92
|
player: Player,
|
|
93
93
|
) PointerType(@TypeOf(self), MoveDetails) {
|
|
@@ -141,7 +141,7 @@ pub const Side = extern struct {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
/// Returns the stored `Pokemon` corresponding to the one-indexed party `slot`.
|
|
144
|
-
pub
|
|
144
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
145
145
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
146
146
|
assert(slot > 0 and slot <= 6);
|
|
147
147
|
const id = self.order[slot - 1];
|
|
@@ -150,7 +150,7 @@ pub const Side = extern struct {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
/// Returns the stored `Pokemon` corresponding to the `active` Pokémon (slot 1).
|
|
153
|
-
pub
|
|
153
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
154
154
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
155
155
|
return self.get(1);
|
|
156
156
|
}
|
|
@@ -176,7 +176,7 @@ pub const ActivePokemon = extern struct {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/// Returns the active Pokémon's current move slot located at the one-indexed `mslot`.
|
|
179
|
-
pub
|
|
179
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
180
180
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == ActivePokemon);
|
|
181
181
|
assert(mslot > 0 and mslot <= 4);
|
|
182
182
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -206,7 +206,7 @@ pub const Pokemon = extern struct {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
/// Returns the Pokémon's original move slot located at the one-indexed `mslot`.
|
|
209
|
-
pub
|
|
209
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
210
210
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
211
211
|
assert(mslot > 0 and mslot <= 4);
|
|
212
212
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -258,36 +258,36 @@ pub const Status = enum(u8) {
|
|
|
258
258
|
const SLP = 0b111;
|
|
259
259
|
|
|
260
260
|
/// Whether or not the status `num` is the same as `status`.
|
|
261
|
-
pub
|
|
261
|
+
pub fn is(num: u8, status: Status) bool {
|
|
262
262
|
if (status == .SLP) return Status.duration(num) > 0;
|
|
263
263
|
return ((num >> @intCast(@intFromEnum(status))) & 1) != 0;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
/// Initializes a non-sleep `status`. Use `slp` or `slf` to initialize a sleep status.
|
|
267
|
-
pub
|
|
267
|
+
pub fn init(status: Status) u8 {
|
|
268
268
|
assert(status != .SLP and status != .EXT);
|
|
269
269
|
return @as(u8, 1) << @intCast(@intFromEnum(status));
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
/// Initializes a non self-inflicted sleep status with duration `dur`.
|
|
273
|
-
pub
|
|
273
|
+
pub fn slp(dur: u3) u8 {
|
|
274
274
|
assert(dur > 0);
|
|
275
275
|
return @as(u8, dur);
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
/// Initializes a self-inflicted sleep status with duration `dur`.
|
|
279
|
-
pub
|
|
279
|
+
pub fn slf(dur: u3) u8 {
|
|
280
280
|
assert(dur > 0);
|
|
281
281
|
return 0x80 | slp(dur);
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
/// Returns the duration of a sleep status.
|
|
285
|
-
pub
|
|
285
|
+
pub fn duration(num: u8) u3 {
|
|
286
286
|
return @intCast(num & SLP);
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
/// Returns whether `num` reflects any status.
|
|
290
|
-
pub
|
|
290
|
+
pub fn any(num: u8) bool {
|
|
291
291
|
return num > 0;
|
|
292
292
|
}
|
|
293
293
|
|
package/src/lib/gen1/helpers.zig
CHANGED
|
@@ -266,7 +266,7 @@ pub const Rolls = struct {
|
|
|
266
266
|
const PLAYERS = [_]Optional(Player){ .P1, .P2 };
|
|
267
267
|
|
|
268
268
|
/// Returns a slice with the correct range of values for speed ties given the `action` state.
|
|
269
|
-
pub
|
|
269
|
+
pub fn speedTie(action: Action) []const Optional(Player) {
|
|
270
270
|
return if (@field(action, "speed_tie") == .None) &PLAYER_NONE else &PLAYERS;
|
|
271
271
|
}
|
|
272
272
|
|
|
@@ -275,14 +275,14 @@ pub const Rolls = struct {
|
|
|
275
275
|
|
|
276
276
|
/// Returns a slice with the correct range of values for hits given the `action` state
|
|
277
277
|
/// and the state of the `parent` (whether the player's Pokémon was fully paralyzed).
|
|
278
|
-
pub
|
|
278
|
+
pub fn hit(action: Action, parent: Optional(bool)) []const Optional(bool) {
|
|
279
279
|
if (parent == .true) return &BOOL_NONE;
|
|
280
280
|
return if (@field(action, "hit") == .None) &BOOL_NONE else &BOOLS;
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
/// Returns a slice with the correct range of values for critical hits given the `action` state
|
|
284
284
|
/// and the state of the `parent` (whether the player's Pokémon's move hit).
|
|
285
|
-
pub
|
|
285
|
+
pub fn criticalHit(
|
|
286
286
|
action: Action,
|
|
287
287
|
parent: Optional(bool),
|
|
288
288
|
) []const Optional(bool) {
|
|
@@ -292,7 +292,7 @@ pub const Rolls = struct {
|
|
|
292
292
|
|
|
293
293
|
/// Returns a slice with the correct range of values for secondary chances hits given the
|
|
294
294
|
/// `action` state and the state of the `parent` (whether the player's Pokémon's move hit).
|
|
295
|
-
pub
|
|
295
|
+
pub fn secondaryChance(
|
|
296
296
|
action: Action,
|
|
297
297
|
parent: Optional(bool),
|
|
298
298
|
) []const Optional(bool) {
|
|
@@ -305,7 +305,7 @@ pub const Rolls = struct {
|
|
|
305
305
|
|
|
306
306
|
/// Returns the range bounding damage rolls given the `action` state and the state of
|
|
307
307
|
/// the `parent` (whether the player's Pokémon's move hit).
|
|
308
|
-
pub
|
|
308
|
+
pub fn damage(action: Action, parent: Optional(bool)) Range {
|
|
309
309
|
return if (parent == .false or @field(action, "damage") == 0)
|
|
310
310
|
.{ .min = 0, .max = 1 }
|
|
311
311
|
else
|
|
@@ -314,7 +314,7 @@ pub const Rolls = struct {
|
|
|
314
314
|
|
|
315
315
|
/// Returns the max damage roll which will produce the same damage as `roll`
|
|
316
316
|
/// given the base damage in `summaries`.
|
|
317
|
-
pub
|
|
317
|
+
pub fn coalesce(player: Player, roll: u8, summaries: *calc.Summaries, cap: bool) !u8 {
|
|
318
318
|
if (roll == 0) return roll;
|
|
319
319
|
|
|
320
320
|
const dmg = summaries.get(player.foe()).damage;
|
|
@@ -326,13 +326,13 @@ pub const Rolls = struct {
|
|
|
326
326
|
|
|
327
327
|
/// Returns a slice with the correct range of values for confused given the `action` state
|
|
328
328
|
/// and the state of the `parent` (the player's Pokémon's remaining confusion turns).
|
|
329
|
-
pub
|
|
329
|
+
pub fn confused(action: Action, parent: u4) []const Optional(bool) {
|
|
330
330
|
return if (parent == 0 or @field(action, "confused") == .None) &BOOL_NONE else &BOOLS;
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
/// Returns a slice with the correct range of values for paralysis given the `action` state
|
|
334
334
|
/// and the state of the `parent` (whether the player's Pokémon was confused).
|
|
335
|
-
pub
|
|
335
|
+
pub fn paralyzed(action: Action, parent: Optional(bool)) []const Optional(bool) {
|
|
336
336
|
if (parent == .true) return &BOOL_NONE;
|
|
337
337
|
return if (@field(action, "paralyzed") == .None) &BOOL_NONE else &BOOLS;
|
|
338
338
|
}
|
|
@@ -342,7 +342,7 @@ pub const Rolls = struct {
|
|
|
342
342
|
|
|
343
343
|
/// Returns a slice with a range of values for duration given the `action` state
|
|
344
344
|
/// and the state of the `parent` (whether the player's Pokémon's move hit).
|
|
345
|
-
pub
|
|
345
|
+
pub fn duration(action: Action, parent: Optional(bool)) []const u1 {
|
|
346
346
|
if (parent == .false) return &DURATION_NONE;
|
|
347
347
|
return if (@field(action, "duration") == 0) &DURATION_NONE else &DURATION;
|
|
348
348
|
}
|
|
@@ -418,7 +418,7 @@ pub const Rolls = struct {
|
|
|
418
418
|
/// and the state of the `parent` (whether the player's Pokémon's move hit).
|
|
419
419
|
///
|
|
420
420
|
/// These slots may or **may not be valid** as slots may be unset / have 0 PP.
|
|
421
|
-
pub
|
|
421
|
+
pub fn moveSlot(action: Action, parent: Optional(bool)) []const u4 {
|
|
422
422
|
if (parent == .false) return &SLOT_NONE;
|
|
423
423
|
return if (@field(action, "move_slot") == 0) &SLOT_NONE else &SLOT;
|
|
424
424
|
}
|
|
@@ -428,7 +428,7 @@ pub const Rolls = struct {
|
|
|
428
428
|
|
|
429
429
|
/// Returns a slice with the correct range of values for multi hit given the `action` state
|
|
430
430
|
/// and the state of the `parent` (whether the player's Pokémon's move hit).
|
|
431
|
-
pub
|
|
431
|
+
pub fn multiHit(action: Action, parent: Optional(bool)) []const u4 {
|
|
432
432
|
if (parent == .false) return &MULTI_NONE;
|
|
433
433
|
return if (@field(action, "multi_hit") == 0) &MULTI_NONE else &MULTI;
|
|
434
434
|
}
|
|
@@ -442,7 +442,7 @@ pub const Rolls = struct {
|
|
|
442
442
|
|
|
443
443
|
/// Returns a slice with the correct range of values for psywave given the `action` state,
|
|
444
444
|
/// the `side`, and the state of the `parent` (whether the player's Pokémon's move hit).
|
|
445
|
-
pub
|
|
445
|
+
pub fn psywave(
|
|
446
446
|
action: Action,
|
|
447
447
|
side: *data.Side,
|
|
448
448
|
parent: Optional(bool),
|
|
@@ -457,7 +457,7 @@ pub const Rolls = struct {
|
|
|
457
457
|
const MOVE_NONE = [_]Move{.None};
|
|
458
458
|
|
|
459
459
|
/// Returns a slice with the correct range of values for metronome given the `action` state.
|
|
460
|
-
pub
|
|
460
|
+
pub fn metronome(action: Action) []const Move {
|
|
461
461
|
return if (@field(action, "metronome") == .None) &MOVE_NONE else &Move.METRONOME;
|
|
462
462
|
}
|
|
463
463
|
};
|