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