@pkmn/engine 0.1.0-dev.736f7a8b → 0.1.0-dev.77410aff
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/README.md +36 -14
- package/build/pkg/addon.js.map +1 -1
- 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 +3 -2
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +2 -2
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +2 -1
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.js +57 -38
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js +3 -1
- package/build/tools/debug.js.map +1 -1
- package/build.zig +40 -23
- package/package.json +30 -17
- package/src/bin/install-pkmn-engine +1 -1
- package/src/lib/binding/node.zig +7 -11
- package/src/lib/common/data.zig +8 -20
- package/src/lib/common/optional.zig +8 -1
- package/src/lib/common/protocol.zig +725 -299
- package/src/lib/common/rational.zig +12 -8
- package/src/lib/common/rng.zig +15 -6
- package/src/lib/gen1/README.md +31 -29
- package/src/lib/gen1/calc.zig +9 -9
- 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 +314 -365
- 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 +80 -68
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +4 -9
- package/src/lib/gen2/mechanics.zig +3238 -85
|
@@ -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
|
-
last_selected_move: Move = .None,
|
|
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,16 +141,23 @@ 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
|
}
|
|
154
|
+
|
|
155
|
+
// TODO
|
|
156
|
+
// pub fn useMove(self: anytype) void {
|
|
157
|
+
// assert(side.last_selected_move != .None);
|
|
158
|
+
// self.last_used_move = side.last_selected_move;
|
|
159
|
+
// self.active.volatiles.dirty = false;
|
|
160
|
+
// }
|
|
153
161
|
};
|
|
154
162
|
|
|
155
163
|
// NOTE: DVs (Gender & Hidden Power) and Happiness are stored only in Pokemon
|
|
@@ -160,13 +168,14 @@ pub const ActivePokemon = extern struct {
|
|
|
160
168
|
boosts: Boosts = .{},
|
|
161
169
|
types: Types = .{},
|
|
162
170
|
species: Species = .None,
|
|
163
|
-
|
|
171
|
+
|
|
172
|
+
_: u8 = 0,
|
|
164
173
|
|
|
165
174
|
comptime {
|
|
166
175
|
assert(@sizeOf(ActivePokemon) == 44);
|
|
167
176
|
}
|
|
168
177
|
|
|
169
|
-
pub
|
|
178
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
170
179
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
171
180
|
assert(mslot > 0 and mslot <= 4);
|
|
172
181
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -191,7 +200,7 @@ pub const Pokemon = extern struct {
|
|
|
191
200
|
assert(@sizeOf(Pokemon) == 32);
|
|
192
201
|
}
|
|
193
202
|
|
|
194
|
-
pub
|
|
203
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
195
204
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
196
205
|
assert(mslot > 0 and mslot <= 4);
|
|
197
206
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -205,7 +214,7 @@ pub const Gender = enum(u2) {
|
|
|
205
214
|
Unknown,
|
|
206
215
|
};
|
|
207
216
|
|
|
208
|
-
pub const DVs = packed struct {
|
|
217
|
+
pub const DVs = packed struct(u16) {
|
|
209
218
|
gender: Gender = .Male,
|
|
210
219
|
pow: u6 = 40,
|
|
211
220
|
type: Type = .Dark,
|
|
@@ -213,10 +222,10 @@ pub const DVs = packed struct {
|
|
|
213
222
|
pub fn init(g: Gender, p: u6, t: Type) DVs {
|
|
214
223
|
assert(p >= 1 and p <= 40);
|
|
215
224
|
assert(t != .Normal and t != .@"???");
|
|
216
|
-
return
|
|
225
|
+
return .{ .gender = g, .pow = p, .type = t };
|
|
217
226
|
}
|
|
218
227
|
|
|
219
|
-
pub
|
|
228
|
+
pub fn power(dvs: DVs) u8 {
|
|
220
229
|
return @as(u8, dvs.pow) + 30;
|
|
221
230
|
}
|
|
222
231
|
|
|
@@ -230,13 +239,8 @@ pub const DVs = packed struct {
|
|
|
230
239
|
};
|
|
231
240
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
232
241
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return DVs{ .gender = g, .pow = p, .type = @enumFromInt(t) };
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
comptime {
|
|
239
|
-
assert(@sizeOf(DVs) == 2);
|
|
242
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
|
+
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
240
244
|
}
|
|
241
245
|
};
|
|
242
246
|
|
|
@@ -261,10 +265,12 @@ test DVs {
|
|
|
261
265
|
try expectEqual(Gender.Female, dvs.gender);
|
|
262
266
|
}
|
|
263
267
|
|
|
264
|
-
|
|
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.
|
|
265
271
|
id: Move = .None,
|
|
266
|
-
|
|
267
|
-
pp:
|
|
272
|
+
/// The remaining PP of the move.
|
|
273
|
+
pp: u8 = 0,
|
|
268
274
|
|
|
269
275
|
comptime {
|
|
270
276
|
assert(@sizeOf(MoveSlot) == 2);
|
|
@@ -273,14 +279,19 @@ pub const MoveSlot = packed struct {
|
|
|
273
279
|
|
|
274
280
|
pub const Status = gen1.Status;
|
|
275
281
|
|
|
276
|
-
|
|
282
|
+
/// TODO
|
|
283
|
+
pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
|
|
284
|
+
|
|
285
|
+
pub const Volatiles = packed struct(u128) {
|
|
277
286
|
Bide: bool = false,
|
|
278
287
|
Thrashing: bool = false,
|
|
288
|
+
BeatUp: bool = false,
|
|
279
289
|
Flinch: bool = false,
|
|
280
290
|
Charging: bool = false,
|
|
281
291
|
Underground: bool = false,
|
|
282
292
|
Flying: bool = false,
|
|
283
293
|
Confusion: bool = false,
|
|
294
|
+
|
|
284
295
|
Mist: bool = false,
|
|
285
296
|
FocusEnergy: bool = false,
|
|
286
297
|
Substitute: bool = false,
|
|
@@ -291,53 +302,55 @@ pub const Volatiles = packed struct {
|
|
|
291
302
|
Transform: bool = false,
|
|
292
303
|
|
|
293
304
|
Nightmare: bool = false,
|
|
294
|
-
|
|
305
|
+
Curse: bool = false,
|
|
295
306
|
Protect: bool = false,
|
|
296
307
|
Foresight: bool = false,
|
|
297
308
|
PerishSong: bool = false,
|
|
298
309
|
Endure: bool = false,
|
|
299
310
|
Rollout: bool = false,
|
|
300
311
|
Attract: bool = false,
|
|
312
|
+
|
|
301
313
|
DefenseCurl: bool = false,
|
|
302
314
|
Encore: bool = false,
|
|
303
315
|
LockOn: bool = false,
|
|
304
316
|
DestinyBond: bool = false,
|
|
305
|
-
|
|
317
|
+
Trapped: bool = false,
|
|
306
318
|
|
|
307
|
-
trapped: bool = false,
|
|
308
319
|
switched: bool = false,
|
|
320
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
309
321
|
switching: bool = false,
|
|
322
|
+
// TODO: simply store both last moves on side
|
|
310
323
|
dirty: bool = false,
|
|
311
324
|
|
|
312
|
-
|
|
325
|
+
frozen: bool = false,
|
|
326
|
+
minimized: bool = false,
|
|
327
|
+
_: u10 = 0,
|
|
328
|
+
// TODO: is this needed for unmodified stats?
|
|
329
|
+
transform: u4 = 0,
|
|
313
330
|
|
|
314
|
-
bind: u4 = 0,
|
|
315
|
-
future_sight: FutureSight = .{},
|
|
316
331
|
bide: u16 = 0,
|
|
317
|
-
|
|
332
|
+
bind: Bind = .{},
|
|
333
|
+
disable: Disable = .{},
|
|
318
334
|
rage: u8 = 0,
|
|
319
335
|
substitute: u8 = 0,
|
|
320
336
|
toxic: u8 = 0,
|
|
321
337
|
confusion: u4 = 0,
|
|
322
338
|
encore: u4 = 0,
|
|
339
|
+
// TODO merge with attacks (ie rollout/thrashing)? need to be zeroed at same time
|
|
323
340
|
fury_cutter: u4 = 0,
|
|
324
341
|
perish_song: u4 = 0,
|
|
325
342
|
protect: u4 = 0,
|
|
326
|
-
|
|
343
|
+
attacks: u4 = 0, // bide/thrashing/rollout turns
|
|
327
344
|
|
|
328
|
-
const
|
|
329
|
-
move: u4 = 0,
|
|
345
|
+
const Bind = packed struct(u8) {
|
|
330
346
|
duration: u4 = 0,
|
|
347
|
+
reason: u4 = 0,
|
|
331
348
|
};
|
|
332
349
|
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
350
|
+
const Disable = packed struct(u8) {
|
|
351
|
+
move: u4 = 0,
|
|
352
|
+
duration: u4 = 0,
|
|
336
353
|
};
|
|
337
|
-
|
|
338
|
-
comptime {
|
|
339
|
-
assert(@sizeOf(Volatiles) == 16);
|
|
340
|
-
}
|
|
341
354
|
};
|
|
342
355
|
|
|
343
356
|
pub fn Stats(comptime T: type) type {
|
|
@@ -372,7 +385,7 @@ test Stats {
|
|
|
372
385
|
try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
373
386
|
}
|
|
374
387
|
|
|
375
|
-
pub const Boosts = packed struct {
|
|
388
|
+
pub const Boosts = packed struct(u32) {
|
|
376
389
|
atk: i4 = 0,
|
|
377
390
|
def: i4 = 0,
|
|
378
391
|
spe: i4 = 0,
|
|
@@ -388,7 +401,7 @@ pub const Boosts = packed struct {
|
|
|
388
401
|
};
|
|
389
402
|
|
|
390
403
|
test Boosts {
|
|
391
|
-
const boosts =
|
|
404
|
+
const boosts: Boosts = .{ .spd = -6 };
|
|
392
405
|
try expectEqual(0, boosts.atk);
|
|
393
406
|
try expectEqual(-6, boosts.spd);
|
|
394
407
|
}
|
|
@@ -401,15 +414,10 @@ test Item {
|
|
|
401
414
|
try expectEqual(Type.Normal, Item.boost(.PolkadotBow).?);
|
|
402
415
|
try expectEqual(Type.Dark, Item.boost(.BlackGlasses).?);
|
|
403
416
|
|
|
404
|
-
try expect(!Item.
|
|
405
|
-
try expect(Item.
|
|
406
|
-
try expect(Item.
|
|
407
|
-
try expect(!Item.
|
|
408
|
-
|
|
409
|
-
try expect(!Item.berry(.LightBall));
|
|
410
|
-
try expect(Item.berry(.PSNCureBerry));
|
|
411
|
-
try expect(Item.berry(.GoldBerry));
|
|
412
|
-
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));
|
|
413
421
|
}
|
|
414
422
|
|
|
415
423
|
pub const Move = moves.Move;
|
|
@@ -418,9 +426,13 @@ test Move {
|
|
|
418
426
|
try expectEqual(251, @intFromEnum(Move.BeatUp));
|
|
419
427
|
const move = Move.get(.DynamicPunch);
|
|
420
428
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
421
|
-
try expectEqual(
|
|
422
|
-
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));
|
|
423
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());
|
|
424
436
|
}
|
|
425
437
|
|
|
426
438
|
pub const Species = species.Species;
|