@pkmn/engine 0.1.0-dev.d3e796d5 → 0.1.0-dev.d56bdadd
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/pkg/data/ids.json +12 -12
- package/build/pkg/data/layout.json +2 -2
- package/build/pkg/data/protocol.json +69 -12
- package/build/pkg/data.d.ts +2 -2
- package/build/pkg/gen1.js +2 -2
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/protocol.js +56 -37
- package/build/pkg/protocol.js.map +1 -1
- package/build.zig +21 -15
- package/package.json +26 -14
- package/src/lib/binding/node.zig +1 -1
- package/src/lib/common/data.zig +8 -20
- package/src/lib/common/optional.zig +8 -1
- package/src/lib/common/protocol.zig +500 -56
- package/src/lib/common/rational.zig +5 -5
- package/src/lib/common/rng.zig +15 -6
- package/src/lib/gen1/README.md +31 -29
- package/src/lib/gen1/calc.zig +4 -4
- package/src/lib/gen1/chance.zig +55 -39
- package/src/lib/gen1/data/moves.zig +192 -180
- package/src/lib/gen1/data/species.zig +2 -2
- package/src/lib/gen1/data/types.zig +7 -7
- package/src/lib/gen1/data.zig +31 -43
- package/src/lib/gen1/helpers.zig +26 -41
- package/src/lib/gen1/mechanics.zig +131 -169
- package/src/lib/gen2/README.md +18 -72
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1314 -0
- package/src/lib/gen2/data/items.zig +12 -18
- package/src/lib/gen2/data/moves.zig +649 -568
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +134 -31
- package/src/lib/gen2/data.zig +70 -67
- package/src/lib/gen2/generated.zig +808 -0
- package/src/lib/gen2/helpers.zig +4 -9
- package/src/lib/gen2/mechanics.zig +3113 -100
|
@@ -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
|
|
|
@@ -14,15 +14,15 @@ const I = Effectiveness.Immune;
|
|
|
14
14
|
|
|
15
15
|
/// Representation of a Generation II type in Pokémon.
|
|
16
16
|
pub const Type = enum(u8) {
|
|
17
|
+
Ground,
|
|
18
|
+
Rock,
|
|
19
|
+
Steel,
|
|
17
20
|
Normal,
|
|
18
21
|
Fighting,
|
|
19
22
|
Flying,
|
|
20
23
|
Poison,
|
|
21
|
-
Ground,
|
|
22
|
-
Rock,
|
|
23
24
|
Bug,
|
|
24
25
|
Ghost,
|
|
25
|
-
Steel,
|
|
26
26
|
@"???",
|
|
27
27
|
Fire,
|
|
28
28
|
Water,
|
|
@@ -33,37 +33,37 @@ pub const Type = enum(u8) {
|
|
|
33
33
|
Dragon,
|
|
34
34
|
Dark,
|
|
35
35
|
|
|
36
|
-
const CHART
|
|
37
|
-
[_]Effectiveness{ N,
|
|
38
|
-
[_]Effectiveness{
|
|
39
|
-
[_]Effectiveness{ N, S,
|
|
40
|
-
[_]Effectiveness{ N,
|
|
41
|
-
[_]Effectiveness{ N,
|
|
42
|
-
[_]Effectiveness{ N, R,
|
|
43
|
-
[_]Effectiveness{
|
|
44
|
-
[_]Effectiveness{
|
|
45
|
-
[_]Effectiveness{ N, N,
|
|
36
|
+
const CHART: [18][18]Effectiveness = .{
|
|
37
|
+
[_]Effectiveness{ N, S, S, N, N, I, S, R, N, N, S, N, R, S, N, N, N, N }, // Ground
|
|
38
|
+
[_]Effectiveness{ R, N, R, N, R, S, N, S, N, N, S, N, N, N, N, S, N, N }, // Rock
|
|
39
|
+
[_]Effectiveness{ N, S, R, N, N, N, N, N, N, N, R, R, N, R, N, S, N, N }, // Steel
|
|
40
|
+
[_]Effectiveness{ N, R, R, N, N, N, N, N, I, N, N, N, N, N, N, N, N, N }, // Normal
|
|
41
|
+
[_]Effectiveness{ N, S, S, S, N, R, R, R, I, N, N, N, N, N, R, S, N, S }, // Fighting
|
|
42
|
+
[_]Effectiveness{ N, R, R, N, S, N, N, S, N, N, N, N, S, R, N, N, N, N }, // Flying
|
|
43
|
+
[_]Effectiveness{ R, R, I, N, N, N, R, N, R, N, N, N, S, N, N, N, N, N }, // Poison
|
|
44
|
+
[_]Effectiveness{ N, N, R, N, R, R, R, N, R, N, R, N, S, N, S, N, N, S }, // Bug
|
|
45
|
+
[_]Effectiveness{ N, N, R, I, N, N, N, N, S, N, N, N, N, N, S, N, N, R }, // Ghost
|
|
46
46
|
[_]Effectiveness{ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N }, // ???
|
|
47
|
-
[_]Effectiveness{ N,
|
|
48
|
-
[_]Effectiveness{
|
|
49
|
-
[_]Effectiveness{
|
|
50
|
-
[_]Effectiveness{
|
|
51
|
-
[_]Effectiveness{ N,
|
|
52
|
-
[_]Effectiveness{
|
|
53
|
-
[_]Effectiveness{ N, N,
|
|
54
|
-
[_]Effectiveness{ N, R, N,
|
|
47
|
+
[_]Effectiveness{ N, R, S, N, N, N, N, S, N, N, R, R, S, N, N, S, R, N }, // Fire
|
|
48
|
+
[_]Effectiveness{ S, S, N, N, N, N, N, N, N, N, S, R, R, N, N, N, R, N }, // Water
|
|
49
|
+
[_]Effectiveness{ S, S, R, N, N, R, R, R, N, N, R, S, R, N, N, N, R, N }, // Grass
|
|
50
|
+
[_]Effectiveness{ I, N, N, N, N, S, N, N, N, N, N, S, R, R, N, N, R, N }, // Electric
|
|
51
|
+
[_]Effectiveness{ N, N, R, N, S, N, S, N, N, N, N, N, N, N, R, N, N, I }, // Psychic
|
|
52
|
+
[_]Effectiveness{ S, N, R, N, N, S, N, N, N, N, R, R, S, N, N, R, S, N }, // Ice
|
|
53
|
+
[_]Effectiveness{ N, N, R, N, N, N, N, N, N, N, N, N, N, N, N, N, S, N }, // Dragon
|
|
54
|
+
[_]Effectiveness{ N, N, R, N, R, N, N, N, S, N, N, N, N, N, S, N, N, R }, // Dark
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
const PRECEDENCE = [_]u8{
|
|
58
|
+
9, // Ground
|
|
59
|
+
13, // Rock
|
|
60
|
+
17, // Steel
|
|
58
61
|
1, // Normal
|
|
59
62
|
7, // Fighting
|
|
60
63
|
10, // Flying
|
|
61
64
|
8, // Poison
|
|
62
|
-
9, // Ground
|
|
63
|
-
13, // Rock
|
|
64
65
|
12, // Bug
|
|
65
66
|
14, // Ghost
|
|
66
|
-
17, // Steel
|
|
67
67
|
0, // ???
|
|
68
68
|
2, // Fire
|
|
69
69
|
3, // Water
|
|
@@ -75,29 +75,126 @@ pub const Type = enum(u8) {
|
|
|
75
75
|
16, // Dark
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
const INDEXES = [_]u8{
|
|
79
|
+
4, // Ground
|
|
80
|
+
5, // Rock
|
|
81
|
+
9, // Steel
|
|
82
|
+
0, // Normal
|
|
83
|
+
1, // Fighting
|
|
84
|
+
2, // Flying
|
|
85
|
+
3, // Poison
|
|
86
|
+
7, // Bug
|
|
87
|
+
8, // Ghost
|
|
88
|
+
19, // ???
|
|
89
|
+
20, // Fire
|
|
90
|
+
21, // Water
|
|
91
|
+
22, // Grass
|
|
92
|
+
23, // Electric
|
|
93
|
+
24, // Psychic
|
|
94
|
+
25, // Ice
|
|
95
|
+
26, // Dragon
|
|
96
|
+
27, // Dark
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const CONVERSION_2 = [_]Type{
|
|
100
|
+
.Normal,
|
|
101
|
+
.Fighting,
|
|
102
|
+
.Flying,
|
|
103
|
+
.Poison,
|
|
104
|
+
.Ground,
|
|
105
|
+
.Rock,
|
|
106
|
+
.@"???", // placeholder
|
|
107
|
+
.Bug,
|
|
108
|
+
.Ghost,
|
|
109
|
+
.Steel,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const HIDDEN_POWER = [_]Type{
|
|
113
|
+
.Fighting,
|
|
114
|
+
.Flying,
|
|
115
|
+
.Poison,
|
|
116
|
+
.Ground,
|
|
117
|
+
.Rock,
|
|
118
|
+
.Bug,
|
|
119
|
+
.Ghost,
|
|
120
|
+
.Steel,
|
|
121
|
+
.Fire,
|
|
122
|
+
.Water,
|
|
123
|
+
.Grass,
|
|
124
|
+
.Electric,
|
|
125
|
+
.Psychic,
|
|
126
|
+
.Ice,
|
|
127
|
+
.Dragon,
|
|
128
|
+
.Dark,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/// Order of Pokémon Showdown's types.
|
|
132
|
+
pub const SHOWDOWN = [_]Type{
|
|
133
|
+
.Fire,
|
|
134
|
+
.Ice,
|
|
135
|
+
.Steel,
|
|
136
|
+
.Electric,
|
|
137
|
+
.Ghost,
|
|
138
|
+
.Grass,
|
|
139
|
+
.Dark,
|
|
140
|
+
.Bug,
|
|
141
|
+
.Dragon,
|
|
142
|
+
.Fighting,
|
|
143
|
+
.Flying,
|
|
144
|
+
.Ground,
|
|
145
|
+
.Normal,
|
|
146
|
+
.Poison,
|
|
147
|
+
.Psychic,
|
|
148
|
+
.Rock,
|
|
149
|
+
.Water,
|
|
150
|
+
.@"???",
|
|
151
|
+
};
|
|
152
|
+
|
|
78
153
|
comptime {
|
|
79
154
|
assert(@bitSizeOf(Type) == 8);
|
|
80
155
|
assert(@sizeOf(@TypeOf(CHART)) == 324);
|
|
81
156
|
assert(@sizeOf(@TypeOf(PRECEDENCE)) == 18);
|
|
157
|
+
assert(@sizeOf(@TypeOf(INDEXES)) == 18);
|
|
158
|
+
assert(@sizeOf(@TypeOf(CONVERSION_2)) == 10);
|
|
159
|
+
assert(@sizeOf(@TypeOf(HIDDEN_POWER)) == 16);
|
|
160
|
+
assert(@sizeOf(@TypeOf(SHOWDOWN)) == 18);
|
|
82
161
|
}
|
|
83
162
|
|
|
84
163
|
/// The number of types in this generation.
|
|
85
164
|
pub const size = 18;
|
|
86
165
|
|
|
87
166
|
/// Whether or not this type is considered to be special as opposed to physical.
|
|
88
|
-
pub
|
|
167
|
+
pub fn special(self: Type) bool {
|
|
89
168
|
return @intFromEnum(self) >= @intFromEnum(Type.Fire);
|
|
90
169
|
}
|
|
91
170
|
|
|
92
171
|
/// The `Effectiveness` of type `t2` vs. type `t1`.
|
|
93
|
-
pub
|
|
172
|
+
pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
|
|
94
173
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
95
174
|
}
|
|
96
175
|
|
|
97
|
-
/// The precedence order of
|
|
98
|
-
pub
|
|
176
|
+
/// The precedence order of Type `type`.
|
|
177
|
+
pub fn precedence(self: Type) u8 {
|
|
99
178
|
return PRECEDENCE[@intFromEnum(self)];
|
|
100
179
|
}
|
|
180
|
+
|
|
181
|
+
/// The internal index of this Type used by Present.
|
|
182
|
+
pub fn present(self: Type) u8 {
|
|
183
|
+
return INDEXES[@intFromEnum(self)];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/// The Type corresponding to a random roll of `num` for Conversion 2.
|
|
187
|
+
pub fn conversion2(num: u8) Type {
|
|
188
|
+
assert(num != 6);
|
|
189
|
+
assert(num < 10 or num >= 20);
|
|
190
|
+
assert(num <= 27);
|
|
191
|
+
return if (num < 10) CONVERSION_2[num] else @enumFromInt(num - 10);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// The Type corresponding to a Hidden Power `index`.
|
|
195
|
+
pub fn hiddenPower(index: u8) Type {
|
|
196
|
+
return HIDDEN_POWER[index];
|
|
197
|
+
}
|
|
101
198
|
};
|
|
102
199
|
|
|
103
200
|
/// Representation of a Pokémon's typing.
|
|
@@ -112,12 +209,18 @@ pub const Types = extern struct {
|
|
|
112
209
|
}
|
|
113
210
|
|
|
114
211
|
/// Whether this typing is immune to type `t`.
|
|
115
|
-
pub
|
|
212
|
+
pub fn immune(self: Types, t: Type) bool {
|
|
116
213
|
return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
|
|
117
214
|
}
|
|
118
215
|
|
|
119
216
|
/// Whether this typing includes type `t`.
|
|
120
|
-
pub
|
|
217
|
+
pub fn includes(self: Types, t: Type) bool {
|
|
121
218
|
return self.type1 == t or self.type2 == t;
|
|
122
219
|
}
|
|
220
|
+
|
|
221
|
+
/// Whether this typing is immune to damage from Sandstorm.
|
|
222
|
+
pub fn sandstormImmune(self: Types) bool {
|
|
223
|
+
return @intFromEnum(self.type1) <= @intFromEnum(Type.Steel) or
|
|
224
|
+
@intFromEnum(self.type2) <= @intFromEnum(Type.Steel);
|
|
225
|
+
}
|
|
123
226
|
};
|
package/src/lib/gen2/data.zig
CHANGED
|
@@ -51,6 +51,7 @@ const showdown = pkmn.options.showdown;
|
|
|
51
51
|
pub const PRNG = rng.PRNG(2);
|
|
52
52
|
|
|
53
53
|
pub fn Battle(comptime RNG: anytype) type {
|
|
54
|
+
const padding = if (!showdown) 3 else 5;
|
|
54
55
|
return extern struct {
|
|
55
56
|
const Self = @This();
|
|
56
57
|
|
|
@@ -59,17 +60,19 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
59
60
|
turn: u16 = 0,
|
|
60
61
|
field: Field = .{},
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
_: [padding]u8 = .{0} ** padding,
|
|
64
|
+
|
|
65
|
+
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
63
66
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
64
67
|
return &self.sides[@intFromEnum(player)];
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
pub
|
|
70
|
+
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
68
71
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
69
72
|
return &self.sides[@intFromEnum(player.foe())];
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
pub
|
|
75
|
+
pub fn active(self: *const Self, player: Player) ID {
|
|
73
76
|
return player.ident(@intCast(self.side(player).pokemon[0].position));
|
|
74
77
|
}
|
|
75
78
|
|
|
@@ -83,18 +86,13 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
83
86
|
};
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
// TODO
|
|
87
89
|
test Battle {
|
|
88
|
-
try expectEqual(
|
|
90
|
+
try expectEqual(512, @sizeOf(Battle(PRNG)));
|
|
89
91
|
}
|
|
90
92
|
|
|
91
|
-
pub const Field = packed struct {
|
|
93
|
+
pub const Field = packed struct(u8) {
|
|
92
94
|
weather: Weather = .None,
|
|
93
95
|
weather_duration: u4 = 0,
|
|
94
|
-
|
|
95
|
-
comptime {
|
|
96
|
-
assert(@sizeOf(Field) == 1);
|
|
97
|
-
}
|
|
98
96
|
};
|
|
99
97
|
|
|
100
98
|
pub const Weather = enum(u4) {
|
|
@@ -106,14 +104,14 @@ pub const Weather = enum(u4) {
|
|
|
106
104
|
|
|
107
105
|
pub const Side = extern struct {
|
|
108
106
|
pokemon: [6]Pokemon = [_]Pokemon{.{}} ** 6,
|
|
109
|
-
active: ActivePokemon = .{},
|
|
107
|
+
active: ActivePokemon align(8) = .{},
|
|
110
108
|
conditions: Conditions = .{},
|
|
111
|
-
// NB: wCurPlayerMove / wCurEnemyMove (?)
|
|
112
|
-
_: u8 = 0,
|
|
113
109
|
// NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
|
|
114
110
|
last_used_move: Move = .None,
|
|
115
111
|
|
|
116
|
-
|
|
112
|
+
_: [7]u8 = .{0} ** 7,
|
|
113
|
+
|
|
114
|
+
const Conditions = packed struct(u32) {
|
|
117
115
|
Spikes: bool = false,
|
|
118
116
|
Safeguard: bool = false,
|
|
119
117
|
LightScreen: bool = false,
|
|
@@ -123,16 +121,19 @@ pub const Side = extern struct {
|
|
|
123
121
|
light_screen: u4 = 0,
|
|
124
122
|
reflect: u4 = 0,
|
|
125
123
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
future_sight: FutureSight = .{},
|
|
125
|
+
|
|
126
|
+
const FutureSight = packed struct(u16) {
|
|
127
|
+
damage: u12 = 0,
|
|
128
|
+
count: u4 = 0,
|
|
129
|
+
};
|
|
129
130
|
};
|
|
130
131
|
|
|
131
132
|
comptime {
|
|
132
|
-
assert(@sizeOf(Side) ==
|
|
133
|
+
assert(@sizeOf(Side) == 248);
|
|
133
134
|
}
|
|
134
135
|
|
|
135
|
-
pub
|
|
136
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
136
137
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
137
138
|
assert(slot > 0 and slot <= 6);
|
|
138
139
|
const id = self.pokemon[slot - 1].position;
|
|
@@ -140,19 +141,19 @@ pub const Side = extern struct {
|
|
|
140
141
|
return &self.pokemon[id - 1];
|
|
141
142
|
}
|
|
142
143
|
|
|
143
|
-
pub
|
|
144
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
144
145
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
145
146
|
return self.get(1);
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
pub
|
|
149
|
+
pub fn lastMove(self: anytype, encore: bool) Move {
|
|
149
150
|
assert(self.last_used_move != .None or !self.active.volatiles.dirty);
|
|
150
151
|
if (encore) return self.last_used_move;
|
|
151
152
|
return if (self.active.volatiles.dirty) .None else self.last_used_move;
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
// TODO
|
|
155
|
-
// pub
|
|
156
|
+
// pub fn useMove(self: anytype) void {
|
|
156
157
|
// assert(side.last_selected_move != .None);
|
|
157
158
|
// self.last_used_move = side.last_selected_move;
|
|
158
159
|
// self.active.volatiles.dirty = false;
|
|
@@ -174,7 +175,7 @@ pub const ActivePokemon = extern struct {
|
|
|
174
175
|
assert(@sizeOf(ActivePokemon) == 44);
|
|
175
176
|
}
|
|
176
177
|
|
|
177
|
-
pub
|
|
178
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
178
179
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
179
180
|
assert(mslot > 0 and mslot <= 4);
|
|
180
181
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -199,7 +200,7 @@ pub const Pokemon = extern struct {
|
|
|
199
200
|
assert(@sizeOf(Pokemon) == 32);
|
|
200
201
|
}
|
|
201
202
|
|
|
202
|
-
pub
|
|
203
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
203
204
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
204
205
|
assert(mslot > 0 and mslot <= 4);
|
|
205
206
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -213,7 +214,7 @@ pub const Gender = enum(u2) {
|
|
|
213
214
|
Unknown,
|
|
214
215
|
};
|
|
215
216
|
|
|
216
|
-
pub const DVs = packed struct {
|
|
217
|
+
pub const DVs = packed struct(u16) {
|
|
217
218
|
gender: Gender = .Male,
|
|
218
219
|
pow: u6 = 40,
|
|
219
220
|
type: Type = .Dark,
|
|
@@ -221,10 +222,10 @@ pub const DVs = packed struct {
|
|
|
221
222
|
pub fn init(g: Gender, p: u6, t: Type) DVs {
|
|
222
223
|
assert(p >= 1 and p <= 40);
|
|
223
224
|
assert(t != .Normal and t != .@"???");
|
|
224
|
-
return
|
|
225
|
+
return .{ .gender = g, .pow = p, .type = t };
|
|
225
226
|
}
|
|
226
227
|
|
|
227
|
-
pub
|
|
228
|
+
pub fn power(dvs: DVs) u8 {
|
|
228
229
|
return @as(u8, dvs.pow) + 30;
|
|
229
230
|
}
|
|
230
231
|
|
|
@@ -238,13 +239,8 @@ pub const DVs = packed struct {
|
|
|
238
239
|
};
|
|
239
240
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
240
241
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
241
|
-
var t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2)
|
|
242
|
-
|
|
243
|
-
return DVs{ .gender = g, .pow = p, .type = @enumFromInt(t) };
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
comptime {
|
|
247
|
-
assert(@sizeOf(DVs) == 2);
|
|
242
|
+
var t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
|
+
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
248
244
|
}
|
|
249
245
|
};
|
|
250
246
|
|
|
@@ -269,10 +265,12 @@ test DVs {
|
|
|
269
265
|
try expectEqual(Gender.Female, dvs.gender);
|
|
270
266
|
}
|
|
271
267
|
|
|
272
|
-
|
|
268
|
+
/// Representation of a Generation II Pokémon's move slot in a battle.
|
|
269
|
+
pub const MoveSlot = extern struct {
|
|
270
|
+
/// The identifier for the move.
|
|
273
271
|
id: Move = .None,
|
|
274
|
-
|
|
275
|
-
pp:
|
|
272
|
+
/// The remaining PP of the move.
|
|
273
|
+
pp: u8 = 0,
|
|
276
274
|
|
|
277
275
|
comptime {
|
|
278
276
|
assert(@sizeOf(MoveSlot) == 2);
|
|
@@ -281,14 +279,19 @@ pub const MoveSlot = packed struct {
|
|
|
281
279
|
|
|
282
280
|
pub const Status = gen1.Status;
|
|
283
281
|
|
|
284
|
-
|
|
282
|
+
/// TODO
|
|
283
|
+
pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
|
|
284
|
+
|
|
285
|
+
pub const Volatiles = packed struct(u128) {
|
|
285
286
|
Bide: bool = false,
|
|
286
287
|
Thrashing: bool = false,
|
|
288
|
+
BeatUp: bool = false,
|
|
287
289
|
Flinch: bool = false,
|
|
288
290
|
Charging: bool = false,
|
|
289
291
|
Underground: bool = false,
|
|
290
292
|
Flying: bool = false,
|
|
291
293
|
Confusion: bool = false,
|
|
294
|
+
|
|
292
295
|
Mist: bool = false,
|
|
293
296
|
FocusEnergy: bool = false,
|
|
294
297
|
Substitute: bool = false,
|
|
@@ -299,30 +302,35 @@ pub const Volatiles = packed struct {
|
|
|
299
302
|
Transform: bool = false,
|
|
300
303
|
|
|
301
304
|
Nightmare: bool = false,
|
|
302
|
-
|
|
305
|
+
Curse: bool = false,
|
|
303
306
|
Protect: bool = false,
|
|
304
307
|
Foresight: bool = false,
|
|
305
308
|
PerishSong: bool = false,
|
|
306
309
|
Endure: bool = false,
|
|
307
310
|
Rollout: bool = false,
|
|
308
311
|
Attract: bool = false,
|
|
312
|
+
|
|
309
313
|
DefenseCurl: bool = false,
|
|
310
314
|
Encore: bool = false,
|
|
311
315
|
LockOn: bool = false,
|
|
312
316
|
DestinyBond: bool = false,
|
|
313
|
-
|
|
317
|
+
Trapped: bool = false,
|
|
314
318
|
|
|
315
|
-
trapped: bool = false,
|
|
316
319
|
switched: bool = false,
|
|
320
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
317
321
|
switching: bool = false,
|
|
322
|
+
// TODO: simply store both last moves on side
|
|
318
323
|
dirty: bool = false,
|
|
319
324
|
|
|
320
|
-
|
|
325
|
+
frozen: bool = false,
|
|
326
|
+
minimized: bool = false,
|
|
327
|
+
_: u10 = 0,
|
|
328
|
+
// TODO: is this needed for unmodified stats?
|
|
329
|
+
transform: u4 = 0,
|
|
321
330
|
|
|
322
|
-
bind: u4 = 0,
|
|
323
|
-
future_sight: FutureSight = .{},
|
|
324
331
|
bide: u16 = 0,
|
|
325
|
-
|
|
332
|
+
bind: Bind = .{},
|
|
333
|
+
disable: Disable = .{},
|
|
326
334
|
rage: u8 = 0,
|
|
327
335
|
substitute: u8 = 0,
|
|
328
336
|
toxic: u8 = 0,
|
|
@@ -334,19 +342,15 @@ pub const Volatiles = packed struct {
|
|
|
334
342
|
protect: u4 = 0,
|
|
335
343
|
attacks: u4 = 0, // bide/thrashing/rollout turns
|
|
336
344
|
|
|
337
|
-
const
|
|
338
|
-
move: u4 = 0,
|
|
345
|
+
const Bind = packed struct(u8) {
|
|
339
346
|
duration: u4 = 0,
|
|
347
|
+
reason: u4 = 0,
|
|
340
348
|
};
|
|
341
349
|
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
350
|
+
const Disable = packed struct(u8) {
|
|
351
|
+
move: u4 = 0,
|
|
352
|
+
duration: u4 = 0,
|
|
345
353
|
};
|
|
346
|
-
|
|
347
|
-
comptime {
|
|
348
|
-
assert(@sizeOf(Volatiles) == 16);
|
|
349
|
-
}
|
|
350
354
|
};
|
|
351
355
|
|
|
352
356
|
pub fn Stats(comptime T: type) type {
|
|
@@ -381,7 +385,7 @@ test Stats {
|
|
|
381
385
|
try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
382
386
|
}
|
|
383
387
|
|
|
384
|
-
pub const Boosts = packed struct {
|
|
388
|
+
pub const Boosts = packed struct(u32) {
|
|
385
389
|
atk: i4 = 0,
|
|
386
390
|
def: i4 = 0,
|
|
387
391
|
spe: i4 = 0,
|
|
@@ -397,7 +401,7 @@ pub const Boosts = packed struct {
|
|
|
397
401
|
};
|
|
398
402
|
|
|
399
403
|
test Boosts {
|
|
400
|
-
const boosts =
|
|
404
|
+
const boosts: Boosts = .{ .spd = -6 };
|
|
401
405
|
try expectEqual(0, boosts.atk);
|
|
402
406
|
try expectEqual(-6, boosts.spd);
|
|
403
407
|
}
|
|
@@ -410,15 +414,10 @@ test Item {
|
|
|
410
414
|
try expectEqual(Type.Normal, Item.boost(.PolkadotBow).?);
|
|
411
415
|
try expectEqual(Type.Dark, Item.boost(.BlackGlasses).?);
|
|
412
416
|
|
|
413
|
-
try expect(!Item.
|
|
414
|
-
try expect(Item.
|
|
415
|
-
try expect(Item.
|
|
416
|
-
try expect(!Item.
|
|
417
|
-
|
|
418
|
-
try expect(!Item.berry(.LightBall));
|
|
419
|
-
try expect(Item.berry(.PSNCureBerry));
|
|
420
|
-
try expect(Item.berry(.GoldBerry));
|
|
421
|
-
try expect(!Item.berry(.MasterBall));
|
|
417
|
+
try expect(!Item.isMail(.UpGrade));
|
|
418
|
+
try expect(Item.isMail(.FlowerMail));
|
|
419
|
+
try expect(Item.isMail(.MirageMail));
|
|
420
|
+
try expect(!Item.isMail(.TownMap));
|
|
422
421
|
}
|
|
423
422
|
|
|
424
423
|
pub const Move = moves.Move;
|
|
@@ -427,9 +426,13 @@ test Move {
|
|
|
427
426
|
try expectEqual(251, @intFromEnum(Move.BeatUp));
|
|
428
427
|
const move = Move.get(.DynamicPunch);
|
|
429
428
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
430
|
-
try expectEqual(
|
|
431
|
-
try expectEqual(
|
|
429
|
+
try expectEqual(rng.Gen12.percent(50), move.accuracy);
|
|
430
|
+
try expectEqual(rng.Gen12.percent(100), move.chance);
|
|
431
|
+
try expectEqual(@as(u8, 5), Move.pp(.DynamicPunch));
|
|
432
432
|
try expectEqual(@as(i8, -1), Move.get(.Counter).priority);
|
|
433
|
+
try expect(!move.effect.isHighCritical());
|
|
434
|
+
try expect(Move.get(.KarateChop).effect.isHighCritical());
|
|
435
|
+
try expect(Move.get(.RazorWind).effect.isHighCritical());
|
|
433
436
|
}
|
|
434
437
|
|
|
435
438
|
pub const Species = species.Species;
|