@pkmn/engine 0.1.0-dev.f3aab252 → 0.1.0-dev.f3b63b86
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 -1
- package/README.md +35 -8
- 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 +26 -4
- package/build/pkg/addon.js +34 -65
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/layout.json +15 -2
- package/build/pkg/data/protocol.json +23 -9
- package/build/pkg/data.d.ts +23 -1
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +15 -18
- package/build/pkg/gen1.js +28 -19
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +39 -89
- package/build/pkg/index.js +23 -70
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +20 -1
- package/build/pkg/protocol.js +105 -103
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +68 -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 +235 -213
- package/package.json +59 -141
- package/src/bin/install-pkmn-engine +25 -9
- 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 +5 -12
- package/src/lib/common/debug.zig +30 -9
- package/src/lib/common/js.zig +3 -9
- package/src/lib/common/optional.zig +11 -21
- package/src/lib/common/options.zig +4 -0
- package/src/lib/common/protocol.zig +180 -171
- package/src/lib/common/rational.zig +278 -285
- package/src/lib/common/rng.zig +1 -3
- package/src/lib/common/util.zig +14 -31
- package/src/lib/gen1/calc.zig +258 -106
- package/src/lib/gen1/chance.zig +57 -54
- package/src/lib/gen1/data/moves.zig +2 -4
- package/src/lib/gen1/data/species.zig +1 -3
- package/src/lib/gen1/data/types.zig +3 -4
- package/src/lib/gen1/data.zig +12 -16
- package/src/lib/gen1/helpers.zig +13 -28
- package/src/lib/gen1/mechanics.zig +131 -101
- package/src/lib/gen2/calc.zig +12 -23
- package/src/lib/gen2/chance.zig +12 -18
- package/src/lib/gen2/data/items.zig +1 -3
- package/src/lib/gen2/data/moves.zig +2 -4
- package/src/lib/gen2/data/species.zig +1 -3
- package/src/lib/gen2/data/types.zig +7 -5
- package/src/lib/gen2/data.zig +19 -22
- package/src/lib/gen2/generated.zig +18 -23
- package/src/lib/gen2/helpers.zig +9 -18
- package/src/lib/gen2/mechanics.zig +50 -47
- package/src/lib/napi.h +2 -0
- package/src/lib/node.zig +4 -121
- package/src/lib/pkmn.zig +98 -19
- package/src/lib/wasm.zig +9 -9
- package/src/tools/display/dom.ts +93 -0
- package/src/tools/display/ui.css +354 -0
- package/build/test/display.js +0 -405
- package/build/test/display.js.map +0 -1
- package/src/test/display/pkmn.html.tmpl +0 -368
package/src/lib/gen1/chance.zig
CHANGED
|
@@ -1,34 +1,27 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
|
|
3
|
-
const assert = std.debug.assert;
|
|
4
|
-
const print = std.debug.print;
|
|
5
|
-
|
|
6
|
-
const expect = std.testing.expect;
|
|
7
|
-
const expectEqual = std.testing.expectEqual;
|
|
8
|
-
|
|
9
1
|
const DEBUG = @import("../common/debug.zig").print;
|
|
2
|
+
|
|
3
|
+
const array = @import("../common/array.zig");
|
|
4
|
+
const common = @import("../common/data.zig");
|
|
5
|
+
const data = @import("data.zig");
|
|
6
|
+
const optional = @import("../common/optional.zig");
|
|
10
7
|
const options = @import("../common/options.zig");
|
|
11
8
|
const rational = @import("../common/rational.zig");
|
|
9
|
+
const std = @import("std");
|
|
12
10
|
const util = @import("../common/util.zig");
|
|
13
11
|
|
|
14
|
-
const Array =
|
|
15
|
-
const
|
|
16
|
-
const Optional = @import("../common/optional.zig").Optional;
|
|
17
|
-
|
|
18
|
-
const data = @import("data.zig");
|
|
19
|
-
|
|
12
|
+
const Array = array.Array;
|
|
13
|
+
const assert = std.debug.assert;
|
|
20
14
|
const enabled = options.chance;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
const PointerType = util.PointerType;
|
|
15
|
+
const expect = std.testing.expect;
|
|
16
|
+
const expectEqual = std.testing.expectEqual;
|
|
24
17
|
const isPointerTo = util.isPointerTo;
|
|
25
|
-
|
|
26
18
|
const Move = data.Move;
|
|
27
19
|
const MoveSlot = data.MoveSlot;
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
20
|
+
const Optional = optional.Optional;
|
|
21
|
+
const Player = common.Player;
|
|
22
|
+
const PointerType = util.PointerType;
|
|
23
|
+
const print = std.debug.print;
|
|
24
|
+
const showdown = options.showdown;
|
|
32
25
|
|
|
33
26
|
/// Actions taken by a hypothetical "chance player" that convey information about which RNG events
|
|
34
27
|
/// were observed during a Generation I battle `update`. This can additionally be provided as input
|
|
@@ -59,15 +52,15 @@ pub const Actions = extern struct {
|
|
|
59
52
|
/// same shape if they have the same fields set (though those fields need not necessarily be
|
|
60
53
|
/// set to the same value).
|
|
61
54
|
pub fn matches(a: Actions, b: Actions) bool {
|
|
62
|
-
inline for (@
|
|
63
|
-
inline for (@
|
|
55
|
+
inline for (@typeInfo(Actions).@"struct".fields) |player| {
|
|
56
|
+
inline for (@typeInfo(Action).@"struct".fields) |field| {
|
|
64
57
|
const a_val = @field(@field(a, player.name), field.name);
|
|
65
58
|
const b_val = @field(@field(b, player.name), field.name);
|
|
66
59
|
|
|
67
60
|
switch (@typeInfo(@TypeOf(a_val))) {
|
|
68
|
-
|
|
61
|
+
.@"enum" => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
69
62
|
return false,
|
|
70
|
-
|
|
63
|
+
.int => if ((a_val > 0) != (b_val > 0)) return false,
|
|
71
64
|
else => unreachable,
|
|
72
65
|
}
|
|
73
66
|
}
|
|
@@ -75,7 +68,26 @@ pub const Actions = extern struct {
|
|
|
75
68
|
return true;
|
|
76
69
|
}
|
|
77
70
|
|
|
78
|
-
|
|
71
|
+
/// TODO
|
|
72
|
+
pub fn matchesAny(a: Actions, bs: []Actions, i: usize) bool {
|
|
73
|
+
for (bs, 0..) |b, j| {
|
|
74
|
+
// TODO: is skipping this redundant check worth it?
|
|
75
|
+
if (i == j) continue;
|
|
76
|
+
if (b.matches(a)) return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// TODO
|
|
82
|
+
pub fn relax(actions: Actions) Actions {
|
|
83
|
+
if (!options.overwrite) return actions;
|
|
84
|
+
var a = actions;
|
|
85
|
+
if (a.p1.confusion == .overwritten) a.p1.confusion = .continuing;
|
|
86
|
+
if (a.p2.confusion == .overwritten) a.p2.confusion = .continuing;
|
|
87
|
+
return a;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
pub fn fmt(self: Actions, writer: *std.Io.Writer, shape: bool) !void {
|
|
79
91
|
try writer.writeAll("<P1 = ");
|
|
80
92
|
try self.p1.fmt(writer, shape);
|
|
81
93
|
try writer.writeAll(", P2 = ");
|
|
@@ -83,8 +95,7 @@ pub const Actions = extern struct {
|
|
|
83
95
|
try writer.writeAll(">");
|
|
84
96
|
}
|
|
85
97
|
|
|
86
|
-
pub fn format(a: Actions,
|
|
87
|
-
_ = .{ f, o };
|
|
98
|
+
pub fn format(a: Actions, w: *std.Io.Writer) !void {
|
|
88
99
|
try fmt(a, w, false);
|
|
89
100
|
}
|
|
90
101
|
};
|
|
@@ -175,18 +186,17 @@ pub const Action = packed struct(u64) {
|
|
|
175
186
|
|
|
176
187
|
pub const Field = std.meta.FieldEnum(Action);
|
|
177
188
|
|
|
178
|
-
pub fn format(a: Action,
|
|
179
|
-
_ = .{ f, o };
|
|
189
|
+
pub fn format(a: Action, w: *std.Io.Writer) !void {
|
|
180
190
|
try fmt(a, w, false);
|
|
181
191
|
}
|
|
182
192
|
|
|
183
|
-
pub fn fmt(self: Action, writer:
|
|
193
|
+
pub fn fmt(self: Action, writer: *std.Io.Writer, shape: bool) !void {
|
|
184
194
|
try writer.writeByte('(');
|
|
185
195
|
var printed = false;
|
|
186
|
-
inline for (@
|
|
196
|
+
inline for (@typeInfo(Action).@"struct".fields) |field| {
|
|
187
197
|
const val = @field(self, field.name);
|
|
188
198
|
switch (@typeInfo(@TypeOf(val))) {
|
|
189
|
-
|
|
199
|
+
.@"enum" => if (val != .None) {
|
|
190
200
|
if (printed) try writer.writeAll(", ");
|
|
191
201
|
if (shape) {
|
|
192
202
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -207,7 +217,7 @@ pub const Action = packed struct(u64) {
|
|
|
207
217
|
}
|
|
208
218
|
printed = true;
|
|
209
219
|
},
|
|
210
|
-
|
|
220
|
+
.int => if (val != 0) {
|
|
211
221
|
if (printed) try writer.writeAll(", ");
|
|
212
222
|
if (shape) {
|
|
213
223
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -224,7 +234,7 @@ pub const Action = packed struct(u64) {
|
|
|
224
234
|
};
|
|
225
235
|
|
|
226
236
|
/// TODO
|
|
227
|
-
pub const Durations = struct {
|
|
237
|
+
pub const Durations = extern struct {
|
|
228
238
|
/// TODO
|
|
229
239
|
p1: Duration = .{},
|
|
230
240
|
/// TODO
|
|
@@ -240,18 +250,12 @@ pub const Durations = struct {
|
|
|
240
250
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
241
251
|
}
|
|
242
252
|
|
|
243
|
-
pub fn format(
|
|
244
|
-
self
|
|
245
|
-
comptime fmt: []const u8,
|
|
246
|
-
opts: std.fmt.FormatOptions,
|
|
247
|
-
writer: anytype,
|
|
248
|
-
) !void {
|
|
249
|
-
_ = .{ fmt, opts };
|
|
250
|
-
try writer.print("[P1 = {}, P2 = {}]", .{ self.p1, self.p2 });
|
|
253
|
+
pub fn format(self: Durations, writer: *std.Io.Writer) !void {
|
|
254
|
+
try writer.print("[P1 = {f}, P2 = {f}]", .{ self.p1, self.p2 });
|
|
251
255
|
}
|
|
252
256
|
};
|
|
253
257
|
|
|
254
|
-
const Sleeps = Array(6, u3);
|
|
258
|
+
pub const Sleeps = Array(6, u3);
|
|
255
259
|
|
|
256
260
|
/// TODO
|
|
257
261
|
pub const Duration = packed struct(u32) {
|
|
@@ -265,17 +269,14 @@ pub const Duration = packed struct(u32) {
|
|
|
265
269
|
|
|
266
270
|
pub fn format(
|
|
267
271
|
self: Duration,
|
|
268
|
-
|
|
269
|
-
opts: std.fmt.FormatOptions,
|
|
270
|
-
writer: anytype,
|
|
272
|
+
writer: *std.Io.Writer,
|
|
271
273
|
) !void {
|
|
272
|
-
_ = .{ fmt, opts };
|
|
273
274
|
try writer.writeByte('(');
|
|
274
275
|
var printed = false;
|
|
275
|
-
inline for (@
|
|
276
|
+
inline for (@typeInfo(Duration).@"struct".fields) |field| {
|
|
276
277
|
const val = @field(self, field.name);
|
|
277
278
|
switch (@typeInfo(@TypeOf(val))) {
|
|
278
|
-
|
|
279
|
+
.int => if (val != 0) {
|
|
279
280
|
if (printed) try writer.writeAll(", ");
|
|
280
281
|
if (comptime std.mem.eql(u8, field.name, "sleeps")) {
|
|
281
282
|
try writer.print("{s}:[", .{field.name});
|
|
@@ -375,7 +376,7 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
375
376
|
|
|
376
377
|
// If the move actually lands we can commit any past critical hit / damage rolls. Note
|
|
377
378
|
// we can't rely on the presence or absence of a damage roll to determine whether a
|
|
378
|
-
// "critical hit" was spurious or not as moves that do 1 or less damage don't
|
|
379
|
+
// "critical hit" was spurious or not as moves that do 1 or less damage don't roll for
|
|
379
380
|
// damage but can still crit (instead, whether or not a roll is deemed to be a no-op is
|
|
380
381
|
// passed to the critical hit helper).
|
|
381
382
|
//
|
|
@@ -391,7 +392,7 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
391
392
|
action.critical_hit = if (self.pending.crit) .true else .false;
|
|
392
393
|
} else assert(!self.pending.glitch);
|
|
393
394
|
|
|
394
|
-
if (self.pending.damage_roll > 0) {
|
|
395
|
+
if (self.pending.damage_roll > 0 and (!self.pending.glitch or self.pending.hit)) {
|
|
395
396
|
try self.probability.update(1, 39);
|
|
396
397
|
action.damage = self.pending.damage_roll;
|
|
397
398
|
}
|
|
@@ -656,6 +657,7 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
656
657
|
var d = self.durations.get(player);
|
|
657
658
|
const n = d.attacking;
|
|
658
659
|
if (obs == .ended) {
|
|
660
|
+
// "3-4 turns" includes the turn for the initial attack *plus* the forced attacks
|
|
659
661
|
assert(n >= 2 and n <= 3);
|
|
660
662
|
if (n != 3) try self.probability.update(1, 4 - @as(u4, n));
|
|
661
663
|
d.attacking = 0;
|
|
@@ -682,6 +684,7 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
682
684
|
const q: u4 = if (n < 3) 8 - ((n - 1) * p) else 2;
|
|
683
685
|
|
|
684
686
|
if (obs == .ended) {
|
|
687
|
+
// "2-5 turns" includes the turn for the initial attack *plus* the forced attacks
|
|
685
688
|
assert(n >= 1 and n <= 4);
|
|
686
689
|
if (n != 4) try self.probability.update(p, q);
|
|
687
690
|
d.binding = 0;
|
|
@@ -1049,7 +1052,7 @@ pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
|
1049
1052
|
|
|
1050
1053
|
r.reduce();
|
|
1051
1054
|
if (r.p != p or r.q != q) {
|
|
1052
|
-
print("expected {d}/{d}, found {}\n", .{ p, q, r });
|
|
1055
|
+
print("expected {d}/{d}, found {f}\n", .{ p, q, r });
|
|
1053
1056
|
return error.TestExpectedEqual;
|
|
1054
1057
|
}
|
|
1055
1058
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
|
-
const std = @import("std");
|
|
4
|
-
|
|
5
|
-
const rng = @import("../../common/rng.zig");
|
|
6
3
|
const gen1 = @import("../../gen1/data.zig");
|
|
4
|
+
const rng = @import("../../common/rng.zig");
|
|
5
|
+
const std = @import("std");
|
|
7
6
|
|
|
8
7
|
const assert = std.debug.assert;
|
|
9
|
-
|
|
10
8
|
const percent = rng.Gen12.percent;
|
|
11
9
|
const Type = gen1.Type;
|
|
12
10
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
|
-
const std = @import("std");
|
|
4
|
-
|
|
5
3
|
const gen1 = @import("../../gen1/data.zig");
|
|
4
|
+
const std = @import("std");
|
|
6
5
|
|
|
7
6
|
const assert = std.debug.assert;
|
|
8
|
-
|
|
9
7
|
const Stats = gen1.Stats;
|
|
10
8
|
const Types = gen1.Types;
|
|
11
9
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
|
-
const std = @import("std");
|
|
4
|
-
|
|
5
3
|
const gen1 = @import("../../gen1/data.zig");
|
|
4
|
+
const std = @import("std");
|
|
6
5
|
|
|
7
6
|
const assert = std.debug.assert;
|
|
8
7
|
const Effectiveness = gen1.Effectiveness;
|
|
@@ -99,7 +98,7 @@ pub const Type = enum(u4) {
|
|
|
99
98
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
/// The precedence order of Type `
|
|
101
|
+
/// The precedence order of Type `t1` vs. Type `t2`.
|
|
103
102
|
pub fn precedence(t1: Type, t2: Type) u8 {
|
|
104
103
|
for (PRECEDENCE, 0..) |matchup, i| {
|
|
105
104
|
if (matchup.type1 == t1 and matchup.type2 == t2) return @intCast(i);
|
|
@@ -109,7 +108,7 @@ pub const Type = enum(u4) {
|
|
|
109
108
|
};
|
|
110
109
|
|
|
111
110
|
/// Representation of a Pokémon's typing.
|
|
112
|
-
pub const Types = packed struct {
|
|
111
|
+
pub const Types = packed struct(u8) {
|
|
113
112
|
/// A Pokémon's primary type.
|
|
114
113
|
type1: Type = .Normal,
|
|
115
114
|
/// A Pokémon's secondary type (may be identical to its primary type).
|
package/src/lib/gen1/data.zig
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
1
|
const builtin = @import("builtin");
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
2
|
+
const calc = @import("calc.zig");
|
|
3
|
+
const chance = @import("chance.zig");
|
|
6
4
|
const data = @import("../common/data.zig");
|
|
5
|
+
const mechanics = @import("mechanics.zig");
|
|
6
|
+
const moves = @import("data/moves.zig");
|
|
7
|
+
const pkmn = @import("../pkmn.zig");
|
|
7
8
|
const protocol = @import("../common/protocol.zig");
|
|
8
9
|
const rng = @import("../common/rng.zig");
|
|
9
|
-
const util = @import("../common/util.zig");
|
|
10
|
-
|
|
11
|
-
const moves = @import("data/moves.zig");
|
|
12
10
|
const species = @import("data/species.zig");
|
|
11
|
+
const std = @import("std");
|
|
13
12
|
const types = @import("data/types.zig");
|
|
14
|
-
|
|
15
|
-
const calc = @import("calc.zig");
|
|
16
|
-
const chance = @import("chance.zig");
|
|
17
|
-
const mechanics = @import("mechanics.zig");
|
|
13
|
+
const util = @import("../common/util.zig");
|
|
18
14
|
|
|
19
15
|
const assert = std.debug.assert;
|
|
20
16
|
const expectEqual = std.testing.expectEqual;
|
|
@@ -66,7 +62,7 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
66
62
|
/// The last damage dealt by either side.
|
|
67
63
|
last_damage: u16 = 0,
|
|
68
64
|
/// Details about the last move selected/used by each player required to detect desyncs.
|
|
69
|
-
last_moves: [2]MoveDetails =
|
|
65
|
+
last_moves: [2]MoveDetails = @splat(.{}),
|
|
70
66
|
/// The pseudo random number generator.
|
|
71
67
|
rng: RNG,
|
|
72
68
|
|
|
@@ -126,12 +122,12 @@ test Battle {
|
|
|
126
122
|
/// Representation of one side of a Generation I Pokémon battle.
|
|
127
123
|
pub const Side = extern struct {
|
|
128
124
|
/// The player's party in its original order
|
|
129
|
-
pokemon: [6]Pokemon =
|
|
125
|
+
pokemon: [6]Pokemon = @splat(.{}),
|
|
130
126
|
/// The active Pokémon for the side, zero initialized if the battle has yet to start.
|
|
131
127
|
/// Note that fainted Pokémon are still consider "active" until their replacement switches in.
|
|
132
128
|
active: ActivePokemon = .{},
|
|
133
129
|
/// One-based slot indexes reflecting the current order of the player's party.
|
|
134
|
-
order: [6]u8 =
|
|
130
|
+
order: [6]u8 = @splat(0),
|
|
135
131
|
/// The last move the player selected.
|
|
136
132
|
last_selected_move: Move = .None,
|
|
137
133
|
/// The last move the player used.
|
|
@@ -170,7 +166,7 @@ pub const ActivePokemon = extern struct {
|
|
|
170
166
|
/// The active Pokémon's volatile statuses and associated data.
|
|
171
167
|
volatiles: Volatiles = .{},
|
|
172
168
|
/// The active Pokémon's current move slots.
|
|
173
|
-
moves: [4]MoveSlot =
|
|
169
|
+
moves: [4]MoveSlot = @splat(.{}),
|
|
174
170
|
|
|
175
171
|
comptime {
|
|
176
172
|
assert(@sizeOf(ActivePokemon) == 32);
|
|
@@ -190,7 +186,7 @@ pub const Pokemon = extern struct {
|
|
|
190
186
|
/// The Pokémon's unmodified stats.
|
|
191
187
|
stats: Stats(u16) = .{},
|
|
192
188
|
/// The Pokémon's original stored move slots.
|
|
193
|
-
moves: [4]MoveSlot =
|
|
189
|
+
moves: [4]MoveSlot = @splat(.{}),
|
|
194
190
|
/// The Pokémon's current HP.
|
|
195
191
|
hp: u16 = 0,
|
|
196
192
|
/// The Pokémon's current status.
|
package/src/lib/gen1/helpers.zig
CHANGED
|
@@ -1,32 +1,24 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
1
|
const builtin = @import("builtin");
|
|
3
|
-
|
|
4
2
|
const common = @import("../common/data.zig");
|
|
3
|
+
const data = @import("data.zig");
|
|
5
4
|
const options = @import("../common/options.zig");
|
|
6
5
|
const protocol = @import("../common/protocol.zig");
|
|
7
6
|
const rng = @import("../common/rng.zig");
|
|
7
|
+
const std = @import("std");
|
|
8
8
|
const util = @import("../common/util.zig");
|
|
9
9
|
|
|
10
|
-
const data = @import("data.zig");
|
|
11
|
-
|
|
12
10
|
const assert = std.debug.assert;
|
|
13
|
-
|
|
14
11
|
const Choice = common.Choice;
|
|
15
|
-
|
|
16
|
-
const showdown = options.showdown;
|
|
17
|
-
|
|
18
|
-
const PSRNG = rng.PSRNG;
|
|
19
|
-
|
|
20
12
|
const DVs = data.DVs;
|
|
21
13
|
const Move = data.Move;
|
|
22
14
|
const MoveSlot = data.MoveSlot;
|
|
15
|
+
const PSRNG = rng.PSRNG;
|
|
16
|
+
const showdown = options.showdown;
|
|
23
17
|
const Species = data.Species;
|
|
24
18
|
const Stats = data.Stats;
|
|
25
19
|
|
|
26
20
|
const endian = builtin.cpu.arch.endian();
|
|
27
21
|
|
|
28
|
-
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
29
|
-
|
|
30
22
|
/// Configuration options controlling the domain of valid Pokémon that can be generated by the
|
|
31
23
|
/// random generator helpers.
|
|
32
24
|
pub const Options = struct {
|
|
@@ -169,7 +161,7 @@ pub const Pokemon = struct {
|
|
|
169
161
|
var pokemon = data.Pokemon{};
|
|
170
162
|
pokemon.species = p.species;
|
|
171
163
|
const species = Species.get(p.species);
|
|
172
|
-
inline for (@
|
|
164
|
+
inline for (@typeInfo(@TypeOf(pokemon.stats)).@"struct".fields) |field| {
|
|
173
165
|
const hp = comptime std.mem.eql(u8, field.name, "hp");
|
|
174
166
|
const spc =
|
|
175
167
|
comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
|
|
@@ -205,7 +197,7 @@ pub const Pokemon = struct {
|
|
|
205
197
|
const lvl = if (rand.chance(u8, 1, 20)) rand.range(u8, 1, 99 + 1) else 100;
|
|
206
198
|
var stats: Stats(u16) = .{};
|
|
207
199
|
const dvs = DVs.random(rand);
|
|
208
|
-
inline for (@
|
|
200
|
+
inline for (@typeInfo(@TypeOf(stats)).@"struct".fields) |field| {
|
|
209
201
|
@field(stats, field.name) = Stats(u16).calc(
|
|
210
202
|
field.name,
|
|
211
203
|
@field(species.stats, field.name),
|
|
@@ -218,7 +210,7 @@ pub const Pokemon = struct {
|
|
|
218
210
|
);
|
|
219
211
|
}
|
|
220
212
|
|
|
221
|
-
var ms
|
|
213
|
+
var ms: [4]MoveSlot = @splat(.{});
|
|
222
214
|
const n = if (rand.chance(u8, 1, 100)) rand.range(u4, 1, 3 + 1) else 4;
|
|
223
215
|
for (0..n) |i| {
|
|
224
216
|
var m: Move = .None;
|
|
@@ -266,14 +258,7 @@ fn blocked(m: Move) bool {
|
|
|
266
258
|
fn durations(m: Move) bool {
|
|
267
259
|
// Any moves that have effects that result in duration tracking with -Dchance
|
|
268
260
|
return switch (Move.get(m).effect) {
|
|
269
|
-
.
|
|
270
|
-
.Bide,
|
|
271
|
-
.Sleep,
|
|
272
|
-
.Rage,
|
|
273
|
-
.Binding,
|
|
274
|
-
.Thrashing,
|
|
275
|
-
.ConfusionChance,
|
|
276
|
-
.Disable,
|
|
261
|
+
.Haze,
|
|
277
262
|
.Metronome,
|
|
278
263
|
=> true,
|
|
279
264
|
else => false,
|
|
@@ -305,23 +290,23 @@ else
|
|
|
305
290
|
pub fn diff(
|
|
306
291
|
a: *const data.Battle(data.PRNG),
|
|
307
292
|
b: *const data.Battle(data.PRNG),
|
|
308
|
-
w: protocol.
|
|
293
|
+
w: *protocol.Writer,
|
|
309
294
|
) !usize {
|
|
310
|
-
const pos = w.
|
|
295
|
+
const pos = w.pos;
|
|
311
296
|
const size = @sizeOf(data.Battle(data.PRNG)) - @sizeOf(data.PRNG);
|
|
312
297
|
assert(size % 2 == 0);
|
|
313
298
|
assert(size / 2 < 255);
|
|
314
299
|
|
|
315
300
|
var i: usize = 0;
|
|
316
301
|
while (i < size) : (i += 2) {
|
|
317
|
-
const val =
|
|
318
|
-
if (val !=
|
|
302
|
+
const val = std.mem.bytesAsValue(u16, std.mem.asBytes(a)[i .. i + 2]).*;
|
|
303
|
+
if (val != std.mem.bytesAsValue(u16, std.mem.asBytes(b)[i .. i + 2]).*) {
|
|
319
304
|
try w.writeByte(@intCast(i / 2));
|
|
320
305
|
try w.writeInt(u16, val, endian);
|
|
321
306
|
}
|
|
322
307
|
}
|
|
323
308
|
|
|
324
|
-
return w.
|
|
309
|
+
return w.pos - pos;
|
|
325
310
|
}
|
|
326
311
|
|
|
327
312
|
/// TODO
|