@pkmn/engine 0.1.0-dev.dd5b9081 → 0.1.0-dev.deda8593
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 +44 -19
- package/build/pkg/addon.js +6 -7
- 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 +4 -4
- 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 +61 -42
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js +2 -2
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js +5 -4
- package/build/tools/debug.js.map +1 -1
- package/build.zig +102 -104
- package/package.json +43 -23
- package/src/bin/install-pkmn-engine +26 -18
- package/src/lib/common/data.zig +9 -9
- package/src/lib/common/debug.zig +2 -2
- package/src/lib/common/optional.zig +9 -2
- package/src/lib/common/options.zig +2 -0
- package/src/lib/common/protocol.zig +739 -318
- package/src/lib/common/rational.zig +12 -9
- package/src/lib/common/rng.zig +25 -16
- package/src/lib/gen1/calc.zig +219 -49
- package/src/lib/gen1/chance.zig +138 -115
- package/src/lib/gen1/data/moves.zig +190 -176
- package/src/lib/gen1/data/species.zig +3 -3
- package/src/lib/gen1/data/types.zig +7 -7
- package/src/lib/gen1/data.zig +44 -44
- package/src/lib/gen1/helpers.zig +148 -82
- package/src/lib/gen1/mechanics.zig +392 -406
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1315 -0
- package/src/lib/gen2/data/items.zig +12 -18
- package/src/lib/gen2/data/moves.zig +377 -344
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +134 -31
- package/src/lib/gen2/data.zig +52 -44
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +37 -7
- package/src/lib/gen2/mechanics.zig +3086 -211
- package/src/lib/{binding/node.zig → node.zig} +10 -13
- package/src/lib/pkmn.zig +27 -12
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
- package/src/test/display/pkmn.html.tmpl +5 -5
- package/src/lib/gen1/README.md +0 -894
- package/src/lib/gen2/README.md +0 -383
|
@@ -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,20 +60,19 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
59
60
|
turn: u16 = 0,
|
|
60
61
|
field: Field = .{},
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
_2: if (!showdown) u16 else u32 = 0,
|
|
63
|
+
_: [padding]u8 = .{0} ** padding,
|
|
64
64
|
|
|
65
|
-
pub
|
|
65
|
+
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
66
66
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
67
67
|
return &self.sides[@intFromEnum(player)];
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
pub
|
|
70
|
+
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
71
71
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
72
72
|
return &self.sides[@intFromEnum(player.foe())];
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
pub
|
|
75
|
+
pub fn active(self: *const Self, player: Player) ID {
|
|
76
76
|
return player.ident(@intCast(self.side(player).pokemon[0].position));
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -106,13 +106,11 @@ pub const Side = extern struct {
|
|
|
106
106
|
pokemon: [6]Pokemon = [_]Pokemon{.{}} ** 6,
|
|
107
107
|
active: ActivePokemon align(8) = .{},
|
|
108
108
|
conditions: Conditions = .{},
|
|
109
|
-
_1: u32 = 0,
|
|
110
|
-
_2: u16 = 0,
|
|
111
|
-
// NB: wCurPlayerMove / wCurEnemyMove (?)
|
|
112
|
-
_3: u8 = 0,
|
|
113
109
|
// NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
|
|
114
110
|
last_used_move: Move = .None,
|
|
115
111
|
|
|
112
|
+
_: [7]u8 = .{0} ** 7,
|
|
113
|
+
|
|
116
114
|
const Conditions = packed struct(u32) {
|
|
117
115
|
Spikes: bool = false,
|
|
118
116
|
Safeguard: bool = false,
|
|
@@ -135,7 +133,7 @@ pub const Side = extern struct {
|
|
|
135
133
|
assert(@sizeOf(Side) == 248);
|
|
136
134
|
}
|
|
137
135
|
|
|
138
|
-
pub
|
|
136
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
139
137
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
140
138
|
assert(slot > 0 and slot <= 6);
|
|
141
139
|
const id = self.pokemon[slot - 1].position;
|
|
@@ -143,19 +141,19 @@ pub const Side = extern struct {
|
|
|
143
141
|
return &self.pokemon[id - 1];
|
|
144
142
|
}
|
|
145
143
|
|
|
146
|
-
pub
|
|
144
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
147
145
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
148
146
|
return self.get(1);
|
|
149
147
|
}
|
|
150
148
|
|
|
151
|
-
pub
|
|
149
|
+
pub fn lastMove(self: anytype, encore: bool) Move {
|
|
152
150
|
assert(self.last_used_move != .None or !self.active.volatiles.dirty);
|
|
153
151
|
if (encore) return self.last_used_move;
|
|
154
152
|
return if (self.active.volatiles.dirty) .None else self.last_used_move;
|
|
155
153
|
}
|
|
156
154
|
|
|
157
155
|
// TODO
|
|
158
|
-
// pub
|
|
156
|
+
// pub fn useMove(self: anytype) void {
|
|
159
157
|
// assert(side.last_selected_move != .None);
|
|
160
158
|
// self.last_used_move = side.last_selected_move;
|
|
161
159
|
// self.active.volatiles.dirty = false;
|
|
@@ -177,7 +175,7 @@ pub const ActivePokemon = extern struct {
|
|
|
177
175
|
assert(@sizeOf(ActivePokemon) == 44);
|
|
178
176
|
}
|
|
179
177
|
|
|
180
|
-
pub
|
|
178
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
181
179
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
182
180
|
assert(mslot > 0 and mslot <= 4);
|
|
183
181
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -202,7 +200,7 @@ pub const Pokemon = extern struct {
|
|
|
202
200
|
assert(@sizeOf(Pokemon) == 32);
|
|
203
201
|
}
|
|
204
202
|
|
|
205
|
-
pub
|
|
203
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
206
204
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
207
205
|
assert(mslot > 0 and mslot <= 4);
|
|
208
206
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -224,10 +222,10 @@ pub const DVs = packed struct(u16) {
|
|
|
224
222
|
pub fn init(g: Gender, p: u6, t: Type) DVs {
|
|
225
223
|
assert(p >= 1 and p <= 40);
|
|
226
224
|
assert(t != .Normal and t != .@"???");
|
|
227
|
-
return
|
|
225
|
+
return .{ .gender = g, .pow = p, .type = t };
|
|
228
226
|
}
|
|
229
227
|
|
|
230
|
-
pub
|
|
228
|
+
pub fn power(dvs: DVs) u8 {
|
|
231
229
|
return @as(u8, dvs.pow) + 30;
|
|
232
230
|
}
|
|
233
231
|
|
|
@@ -241,9 +239,8 @@ pub const DVs = packed struct(u16) {
|
|
|
241
239
|
};
|
|
242
240
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
243
241
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return DVs{ .gender = g, .pow = p, .type = @enumFromInt(t) };
|
|
242
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
|
+
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
247
244
|
}
|
|
248
245
|
};
|
|
249
246
|
|
|
@@ -251,12 +248,12 @@ test DVs {
|
|
|
251
248
|
var dvs = DVs.from(.Mewtwo, .{ .def = 13 });
|
|
252
249
|
try expectEqual(Gender.Unknown, dvs.gender);
|
|
253
250
|
try expectEqual(Type.Ice, dvs.type);
|
|
254
|
-
try expectEqual(
|
|
251
|
+
try expectEqual(70, dvs.power());
|
|
255
252
|
|
|
256
253
|
dvs = DVs.from(.Pikachu, .{ .spc = 14 });
|
|
257
254
|
try expectEqual(Gender.Male, dvs.gender);
|
|
258
255
|
try expectEqual(Type.Dark, dvs.type);
|
|
259
|
-
try expectEqual(
|
|
256
|
+
try expectEqual(69, dvs.power());
|
|
260
257
|
|
|
261
258
|
dvs = DVs.from(.Cyndaquil, .{ .atk = 1, .def = 3, .spe = 10, .spc = 9 });
|
|
262
259
|
try expectEqual(Gender.Female, dvs.gender);
|
|
@@ -282,14 +279,19 @@ pub const MoveSlot = extern struct {
|
|
|
282
279
|
|
|
283
280
|
pub const Status = gen1.Status;
|
|
284
281
|
|
|
282
|
+
/// TODO
|
|
283
|
+
pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
|
|
284
|
+
|
|
285
285
|
pub const Volatiles = packed struct(u128) {
|
|
286
286
|
Bide: bool = false,
|
|
287
287
|
Thrashing: bool = false,
|
|
288
|
+
BeatUp: bool = false,
|
|
288
289
|
Flinch: bool = false,
|
|
289
290
|
Charging: bool = false,
|
|
290
291
|
Underground: bool = false,
|
|
291
292
|
Flying: bool = false,
|
|
292
293
|
Confusion: bool = false,
|
|
294
|
+
|
|
293
295
|
Mist: bool = false,
|
|
294
296
|
FocusEnergy: bool = false,
|
|
295
297
|
Substitute: bool = false,
|
|
@@ -307,22 +309,28 @@ pub const Volatiles = packed struct(u128) {
|
|
|
307
309
|
Endure: bool = false,
|
|
308
310
|
Rollout: bool = false,
|
|
309
311
|
Attract: bool = false,
|
|
312
|
+
|
|
310
313
|
DefenseCurl: bool = false,
|
|
311
314
|
Encore: bool = false,
|
|
312
315
|
LockOn: bool = false,
|
|
313
316
|
DestinyBond: bool = false,
|
|
314
|
-
|
|
317
|
+
Trapped: bool = false,
|
|
315
318
|
|
|
316
|
-
trapped: bool = false,
|
|
317
319
|
switched: bool = false,
|
|
320
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
318
321
|
switching: bool = false,
|
|
322
|
+
// TODO: simply store both last moves on side
|
|
319
323
|
dirty: bool = false,
|
|
320
324
|
|
|
321
|
-
|
|
325
|
+
frozen: bool = false,
|
|
326
|
+
minimized: bool = false,
|
|
327
|
+
_: u10 = 0,
|
|
328
|
+
// TODO: is this needed for unmodified stats?
|
|
329
|
+
transform: u4 = 0,
|
|
322
330
|
|
|
323
|
-
bind: u4 = 0,
|
|
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,7 +342,12 @@ pub const Volatiles = packed struct(u128) {
|
|
|
334
342
|
protect: u4 = 0,
|
|
335
343
|
attacks: u4 = 0, // bide/thrashing/rollout turns
|
|
336
344
|
|
|
337
|
-
const
|
|
345
|
+
const Bind = packed struct(u8) {
|
|
346
|
+
duration: u4 = 0,
|
|
347
|
+
reason: u4 = 0,
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const Disable = packed struct(u8) {
|
|
338
351
|
move: u4 = 0,
|
|
339
352
|
duration: u4 = 0,
|
|
340
353
|
};
|
|
@@ -367,9 +380,9 @@ test Stats {
|
|
|
367
380
|
try expectEqual(0, stats.def);
|
|
368
381
|
|
|
369
382
|
var base = Species.get(.Gyarados).stats;
|
|
370
|
-
try expectEqual(
|
|
383
|
+
try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
371
384
|
base = Species.get(.Pidgeot).stats;
|
|
372
|
-
try expectEqual(
|
|
385
|
+
try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
373
386
|
}
|
|
374
387
|
|
|
375
388
|
pub const Boosts = packed struct(u32) {
|
|
@@ -388,7 +401,7 @@ pub const Boosts = packed struct(u32) {
|
|
|
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;
|
|
@@ -420,8 +428,8 @@ test Move {
|
|
|
420
428
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
421
429
|
try expectEqual(rng.Gen12.percent(50), move.accuracy);
|
|
422
430
|
try expectEqual(rng.Gen12.percent(100), move.chance);
|
|
423
|
-
try expectEqual(
|
|
424
|
-
try expectEqual(
|
|
431
|
+
try expectEqual(5, Move.pp(.DynamicPunch));
|
|
432
|
+
try expectEqual(-1, Move.get(.Counter).priority);
|
|
425
433
|
try expect(!move.effect.isHighCritical());
|
|
426
434
|
try expect(Move.get(.KarateChop).effect.isHighCritical());
|
|
427
435
|
try expect(Move.get(.RazorWind).effect.isHighCritical());
|
|
@@ -431,7 +439,7 @@ pub const Species = species.Species;
|
|
|
431
439
|
|
|
432
440
|
test Species {
|
|
433
441
|
try expectEqual(152, @intFromEnum(Species.Chikorita));
|
|
434
|
-
try expectEqual(
|
|
442
|
+
try expectEqual(100, Species.get(.Celebi).stats.spd);
|
|
435
443
|
}
|
|
436
444
|
|
|
437
445
|
pub const Type = types.Type;
|
|
@@ -444,7 +452,7 @@ test Types {
|
|
|
444
452
|
try expect(!Type.Steel.special());
|
|
445
453
|
try expect(Type.Dark.special());
|
|
446
454
|
|
|
447
|
-
try expectEqual(
|
|
455
|
+
try expectEqual(3, Type.Water.precedence());
|
|
448
456
|
try expect(Type.Bug.precedence() > Type.Poison.precedence());
|
|
449
457
|
|
|
450
458
|
try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
|