@pkmn/engine 0.1.0-dev.7feed58c → 0.1.0-dev.8058a1d0
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 +18 -11
- package/build/pkg/addon/node.js +17 -7
- package/build/pkg/addon/node.js.map +1 -1
- package/build/pkg/addon/wasm.js.map +1 -1
- package/build/pkg/addon.d.ts +4 -4
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +1 -1
- package/build/pkg/gen1.js +17 -7
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.js +17 -7
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +11 -2
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +54 -10
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +19 -94
- package/build/tools/display/debug.jsx.map +1 -1
- package/build/tools/display/index.js +17 -7
- package/build/tools/display/index.js.map +1 -1
- package/build/tools/display/ui.jsx +20 -9
- package/build/tools/display/ui.jsx.map +1 -1
- package/build/tools/display/util.js +125 -1
- package/build/tools/display/util.js.map +1 -1
- package/build.zig +141 -231
- package/package.json +26 -24
- package/src/bin/install-pkmn-engine +22 -7
- package/src/lib/bindings/c.zig +27 -82
- package/src/lib/bindings/node.zig +7 -11
- package/src/lib/bindings/wasm.zig +6 -15
- package/src/lib/common/array.zig +5 -12
- package/src/lib/common/debug.zig +33 -59
- package/src/lib/common/js.zig +3 -9
- package/src/lib/common/optional.zig +11 -21
- package/src/lib/common/protocol.zig +224 -189
- package/src/lib/common/rational.zig +275 -284
- package/src/lib/common/util.zig +14 -31
- package/src/lib/gen1/calc.zig +131 -109
- package/src/lib/gen1/chance.zig +112 -75
- package/src/lib/gen1/data/types.zig +2 -2
- package/src/lib/gen1/data.zig +5 -5
- package/src/lib/gen1/helpers.zig +8 -10
- package/src/lib/gen1/mechanics.zig +43 -41
- package/src/lib/gen2/calc.zig +3 -6
- package/src/lib/gen2/chance.zig +12 -18
- package/src/lib/gen2/data/types.zig +6 -3
- package/src/lib/gen2/data.zig +8 -7
- package/src/lib/gen2/helpers.zig +4 -6
- package/src/lib/gen2/mechanics.zig +18 -18
- package/src/lib/napi.h +2 -0
- package/src/lib/node.zig +1 -5
- package/src/lib/pkmn.zig +91 -17
- package/src/lib/wasm.zig +2 -6
- package/src/tools/display/dom.ts +43 -31
package/src/lib/gen1/chance.zig
CHANGED
|
@@ -23,10 +23,6 @@ const PointerType = util.PointerType;
|
|
|
23
23
|
const print = std.debug.print;
|
|
24
24
|
const showdown = options.showdown;
|
|
25
25
|
|
|
26
|
-
const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
|
|
27
|
-
const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
|
|
28
|
-
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
29
|
-
|
|
30
26
|
/// Actions taken by a hypothetical "chance player" that convey information about which RNG events
|
|
31
27
|
/// were observed during a Generation I battle `update`. This can additionally be provided as input
|
|
32
28
|
/// to the `update` call to override the normal behavior of the RNG in order to force specific
|
|
@@ -56,15 +52,15 @@ pub const Actions = extern struct {
|
|
|
56
52
|
/// same shape if they have the same fields set (though those fields need not necessarily be
|
|
57
53
|
/// set to the same value).
|
|
58
54
|
pub fn matches(a: Actions, b: Actions) bool {
|
|
59
|
-
inline for (@
|
|
60
|
-
inline for (@
|
|
55
|
+
inline for (@typeInfo(Actions).@"struct".fields) |player| {
|
|
56
|
+
inline for (@typeInfo(Action).@"struct".fields) |field| {
|
|
61
57
|
const a_val = @field(@field(a, player.name), field.name);
|
|
62
58
|
const b_val = @field(@field(b, player.name), field.name);
|
|
63
59
|
|
|
64
60
|
switch (@typeInfo(@TypeOf(a_val))) {
|
|
65
|
-
|
|
61
|
+
.@"enum" => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
66
62
|
return false,
|
|
67
|
-
|
|
63
|
+
.int => if ((a_val > 0) != (b_val > 0)) return false,
|
|
68
64
|
else => unreachable,
|
|
69
65
|
}
|
|
70
66
|
}
|
|
@@ -91,7 +87,7 @@ pub const Actions = extern struct {
|
|
|
91
87
|
return a;
|
|
92
88
|
}
|
|
93
89
|
|
|
94
|
-
pub fn fmt(self: Actions, writer:
|
|
90
|
+
pub fn fmt(self: Actions, writer: *std.Io.Writer, shape: bool) !void {
|
|
95
91
|
try writer.writeAll("<P1 = ");
|
|
96
92
|
try self.p1.fmt(writer, shape);
|
|
97
93
|
try writer.writeAll(", P2 = ");
|
|
@@ -99,8 +95,7 @@ pub const Actions = extern struct {
|
|
|
99
95
|
try writer.writeAll(">");
|
|
100
96
|
}
|
|
101
97
|
|
|
102
|
-
pub fn format(a: Actions,
|
|
103
|
-
_ = .{ f, o };
|
|
98
|
+
pub fn format(a: Actions, w: *std.Io.Writer) !void {
|
|
104
99
|
try fmt(a, w, false);
|
|
105
100
|
}
|
|
106
101
|
};
|
|
@@ -124,18 +119,41 @@ test Actions {
|
|
|
124
119
|
}
|
|
125
120
|
|
|
126
121
|
/// Observation made about a duration - whether the duration has started, been continued, or ended.
|
|
127
|
-
pub
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
122
|
+
pub fn Observation(comptime field: Duration.Field) type {
|
|
123
|
+
return switch (field) {
|
|
124
|
+
.attacking, .binding => enum(u2) {
|
|
125
|
+
started,
|
|
126
|
+
continuing,
|
|
127
|
+
ended,
|
|
128
|
+
},
|
|
129
|
+
.sleep, .disable => enum(u3) {
|
|
130
|
+
started,
|
|
131
|
+
continuing,
|
|
132
|
+
ended,
|
|
133
|
+
// TODO haze support
|
|
134
|
+
unused1,
|
|
135
|
+
unused2,
|
|
136
|
+
unused3,
|
|
137
|
+
unused4,
|
|
138
|
+
},
|
|
139
|
+
.confusion => enum(u4) {
|
|
140
|
+
started,
|
|
141
|
+
continuing,
|
|
142
|
+
ended,
|
|
143
|
+
/// An indicator that an existing confusion duration has been overwritten by a new
|
|
144
|
+
/// confusion duration due to a Thrashing move ending ("hidden" confusion). This is not
|
|
145
|
+
/// immediately observable to an opponent, to compute probabilities from an opponent's
|
|
146
|
+
/// point of view based solely on public information extra work must be done to correct
|
|
147
|
+
/// for the information leak
|
|
148
|
+
overwritten,
|
|
149
|
+
// TODO haze support
|
|
150
|
+
unused1,
|
|
151
|
+
unused2,
|
|
152
|
+
unused3,
|
|
153
|
+
unused4,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
139
157
|
|
|
140
158
|
/// Information about the RNG that was observed during a Generation I battle `update` for a
|
|
141
159
|
/// single player.
|
|
@@ -162,26 +180,24 @@ pub const Action = packed struct(u64) {
|
|
|
162
180
|
duration: u4 = 0,
|
|
163
181
|
|
|
164
182
|
/// TODO
|
|
165
|
-
sleep: Optional(Observation) = .None,
|
|
183
|
+
sleep: Optional(Observation(.sleep)) = .None,
|
|
166
184
|
/// TODO
|
|
167
|
-
confusion: Optional(
|
|
185
|
+
confusion: Optional(Observation(.confusion)) = .None,
|
|
168
186
|
/// TODO
|
|
169
|
-
disable: Optional(Observation) = .None,
|
|
187
|
+
disable: Optional(Observation(.disable)) = .None,
|
|
170
188
|
/// TODO
|
|
171
|
-
attacking: Optional(Observation) = .None,
|
|
189
|
+
attacking: Optional(Observation(.attacking)) = .None,
|
|
172
190
|
/// TODO
|
|
173
|
-
binding: Optional(Observation) = .None,
|
|
174
|
-
|
|
175
|
-
_: u1 = 0,
|
|
191
|
+
binding: Optional(Observation(.binding)) = .None,
|
|
176
192
|
|
|
177
193
|
/// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
|
|
178
194
|
/// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
|
|
179
|
-
move_slot:
|
|
195
|
+
move_slot: u3 = 0,
|
|
196
|
+
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
197
|
+
multi_hit: u3 = 0,
|
|
180
198
|
|
|
181
199
|
/// TODO
|
|
182
200
|
pp: u4 = 0,
|
|
183
|
-
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
184
|
-
multi_hit: u4 = 0,
|
|
185
201
|
|
|
186
202
|
/// If not 0, psywave - 1 should be returned as the damage roll for Rolls.psywave.
|
|
187
203
|
psywave: u8 = 0,
|
|
@@ -191,18 +207,19 @@ pub const Action = packed struct(u64) {
|
|
|
191
207
|
|
|
192
208
|
pub const Field = std.meta.FieldEnum(Action);
|
|
193
209
|
|
|
194
|
-
pub fn format(a: Action,
|
|
195
|
-
_ = .{ f, o };
|
|
210
|
+
pub fn format(a: Action, w: *std.Io.Writer) !void {
|
|
196
211
|
try fmt(a, w, false);
|
|
197
212
|
}
|
|
198
213
|
|
|
199
|
-
|
|
214
|
+
const SYMBOLS = [_][]const u8{ "+", "", "-", "#" };
|
|
215
|
+
|
|
216
|
+
pub fn fmt(self: Action, writer: *std.Io.Writer, shape: bool) !void {
|
|
200
217
|
try writer.writeByte('(');
|
|
201
218
|
var printed = false;
|
|
202
|
-
inline for (@
|
|
219
|
+
inline for (@typeInfo(Action).@"struct".fields) |field| {
|
|
203
220
|
const val = @field(self, field.name);
|
|
204
221
|
switch (@typeInfo(@TypeOf(val))) {
|
|
205
|
-
|
|
222
|
+
.@"enum" => if (val != .None) {
|
|
206
223
|
if (printed) try writer.writeAll(", ");
|
|
207
224
|
if (shape) {
|
|
208
225
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -211,19 +228,14 @@ pub const Action = packed struct(u64) {
|
|
|
211
228
|
if (val == .false) "!" else "",
|
|
212
229
|
field.name,
|
|
213
230
|
});
|
|
214
|
-
} else if (@TypeOf(val)
|
|
215
|
-
@
|
|
216
|
-
{
|
|
217
|
-
try writer.print("{s}{s}", .{
|
|
218
|
-
([_][]const u8{ "+", "", "-", "#" })[@intFromEnum(val) - 1],
|
|
219
|
-
field.name,
|
|
220
|
-
});
|
|
231
|
+
} else if (@TypeOf(val) != Move and @TypeOf(val) != Optional(Player)) {
|
|
232
|
+
try writer.print("{s}{s}", .{ SYMBOLS[@intFromEnum(val) - 1], field.name });
|
|
221
233
|
} else {
|
|
222
234
|
try writer.print("{s}:{s}", .{ field.name, @tagName(val) });
|
|
223
235
|
}
|
|
224
236
|
printed = true;
|
|
225
237
|
},
|
|
226
|
-
|
|
238
|
+
.int => if (val != 0) {
|
|
227
239
|
if (printed) try writer.writeAll(", ");
|
|
228
240
|
if (shape) {
|
|
229
241
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -256,14 +268,8 @@ pub const Durations = extern struct {
|
|
|
256
268
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
257
269
|
}
|
|
258
270
|
|
|
259
|
-
pub fn format(
|
|
260
|
-
self
|
|
261
|
-
comptime fmt: []const u8,
|
|
262
|
-
opts: std.fmt.FormatOptions,
|
|
263
|
-
writer: anytype,
|
|
264
|
-
) !void {
|
|
265
|
-
_ = .{ fmt, opts };
|
|
266
|
-
try writer.print("[P1 = {}, P2 = {}]", .{ self.p1, self.p2 });
|
|
271
|
+
pub fn format(self: Durations, writer: *std.Io.Writer) !void {
|
|
272
|
+
try writer.print("[P1 = {f}, P2 = {f}]", .{ self.p1, self.p2 });
|
|
267
273
|
}
|
|
268
274
|
};
|
|
269
275
|
|
|
@@ -279,19 +285,18 @@ pub const Duration = packed struct(u32) {
|
|
|
279
285
|
|
|
280
286
|
_: u1 = 0,
|
|
281
287
|
|
|
288
|
+
pub const Field = enum { attacking, binding, sleep, disable, confusion };
|
|
289
|
+
|
|
282
290
|
pub fn format(
|
|
283
291
|
self: Duration,
|
|
284
|
-
|
|
285
|
-
opts: std.fmt.FormatOptions,
|
|
286
|
-
writer: anytype,
|
|
292
|
+
writer: *std.Io.Writer,
|
|
287
293
|
) !void {
|
|
288
|
-
_ = .{ fmt, opts };
|
|
289
294
|
try writer.writeByte('(');
|
|
290
295
|
var printed = false;
|
|
291
|
-
inline for (@
|
|
296
|
+
inline for (@typeInfo(Duration).@"struct".fields) |field| {
|
|
292
297
|
const val = @field(self, field.name);
|
|
293
298
|
switch (@typeInfo(@TypeOf(val))) {
|
|
294
|
-
|
|
299
|
+
.int => if (val != 0) {
|
|
295
300
|
if (printed) try writer.writeAll(", ");
|
|
296
301
|
if (comptime std.mem.eql(u8, field.name, "sleeps")) {
|
|
297
302
|
try writer.print("{s}:[", .{field.name});
|
|
@@ -552,7 +557,7 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
552
557
|
self: *Self,
|
|
553
558
|
comptime field: Action.Field,
|
|
554
559
|
player: Player,
|
|
555
|
-
obs: Optional(
|
|
560
|
+
obs: Optional(Observation(.confusion)),
|
|
556
561
|
) void {
|
|
557
562
|
if (!enabled) return;
|
|
558
563
|
|
|
@@ -594,7 +599,7 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
594
599
|
}
|
|
595
600
|
}
|
|
596
601
|
|
|
597
|
-
pub fn sleep(self: *Self, player: Player, obs: Optional(Observation)) Error!void {
|
|
602
|
+
pub fn sleep(self: *Self, player: Player, obs: Optional(Observation(.sleep))) Error!void {
|
|
598
603
|
if (!enabled) return;
|
|
599
604
|
|
|
600
605
|
var a = self.actions.get(player);
|
|
@@ -618,7 +623,11 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
618
623
|
}
|
|
619
624
|
}
|
|
620
625
|
|
|
621
|
-
pub fn confusion(
|
|
626
|
+
pub fn confusion(
|
|
627
|
+
self: *Self,
|
|
628
|
+
player: Player,
|
|
629
|
+
obs: Optional(Observation(.confusion)),
|
|
630
|
+
) Error!void {
|
|
622
631
|
if (!enabled) return;
|
|
623
632
|
|
|
624
633
|
var a = self.actions.get(player);
|
|
@@ -640,7 +649,11 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
640
649
|
}
|
|
641
650
|
}
|
|
642
651
|
|
|
643
|
-
pub fn disable(
|
|
652
|
+
pub fn disable(
|
|
653
|
+
self: *Self,
|
|
654
|
+
player: Player,
|
|
655
|
+
obs: Optional(Observation(.disable)),
|
|
656
|
+
) Error!void {
|
|
644
657
|
if (!enabled) return;
|
|
645
658
|
|
|
646
659
|
var a = self.actions.get(player);
|
|
@@ -662,7 +675,11 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
662
675
|
}
|
|
663
676
|
}
|
|
664
677
|
|
|
665
|
-
pub fn attacking(
|
|
678
|
+
pub fn attacking(
|
|
679
|
+
self: *Self,
|
|
680
|
+
player: Player,
|
|
681
|
+
obs: Optional(Observation(.attacking)),
|
|
682
|
+
) Error!void {
|
|
666
683
|
if (!enabled) return;
|
|
667
684
|
|
|
668
685
|
var a = self.actions.get(player);
|
|
@@ -684,7 +701,11 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
684
701
|
}
|
|
685
702
|
}
|
|
686
703
|
|
|
687
|
-
pub fn binding(
|
|
704
|
+
pub fn binding(
|
|
705
|
+
self: *Self,
|
|
706
|
+
player: Player,
|
|
707
|
+
obs: Optional(Observation(.binding)),
|
|
708
|
+
) Error!void {
|
|
688
709
|
if (!enabled) return;
|
|
689
710
|
|
|
690
711
|
var a = self.actions.get(player);
|
|
@@ -894,13 +915,13 @@ test "Chance.moveSlot" {
|
|
|
894
915
|
|
|
895
916
|
try chance.moveSlot(.P2, 2, &ms, 2);
|
|
896
917
|
try expectProbability(&chance.probability, 1, 2);
|
|
897
|
-
try expectValue(@as(
|
|
918
|
+
try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
|
|
898
919
|
|
|
899
920
|
chance.reset();
|
|
900
921
|
|
|
901
922
|
try chance.moveSlot(.P1, 1, &ms, 0);
|
|
902
923
|
try expectProbability(&chance.probability, 1, 3);
|
|
903
|
-
try expectValue(@as(
|
|
924
|
+
try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
|
|
904
925
|
}
|
|
905
926
|
|
|
906
927
|
test "Chance.multiHit" {
|
|
@@ -1067,7 +1088,7 @@ pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
|
1067
1088
|
|
|
1068
1089
|
r.reduce();
|
|
1069
1090
|
if (r.p != p or r.q != q) {
|
|
1070
|
-
print("expected {d}/{d}, found {}\n", .{ p, q, r });
|
|
1091
|
+
print("expected {d}/{d}, found {f}\n", .{ p, q, r });
|
|
1071
1092
|
return error.TestExpectedEqual;
|
|
1072
1093
|
}
|
|
1073
1094
|
}
|
|
@@ -1145,28 +1166,44 @@ const Null = struct {
|
|
|
1145
1166
|
self: Null,
|
|
1146
1167
|
comptime field: Action.Field,
|
|
1147
1168
|
player: Player,
|
|
1148
|
-
obs: Optional(
|
|
1169
|
+
obs: Optional(Observation(.confusion)),
|
|
1149
1170
|
) void {
|
|
1150
1171
|
_ = .{ self, field, player, obs };
|
|
1151
1172
|
}
|
|
1152
1173
|
|
|
1153
|
-
pub fn sleep(self: Null, player: Player, obs: Optional(Observation)) Error!void {
|
|
1174
|
+
pub fn sleep(self: Null, player: Player, obs: Optional(Observation(.sleep))) Error!void {
|
|
1154
1175
|
_ = .{ self, player, obs };
|
|
1155
1176
|
}
|
|
1156
1177
|
|
|
1157
|
-
pub fn confusion(
|
|
1178
|
+
pub fn confusion(
|
|
1179
|
+
self: Null,
|
|
1180
|
+
player: Player,
|
|
1181
|
+
obs: Optional(Observation(.confusion)),
|
|
1182
|
+
) Error!void {
|
|
1158
1183
|
_ = .{ self, player, obs };
|
|
1159
1184
|
}
|
|
1160
1185
|
|
|
1161
|
-
pub fn disable(
|
|
1186
|
+
pub fn disable(
|
|
1187
|
+
self: Null,
|
|
1188
|
+
player: Player,
|
|
1189
|
+
obs: Optional(Observation(.disable)),
|
|
1190
|
+
) Error!void {
|
|
1162
1191
|
_ = .{ self, player, obs };
|
|
1163
1192
|
}
|
|
1164
1193
|
|
|
1165
|
-
pub fn attacking(
|
|
1194
|
+
pub fn attacking(
|
|
1195
|
+
self: Null,
|
|
1196
|
+
player: Player,
|
|
1197
|
+
obs: Optional(Observation(.attacking)),
|
|
1198
|
+
) Error!void {
|
|
1166
1199
|
_ = .{ self, player, obs };
|
|
1167
1200
|
}
|
|
1168
1201
|
|
|
1169
|
-
pub fn binding(
|
|
1202
|
+
pub fn binding(
|
|
1203
|
+
self: Null,
|
|
1204
|
+
player: Player,
|
|
1205
|
+
obs: Optional(Observation(.binding)),
|
|
1206
|
+
) Error!void {
|
|
1170
1207
|
_ = .{ self, player, obs };
|
|
1171
1208
|
}
|
|
1172
1209
|
|
|
@@ -98,7 +98,7 @@ pub const Type = enum(u4) {
|
|
|
98
98
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
/// The precedence order of Type `
|
|
101
|
+
/// The precedence order of Type `t1` vs. Type `t2`.
|
|
102
102
|
pub fn precedence(t1: Type, t2: Type) u8 {
|
|
103
103
|
for (PRECEDENCE, 0..) |matchup, i| {
|
|
104
104
|
if (matchup.type1 == t1 and matchup.type2 == t2) return @intCast(i);
|
|
@@ -108,7 +108,7 @@ pub const Type = enum(u4) {
|
|
|
108
108
|
};
|
|
109
109
|
|
|
110
110
|
/// Representation of a Pokémon's typing.
|
|
111
|
-
pub const Types = packed struct {
|
|
111
|
+
pub const Types = packed struct(u8) {
|
|
112
112
|
/// A Pokémon's primary type.
|
|
113
113
|
type1: Type = .Normal,
|
|
114
114
|
/// A Pokémon's secondary type (may be identical to its primary type).
|
package/src/lib/gen1/data.zig
CHANGED
|
@@ -62,7 +62,7 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
62
62
|
/// The last damage dealt by either side.
|
|
63
63
|
last_damage: u16 = 0,
|
|
64
64
|
/// Details about the last move selected/used by each player required to detect desyncs.
|
|
65
|
-
last_moves: [2]MoveDetails =
|
|
65
|
+
last_moves: [2]MoveDetails = @splat(.{}),
|
|
66
66
|
/// The pseudo random number generator.
|
|
67
67
|
rng: RNG,
|
|
68
68
|
|
|
@@ -122,12 +122,12 @@ test Battle {
|
|
|
122
122
|
/// Representation of one side of a Generation I Pokémon battle.
|
|
123
123
|
pub const Side = extern struct {
|
|
124
124
|
/// The player's party in its original order
|
|
125
|
-
pokemon: [6]Pokemon =
|
|
125
|
+
pokemon: [6]Pokemon = @splat(.{}),
|
|
126
126
|
/// The active Pokémon for the side, zero initialized if the battle has yet to start.
|
|
127
127
|
/// Note that fainted Pokémon are still consider "active" until their replacement switches in.
|
|
128
128
|
active: ActivePokemon = .{},
|
|
129
129
|
/// One-based slot indexes reflecting the current order of the player's party.
|
|
130
|
-
order: [6]u8 =
|
|
130
|
+
order: [6]u8 = @splat(0),
|
|
131
131
|
/// The last move the player selected.
|
|
132
132
|
last_selected_move: Move = .None,
|
|
133
133
|
/// The last move the player used.
|
|
@@ -166,7 +166,7 @@ pub const ActivePokemon = extern struct {
|
|
|
166
166
|
/// The active Pokémon's volatile statuses and associated data.
|
|
167
167
|
volatiles: Volatiles = .{},
|
|
168
168
|
/// The active Pokémon's current move slots.
|
|
169
|
-
moves: [4]MoveSlot =
|
|
169
|
+
moves: [4]MoveSlot = @splat(.{}),
|
|
170
170
|
|
|
171
171
|
comptime {
|
|
172
172
|
assert(@sizeOf(ActivePokemon) == 32);
|
|
@@ -186,7 +186,7 @@ pub const Pokemon = extern struct {
|
|
|
186
186
|
/// The Pokémon's unmodified stats.
|
|
187
187
|
stats: Stats(u16) = .{},
|
|
188
188
|
/// The Pokémon's original stored move slots.
|
|
189
|
-
moves: [4]MoveSlot =
|
|
189
|
+
moves: [4]MoveSlot = @splat(.{}),
|
|
190
190
|
/// The Pokémon's current HP.
|
|
191
191
|
hp: u16 = 0,
|
|
192
192
|
/// The Pokémon's current status.
|
package/src/lib/gen1/helpers.zig
CHANGED
|
@@ -19,8 +19,6 @@ const Stats = data.Stats;
|
|
|
19
19
|
|
|
20
20
|
const endian = builtin.cpu.arch.endian();
|
|
21
21
|
|
|
22
|
-
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
23
|
-
|
|
24
22
|
/// Configuration options controlling the domain of valid Pokémon that can be generated by the
|
|
25
23
|
/// random generator helpers.
|
|
26
24
|
pub const Options = struct {
|
|
@@ -163,7 +161,7 @@ pub const Pokemon = struct {
|
|
|
163
161
|
var pokemon = data.Pokemon{};
|
|
164
162
|
pokemon.species = p.species;
|
|
165
163
|
const species = Species.get(p.species);
|
|
166
|
-
inline for (@
|
|
164
|
+
inline for (@typeInfo(@TypeOf(pokemon.stats)).@"struct".fields) |field| {
|
|
167
165
|
const hp = comptime std.mem.eql(u8, field.name, "hp");
|
|
168
166
|
const spc =
|
|
169
167
|
comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
|
|
@@ -199,7 +197,7 @@ pub const Pokemon = struct {
|
|
|
199
197
|
const lvl = if (rand.chance(u8, 1, 20)) rand.range(u8, 1, 99 + 1) else 100;
|
|
200
198
|
var stats: Stats(u16) = .{};
|
|
201
199
|
const dvs = DVs.random(rand);
|
|
202
|
-
inline for (@
|
|
200
|
+
inline for (@typeInfo(@TypeOf(stats)).@"struct".fields) |field| {
|
|
203
201
|
@field(stats, field.name) = Stats(u16).calc(
|
|
204
202
|
field.name,
|
|
205
203
|
@field(species.stats, field.name),
|
|
@@ -212,7 +210,7 @@ pub const Pokemon = struct {
|
|
|
212
210
|
);
|
|
213
211
|
}
|
|
214
212
|
|
|
215
|
-
var ms
|
|
213
|
+
var ms: [4]MoveSlot = @splat(.{});
|
|
216
214
|
const n = if (rand.chance(u8, 1, 100)) rand.range(u4, 1, 3 + 1) else 4;
|
|
217
215
|
for (0..n) |i| {
|
|
218
216
|
var m: Move = .None;
|
|
@@ -292,23 +290,23 @@ else
|
|
|
292
290
|
pub fn diff(
|
|
293
291
|
a: *const data.Battle(data.PRNG),
|
|
294
292
|
b: *const data.Battle(data.PRNG),
|
|
295
|
-
w: protocol.
|
|
293
|
+
w: *protocol.Writer,
|
|
296
294
|
) !usize {
|
|
297
|
-
const pos = w.
|
|
295
|
+
const pos = w.pos;
|
|
298
296
|
const size = @sizeOf(data.Battle(data.PRNG)) - @sizeOf(data.PRNG);
|
|
299
297
|
assert(size % 2 == 0);
|
|
300
298
|
assert(size / 2 < 255);
|
|
301
299
|
|
|
302
300
|
var i: usize = 0;
|
|
303
301
|
while (i < size) : (i += 2) {
|
|
304
|
-
const val =
|
|
305
|
-
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]).*) {
|
|
306
304
|
try w.writeByte(@intCast(i / 2));
|
|
307
305
|
try w.writeInt(u16, val, endian);
|
|
308
306
|
}
|
|
309
307
|
}
|
|
310
308
|
|
|
311
|
-
return w.
|
|
309
|
+
return w.pos - pos;
|
|
312
310
|
}
|
|
313
311
|
|
|
314
312
|
/// TODO
|