@pkmn/engine 0.1.0-dev.a02611a4 → 0.1.0-dev.a0447192
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 +46 -19
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +43 -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 +96 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon.d.ts +2 -0
- package/build/pkg/addon.js +35 -58
- 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 +27 -5
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +3 -3
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +24 -10
- package/build/pkg/index.js +15 -10
- 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 -68
- 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 +132 -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 +227 -96
- package/package.json +67 -30
- package/src/bin/install-pkmn-engine +29 -19
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/data.zig +12 -24
- 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 +4 -0
- package/src/lib/common/protocol.zig +774 -356
- package/src/lib/common/rational.zig +132 -36
- package/src/lib/common/rng.zig +22 -13
- package/src/lib/common/util.zig +50 -1
- package/src/lib/gen1/calc.zig +685 -132
- package/src/lib/gen1/chance.zig +408 -283
- package/src/lib/gen1/data/moves.zig +192 -180
- package/src/lib/gen1/data/species.zig +3 -3
- package/src/lib/gen1/data/types.zig +7 -7
- package/src/lib/gen1/data.zig +48 -59
- package/src/lib/gen1/helpers.zig +87 -552
- package/src/lib/gen1/mechanics.zig +600 -543
- package/src/lib/gen2/calc.zig +161 -0
- package/src/lib/gen2/chance.zig +902 -0
- package/src/lib/gen2/data/items.zig +12 -18
- package/src/lib/gen2/data/moves.zig +661 -580
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +134 -31
- package/src/lib/gen2/data.zig +97 -76
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +45 -22
- package/src/lib/gen2/mechanics.zig +3296 -90
- package/src/lib/{binding/node.zig → node.zig} +10 -13
- package/src/lib/pkmn.zig +32 -15
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +359 -0
- package/build/test/display.js +0 -400
- package/build/test/display.js.map +0 -1
- package/src/lib/gen1/README.md +0 -892
- package/src/lib/gen2/README.md +0 -308
- package/src/test/display/pkmn.html.tmpl +0 -368
|
@@ -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
|
@@ -45,12 +45,14 @@ const Player = data.Player;
|
|
|
45
45
|
const Result = data.Result;
|
|
46
46
|
|
|
47
47
|
const PointerType = util.PointerType;
|
|
48
|
+
const isPointerTo = util.isPointerTo;
|
|
48
49
|
|
|
49
50
|
const showdown = pkmn.options.showdown;
|
|
50
51
|
|
|
51
52
|
pub const PRNG = rng.PRNG(2);
|
|
52
53
|
|
|
53
54
|
pub fn Battle(comptime RNG: anytype) type {
|
|
55
|
+
const padding = if (!showdown) 3 else 5;
|
|
54
56
|
return extern struct {
|
|
55
57
|
const Self = @This();
|
|
56
58
|
|
|
@@ -59,17 +61,19 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
59
61
|
turn: u16 = 0,
|
|
60
62
|
field: Field = .{},
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
_: [padding]u8 = .{0} ** padding,
|
|
65
|
+
|
|
66
|
+
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
67
|
+
assert(isPointerTo(self, Self));
|
|
64
68
|
return &self.sides[@intFromEnum(player)];
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
pub
|
|
68
|
-
assert(
|
|
71
|
+
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
72
|
+
assert(isPointerTo(self, Self));
|
|
69
73
|
return &self.sides[@intFromEnum(player.foe())];
|
|
70
74
|
}
|
|
71
75
|
|
|
72
|
-
pub
|
|
76
|
+
pub fn active(self: *const Self, player: Player) ID {
|
|
73
77
|
return player.ident(@intCast(self.side(player).pokemon[0].position));
|
|
74
78
|
}
|
|
75
79
|
|
|
@@ -83,18 +87,13 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
83
87
|
};
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
// TODO
|
|
87
90
|
test Battle {
|
|
88
|
-
try expectEqual(
|
|
91
|
+
try expectEqual(512, @sizeOf(Battle(PRNG)));
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
pub const Field = packed struct {
|
|
94
|
+
pub const Field = packed struct(u8) {
|
|
92
95
|
weather: Weather = .None,
|
|
93
96
|
weather_duration: u4 = 0,
|
|
94
|
-
|
|
95
|
-
comptime {
|
|
96
|
-
assert(@sizeOf(Field) == 1);
|
|
97
|
-
}
|
|
98
97
|
};
|
|
99
98
|
|
|
100
99
|
pub const Weather = enum(u4) {
|
|
@@ -106,14 +105,14 @@ pub const Weather = enum(u4) {
|
|
|
106
105
|
|
|
107
106
|
pub const Side = extern struct {
|
|
108
107
|
pokemon: [6]Pokemon = [_]Pokemon{.{}} ** 6,
|
|
109
|
-
active: ActivePokemon = .{},
|
|
108
|
+
active: ActivePokemon align(8) = .{},
|
|
110
109
|
conditions: Conditions = .{},
|
|
111
|
-
// NB: wLastPlayerMove
|
|
112
|
-
|
|
113
|
-
// NB: wLastPlayerCounterMove / wLastEnemyCounterMove
|
|
114
|
-
last_counter_move: Move = .None,
|
|
110
|
+
// NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
|
|
111
|
+
last_used_move: Move = .None,
|
|
115
112
|
|
|
116
|
-
|
|
113
|
+
_: [7]u8 = .{0} ** 7,
|
|
114
|
+
|
|
115
|
+
const Conditions = packed struct(u32) {
|
|
117
116
|
Spikes: bool = false,
|
|
118
117
|
Safeguard: bool = false,
|
|
119
118
|
LightScreen: bool = false,
|
|
@@ -123,27 +122,43 @@ pub const Side = extern struct {
|
|
|
123
122
|
light_screen: u4 = 0,
|
|
124
123
|
reflect: u4 = 0,
|
|
125
124
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
future_sight: FutureSight = .{},
|
|
126
|
+
|
|
127
|
+
const FutureSight = packed struct(u16) {
|
|
128
|
+
damage: u12 = 0,
|
|
129
|
+
count: u4 = 0,
|
|
130
|
+
};
|
|
129
131
|
};
|
|
130
132
|
|
|
131
133
|
comptime {
|
|
132
|
-
assert(@sizeOf(Side) ==
|
|
134
|
+
assert(@sizeOf(Side) == 248);
|
|
133
135
|
}
|
|
134
136
|
|
|
135
|
-
pub
|
|
136
|
-
assert(
|
|
137
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
138
|
+
assert(isPointerTo(self, Side));
|
|
137
139
|
assert(slot > 0 and slot <= 6);
|
|
138
140
|
const id = self.pokemon[slot - 1].position;
|
|
139
141
|
assert(id > 0 and id <= 6);
|
|
140
142
|
return &self.pokemon[id - 1];
|
|
141
143
|
}
|
|
142
144
|
|
|
143
|
-
pub
|
|
144
|
-
assert(
|
|
145
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
146
|
+
assert(isPointerTo(self, Side));
|
|
145
147
|
return self.get(1);
|
|
146
148
|
}
|
|
149
|
+
|
|
150
|
+
pub fn lastMove(self: anytype, encore: bool) Move {
|
|
151
|
+
assert(self.last_used_move != .None or !self.active.volatiles.dirty);
|
|
152
|
+
if (encore) return self.last_used_move;
|
|
153
|
+
return if (self.active.volatiles.dirty) .None else self.last_used_move;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// TODO
|
|
157
|
+
// pub fn useMove(self: anytype) void {
|
|
158
|
+
// assert(side.last_selected_move != .None);
|
|
159
|
+
// self.last_used_move = side.last_selected_move;
|
|
160
|
+
// self.active.volatiles.dirty = false;
|
|
161
|
+
// }
|
|
147
162
|
};
|
|
148
163
|
|
|
149
164
|
// NOTE: DVs (Gender & Hidden Power) and Happiness are stored only in Pokemon
|
|
@@ -152,16 +167,17 @@ pub const ActivePokemon = extern struct {
|
|
|
152
167
|
stats: Stats(u16) = .{},
|
|
153
168
|
moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
|
|
154
169
|
boosts: Boosts = .{},
|
|
155
|
-
species: Species = .None,
|
|
156
|
-
item: Item = .None,
|
|
157
170
|
types: Types = .{},
|
|
171
|
+
species: Species = .None,
|
|
172
|
+
|
|
173
|
+
_: u8 = 0,
|
|
158
174
|
|
|
159
175
|
comptime {
|
|
160
176
|
assert(@sizeOf(ActivePokemon) == 44);
|
|
161
177
|
}
|
|
162
178
|
|
|
163
|
-
pub
|
|
164
|
-
assert(
|
|
179
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
180
|
+
assert(isPointerTo(self, Pokemon));
|
|
165
181
|
assert(mslot > 0 and mslot <= 4);
|
|
166
182
|
assert(self.moves[mslot - 1].id != .None);
|
|
167
183
|
return &self.moves[mslot - 1];
|
|
@@ -185,8 +201,8 @@ pub const Pokemon = extern struct {
|
|
|
185
201
|
assert(@sizeOf(Pokemon) == 32);
|
|
186
202
|
}
|
|
187
203
|
|
|
188
|
-
pub
|
|
189
|
-
assert(
|
|
204
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
205
|
+
assert(isPointerTo(self, Pokemon));
|
|
190
206
|
assert(mslot > 0 and mslot <= 4);
|
|
191
207
|
assert(self.moves[mslot - 1].id != .None);
|
|
192
208
|
return &self.moves[mslot - 1];
|
|
@@ -199,7 +215,7 @@ pub const Gender = enum(u2) {
|
|
|
199
215
|
Unknown,
|
|
200
216
|
};
|
|
201
217
|
|
|
202
|
-
pub const DVs = packed struct {
|
|
218
|
+
pub const DVs = packed struct(u16) {
|
|
203
219
|
gender: Gender = .Male,
|
|
204
220
|
pow: u6 = 40,
|
|
205
221
|
type: Type = .Dark,
|
|
@@ -207,10 +223,10 @@ pub const DVs = packed struct {
|
|
|
207
223
|
pub fn init(g: Gender, p: u6, t: Type) DVs {
|
|
208
224
|
assert(p >= 1 and p <= 40);
|
|
209
225
|
assert(t != .Normal and t != .@"???");
|
|
210
|
-
return
|
|
226
|
+
return .{ .gender = g, .pow = p, .type = t };
|
|
211
227
|
}
|
|
212
228
|
|
|
213
|
-
pub
|
|
229
|
+
pub fn power(dvs: DVs) u8 {
|
|
214
230
|
return @as(u8, dvs.pow) + 30;
|
|
215
231
|
}
|
|
216
232
|
|
|
@@ -224,13 +240,8 @@ pub const DVs = packed struct {
|
|
|
224
240
|
};
|
|
225
241
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
226
242
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
return DVs{ .gender = g, .pow = p, .type = @enumFromInt(t) };
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
comptime {
|
|
233
|
-
assert(@sizeOf(DVs) == 2);
|
|
243
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
244
|
+
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
234
245
|
}
|
|
235
246
|
};
|
|
236
247
|
|
|
@@ -255,10 +266,12 @@ test DVs {
|
|
|
255
266
|
try expectEqual(Gender.Female, dvs.gender);
|
|
256
267
|
}
|
|
257
268
|
|
|
258
|
-
|
|
269
|
+
/// Representation of a Generation II Pokémon's move slot in a battle.
|
|
270
|
+
pub const MoveSlot = extern struct {
|
|
271
|
+
/// The identifier for the move.
|
|
259
272
|
id: Move = .None,
|
|
260
|
-
|
|
261
|
-
pp:
|
|
273
|
+
/// The remaining PP of the move.
|
|
274
|
+
pp: u8 = 0,
|
|
262
275
|
|
|
263
276
|
comptime {
|
|
264
277
|
assert(@sizeOf(MoveSlot) == 2);
|
|
@@ -267,14 +280,19 @@ pub const MoveSlot = packed struct {
|
|
|
267
280
|
|
|
268
281
|
pub const Status = gen1.Status;
|
|
269
282
|
|
|
270
|
-
|
|
283
|
+
/// TODO
|
|
284
|
+
pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
|
|
285
|
+
|
|
286
|
+
pub const Volatiles = packed struct(u128) {
|
|
271
287
|
Bide: bool = false,
|
|
272
288
|
Thrashing: bool = false,
|
|
289
|
+
BeatUp: bool = false,
|
|
273
290
|
Flinch: bool = false,
|
|
274
291
|
Charging: bool = false,
|
|
275
292
|
Underground: bool = false,
|
|
276
293
|
Flying: bool = false,
|
|
277
294
|
Confusion: bool = false,
|
|
295
|
+
|
|
278
296
|
Mist: bool = false,
|
|
279
297
|
FocusEnergy: bool = false,
|
|
280
298
|
Substitute: bool = false,
|
|
@@ -285,52 +303,55 @@ pub const Volatiles = packed struct {
|
|
|
285
303
|
Transform: bool = false,
|
|
286
304
|
|
|
287
305
|
Nightmare: bool = false,
|
|
288
|
-
|
|
306
|
+
Curse: bool = false,
|
|
289
307
|
Protect: bool = false,
|
|
290
308
|
Foresight: bool = false,
|
|
291
309
|
PerishSong: bool = false,
|
|
292
310
|
Endure: bool = false,
|
|
293
311
|
Rollout: bool = false,
|
|
294
312
|
Attract: bool = false,
|
|
313
|
+
|
|
295
314
|
DefenseCurl: bool = false,
|
|
296
315
|
Encore: bool = false,
|
|
297
316
|
LockOn: bool = false,
|
|
298
317
|
DestinyBond: bool = false,
|
|
299
|
-
|
|
318
|
+
Trapped: bool = false,
|
|
300
319
|
|
|
301
|
-
trapped: bool = false,
|
|
302
320
|
switched: bool = false,
|
|
321
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
303
322
|
switching: bool = false,
|
|
323
|
+
// TODO: simply store both last moves on side
|
|
324
|
+
dirty: bool = false,
|
|
304
325
|
|
|
305
|
-
|
|
326
|
+
frozen: bool = false,
|
|
327
|
+
minimized: bool = false,
|
|
328
|
+
_: u10 = 0,
|
|
329
|
+
// TODO: is this needed for unmodified stats?
|
|
330
|
+
transform: u4 = 0,
|
|
306
331
|
|
|
307
|
-
bind: u4 = 0,
|
|
308
|
-
future_sight: FutureSight = .{},
|
|
309
332
|
bide: u16 = 0,
|
|
310
|
-
|
|
333
|
+
bind: Bind = .{},
|
|
334
|
+
disable: Disable = .{},
|
|
311
335
|
rage: u8 = 0,
|
|
312
336
|
substitute: u8 = 0,
|
|
313
337
|
toxic: u8 = 0,
|
|
314
338
|
confusion: u4 = 0,
|
|
315
339
|
encore: u4 = 0,
|
|
340
|
+
// TODO merge with attacks (ie rollout/thrashing)? need to be zeroed at same time
|
|
316
341
|
fury_cutter: u4 = 0,
|
|
317
342
|
perish_song: u4 = 0,
|
|
318
343
|
protect: u4 = 0,
|
|
319
|
-
|
|
344
|
+
attacks: u4 = 0, // bide/thrashing/rollout turns
|
|
320
345
|
|
|
321
|
-
const
|
|
322
|
-
move: u4 = 0,
|
|
346
|
+
const Bind = packed struct(u8) {
|
|
323
347
|
duration: u4 = 0,
|
|
348
|
+
reason: u4 = 0,
|
|
324
349
|
};
|
|
325
350
|
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
351
|
+
const Disable = packed struct(u8) {
|
|
352
|
+
move: u4 = 0,
|
|
353
|
+
duration: u4 = 0,
|
|
329
354
|
};
|
|
330
|
-
|
|
331
|
-
comptime {
|
|
332
|
-
assert(@sizeOf(Volatiles) == 16);
|
|
333
|
-
}
|
|
334
355
|
};
|
|
335
356
|
|
|
336
357
|
pub fn Stats(comptime T: type) type {
|
|
@@ -365,7 +386,7 @@ test Stats {
|
|
|
365
386
|
try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
366
387
|
}
|
|
367
388
|
|
|
368
|
-
pub const Boosts = packed struct {
|
|
389
|
+
pub const Boosts = packed struct(u32) {
|
|
369
390
|
atk: i4 = 0,
|
|
370
391
|
def: i4 = 0,
|
|
371
392
|
spe: i4 = 0,
|
|
@@ -381,7 +402,7 @@ pub const Boosts = packed struct {
|
|
|
381
402
|
};
|
|
382
403
|
|
|
383
404
|
test Boosts {
|
|
384
|
-
const boosts =
|
|
405
|
+
const boosts: Boosts = .{ .spd = -6 };
|
|
385
406
|
try expectEqual(0, boosts.atk);
|
|
386
407
|
try expectEqual(-6, boosts.spd);
|
|
387
408
|
}
|
|
@@ -394,15 +415,10 @@ test Item {
|
|
|
394
415
|
try expectEqual(Type.Normal, Item.boost(.PolkadotBow).?);
|
|
395
416
|
try expectEqual(Type.Dark, Item.boost(.BlackGlasses).?);
|
|
396
417
|
|
|
397
|
-
try expect(!Item.
|
|
398
|
-
try expect(Item.
|
|
399
|
-
try expect(Item.
|
|
400
|
-
try expect(!Item.
|
|
401
|
-
|
|
402
|
-
try expect(!Item.berry(.LightBall));
|
|
403
|
-
try expect(Item.berry(.PSNCureBerry));
|
|
404
|
-
try expect(Item.berry(.GoldBerry));
|
|
405
|
-
try expect(!Item.berry(.MasterBall));
|
|
418
|
+
try expect(!Item.isMail(.UpGrade));
|
|
419
|
+
try expect(Item.isMail(.FlowerMail));
|
|
420
|
+
try expect(Item.isMail(.MirageMail));
|
|
421
|
+
try expect(!Item.isMail(.TownMap));
|
|
406
422
|
}
|
|
407
423
|
|
|
408
424
|
pub const Move = moves.Move;
|
|
@@ -411,8 +427,13 @@ test Move {
|
|
|
411
427
|
try expectEqual(251, @intFromEnum(Move.BeatUp));
|
|
412
428
|
const move = Move.get(.DynamicPunch);
|
|
413
429
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
414
|
-
try expectEqual(
|
|
415
|
-
try expectEqual(
|
|
430
|
+
try expectEqual(rng.Gen12.percent(50), move.accuracy);
|
|
431
|
+
try expectEqual(rng.Gen12.percent(100), move.chance);
|
|
432
|
+
try expectEqual(@as(u8, 5), Move.pp(.DynamicPunch));
|
|
433
|
+
try expectEqual(@as(i8, -1), Move.get(.Counter).priority);
|
|
434
|
+
try expect(!move.effect.isHighCritical());
|
|
435
|
+
try expect(Move.get(.KarateChop).effect.isHighCritical());
|
|
436
|
+
try expect(Move.get(.RazorWind).effect.isHighCritical());
|
|
416
437
|
}
|
|
417
438
|
|
|
418
439
|
pub const Species = species.Species;
|