@pkmn/engine 0.1.0-dev.f918c3bd → 0.1.0-dev.fb6653d6
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 +51 -23
- 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 +23 -9
- 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 +109 -107
- 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 +303 -101
- package/package.json +61 -132
- package/src/bin/install-pkmn-engine +30 -20
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/{binding → bindings}/node.zig +8 -21
- package/src/lib/bindings/wasm.zig +58 -0
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/debug.zig +39 -8
- package/src/lib/common/js.zig +4 -2
- package/src/lib/common/optional.zig +21 -10
- package/src/lib/common/options.zig +6 -0
- package/src/lib/common/protocol.zig +421 -393
- package/src/lib/common/rational.zig +131 -35
- package/src/lib/common/rng.zig +16 -9
- package/src/lib/common/util.zig +50 -1
- package/src/lib/gen1/calc.zig +687 -160
- package/src/lib/gen1/chance.zig +434 -307
- package/src/lib/gen1/data/moves.zig +26 -14
- package/src/lib/gen1/data/species.zig +4 -6
- package/src/lib/gen1/data/types.zig +7 -8
- package/src/lib/gen1/data.zig +44 -47
- package/src/lib/gen1/helpers.zig +91 -562
- package/src/lib/gen1/mechanics.zig +641 -557
- 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 +67 -47
- package/src/lib/gen2/data/species.zig +2 -4
- package/src/lib/gen2/data/types.zig +134 -32
- package/src/lib/gen2/data.zig +56 -54
- package/src/lib/gen2/generated.zig +801 -0
- package/src/lib/gen2/helpers.zig +46 -25
- package/src/lib/gen2/mechanics.zig +2778 -362
- 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 -894
- package/src/lib/gen2/README.md +0 -328
- package/src/test/display/pkmn.html.tmpl +0 -368
|
@@ -1,12 +1,10 @@
|
|
|
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
|
-
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
|
|
|
@@ -1599,43 +1597,43 @@ pub const Move = enum(u8) {
|
|
|
1599
1597
|
}
|
|
1600
1598
|
|
|
1601
1599
|
/// Whether this effect activates during the "begin" step of move execution.
|
|
1602
|
-
pub
|
|
1600
|
+
pub fn onBegin(effect: Effect) bool {
|
|
1603
1601
|
return @intFromEnum(effect) > 0 and @intFromEnum(effect) <= 16;
|
|
1604
1602
|
}
|
|
1605
1603
|
|
|
1606
1604
|
/// Whether this effect lowers stats.
|
|
1607
|
-
pub
|
|
1605
|
+
pub fn isStatDown(effect: Effect) bool {
|
|
1608
1606
|
return @intFromEnum(effect) > 16 and @intFromEnum(effect) <= 21;
|
|
1609
1607
|
}
|
|
1610
1608
|
|
|
1611
1609
|
/// Whether this effect activates during the "end" step of move execution.
|
|
1612
|
-
pub
|
|
1610
|
+
pub fn onEnd(effect: Effect) bool {
|
|
1613
1611
|
return @intFromEnum(effect) > 16 and @intFromEnum(effect) <= 31;
|
|
1614
1612
|
}
|
|
1615
1613
|
|
|
1616
1614
|
/// Whether this effect is considered to "always happen".
|
|
1617
|
-
pub
|
|
1615
|
+
pub fn alwaysHappens(effect: Effect) bool {
|
|
1618
1616
|
return @intFromEnum(effect) > 31 and @intFromEnum(effect) <= 38;
|
|
1619
1617
|
}
|
|
1620
1618
|
|
|
1621
1619
|
/// Whether this effect is handled specially by the engine.
|
|
1622
|
-
pub
|
|
1620
|
+
pub fn isSpecial(effect: Effect) bool {
|
|
1623
1621
|
// NB: isSpecial includes isMulti up to Twineedle
|
|
1624
1622
|
return @intFromEnum(effect) > 31 and @intFromEnum(effect) <= 46;
|
|
1625
1623
|
}
|
|
1626
1624
|
|
|
1627
1625
|
/// Whether this effect is a multi-hit effect.
|
|
1628
|
-
pub
|
|
1626
|
+
pub fn isMulti(effect: Effect) bool {
|
|
1629
1627
|
return @intFromEnum(effect) > 44 and @intFromEnum(effect) <= 47;
|
|
1630
1628
|
}
|
|
1631
1629
|
|
|
1632
1630
|
/// Whether this effect is has chance of lowering stats.
|
|
1633
|
-
pub
|
|
1631
|
+
pub fn isStatDownChance(effect: Effect) bool {
|
|
1634
1632
|
return @intFromEnum(effect) > 47 and @intFromEnum(effect) <= 51;
|
|
1635
1633
|
}
|
|
1636
1634
|
|
|
1637
1635
|
/// Whether this effect has a secondary chance.
|
|
1638
|
-
pub
|
|
1636
|
+
pub fn isSecondaryChance(effect: Effect) bool {
|
|
1639
1637
|
// NB: isSecondaryChance includes isStatDownChance as well as Twineedle
|
|
1640
1638
|
return (@intFromEnum(effect) > 46 and @intFromEnum(effect) <= 61);
|
|
1641
1639
|
}
|
|
@@ -1838,8 +1836,22 @@ pub const Move = enum(u8) {
|
|
|
1838
1836
|
/// The number of Pokémon moves in this generation.
|
|
1839
1837
|
pub const size = 165;
|
|
1840
1838
|
|
|
1839
|
+
/// Pokémon moves that can be called by Metronome in this generation.
|
|
1840
|
+
pub const METRONOME = init: {
|
|
1841
|
+
var num = 0;
|
|
1842
|
+
var moves: [163]Move = undefined;
|
|
1843
|
+
for (1..Move.size) |i| {
|
|
1844
|
+
if (i != @intFromEnum(Move.Metronome)) {
|
|
1845
|
+
moves[num] = @enumFromInt(i);
|
|
1846
|
+
num += 1;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
assert(num == moves.len);
|
|
1850
|
+
break :init moves;
|
|
1851
|
+
};
|
|
1852
|
+
|
|
1841
1853
|
/// Returns the `Data` corresponding to the move.
|
|
1842
|
-
pub
|
|
1854
|
+
pub fn get(id: Move) Data {
|
|
1843
1855
|
assert(id != .None and id != .SKIP_TURN);
|
|
1844
1856
|
return DATA[@intFromEnum(id) - 1];
|
|
1845
1857
|
}
|
|
@@ -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;
|
|
@@ -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
|
|
|
@@ -70,28 +67,28 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
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
|
|
|
89
86
|
/// Returns the `MoveDetails` for the given `player`.
|
|
90
|
-
pub
|
|
87
|
+
pub fn lastMove(
|
|
91
88
|
self: anytype,
|
|
92
89
|
player: Player,
|
|
93
90
|
) PointerType(@TypeOf(self), MoveDetails) {
|
|
94
|
-
assert(
|
|
91
|
+
assert(isPointerTo(self, Self));
|
|
95
92
|
return &self.last_moves[@intFromEnum(player)];
|
|
96
93
|
}
|
|
97
94
|
|
|
@@ -112,7 +109,7 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
112
109
|
/// make (i.e. on the cartridge a soft-lock occurs).
|
|
113
110
|
///
|
|
114
111
|
/// This function will always return choices > 0 if `pkmn.options.showdown` is true.
|
|
115
|
-
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 {
|
|
116
113
|
return mechanics.choices(self, player, request, out);
|
|
117
114
|
}
|
|
118
115
|
};
|
|
@@ -141,8 +138,8 @@ pub const Side = extern struct {
|
|
|
141
138
|
}
|
|
142
139
|
|
|
143
140
|
/// Returns the stored `Pokemon` corresponding to the one-indexed party `slot`.
|
|
144
|
-
pub
|
|
145
|
-
assert(
|
|
141
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
142
|
+
assert(isPointerTo(self, Side));
|
|
146
143
|
assert(slot > 0 and slot <= 6);
|
|
147
144
|
const id = self.order[slot - 1];
|
|
148
145
|
assert(id > 0 and id <= 6);
|
|
@@ -150,8 +147,8 @@ pub const Side = extern struct {
|
|
|
150
147
|
}
|
|
151
148
|
|
|
152
149
|
/// Returns the stored `Pokemon` corresponding to the `active` Pokémon (slot 1).
|
|
153
|
-
pub
|
|
154
|
-
assert(
|
|
150
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
151
|
+
assert(isPointerTo(self, Side));
|
|
155
152
|
return self.get(1);
|
|
156
153
|
}
|
|
157
154
|
};
|
|
@@ -176,8 +173,8 @@ pub const ActivePokemon = extern struct {
|
|
|
176
173
|
}
|
|
177
174
|
|
|
178
175
|
/// Returns the active Pokémon's current move slot located at the one-indexed `mslot`.
|
|
179
|
-
pub
|
|
180
|
-
assert(
|
|
176
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
177
|
+
assert(isPointerTo(self, ActivePokemon));
|
|
181
178
|
assert(mslot > 0 and mslot <= 4);
|
|
182
179
|
assert(self.moves[mslot - 1].id != .None);
|
|
183
180
|
return &self.moves[mslot - 1];
|
|
@@ -206,8 +203,8 @@ pub const Pokemon = extern struct {
|
|
|
206
203
|
}
|
|
207
204
|
|
|
208
205
|
/// Returns the Pokémon's original move slot located at the one-indexed `mslot`.
|
|
209
|
-
pub
|
|
210
|
-
assert(
|
|
206
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
207
|
+
assert(isPointerTo(self, Pokemon));
|
|
211
208
|
assert(mslot > 0 and mslot <= 4);
|
|
212
209
|
assert(self.moves[mslot - 1].id != .None);
|
|
213
210
|
return &self.moves[mslot - 1];
|
|
@@ -255,39 +252,39 @@ pub const Status = enum(u8) {
|
|
|
255
252
|
|
|
256
253
|
pub const TOX = 0b10001000;
|
|
257
254
|
|
|
258
|
-
const
|
|
255
|
+
const SLEEP = 0b111;
|
|
259
256
|
|
|
260
257
|
/// Whether or not the status `num` is the same as `status`.
|
|
261
|
-
pub
|
|
258
|
+
pub fn is(num: u8, status: Status) bool {
|
|
262
259
|
if (status == .SLP) return Status.duration(num) > 0;
|
|
263
260
|
return ((num >> @intCast(@intFromEnum(status))) & 1) != 0;
|
|
264
261
|
}
|
|
265
262
|
|
|
266
263
|
/// Initializes a non-sleep `status`. Use `slp` or `slf` to initialize a sleep status.
|
|
267
|
-
pub
|
|
264
|
+
pub fn init(status: Status) u8 {
|
|
268
265
|
assert(status != .SLP and status != .EXT);
|
|
269
266
|
return @as(u8, 1) << @intCast(@intFromEnum(status));
|
|
270
267
|
}
|
|
271
268
|
|
|
272
269
|
/// Initializes a non self-inflicted sleep status with duration `dur`.
|
|
273
|
-
pub
|
|
270
|
+
pub fn slp(dur: u3) u8 {
|
|
274
271
|
assert(dur > 0);
|
|
275
272
|
return @as(u8, dur);
|
|
276
273
|
}
|
|
277
274
|
|
|
278
275
|
/// Initializes a self-inflicted sleep status with duration `dur`.
|
|
279
|
-
pub
|
|
276
|
+
pub fn slf(dur: u3) u8 {
|
|
280
277
|
assert(dur > 0);
|
|
281
278
|
return 0x80 | slp(dur);
|
|
282
279
|
}
|
|
283
280
|
|
|
284
281
|
/// Returns the duration of a sleep status.
|
|
285
|
-
pub
|
|
286
|
-
return @intCast(num &
|
|
282
|
+
pub fn duration(num: u8) u3 {
|
|
283
|
+
return @intCast(num & SLEEP);
|
|
287
284
|
}
|
|
288
285
|
|
|
289
286
|
/// Returns whether `num` reflects any status.
|
|
290
|
-
pub
|
|
287
|
+
pub fn any(num: u8) bool {
|
|
291
288
|
return num > 0;
|
|
292
289
|
}
|
|
293
290
|
|
|
@@ -378,9 +375,9 @@ pub const Volatiles = packed struct(u64) {
|
|
|
378
375
|
/// The identity of whom the active Pokémon is transformed into.
|
|
379
376
|
transform: u4 = 0,
|
|
380
377
|
/// The remaining turns the move is disabled.
|
|
381
|
-
|
|
378
|
+
disable_duration: u4 = 0,
|
|
382
379
|
/// The move slot (1-4) that is disabled.
|
|
383
|
-
|
|
380
|
+
disable_move: u3 = 0,
|
|
384
381
|
/// The number of turns toxic damage has been accumulating.
|
|
385
382
|
toxic: u5 = 0,
|
|
386
383
|
};
|
|
@@ -395,8 +392,8 @@ test Volatiles {
|
|
|
395
392
|
volatiles.Substitute = true;
|
|
396
393
|
volatiles.substitute = 42;
|
|
397
394
|
volatiles.toxic = 4;
|
|
398
|
-
volatiles.
|
|
399
|
-
volatiles.
|
|
395
|
+
volatiles.disable_move = 2;
|
|
396
|
+
volatiles.disable_duration = 4;
|
|
400
397
|
|
|
401
398
|
try expect(volatiles.Confusion);
|
|
402
399
|
try expect(volatiles.Thrashing);
|
|
@@ -407,14 +404,14 @@ test Volatiles {
|
|
|
407
404
|
|
|
408
405
|
try expectEqual(@as(u16, 235), volatiles.state);
|
|
409
406
|
try expectEqual(@as(u8, 42), volatiles.substitute);
|
|
410
|
-
try expectEqual(@as(u4, 2), volatiles.
|
|
411
|
-
try expectEqual(@as(u4, 4), volatiles.
|
|
412
|
-
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);
|
|
413
410
|
try expectEqual(@as(u5, 4), volatiles.toxic);
|
|
414
|
-
try expectEqual(@as(
|
|
411
|
+
try expectEqual(@as(u3, 3), volatiles.attacks);
|
|
415
412
|
}
|
|
416
413
|
|
|
417
|
-
///
|
|
414
|
+
/// Representation of a Pokémon's stats in Generation I.
|
|
418
415
|
pub fn Stats(comptime T: type) type {
|
|
419
416
|
return extern struct {
|
|
420
417
|
hp: T = 0,
|