@pkmn/engine 0.1.0-dev.736f7a8b → 0.1.0-dev.73fa6bda
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 +64 -29
- 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 +26 -4
- 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 +29 -1
- package/build/pkg/protocol.js +123 -102
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +84 -73
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +66 -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 +360 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +157 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +275 -122
- package/package.json +64 -123
- package/src/bin/install-pkmn-engine +47 -21
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/bindings/c.zig +200 -0
- package/src/lib/{binding → bindings}/node.zig +15 -32
- package/src/lib/bindings/wasm.zig +50 -0
- package/src/lib/common/array.zig +70 -0
- package/src/lib/common/data.zig +12 -24
- package/src/lib/common/debug.zig +33 -28
- package/src/lib/common/js.zig +3 -7
- package/src/lib/common/optional.zig +19 -18
- package/src/lib/common/options.zig +6 -0
- package/src/lib/common/protocol.zig +898 -441
- package/src/lib/common/rational.zig +341 -254
- package/src/lib/common/rng.zig +22 -15
- package/src/lib/common/util.zig +33 -1
- package/src/lib/gen1/calc.zig +726 -177
- package/src/lib/gen1/chance.zig +484 -306
- 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 +9 -10
- package/src/lib/gen1/data.zig +60 -75
- package/src/lib/gen1/helpers.zig +90 -563
- package/src/lib/gen1/mechanics.zig +696 -614
- package/src/lib/gen2/calc.zig +150 -0
- package/src/lib/gen2/chance.zig +896 -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 +139 -34
- package/src/lib/gen2/data.zig +104 -94
- package/src/lib/gen2/generated.zig +801 -0
- package/src/lib/gen2/helpers.zig +49 -35
- package/src/lib/gen2/mechanics.zig +3324 -113
- package/src/lib/napi.h +2 -0
- package/src/lib/node.zig +14 -0
- package/src/lib/pkmn.zig +125 -29
- package/src/lib/wasm.zig +13 -0
- package/src/tools/display/dom.ts +108 -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,28 +74,128 @@ 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
|
|
99
|
-
return
|
|
175
|
+
/// The precedence order of Type `t1` vs. Type `t2`.
|
|
176
|
+
pub fn precedence(t1: Type, t2: Type) u8 {
|
|
177
|
+
// The Ice vs. Fire matchup is out of order - return a higher
|
|
178
|
+
// number than anything else so that it sorts last correctly
|
|
179
|
+
if (t1 == .Ice and t2 == .Fire) return 18;
|
|
180
|
+
return PRECEDENCE[@intFromEnum(t2)];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/// The internal index of this Type used by Present.
|
|
184
|
+
pub fn present(self: Type) u8 {
|
|
185
|
+
return INDEXES[@intFromEnum(self)];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/// The Type corresponding to a random roll of `num` for Conversion 2.
|
|
189
|
+
pub fn conversion2(num: u8) Type {
|
|
190
|
+
assert(num != 6);
|
|
191
|
+
assert(num < 10 or num >= 20);
|
|
192
|
+
assert(num <= 27);
|
|
193
|
+
return if (num < 10) CONVERSION_2[num] else @enumFromInt(num - 10);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/// The Type corresponding to a Hidden Power `index`.
|
|
197
|
+
pub fn hiddenPower(index: u8) Type {
|
|
198
|
+
return HIDDEN_POWER[index];
|
|
100
199
|
}
|
|
101
200
|
};
|
|
102
201
|
|
|
@@ -112,12 +211,18 @@ pub const Types = extern struct {
|
|
|
112
211
|
}
|
|
113
212
|
|
|
114
213
|
/// Whether this typing is immune to type `t`.
|
|
115
|
-
pub
|
|
214
|
+
pub fn immune(self: Types, t: Type) bool {
|
|
116
215
|
return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
|
|
117
216
|
}
|
|
118
217
|
|
|
119
218
|
/// Whether this typing includes type `t`.
|
|
120
|
-
pub
|
|
219
|
+
pub fn includes(self: Types, t: Type) bool {
|
|
121
220
|
return self.type1 == t or self.type2 == t;
|
|
122
221
|
}
|
|
222
|
+
|
|
223
|
+
/// Whether this typing is immune to damage from Sandstorm.
|
|
224
|
+
pub fn sandstormImmune(self: Types) bool {
|
|
225
|
+
return @intFromEnum(self.type1) <= @intFromEnum(Type.Steel) or
|
|
226
|
+
@intFromEnum(self.type2) <= @intFromEnum(Type.Steel);
|
|
227
|
+
}
|
|
123
228
|
};
|
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 = @splat(0),
|
|
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) {
|
|
@@ -105,15 +100,15 @@ pub const Weather = enum(u4) {
|
|
|
105
100
|
};
|
|
106
101
|
|
|
107
102
|
pub const Side = extern struct {
|
|
108
|
-
pokemon: [6]Pokemon =
|
|
109
|
-
active: ActivePokemon = .{},
|
|
103
|
+
pokemon: [6]Pokemon = @splat(.{}),
|
|
104
|
+
active: ActivePokemon align(8) = .{},
|
|
110
105
|
conditions: Conditions = .{},
|
|
111
|
-
// NB: wCurPlayerMove / wCurEnemyMove
|
|
112
|
-
last_selected_move: Move = .None,
|
|
113
106
|
// NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
|
|
114
107
|
last_used_move: Move = .None,
|
|
115
108
|
|
|
116
|
-
|
|
109
|
+
_: [7]u8 = @splat(0),
|
|
110
|
+
|
|
111
|
+
const Conditions = packed struct(u32) {
|
|
117
112
|
Spikes: bool = false,
|
|
118
113
|
Safeguard: bool = false,
|
|
119
114
|
LightScreen: bool = false,
|
|
@@ -123,51 +118,62 @@ 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
|
}
|
|
151
|
+
|
|
152
|
+
// TODO
|
|
153
|
+
// pub fn useMove(self: anytype) void {
|
|
154
|
+
// assert(side.last_selected_move != .None);
|
|
155
|
+
// self.last_used_move = side.last_selected_move;
|
|
156
|
+
// self.active.volatiles.dirty = false;
|
|
157
|
+
// }
|
|
153
158
|
};
|
|
154
159
|
|
|
155
160
|
// NOTE: DVs (Gender & Hidden Power) and Happiness are stored only in Pokemon
|
|
156
161
|
pub const ActivePokemon = extern struct {
|
|
157
162
|
volatiles: Volatiles align(4) = .{},
|
|
158
163
|
stats: Stats(u16) = .{},
|
|
159
|
-
moves: [4]MoveSlot =
|
|
164
|
+
moves: [4]MoveSlot = @splat(.{}),
|
|
160
165
|
boosts: Boosts = .{},
|
|
161
166
|
types: Types = .{},
|
|
162
167
|
species: Species = .None,
|
|
163
|
-
|
|
168
|
+
|
|
169
|
+
_: u8 = 0,
|
|
164
170
|
|
|
165
171
|
comptime {
|
|
166
172
|
assert(@sizeOf(ActivePokemon) == 44);
|
|
167
173
|
}
|
|
168
174
|
|
|
169
|
-
pub
|
|
170
|
-
assert(
|
|
175
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
176
|
+
assert(isPointerTo(self, Pokemon));
|
|
171
177
|
assert(mslot > 0 and mslot <= 4);
|
|
172
178
|
assert(self.moves[mslot - 1].id != .None);
|
|
173
179
|
return &self.moves[mslot - 1];
|
|
@@ -176,7 +182,7 @@ pub const ActivePokemon = extern struct {
|
|
|
176
182
|
|
|
177
183
|
pub const Pokemon = extern struct {
|
|
178
184
|
stats: Stats(u16) = .{},
|
|
179
|
-
moves: [4]MoveSlot =
|
|
185
|
+
moves: [4]MoveSlot = @splat(.{}),
|
|
180
186
|
types: Types = .{},
|
|
181
187
|
dvs: DVs = .{},
|
|
182
188
|
hp: u16 = 0,
|
|
@@ -191,8 +197,8 @@ pub const Pokemon = extern struct {
|
|
|
191
197
|
assert(@sizeOf(Pokemon) == 32);
|
|
192
198
|
}
|
|
193
199
|
|
|
194
|
-
pub
|
|
195
|
-
assert(
|
|
200
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
201
|
+
assert(isPointerTo(self, Pokemon));
|
|
196
202
|
assert(mslot > 0 and mslot <= 4);
|
|
197
203
|
assert(self.moves[mslot - 1].id != .None);
|
|
198
204
|
return &self.moves[mslot - 1];
|
|
@@ -205,7 +211,7 @@ pub const Gender = enum(u2) {
|
|
|
205
211
|
Unknown,
|
|
206
212
|
};
|
|
207
213
|
|
|
208
|
-
pub const DVs = packed struct {
|
|
214
|
+
pub const DVs = packed struct(u16) {
|
|
209
215
|
gender: Gender = .Male,
|
|
210
216
|
pow: u6 = 40,
|
|
211
217
|
type: Type = .Dark,
|
|
@@ -213,10 +219,10 @@ pub const DVs = packed struct {
|
|
|
213
219
|
pub fn init(g: Gender, p: u6, t: Type) DVs {
|
|
214
220
|
assert(p >= 1 and p <= 40);
|
|
215
221
|
assert(t != .Normal and t != .@"???");
|
|
216
|
-
return
|
|
222
|
+
return .{ .gender = g, .pow = p, .type = t };
|
|
217
223
|
}
|
|
218
224
|
|
|
219
|
-
pub
|
|
225
|
+
pub fn power(dvs: DVs) u8 {
|
|
220
226
|
return @as(u8, dvs.pow) + 30;
|
|
221
227
|
}
|
|
222
228
|
|
|
@@ -230,13 +236,8 @@ pub const DVs = packed struct {
|
|
|
230
236
|
};
|
|
231
237
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
232
238
|
((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);
|
|
239
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
240
|
+
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
240
241
|
}
|
|
241
242
|
};
|
|
242
243
|
|
|
@@ -261,10 +262,12 @@ test DVs {
|
|
|
261
262
|
try expectEqual(Gender.Female, dvs.gender);
|
|
262
263
|
}
|
|
263
264
|
|
|
264
|
-
|
|
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.
|
|
265
268
|
id: Move = .None,
|
|
266
|
-
|
|
267
|
-
pp:
|
|
269
|
+
/// The remaining PP of the move.
|
|
270
|
+
pp: u8 = 0,
|
|
268
271
|
|
|
269
272
|
comptime {
|
|
270
273
|
assert(@sizeOf(MoveSlot) == 2);
|
|
@@ -273,14 +276,19 @@ pub const MoveSlot = packed struct {
|
|
|
273
276
|
|
|
274
277
|
pub const Status = gen1.Status;
|
|
275
278
|
|
|
276
|
-
|
|
279
|
+
/// TODO
|
|
280
|
+
pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
|
|
281
|
+
|
|
282
|
+
pub const Volatiles = packed struct(u128) {
|
|
277
283
|
Bide: bool = false,
|
|
278
284
|
Thrashing: bool = false,
|
|
285
|
+
BeatUp: bool = false,
|
|
279
286
|
Flinch: bool = false,
|
|
280
287
|
Charging: bool = false,
|
|
281
288
|
Underground: bool = false,
|
|
282
289
|
Flying: bool = false,
|
|
283
290
|
Confusion: bool = false,
|
|
291
|
+
|
|
284
292
|
Mist: bool = false,
|
|
285
293
|
FocusEnergy: bool = false,
|
|
286
294
|
Substitute: bool = false,
|
|
@@ -291,53 +299,55 @@ pub const Volatiles = packed struct {
|
|
|
291
299
|
Transform: bool = false,
|
|
292
300
|
|
|
293
301
|
Nightmare: bool = false,
|
|
294
|
-
|
|
302
|
+
Curse: bool = false,
|
|
295
303
|
Protect: bool = false,
|
|
296
304
|
Foresight: bool = false,
|
|
297
305
|
PerishSong: bool = false,
|
|
298
306
|
Endure: bool = false,
|
|
299
307
|
Rollout: bool = false,
|
|
300
308
|
Attract: bool = false,
|
|
309
|
+
|
|
301
310
|
DefenseCurl: bool = false,
|
|
302
311
|
Encore: bool = false,
|
|
303
312
|
LockOn: bool = false,
|
|
304
313
|
DestinyBond: bool = false,
|
|
305
|
-
|
|
314
|
+
Trapped: bool = false,
|
|
306
315
|
|
|
307
|
-
trapped: bool = false,
|
|
308
316
|
switched: bool = false,
|
|
317
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
309
318
|
switching: bool = false,
|
|
319
|
+
// TODO: simply store both last moves on side
|
|
310
320
|
dirty: bool = false,
|
|
311
321
|
|
|
312
|
-
|
|
322
|
+
frozen: bool = false,
|
|
323
|
+
minimized: bool = false,
|
|
324
|
+
_: u10 = 0,
|
|
325
|
+
// TODO: is this needed for unmodified stats?
|
|
326
|
+
transform: u4 = 0,
|
|
313
327
|
|
|
314
|
-
bind: u4 = 0,
|
|
315
|
-
future_sight: FutureSight = .{},
|
|
316
328
|
bide: u16 = 0,
|
|
317
|
-
|
|
329
|
+
bind: Bind = .{},
|
|
330
|
+
disable: Disable = .{},
|
|
318
331
|
rage: u8 = 0,
|
|
319
332
|
substitute: u8 = 0,
|
|
320
333
|
toxic: u8 = 0,
|
|
321
334
|
confusion: u4 = 0,
|
|
322
335
|
encore: u4 = 0,
|
|
336
|
+
// TODO merge with attacks (ie rollout/thrashing)? need to be zeroed at same time
|
|
323
337
|
fury_cutter: u4 = 0,
|
|
324
338
|
perish_song: u4 = 0,
|
|
325
339
|
protect: u4 = 0,
|
|
326
|
-
|
|
340
|
+
attacks: u4 = 0, // bide/thrashing/rollout turns
|
|
327
341
|
|
|
328
|
-
const
|
|
329
|
-
move: u4 = 0,
|
|
342
|
+
const Bind = packed struct(u8) {
|
|
330
343
|
duration: u4 = 0,
|
|
344
|
+
reason: u4 = 0,
|
|
331
345
|
};
|
|
332
346
|
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
347
|
+
const Disable = packed struct(u8) {
|
|
348
|
+
move: u4 = 0,
|
|
349
|
+
duration: u4 = 0,
|
|
336
350
|
};
|
|
337
|
-
|
|
338
|
-
comptime {
|
|
339
|
-
assert(@sizeOf(Volatiles) == 16);
|
|
340
|
-
}
|
|
341
351
|
};
|
|
342
352
|
|
|
343
353
|
pub fn Stats(comptime T: type) type {
|
|
@@ -372,7 +382,7 @@ test Stats {
|
|
|
372
382
|
try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
373
383
|
}
|
|
374
384
|
|
|
375
|
-
pub const Boosts = packed struct {
|
|
385
|
+
pub const Boosts = packed struct(u32) {
|
|
376
386
|
atk: i4 = 0,
|
|
377
387
|
def: i4 = 0,
|
|
378
388
|
spe: i4 = 0,
|
|
@@ -388,7 +398,7 @@ pub const Boosts = packed struct {
|
|
|
388
398
|
};
|
|
389
399
|
|
|
390
400
|
test Boosts {
|
|
391
|
-
const boosts =
|
|
401
|
+
const boosts: Boosts = .{ .spd = -6 };
|
|
392
402
|
try expectEqual(0, boosts.atk);
|
|
393
403
|
try expectEqual(-6, boosts.spd);
|
|
394
404
|
}
|
|
@@ -401,15 +411,10 @@ test Item {
|
|
|
401
411
|
try expectEqual(Type.Normal, Item.boost(.PolkadotBow).?);
|
|
402
412
|
try expectEqual(Type.Dark, Item.boost(.BlackGlasses).?);
|
|
403
413
|
|
|
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));
|
|
414
|
+
try expect(!Item.isMail(.UpGrade));
|
|
415
|
+
try expect(Item.isMail(.FlowerMail));
|
|
416
|
+
try expect(Item.isMail(.MirageMail));
|
|
417
|
+
try expect(!Item.isMail(.TownMap));
|
|
413
418
|
}
|
|
414
419
|
|
|
415
420
|
pub const Move = moves.Move;
|
|
@@ -418,9 +423,13 @@ test Move {
|
|
|
418
423
|
try expectEqual(251, @intFromEnum(Move.BeatUp));
|
|
419
424
|
const move = Move.get(.DynamicPunch);
|
|
420
425
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
421
|
-
try expectEqual(
|
|
422
|
-
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));
|
|
423
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());
|
|
424
433
|
}
|
|
425
434
|
|
|
426
435
|
pub const Species = species.Species;
|
|
@@ -440,8 +449,9 @@ test Types {
|
|
|
440
449
|
try expect(!Type.Steel.special());
|
|
441
450
|
try expect(Type.Dark.special());
|
|
442
451
|
|
|
443
|
-
try expectEqual(@as(u8, 3), Type.Water.
|
|
444
|
-
try expect(Type.
|
|
452
|
+
try expectEqual(@as(u8, 3), Type.precedence(.Water, .Water));
|
|
453
|
+
try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
|
|
454
|
+
try expect(Type.precedence(.Ice, .Fire) > Type.precedence(.Ice, .Water));
|
|
445
455
|
|
|
446
456
|
try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
|
|
447
457
|
try expectEqual(Effectiveness.Super, Type.effectiveness(.Water, .Fire));
|