@pkmn/engine 0.1.0-dev.a324c50f → 0.1.0-dev.a5846b2d
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 +92 -56
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +44 -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 +97 -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 +25 -3
- package/build/pkg/addon.js +39 -71
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/ids.json +12 -12
- package/build/pkg/data/layout.json +17 -4
- 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 +13 -17
- package/build/pkg/gen1.js +8 -12
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +40 -91
- package/build/pkg/index.js +6 -63
- 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 -69
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +141 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +142 -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 +345 -126
- package/package.json +68 -121
- package/src/bin/install-pkmn-engine +32 -22
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/{binding → bindings}/node.zig +9 -22
- package/src/lib/bindings/wasm.zig +59 -0
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/data.zig +12 -24
- package/src/lib/common/debug.zig +39 -8
- package/src/lib/common/js.zig +120 -0
- package/src/lib/common/optional.zig +71 -0
- package/src/lib/common/options.zig +6 -0
- package/src/lib/common/protocol.zig +811 -332
- package/src/lib/common/rational.zig +449 -0
- package/src/lib/common/rng.zig +22 -15
- package/src/lib/common/util.zig +61 -0
- package/src/lib/gen1/calc.zig +953 -0
- package/src/lib/gen1/chance.zig +1185 -0
- package/src/lib/gen1/data/moves.zig +193 -183
- package/src/lib/gen1/data/species.zig +4 -6
- package/src/lib/gen1/data/types.zig +8 -9
- package/src/lib/gen1/data.zig +67 -77
- package/src/lib/gen1/helpers.zig +91 -409
- package/src/lib/gen1/mechanics.zig +675 -613
- package/src/lib/gen2/calc.zig +153 -0
- package/src/lib/gen2/chance.zig +902 -0
- package/src/lib/gen2/data/items.zig +13 -21
- package/src/lib/gen2/data/moves.zig +664 -572
- package/src/lib/gen2/data/species.zig +2 -4
- package/src/lib/gen2/data/types.zig +135 -33
- package/src/lib/gen2/data.zig +115 -91
- package/src/lib/gen2/generated.zig +801 -0
- package/src/lib/gen2/helpers.zig +54 -37
- package/src/lib/gen2/mechanics.zig +3580 -29
- package/src/lib/node.zig +18 -0
- package/src/lib/pkmn.zig +37 -15
- package/src/lib/wasm.zig +17 -0
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +354 -0
- package/build/test/display.js +0 -400
- package/build/test/display.js.map +0 -1
- package/src/lib/binding/wasm.zig +0 -12
- package/src/lib/gen1/README.md +0 -814
- package/src/lib/gen2/README.md +0 -309
- package/src/test/display/pkmn.html.tmpl +0 -368
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
//! Code generated by `tools/generate` - manual edits will be overwritten
|
|
2
|
-
|
|
3
|
-
const std = @import("std");
|
|
1
|
+
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
4
2
|
|
|
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
|
|
|
@@ -1091,8 +1089,8 @@ pub const Species = enum(u8) {
|
|
|
1091
1089
|
/// The number of Pokémon species in this generation.
|
|
1092
1090
|
pub const size = 151;
|
|
1093
1091
|
|
|
1094
|
-
/// The Pokémon's critical hit
|
|
1095
|
-
pub
|
|
1092
|
+
/// The Pokémon's critical hit ratio out of 256.
|
|
1093
|
+
pub fn chance(id: Species) u8 {
|
|
1096
1094
|
assert(id != .None);
|
|
1097
1095
|
return CHANCES[@intFromEnum(id) - 1];
|
|
1098
1096
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
//! Code generated by `tools/generate` - manual edits will be overwritten
|
|
2
|
-
|
|
3
|
-
const std = @import("std");
|
|
1
|
+
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
4
2
|
|
|
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;
|
|
@@ -30,7 +29,7 @@ pub const Type = enum(u4) {
|
|
|
30
29
|
Ice,
|
|
31
30
|
Dragon,
|
|
32
31
|
|
|
33
|
-
const CHART
|
|
32
|
+
const CHART: [15][15]Effectiveness = .{
|
|
34
33
|
[_]Effectiveness{ N, N, N, N, N, R, N, I, N, N, N, N, N, N, N }, // Normal
|
|
35
34
|
[_]Effectiveness{ S, N, R, R, N, S, R, I, N, N, N, N, R, S, N }, // Fighting
|
|
36
35
|
[_]Effectiveness{ N, S, N, N, N, R, S, N, N, N, S, R, N, N, N }, // Flying
|
|
@@ -90,16 +89,16 @@ pub const Type = enum(u4) {
|
|
|
90
89
|
pub const size = 15;
|
|
91
90
|
|
|
92
91
|
/// Whether or not this type is considered to be special as opposed to physical.
|
|
93
|
-
pub
|
|
92
|
+
pub fn special(self: Type) bool {
|
|
94
93
|
return @intFromEnum(self) >= @intFromEnum(Type.Fire);
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
/// The `Effectiveness` of type `t2` vs. type `t1`.
|
|
98
|
-
pub
|
|
97
|
+
pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
|
|
99
98
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
/// The precedence order of
|
|
101
|
+
/// The precedence order of Type `t2` vs. Type `t1`.
|
|
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);
|
|
@@ -120,12 +119,12 @@ pub const Types = packed struct {
|
|
|
120
119
|
}
|
|
121
120
|
|
|
122
121
|
/// Whether this typing is immune to type `t`.
|
|
123
|
-
pub
|
|
122
|
+
pub fn immune(self: Types, t: Type) bool {
|
|
124
123
|
return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
/// Whether this typing includes type `t`.
|
|
128
|
-
pub
|
|
127
|
+
pub fn includes(self: Types, t: Type) bool {
|
|
129
128
|
return self.type1 == t or self.type2 == t;
|
|
130
129
|
}
|
|
131
130
|
};
|
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;
|
|
@@ -22,11 +18,11 @@ const expect = std.testing.expect;
|
|
|
22
18
|
|
|
23
19
|
/// The minimum size in bytes required to hold all Generation I choice options.
|
|
24
20
|
pub const MAX_CHOICES: usize = 9; // move 1..4, switch 2..6
|
|
25
|
-
/// The
|
|
26
|
-
/// At least as large as MAX_CHOICES.
|
|
21
|
+
/// The maximum number of bytes possibly logged by a single Generation I update.
|
|
27
22
|
pub const MAX_LOGS: usize = 180;
|
|
28
23
|
|
|
29
|
-
/// The
|
|
24
|
+
/// The optimal size in bytes required to hold all Generation I choice options.
|
|
25
|
+
/// At least as large as MAX_CHOICES.
|
|
30
26
|
pub const CHOICES_SIZE = if (builtin.mode == .ReleaseSmall)
|
|
31
27
|
MAX_CHOICES
|
|
32
28
|
else
|
|
@@ -47,6 +43,7 @@ const Player = data.Player;
|
|
|
47
43
|
const Result = data.Result;
|
|
48
44
|
|
|
49
45
|
const PointerType = util.PointerType;
|
|
46
|
+
const isPointerTo = util.isPointerTo;
|
|
50
47
|
|
|
51
48
|
const showdown = pkmn.options.showdown;
|
|
52
49
|
|
|
@@ -65,27 +62,36 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
65
62
|
/// The last damage dealt by either side.
|
|
66
63
|
last_damage: u16 = 0,
|
|
67
64
|
/// Details about the last move selected/used by each player required to detect desyncs.
|
|
68
|
-
last_moves: MoveDetails = .{},
|
|
65
|
+
last_moves: [2]MoveDetails = [_]MoveDetails{.{}} ** 2,
|
|
69
66
|
/// The pseudo random number generator.
|
|
70
67
|
rng: RNG,
|
|
71
68
|
|
|
72
69
|
/// Returns the `Side` for the given `player`.
|
|
73
|
-
pub
|
|
74
|
-
assert(
|
|
70
|
+
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
71
|
+
assert(isPointerTo(self, Self));
|
|
75
72
|
return &self.sides[@intFromEnum(player)];
|
|
76
73
|
}
|
|
77
74
|
|
|
78
75
|
/// Returns the `Side` of the opponent for the given `player`
|
|
79
|
-
pub
|
|
80
|
-
assert(
|
|
76
|
+
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
77
|
+
assert(isPointerTo(self, Self));
|
|
81
78
|
return &self.sides[@intFromEnum(player.foe())];
|
|
82
79
|
}
|
|
83
80
|
|
|
84
81
|
/// Returns an identifier for the active Pokémon of `player`.
|
|
85
|
-
pub
|
|
82
|
+
pub fn active(self: *const Self, player: Player) ID {
|
|
86
83
|
return player.ident(@intCast(self.side(player).order[0]));
|
|
87
84
|
}
|
|
88
85
|
|
|
86
|
+
/// Returns the `MoveDetails` for the given `player`.
|
|
87
|
+
pub fn lastMove(
|
|
88
|
+
self: anytype,
|
|
89
|
+
player: Player,
|
|
90
|
+
) PointerType(@TypeOf(self), MoveDetails) {
|
|
91
|
+
assert(isPointerTo(self, Self));
|
|
92
|
+
return &self.last_moves[@intFromEnum(player)];
|
|
93
|
+
}
|
|
94
|
+
|
|
89
95
|
/// Returns the result of applying Player 1's choice `c1` and Player 2's choice `c2` to the
|
|
90
96
|
/// battle, optionally writing protocol message logs to `options.log` if `pkmn.options.log`
|
|
91
97
|
/// is enabled.
|
|
@@ -103,7 +109,7 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
103
109
|
/// make (i.e. on the cartridge a soft-lock occurs).
|
|
104
110
|
///
|
|
105
111
|
/// This function will always return choices > 0 if `pkmn.options.showdown` is true.
|
|
106
|
-
pub fn choices(self: *Self, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
112
|
+
pub fn choices(self: *const Self, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
107
113
|
return mechanics.choices(self, player, request, out);
|
|
108
114
|
}
|
|
109
115
|
};
|
|
@@ -132,8 +138,8 @@ pub const Side = extern struct {
|
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
/// Returns the stored `Pokemon` corresponding to the one-indexed party `slot`.
|
|
135
|
-
pub
|
|
136
|
-
assert(
|
|
141
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
142
|
+
assert(isPointerTo(self, Side));
|
|
137
143
|
assert(slot > 0 and slot <= 6);
|
|
138
144
|
const id = self.order[slot - 1];
|
|
139
145
|
assert(id > 0 and id <= 6);
|
|
@@ -141,8 +147,8 @@ pub const Side = extern struct {
|
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
/// Returns the stored `Pokemon` corresponding to the `active` Pokémon (slot 1).
|
|
144
|
-
pub
|
|
145
|
-
assert(
|
|
150
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
151
|
+
assert(isPointerTo(self, Side));
|
|
146
152
|
return self.get(1);
|
|
147
153
|
}
|
|
148
154
|
};
|
|
@@ -167,8 +173,8 @@ pub const ActivePokemon = extern struct {
|
|
|
167
173
|
}
|
|
168
174
|
|
|
169
175
|
/// Returns the active Pokémon's current move slot located at the one-indexed `mslot`.
|
|
170
|
-
pub
|
|
171
|
-
assert(
|
|
176
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
177
|
+
assert(isPointerTo(self, ActivePokemon));
|
|
172
178
|
assert(mslot > 0 and mslot <= 4);
|
|
173
179
|
assert(self.moves[mslot - 1].id != .None);
|
|
174
180
|
return &self.moves[mslot - 1];
|
|
@@ -197,15 +203,15 @@ pub const Pokemon = extern struct {
|
|
|
197
203
|
}
|
|
198
204
|
|
|
199
205
|
/// Returns the Pokémon's original move slot located at the one-indexed `mslot`.
|
|
200
|
-
pub
|
|
201
|
-
assert(
|
|
206
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
207
|
+
assert(isPointerTo(self, Pokemon));
|
|
202
208
|
assert(mslot > 0 and mslot <= 4);
|
|
203
209
|
assert(self.moves[mslot - 1].id != .None);
|
|
204
210
|
return &self.moves[mslot - 1];
|
|
205
211
|
}
|
|
206
212
|
};
|
|
207
213
|
|
|
208
|
-
/// Representation of a Generation I
|
|
214
|
+
/// Representation of a Generation I Pokémon's move slot in a battle.
|
|
209
215
|
pub const MoveSlot = extern struct {
|
|
210
216
|
/// The identifier for the move.
|
|
211
217
|
id: Move = .None,
|
|
@@ -213,24 +219,16 @@ pub const MoveSlot = extern struct {
|
|
|
213
219
|
pp: u8 = 0,
|
|
214
220
|
|
|
215
221
|
comptime {
|
|
216
|
-
assert(@sizeOf(MoveSlot) ==
|
|
222
|
+
assert(@sizeOf(MoveSlot) == 2);
|
|
217
223
|
}
|
|
218
224
|
};
|
|
219
225
|
|
|
220
226
|
/// Details required to detect desyncs based on the move last selected/executed by players.
|
|
221
|
-
pub const MoveDetails = packed struct {
|
|
222
|
-
/// The move slot index of the last move selected in the battle menu
|
|
223
|
-
|
|
224
|
-
/// Whether the last move executed
|
|
225
|
-
|
|
226
|
-
/// The move slot index of the last move selected in the battle menu by Player 2
|
|
227
|
-
p2_index: if (showdown) u8 else u4 = 0,
|
|
228
|
-
/// Whether the last move executed by Player 2 was counterable.
|
|
229
|
-
p2_counterable: if (showdown) u8 else u4 = 0,
|
|
230
|
-
|
|
231
|
-
comptime {
|
|
232
|
-
assert(@sizeOf(MoveDetails) == if (showdown) 4 else 2);
|
|
233
|
-
}
|
|
227
|
+
pub const MoveDetails = packed struct(if (showdown) u16 else u8) {
|
|
228
|
+
/// The move slot index of the last move selected in the battle menu.
|
|
229
|
+
index: if (showdown) u8 else u4 = 0,
|
|
230
|
+
/// Whether the last move executed was counterable.
|
|
231
|
+
counterable: if (showdown) u8 else u4 = 0,
|
|
234
232
|
};
|
|
235
233
|
|
|
236
234
|
/// Bitfield representation of a Generation I & II Pokémon's major status condition.
|
|
@@ -254,39 +252,39 @@ pub const Status = enum(u8) {
|
|
|
254
252
|
|
|
255
253
|
pub const TOX = 0b10001000;
|
|
256
254
|
|
|
257
|
-
const
|
|
255
|
+
const SLEEP = 0b111;
|
|
258
256
|
|
|
259
257
|
/// Whether or not the status `num` is the same as `status`.
|
|
260
|
-
pub
|
|
258
|
+
pub fn is(num: u8, status: Status) bool {
|
|
261
259
|
if (status == .SLP) return Status.duration(num) > 0;
|
|
262
260
|
return ((num >> @intCast(@intFromEnum(status))) & 1) != 0;
|
|
263
261
|
}
|
|
264
262
|
|
|
265
263
|
/// Initializes a non-sleep `status`. Use `slp` or `slf` to initialize a sleep status.
|
|
266
|
-
pub
|
|
264
|
+
pub fn init(status: Status) u8 {
|
|
267
265
|
assert(status != .SLP and status != .EXT);
|
|
268
266
|
return @as(u8, 1) << @intCast(@intFromEnum(status));
|
|
269
267
|
}
|
|
270
268
|
|
|
271
269
|
/// Initializes a non self-inflicted sleep status with duration `dur`.
|
|
272
|
-
pub
|
|
270
|
+
pub fn slp(dur: u3) u8 {
|
|
273
271
|
assert(dur > 0);
|
|
274
272
|
return @as(u8, dur);
|
|
275
273
|
}
|
|
276
274
|
|
|
277
275
|
/// Initializes a self-inflicted sleep status with duration `dur`.
|
|
278
|
-
pub
|
|
276
|
+
pub fn slf(dur: u3) u8 {
|
|
279
277
|
assert(dur > 0);
|
|
280
278
|
return 0x80 | slp(dur);
|
|
281
279
|
}
|
|
282
280
|
|
|
283
281
|
/// Returns the duration of a sleep status.
|
|
284
|
-
pub
|
|
285
|
-
return @intCast(num &
|
|
282
|
+
pub fn duration(num: u8) u3 {
|
|
283
|
+
return @intCast(num & SLEEP);
|
|
286
284
|
}
|
|
287
285
|
|
|
288
286
|
/// Returns whether `num` reflects any status.
|
|
289
|
-
pub
|
|
287
|
+
pub fn any(num: u8) bool {
|
|
290
288
|
return num > 0;
|
|
291
289
|
}
|
|
292
290
|
|
|
@@ -324,7 +322,7 @@ test Status {
|
|
|
324
322
|
}
|
|
325
323
|
|
|
326
324
|
/// Bitfield representation of volatile statuses and associated data in Generation I.
|
|
327
|
-
pub const Volatiles = packed struct {
|
|
325
|
+
pub const Volatiles = packed struct(u64) {
|
|
328
326
|
/// Whether the "Bide" volatile status is present.
|
|
329
327
|
Bide: bool = false,
|
|
330
328
|
/// Whether the "Thrashing" volatile status is present.
|
|
@@ -377,19 +375,15 @@ pub const Volatiles = packed struct {
|
|
|
377
375
|
/// The identity of whom the active Pokémon is transformed into.
|
|
378
376
|
transform: u4 = 0,
|
|
379
377
|
/// The remaining turns the move is disabled.
|
|
380
|
-
|
|
378
|
+
disable_duration: u4 = 0,
|
|
381
379
|
/// The move slot (1-4) that is disabled.
|
|
382
|
-
|
|
380
|
+
disable_move: u3 = 0,
|
|
383
381
|
/// The number of turns toxic damage has been accumulating.
|
|
384
382
|
toxic: u5 = 0,
|
|
385
|
-
|
|
386
|
-
comptime {
|
|
387
|
-
assert(@sizeOf(Volatiles) == 8);
|
|
388
|
-
}
|
|
389
383
|
};
|
|
390
384
|
|
|
391
385
|
test Volatiles {
|
|
392
|
-
var volatiles =
|
|
386
|
+
var volatiles: Volatiles = .{};
|
|
393
387
|
volatiles.Confusion = true;
|
|
394
388
|
volatiles.confusion = 2;
|
|
395
389
|
volatiles.Thrashing = true;
|
|
@@ -398,8 +392,8 @@ test Volatiles {
|
|
|
398
392
|
volatiles.Substitute = true;
|
|
399
393
|
volatiles.substitute = 42;
|
|
400
394
|
volatiles.toxic = 4;
|
|
401
|
-
volatiles.
|
|
402
|
-
volatiles.
|
|
395
|
+
volatiles.disable_move = 2;
|
|
396
|
+
volatiles.disable_duration = 4;
|
|
403
397
|
|
|
404
398
|
try expect(volatiles.Confusion);
|
|
405
399
|
try expect(volatiles.Thrashing);
|
|
@@ -410,14 +404,14 @@ test Volatiles {
|
|
|
410
404
|
|
|
411
405
|
try expectEqual(@as(u16, 235), volatiles.state);
|
|
412
406
|
try expectEqual(@as(u8, 42), volatiles.substitute);
|
|
413
|
-
try expectEqual(@as(u4, 2), volatiles.
|
|
414
|
-
try expectEqual(@as(u4, 4), volatiles.
|
|
415
|
-
try expectEqual(@as(
|
|
407
|
+
try expectEqual(@as(u4, 2), volatiles.disable_move);
|
|
408
|
+
try expectEqual(@as(u4, 4), volatiles.disable_duration);
|
|
409
|
+
try expectEqual(@as(u3, 2), volatiles.confusion);
|
|
416
410
|
try expectEqual(@as(u5, 4), volatiles.toxic);
|
|
417
|
-
try expectEqual(@as(
|
|
411
|
+
try expectEqual(@as(u3, 3), volatiles.attacks);
|
|
418
412
|
}
|
|
419
413
|
|
|
420
|
-
///
|
|
414
|
+
/// Representation of a Pokémon's stats in Generation I.
|
|
421
415
|
pub fn Stats(comptime T: type) type {
|
|
422
416
|
return extern struct {
|
|
423
417
|
hp: T = 0,
|
|
@@ -451,7 +445,7 @@ test Stats {
|
|
|
451
445
|
}
|
|
452
446
|
|
|
453
447
|
/// Representation of a Pokémon's boosts in Generation I.
|
|
454
|
-
pub const Boosts = packed struct {
|
|
448
|
+
pub const Boosts = packed struct(u32) {
|
|
455
449
|
/// A Pokémon's Attack boosts.
|
|
456
450
|
atk: i4 = 0,
|
|
457
451
|
/// A Pokémon's Defense boosts.
|
|
@@ -466,14 +460,10 @@ pub const Boosts = packed struct {
|
|
|
466
460
|
evasion: i4 = 0,
|
|
467
461
|
|
|
468
462
|
_: u8 = 0,
|
|
469
|
-
|
|
470
|
-
comptime {
|
|
471
|
-
assert(@sizeOf(Boosts) == 4);
|
|
472
|
-
}
|
|
473
463
|
};
|
|
474
464
|
|
|
475
465
|
test Boosts {
|
|
476
|
-
const boosts =
|
|
466
|
+
const boosts: Boosts = .{ .spc = -6 };
|
|
477
467
|
try expectEqual(0, boosts.atk);
|
|
478
468
|
try expectEqual(-6, boosts.spc);
|
|
479
469
|
}
|
|
@@ -485,7 +475,7 @@ test Move {
|
|
|
485
475
|
try expectEqual(2, @intFromEnum(Move.KarateChop));
|
|
486
476
|
const move = Move.get(.Fissure);
|
|
487
477
|
try expectEqual(Move.Effect.OHKO, move.effect);
|
|
488
|
-
try expectEqual(
|
|
478
|
+
try expectEqual(rng.Gen12.percent(30), move.accuracy);
|
|
489
479
|
try expectEqual(Type.Ground, move.type);
|
|
490
480
|
|
|
491
481
|
try expect(!Move.Effect.onBegin(.None));
|
|
@@ -623,16 +613,16 @@ pub const DVs = struct {
|
|
|
623
613
|
};
|
|
624
614
|
|
|
625
615
|
test DVs {
|
|
626
|
-
var dvs =
|
|
616
|
+
var dvs: DVs = .{ .spc = 15, .spe = 15 };
|
|
627
617
|
try expectEqual(@as(u4, 15), dvs.hp());
|
|
628
|
-
dvs =
|
|
618
|
+
dvs = .{
|
|
629
619
|
.atk = 5,
|
|
630
620
|
.def = 15,
|
|
631
621
|
.spe = 13,
|
|
632
622
|
.spc = 13,
|
|
633
623
|
};
|
|
634
624
|
try expectEqual(@as(u4, 15), dvs.hp());
|
|
635
|
-
dvs =
|
|
625
|
+
dvs = .{
|
|
636
626
|
.def = 3,
|
|
637
627
|
.spe = 10,
|
|
638
628
|
.spc = 11,
|