@pkmn/engine 0.1.0-dev.305a932f → 0.1.0-dev.32adfe77
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 +37 -14
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/layout.json +2 -2
- package/build/pkg/data.d.ts +3 -2
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +2 -2
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +2 -1
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.js +1 -1
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js +3 -1
- package/build/tools/debug.js.map +1 -1
- package/build.zig +78 -68
- package/package.json +34 -23
- package/src/bin/install-pkmn-engine +14 -14
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/optional.zig +9 -2
- package/src/lib/common/protocol.zig +402 -383
- package/src/lib/common/rational.zig +11 -7
- package/src/lib/common/rng.zig +20 -11
- package/src/lib/gen1/README.md +28 -28
- package/src/lib/gen1/calc.zig +7 -7
- package/src/lib/gen1/chance.zig +70 -68
- package/src/lib/gen1/data/moves.zig +24 -10
- package/src/lib/gen1/data/species.zig +3 -3
- package/src/lib/gen1/data/types.zig +5 -5
- package/src/lib/gen1/data.zig +36 -36
- package/src/lib/gen1/helpers.zig +21 -36
- package/src/lib/gen1/mechanics.zig +333 -344
- package/src/lib/gen2/README.md +1 -2
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1314 -0
- package/src/lib/gen2/data/items.zig +3 -3
- package/src/lib/gen2/data/moves.zig +32 -15
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +75 -28
- package/src/lib/gen2/data.zig +37 -25
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/mechanics.zig +2612 -349
- package/src/lib/{binding/node.zig → node.zig} +9 -12
- package/src/lib/pkmn.zig +26 -3
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
|
@@ -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
|
|
|
@@ -216,14 +216,14 @@ pub const Item = enum(u8) {
|
|
|
216
216
|
pub const size = 196;
|
|
217
217
|
|
|
218
218
|
/// Returns a `Type` boosted by this item or `null` if the item is not a type-boosting item.
|
|
219
|
-
pub
|
|
219
|
+
pub fn boost(item: Item) ?Type {
|
|
220
220
|
assert(item != .None);
|
|
221
221
|
if (item == .PolkadotBow) return .Normal;
|
|
222
222
|
return if (@intFromEnum(item) <= 18) @enumFromInt(@intFromEnum(item) - 1) else null;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
/// Whether or not this item is Mail.
|
|
226
|
-
pub
|
|
226
|
+
pub fn isMail(item: Item) bool {
|
|
227
227
|
assert(item != .None);
|
|
228
228
|
return @intFromEnum(item) > 60 and @intFromEnum(item) <= 70;
|
|
229
229
|
}
|
|
@@ -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
|
|
|
@@ -288,6 +288,8 @@ pub const Move = enum(u8) {
|
|
|
288
288
|
const Extra = packed struct(u8) {
|
|
289
289
|
/// Whether this move can be called via Metronome.
|
|
290
290
|
metronome: bool = true,
|
|
291
|
+
/// Whether this move can be called via Sleep Talk.
|
|
292
|
+
sleep_talk: bool = true,
|
|
291
293
|
/// Whether this move is considered to be "continuous".
|
|
292
294
|
continuous: bool = false,
|
|
293
295
|
/// Whether this move can hit a flying target.
|
|
@@ -295,7 +297,7 @@ pub const Move = enum(u8) {
|
|
|
295
297
|
/// Whether this move can hit an underground target.
|
|
296
298
|
underground: bool = false,
|
|
297
299
|
/// Protocol reason offset associated with this move.
|
|
298
|
-
protocol:
|
|
300
|
+
protocol: u3 = 0,
|
|
299
301
|
};
|
|
300
302
|
|
|
301
303
|
comptime {
|
|
@@ -410,7 +412,7 @@ pub const Move = enum(u8) {
|
|
|
410
412
|
.type = .Normal,
|
|
411
413
|
.accuracy = percent(75),
|
|
412
414
|
.target = .Foes,
|
|
413
|
-
.extra = .{ .continuous = true },
|
|
415
|
+
.extra = .{ .sleep_talk = false, .continuous = true },
|
|
414
416
|
},
|
|
415
417
|
// SwordsDance
|
|
416
418
|
.{
|
|
@@ -457,12 +459,12 @@ pub const Move = enum(u8) {
|
|
|
457
459
|
},
|
|
458
460
|
// Fly
|
|
459
461
|
.{
|
|
460
|
-
.effect = .
|
|
462
|
+
.effect = .FlyDig,
|
|
461
463
|
.bp = 70,
|
|
462
464
|
.type = .Flying,
|
|
463
465
|
.accuracy = percent(95),
|
|
464
466
|
.target = .Any,
|
|
465
|
-
.extra = .{ .continuous = true },
|
|
467
|
+
.extra = .{ .sleep_talk = false, .continuous = true },
|
|
466
468
|
},
|
|
467
469
|
// Bind
|
|
468
470
|
.{
|
|
@@ -936,12 +938,12 @@ pub const Move = enum(u8) {
|
|
|
936
938
|
},
|
|
937
939
|
// SolarBeam
|
|
938
940
|
.{
|
|
939
|
-
.effect = .
|
|
941
|
+
.effect = .SolarBeam,
|
|
940
942
|
.bp = 120,
|
|
941
943
|
.type = .Grass,
|
|
942
944
|
.accuracy = percent(100),
|
|
943
945
|
.target = .Other,
|
|
944
|
-
.extra = .{ .continuous = true },
|
|
946
|
+
.extra = .{ .sleep_talk = false, .continuous = true },
|
|
945
947
|
},
|
|
946
948
|
// PoisonPowder
|
|
947
949
|
.{
|
|
@@ -1065,11 +1067,12 @@ pub const Move = enum(u8) {
|
|
|
1065
1067
|
},
|
|
1066
1068
|
// Dig
|
|
1067
1069
|
.{
|
|
1068
|
-
.effect = .
|
|
1070
|
+
.effect = .FlyDig,
|
|
1069
1071
|
.bp = 60,
|
|
1070
1072
|
.type = .Ground,
|
|
1071
1073
|
.accuracy = percent(100),
|
|
1072
1074
|
.target = .Other,
|
|
1075
|
+
.extra = .{ .sleep_talk = false },
|
|
1073
1076
|
},
|
|
1074
1077
|
// Toxic
|
|
1075
1078
|
.{
|
|
@@ -1282,7 +1285,7 @@ pub const Move = enum(u8) {
|
|
|
1282
1285
|
.type = .Normal,
|
|
1283
1286
|
.accuracy = percent(100),
|
|
1284
1287
|
.target = .Self,
|
|
1285
|
-
.extra = .{ .continuous = true },
|
|
1288
|
+
.extra = .{ .sleep_talk = false, .continuous = true },
|
|
1286
1289
|
},
|
|
1287
1290
|
// Metronome
|
|
1288
1291
|
.{
|
|
@@ -1394,7 +1397,7 @@ pub const Move = enum(u8) {
|
|
|
1394
1397
|
.type = .Normal,
|
|
1395
1398
|
.accuracy = percent(100),
|
|
1396
1399
|
.target = .Other,
|
|
1397
|
-
.extra = .{ .continuous = true },
|
|
1400
|
+
.extra = .{ .sleep_talk = false, .continuous = true },
|
|
1398
1401
|
},
|
|
1399
1402
|
// SpikeCannon
|
|
1400
1403
|
.{
|
|
@@ -1500,7 +1503,7 @@ pub const Move = enum(u8) {
|
|
|
1500
1503
|
.type = .Flying,
|
|
1501
1504
|
.accuracy = percent(90),
|
|
1502
1505
|
.target = .Any,
|
|
1503
|
-
.extra = .{ .continuous = true },
|
|
1506
|
+
.extra = .{ .sleep_talk = false, .continuous = true },
|
|
1504
1507
|
},
|
|
1505
1508
|
// Transform
|
|
1506
1509
|
.{
|
|
@@ -2463,7 +2466,7 @@ pub const Move = enum(u8) {
|
|
|
2463
2466
|
FixedDamage,
|
|
2464
2467
|
FlameWheel,
|
|
2465
2468
|
FlinchChance,
|
|
2466
|
-
|
|
2469
|
+
FlyDig,
|
|
2467
2470
|
FocusEnergy,
|
|
2468
2471
|
ForceSwitch,
|
|
2469
2472
|
Foresight,
|
|
@@ -2526,7 +2529,7 @@ pub const Move = enum(u8) {
|
|
|
2526
2529
|
Sleep,
|
|
2527
2530
|
SleepTalk,
|
|
2528
2531
|
Snore,
|
|
2529
|
-
|
|
2532
|
+
SolarBeam,
|
|
2530
2533
|
SpAtkUp1,
|
|
2531
2534
|
SpDefDownChance,
|
|
2532
2535
|
SpDefUp2,
|
|
@@ -2559,7 +2562,7 @@ pub const Move = enum(u8) {
|
|
|
2559
2562
|
}
|
|
2560
2563
|
|
|
2561
2564
|
/// Whether this effect has a high critical rate.
|
|
2562
|
-
pub
|
|
2565
|
+
pub fn isHighCritical(effect: Effect) bool {
|
|
2563
2566
|
return effect == .HighCritical or effect == .RazorWind;
|
|
2564
2567
|
}
|
|
2565
2568
|
};
|
|
@@ -2847,8 +2850,22 @@ pub const Move = enum(u8) {
|
|
|
2847
2850
|
/// The number of Pokémon moves in this generation.
|
|
2848
2851
|
pub const size = 251;
|
|
2849
2852
|
|
|
2853
|
+
/// Pokémon moves that can be called by Metronome in this generation.
|
|
2854
|
+
pub const METRONOME = init: {
|
|
2855
|
+
var num = 0;
|
|
2856
|
+
var moves: [239]Move = undefined;
|
|
2857
|
+
for (1..Move.size + 1) |i| {
|
|
2858
|
+
if (Move.get(@enumFromInt(i)).extra.metronome) {
|
|
2859
|
+
moves[num] = @enumFromInt(i);
|
|
2860
|
+
num += 1;
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
assert(num == moves.len);
|
|
2864
|
+
break :init moves;
|
|
2865
|
+
};
|
|
2866
|
+
|
|
2850
2867
|
/// Returns the `Data` corresponding to the move.
|
|
2851
|
-
pub
|
|
2868
|
+
pub fn get(id: Move) Data {
|
|
2852
2869
|
assert(id != .None);
|
|
2853
2870
|
return DATA[@intFromEnum(id) - 1];
|
|
2854
2871
|
}
|
|
@@ -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
|
|
|
@@ -96,23 +96,58 @@ pub const Type = enum(u8) {
|
|
|
96
96
|
27, // Dark
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
+
.@"???",
|
|
116
151
|
};
|
|
117
152
|
|
|
118
153
|
comptime {
|
|
@@ -120,34 +155,45 @@ pub const Type = enum(u8) {
|
|
|
120
155
|
assert(@sizeOf(@TypeOf(CHART)) == 324);
|
|
121
156
|
assert(@sizeOf(@TypeOf(PRECEDENCE)) == 18);
|
|
122
157
|
assert(@sizeOf(@TypeOf(INDEXES)) == 18);
|
|
158
|
+
assert(@sizeOf(@TypeOf(CONVERSION_2)) == 10);
|
|
123
159
|
assert(@sizeOf(@TypeOf(HIDDEN_POWER)) == 16);
|
|
160
|
+
assert(@sizeOf(@TypeOf(SHOWDOWN)) == 18);
|
|
124
161
|
}
|
|
125
162
|
|
|
126
163
|
/// The number of types in this generation.
|
|
127
164
|
pub const size = 18;
|
|
128
165
|
|
|
129
166
|
/// Whether or not this type is considered to be special as opposed to physical.
|
|
130
|
-
pub
|
|
167
|
+
pub fn special(self: Type) bool {
|
|
131
168
|
return @intFromEnum(self) >= @intFromEnum(Type.Fire);
|
|
132
169
|
}
|
|
133
170
|
|
|
134
171
|
/// The `Effectiveness` of type `t2` vs. type `t1`.
|
|
135
|
-
pub
|
|
172
|
+
pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
|
|
136
173
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
137
174
|
}
|
|
138
175
|
|
|
139
176
|
/// The precedence order of Type `type`.
|
|
140
|
-
pub
|
|
177
|
+
pub fn precedence(self: Type) u8 {
|
|
141
178
|
return PRECEDENCE[@intFromEnum(self)];
|
|
142
179
|
}
|
|
180
|
+
|
|
143
181
|
/// The internal index of this Type used by Present.
|
|
144
|
-
pub
|
|
182
|
+
pub fn present(self: Type) u8 {
|
|
145
183
|
return INDEXES[@intFromEnum(self)];
|
|
146
184
|
}
|
|
147
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
|
+
|
|
148
194
|
/// The Type corresponding to a Hidden Power `index`.
|
|
149
|
-
pub
|
|
150
|
-
return
|
|
195
|
+
pub fn hiddenPower(index: u8) Type {
|
|
196
|
+
return HIDDEN_POWER[index];
|
|
151
197
|
}
|
|
152
198
|
};
|
|
153
199
|
|
|
@@ -163,17 +209,18 @@ pub const Types = extern struct {
|
|
|
163
209
|
}
|
|
164
210
|
|
|
165
211
|
/// Whether this typing is immune to type `t`.
|
|
166
|
-
pub
|
|
212
|
+
pub fn immune(self: Types, t: Type) bool {
|
|
167
213
|
return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
|
|
168
214
|
}
|
|
169
215
|
|
|
170
216
|
/// Whether this typing includes type `t`.
|
|
171
|
-
pub
|
|
217
|
+
pub fn includes(self: Types, t: Type) bool {
|
|
172
218
|
return self.type1 == t or self.type2 == t;
|
|
173
219
|
}
|
|
174
220
|
|
|
175
221
|
/// Whether this typing is immune to damage from Sandstorm.
|
|
176
|
-
pub
|
|
177
|
-
return self.type1 <= @intFromEnum(Type.Steel) or
|
|
222
|
+
pub fn sandstormImmune(self: Types) bool {
|
|
223
|
+
return @intFromEnum(self.type1) <= @intFromEnum(Type.Steel) or
|
|
224
|
+
@intFromEnum(self.type2) <= @intFromEnum(Type.Steel);
|
|
178
225
|
}
|
|
179
226
|
};
|
package/src/lib/gen2/data.zig
CHANGED
|
@@ -62,17 +62,17 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
62
62
|
|
|
63
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
|
|
|
@@ -133,7 +133,7 @@ pub const Side = extern struct {
|
|
|
133
133
|
assert(@sizeOf(Side) == 248);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
pub
|
|
136
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
137
137
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
138
138
|
assert(slot > 0 and slot <= 6);
|
|
139
139
|
const id = self.pokemon[slot - 1].position;
|
|
@@ -141,19 +141,19 @@ pub const Side = extern struct {
|
|
|
141
141
|
return &self.pokemon[id - 1];
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
pub
|
|
144
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
145
145
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
146
146
|
return self.get(1);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
pub
|
|
149
|
+
pub fn lastMove(self: anytype, encore: bool) Move {
|
|
150
150
|
assert(self.last_used_move != .None or !self.active.volatiles.dirty);
|
|
151
151
|
if (encore) return self.last_used_move;
|
|
152
152
|
return if (self.active.volatiles.dirty) .None else self.last_used_move;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// TODO
|
|
156
|
-
// pub
|
|
156
|
+
// pub fn useMove(self: anytype) void {
|
|
157
157
|
// assert(side.last_selected_move != .None);
|
|
158
158
|
// self.last_used_move = side.last_selected_move;
|
|
159
159
|
// self.active.volatiles.dirty = false;
|
|
@@ -175,7 +175,7 @@ pub const ActivePokemon = extern struct {
|
|
|
175
175
|
assert(@sizeOf(ActivePokemon) == 44);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
pub
|
|
178
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
179
179
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
180
180
|
assert(mslot > 0 and mslot <= 4);
|
|
181
181
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -200,7 +200,7 @@ pub const Pokemon = extern struct {
|
|
|
200
200
|
assert(@sizeOf(Pokemon) == 32);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
pub
|
|
203
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
204
204
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
205
205
|
assert(mslot > 0 and mslot <= 4);
|
|
206
206
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -225,7 +225,7 @@ pub const DVs = packed struct(u16) {
|
|
|
225
225
|
return .{ .gender = g, .pow = p, .type = t };
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
pub
|
|
228
|
+
pub fn power(dvs: DVs) u8 {
|
|
229
229
|
return @as(u8, dvs.pow) + 30;
|
|
230
230
|
}
|
|
231
231
|
|
|
@@ -239,7 +239,7 @@ pub const DVs = packed struct(u16) {
|
|
|
239
239
|
};
|
|
240
240
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
241
241
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
242
|
-
|
|
242
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
243
|
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
244
244
|
}
|
|
245
245
|
};
|
|
@@ -248,12 +248,12 @@ test DVs {
|
|
|
248
248
|
var dvs = DVs.from(.Mewtwo, .{ .def = 13 });
|
|
249
249
|
try expectEqual(Gender.Unknown, dvs.gender);
|
|
250
250
|
try expectEqual(Type.Ice, dvs.type);
|
|
251
|
-
try expectEqual(
|
|
251
|
+
try expectEqual(70, dvs.power());
|
|
252
252
|
|
|
253
253
|
dvs = DVs.from(.Pikachu, .{ .spc = 14 });
|
|
254
254
|
try expectEqual(Gender.Male, dvs.gender);
|
|
255
255
|
try expectEqual(Type.Dark, dvs.type);
|
|
256
|
-
try expectEqual(
|
|
256
|
+
try expectEqual(69, dvs.power());
|
|
257
257
|
|
|
258
258
|
dvs = DVs.from(.Cyndaquil, .{ .atk = 1, .def = 3, .spe = 10, .spc = 9 });
|
|
259
259
|
try expectEqual(Gender.Female, dvs.gender);
|
|
@@ -279,6 +279,9 @@ pub const MoveSlot = extern struct {
|
|
|
279
279
|
|
|
280
280
|
pub const Status = gen1.Status;
|
|
281
281
|
|
|
282
|
+
/// TODO
|
|
283
|
+
pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
|
|
284
|
+
|
|
282
285
|
pub const Volatiles = packed struct(u128) {
|
|
283
286
|
Bide: bool = false,
|
|
284
287
|
Thrashing: bool = false,
|
|
@@ -311,19 +314,23 @@ pub const Volatiles = packed struct(u128) {
|
|
|
311
314
|
Encore: bool = false,
|
|
312
315
|
LockOn: bool = false,
|
|
313
316
|
DestinyBond: bool = false,
|
|
317
|
+
Trapped: bool = false,
|
|
314
318
|
|
|
315
|
-
trapped: bool = false,
|
|
316
319
|
switched: bool = false,
|
|
320
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
317
321
|
switching: bool = false,
|
|
322
|
+
// TODO: simply store both last moves on side
|
|
318
323
|
dirty: bool = false,
|
|
319
324
|
|
|
320
325
|
frozen: bool = false,
|
|
321
|
-
|
|
326
|
+
minimized: bool = false,
|
|
327
|
+
_: u10 = 0,
|
|
328
|
+
// TODO: is this needed for unmodified stats?
|
|
329
|
+
transform: u4 = 0,
|
|
322
330
|
|
|
323
|
-
bind_reason: u4 = 0,
|
|
324
|
-
bind: u4 = 0,
|
|
325
331
|
bide: u16 = 0,
|
|
326
|
-
|
|
332
|
+
bind: Bind = .{},
|
|
333
|
+
disable: Disable = .{},
|
|
327
334
|
rage: u8 = 0,
|
|
328
335
|
substitute: u8 = 0,
|
|
329
336
|
toxic: u8 = 0,
|
|
@@ -335,7 +342,12 @@ pub const Volatiles = packed struct(u128) {
|
|
|
335
342
|
protect: u4 = 0,
|
|
336
343
|
attacks: u4 = 0, // bide/thrashing/rollout turns
|
|
337
344
|
|
|
338
|
-
const
|
|
345
|
+
const Bind = packed struct(u8) {
|
|
346
|
+
duration: u4 = 0,
|
|
347
|
+
reason: u4 = 0,
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const Disable = packed struct(u8) {
|
|
339
351
|
move: u4 = 0,
|
|
340
352
|
duration: u4 = 0,
|
|
341
353
|
};
|
|
@@ -368,9 +380,9 @@ test Stats {
|
|
|
368
380
|
try expectEqual(0, stats.def);
|
|
369
381
|
|
|
370
382
|
var base = Species.get(.Gyarados).stats;
|
|
371
|
-
try expectEqual(
|
|
383
|
+
try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
372
384
|
base = Species.get(.Pidgeot).stats;
|
|
373
|
-
try expectEqual(
|
|
385
|
+
try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
374
386
|
}
|
|
375
387
|
|
|
376
388
|
pub const Boosts = packed struct(u32) {
|
|
@@ -416,8 +428,8 @@ test Move {
|
|
|
416
428
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
417
429
|
try expectEqual(rng.Gen12.percent(50), move.accuracy);
|
|
418
430
|
try expectEqual(rng.Gen12.percent(100), move.chance);
|
|
419
|
-
try expectEqual(
|
|
420
|
-
try expectEqual(
|
|
431
|
+
try expectEqual(5, Move.pp(.DynamicPunch));
|
|
432
|
+
try expectEqual(-1, Move.get(.Counter).priority);
|
|
421
433
|
try expect(!move.effect.isHighCritical());
|
|
422
434
|
try expect(Move.get(.KarateChop).effect.isHighCritical());
|
|
423
435
|
try expect(Move.get(.RazorWind).effect.isHighCritical());
|
|
@@ -427,7 +439,7 @@ pub const Species = species.Species;
|
|
|
427
439
|
|
|
428
440
|
test Species {
|
|
429
441
|
try expectEqual(152, @intFromEnum(Species.Chikorita));
|
|
430
|
-
try expectEqual(
|
|
442
|
+
try expectEqual(100, Species.get(.Celebi).stats.spd);
|
|
431
443
|
}
|
|
432
444
|
|
|
433
445
|
pub const Type = types.Type;
|
|
@@ -440,7 +452,7 @@ test Types {
|
|
|
440
452
|
try expect(!Type.Steel.special());
|
|
441
453
|
try expect(Type.Dark.special());
|
|
442
454
|
|
|
443
|
-
try expectEqual(
|
|
455
|
+
try expectEqual(3, Type.Water.precedence());
|
|
444
456
|
try expect(Type.Bug.precedence() > Type.Poison.precedence());
|
|
445
457
|
|
|
446
458
|
try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
|