@pkmn/engine 0.1.0-dev.cf6f5d2c → 0.1.0-dev.d56bdadd
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/README.md +55 -44
- package/build/pkg/addon.js +3 -2
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/ids.json +12 -12
- package/build/pkg/data/layout.json +27 -5
- package/build/pkg/data/protocol.json +69 -12
- package/build/pkg/data.d.ts +2 -2
- package/build/pkg/gen1.d.ts +2 -1
- package/build/pkg/gen1.js +38 -20
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +4 -2
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +4 -2
- package/build/pkg/protocol.js +60 -39
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js +7 -3
- package/build/test/display.js.map +1 -1
- package/build.zig +103 -73
- package/package.json +41 -20
- package/src/bin/install-pkmn-engine +10 -5
- package/src/lib/binding/node.zig +46 -141
- package/src/lib/binding/wasm.zig +4 -2
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/data.zig +19 -31
- package/src/lib/common/debug.zig +20 -11
- package/src/lib/common/js.zig +118 -0
- package/src/lib/common/optional.zig +67 -0
- package/src/lib/common/options.zig +9 -0
- package/src/lib/common/protocol.zig +770 -208
- package/src/lib/common/rational.zig +353 -0
- package/src/lib/common/rng.zig +24 -15
- package/src/lib/common/util.zig +12 -0
- package/src/lib/gen1/README.md +269 -179
- package/src/lib/gen1/calc.zig +426 -0
- package/src/lib/gen1/chance.zig +1060 -0
- package/src/lib/gen1/data/moves.zig +202 -190
- package/src/lib/gen1/data/species.zig +4 -4
- package/src/lib/gen1/data/types.zig +10 -10
- package/src/lib/gen1/data.zig +85 -71
- package/src/lib/gen1/helpers.zig +577 -35
- package/src/lib/gen1/mechanics.zig +874 -608
- package/src/lib/gen2/README.md +105 -85
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1314 -0
- package/src/lib/gen2/data/items.zig +14 -20
- package/src/lib/gen2/data/moves.zig +664 -570
- package/src/lib/gen2/data/species.zig +2 -2
- package/src/lib/gen2/data/types.zig +137 -34
- package/src/lib/gen2/data.zig +124 -86
- package/src/lib/gen2/generated.zig +808 -0
- package/src/lib/gen2/helpers.zig +16 -22
- package/src/lib/gen2/mechanics.zig +3490 -12
- package/src/lib/pkmn.zig +61 -2
package/src/lib/gen2/data.zig
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
const builtin = @import("builtin");
|
|
3
3
|
|
|
4
|
+
const pkmn = @import("../pkmn.zig");
|
|
5
|
+
|
|
4
6
|
const data = @import("../common/data.zig");
|
|
5
7
|
const DEBUG = @import("../common/debug.zig").print;
|
|
6
|
-
const
|
|
8
|
+
const protocol = @import("../common/protocol.zig");
|
|
7
9
|
const rng = @import("../common/rng.zig");
|
|
10
|
+
const util = @import("../common/util.zig");
|
|
8
11
|
|
|
9
12
|
const items = @import("data/items.zig");
|
|
10
13
|
const moves = @import("data/moves.zig");
|
|
@@ -13,6 +16,8 @@ const types = @import("data/types.zig");
|
|
|
13
16
|
|
|
14
17
|
const gen1 = @import("../gen1/data.zig");
|
|
15
18
|
|
|
19
|
+
const calc = @import("calc.zig");
|
|
20
|
+
const chance = @import("chance.zig");
|
|
16
21
|
const mechanics = @import("mechanics.zig");
|
|
17
22
|
|
|
18
23
|
const assert = std.debug.assert;
|
|
@@ -31,16 +36,22 @@ pub const LOGS_SIZE = if (builtin.mode == .ReleaseSmall)
|
|
|
31
36
|
else
|
|
32
37
|
std.math.ceilPowerOfTwo(usize, MAX_LOGS) catch unreachable;
|
|
33
38
|
|
|
39
|
+
/// Null object pattern implementation of pkmn.battle.Options for Generation II.
|
|
40
|
+
pub const NULL = pkmn.battle.options(protocol.NULL, chance.NULL, calc.NULL);
|
|
41
|
+
|
|
34
42
|
const Choice = data.Choice;
|
|
35
43
|
const ID = data.ID;
|
|
36
44
|
const Player = data.Player;
|
|
37
45
|
const Result = data.Result;
|
|
38
46
|
|
|
39
|
-
const
|
|
47
|
+
const PointerType = util.PointerType;
|
|
48
|
+
|
|
49
|
+
const showdown = pkmn.options.showdown;
|
|
40
50
|
|
|
41
51
|
pub const PRNG = rng.PRNG(2);
|
|
42
52
|
|
|
43
53
|
pub fn Battle(comptime RNG: anytype) type {
|
|
54
|
+
const padding = if (!showdown) 3 else 5;
|
|
44
55
|
return extern struct {
|
|
45
56
|
const Self = @This();
|
|
46
57
|
|
|
@@ -49,20 +60,24 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
49
60
|
turn: u16 = 0,
|
|
50
61
|
field: Field = .{},
|
|
51
62
|
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
_: [padding]u8 = .{0} ** padding,
|
|
64
|
+
|
|
65
|
+
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
66
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
67
|
+
return &self.sides[@intFromEnum(player)];
|
|
54
68
|
}
|
|
55
69
|
|
|
56
|
-
pub
|
|
57
|
-
|
|
70
|
+
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
71
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
72
|
+
return &self.sides[@intFromEnum(player.foe())];
|
|
58
73
|
}
|
|
59
74
|
|
|
60
|
-
pub
|
|
61
|
-
return player.ident(@intCast(
|
|
75
|
+
pub fn active(self: *const Self, player: Player) ID {
|
|
76
|
+
return player.ident(@intCast(self.side(player).pokemon[0].position));
|
|
62
77
|
}
|
|
63
78
|
|
|
64
|
-
pub fn update(self: *Self, c1: Choice, c2: Choice,
|
|
65
|
-
return mechanics.update(self, c1, c2,
|
|
79
|
+
pub fn update(self: *Self, c1: Choice, c2: Choice, options: anytype) !Result {
|
|
80
|
+
return mechanics.update(self, c1, c2, options);
|
|
66
81
|
}
|
|
67
82
|
|
|
68
83
|
pub fn choices(self: *Self, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
@@ -71,35 +86,32 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
71
86
|
};
|
|
72
87
|
}
|
|
73
88
|
|
|
74
|
-
// TODO
|
|
75
89
|
test Battle {
|
|
76
|
-
try expectEqual(
|
|
90
|
+
try expectEqual(512, @sizeOf(Battle(PRNG)));
|
|
77
91
|
}
|
|
78
92
|
|
|
79
|
-
const Field = packed struct {
|
|
93
|
+
pub const Field = packed struct(u8) {
|
|
80
94
|
weather: Weather = .None,
|
|
81
95
|
weather_duration: u4 = 0,
|
|
82
|
-
|
|
83
|
-
comptime {
|
|
84
|
-
assert(@sizeOf(Field) == 1);
|
|
85
|
-
}
|
|
86
96
|
};
|
|
87
97
|
|
|
88
|
-
const Weather = enum(u4) {
|
|
98
|
+
pub const Weather = enum(u4) {
|
|
89
99
|
None,
|
|
90
100
|
Rain,
|
|
91
101
|
Sun,
|
|
92
102
|
Sandstorm,
|
|
93
103
|
};
|
|
94
104
|
|
|
95
|
-
const Side = extern struct {
|
|
105
|
+
pub const Side = extern struct {
|
|
96
106
|
pokemon: [6]Pokemon = [_]Pokemon{.{}} ** 6,
|
|
97
|
-
active: ActivePokemon = .{},
|
|
98
|
-
conditions: Conditions,
|
|
107
|
+
active: ActivePokemon align(8) = .{},
|
|
108
|
+
conditions: Conditions = .{},
|
|
109
|
+
// NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
|
|
99
110
|
last_used_move: Move = .None,
|
|
100
|
-
_: u8 = 0,
|
|
101
111
|
|
|
102
|
-
|
|
112
|
+
_: [7]u8 = .{0} ** 7,
|
|
113
|
+
|
|
114
|
+
const Conditions = packed struct(u32) {
|
|
103
115
|
Spikes: bool = false,
|
|
104
116
|
Safeguard: bool = false,
|
|
105
117
|
LightScreen: bool = false,
|
|
@@ -109,50 +121,69 @@ const Side = extern struct {
|
|
|
109
121
|
light_screen: u4 = 0,
|
|
110
122
|
reflect: u4 = 0,
|
|
111
123
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
future_sight: FutureSight = .{},
|
|
125
|
+
|
|
126
|
+
const FutureSight = packed struct(u16) {
|
|
127
|
+
damage: u12 = 0,
|
|
128
|
+
count: u4 = 0,
|
|
129
|
+
};
|
|
115
130
|
};
|
|
116
131
|
|
|
117
132
|
comptime {
|
|
118
|
-
assert(@sizeOf(Side) ==
|
|
133
|
+
assert(@sizeOf(Side) == 248);
|
|
119
134
|
}
|
|
120
135
|
|
|
121
|
-
pub
|
|
136
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
137
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
122
138
|
assert(slot > 0 and slot <= 6);
|
|
123
139
|
const id = self.pokemon[slot - 1].position;
|
|
124
140
|
assert(id > 0 and id <= 6);
|
|
125
141
|
return &self.pokemon[id - 1];
|
|
126
142
|
}
|
|
127
143
|
|
|
128
|
-
pub
|
|
144
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
145
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
129
146
|
return self.get(1);
|
|
130
147
|
}
|
|
148
|
+
|
|
149
|
+
pub fn lastMove(self: anytype, encore: bool) Move {
|
|
150
|
+
assert(self.last_used_move != .None or !self.active.volatiles.dirty);
|
|
151
|
+
if (encore) return self.last_used_move;
|
|
152
|
+
return if (self.active.volatiles.dirty) .None else self.last_used_move;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// TODO
|
|
156
|
+
// pub fn useMove(self: anytype) void {
|
|
157
|
+
// assert(side.last_selected_move != .None);
|
|
158
|
+
// self.last_used_move = side.last_selected_move;
|
|
159
|
+
// self.active.volatiles.dirty = false;
|
|
160
|
+
// }
|
|
131
161
|
};
|
|
132
162
|
|
|
133
163
|
// NOTE: DVs (Gender & Hidden Power) and Happiness are stored only in Pokemon
|
|
134
|
-
const ActivePokemon = extern struct {
|
|
135
|
-
volatiles:
|
|
164
|
+
pub const ActivePokemon = extern struct {
|
|
165
|
+
volatiles: Volatiles align(4) = .{},
|
|
136
166
|
stats: Stats(u16) = .{},
|
|
137
167
|
moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
|
|
138
168
|
boosts: Boosts = .{},
|
|
169
|
+
types: Types = .{},
|
|
139
170
|
species: Species = .None,
|
|
140
|
-
|
|
141
|
-
last_move: Move = .None,
|
|
171
|
+
|
|
142
172
|
_: u8 = 0,
|
|
143
173
|
|
|
144
174
|
comptime {
|
|
145
175
|
assert(@sizeOf(ActivePokemon) == 44);
|
|
146
176
|
}
|
|
147
177
|
|
|
148
|
-
pub
|
|
178
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
179
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
149
180
|
assert(mslot > 0 and mslot <= 4);
|
|
150
181
|
assert(self.moves[mslot - 1].id != .None);
|
|
151
182
|
return &self.moves[mslot - 1];
|
|
152
183
|
}
|
|
153
184
|
};
|
|
154
185
|
|
|
155
|
-
const Pokemon = extern struct {
|
|
186
|
+
pub const Pokemon = extern struct {
|
|
156
187
|
stats: Stats(u16) = .{},
|
|
157
188
|
moves: [4]MoveSlot = [_]MoveSlot{.{}} ** 4,
|
|
158
189
|
types: Types = .{},
|
|
@@ -169,7 +200,8 @@ const Pokemon = extern struct {
|
|
|
169
200
|
assert(@sizeOf(Pokemon) == 32);
|
|
170
201
|
}
|
|
171
202
|
|
|
172
|
-
pub
|
|
203
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
204
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
173
205
|
assert(mslot > 0 and mslot <= 4);
|
|
174
206
|
assert(self.moves[mslot - 1].id != .None);
|
|
175
207
|
return &self.moves[mslot - 1];
|
|
@@ -182,7 +214,7 @@ pub const Gender = enum(u2) {
|
|
|
182
214
|
Unknown,
|
|
183
215
|
};
|
|
184
216
|
|
|
185
|
-
const DVs = packed struct {
|
|
217
|
+
pub const DVs = packed struct(u16) {
|
|
186
218
|
gender: Gender = .Male,
|
|
187
219
|
pow: u6 = 40,
|
|
188
220
|
type: Type = .Dark,
|
|
@@ -190,10 +222,10 @@ const DVs = packed struct {
|
|
|
190
222
|
pub fn init(g: Gender, p: u6, t: Type) DVs {
|
|
191
223
|
assert(p >= 1 and p <= 40);
|
|
192
224
|
assert(t != .Normal and t != .@"???");
|
|
193
|
-
return
|
|
225
|
+
return .{ .gender = g, .pow = p, .type = t };
|
|
194
226
|
}
|
|
195
227
|
|
|
196
|
-
pub
|
|
228
|
+
pub fn power(dvs: DVs) u8 {
|
|
197
229
|
return @as(u8, dvs.pow) + 30;
|
|
198
230
|
}
|
|
199
231
|
|
|
@@ -205,15 +237,10 @@ const DVs = packed struct {
|
|
|
205
237
|
0xFF => .Unknown,
|
|
206
238
|
else => if ((@as(u8, dvs.atk) << 4 | dvs.spe) < ratio) Gender.Female else Gender.Male,
|
|
207
239
|
};
|
|
208
|
-
const p = @intCast(
|
|
240
|
+
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
209
241
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
210
|
-
var t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2)
|
|
211
|
-
|
|
212
|
-
return DVs{ .gender = g, .pow = p, .type = @intToEnum(Type, t) };
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
comptime {
|
|
216
|
-
assert(@sizeOf(DVs) == 2);
|
|
242
|
+
var t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
|
+
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
217
244
|
}
|
|
218
245
|
};
|
|
219
246
|
|
|
@@ -238,10 +265,12 @@ test DVs {
|
|
|
238
265
|
try expectEqual(Gender.Female, dvs.gender);
|
|
239
266
|
}
|
|
240
267
|
|
|
241
|
-
|
|
268
|
+
/// Representation of a Generation II Pokémon's move slot in a battle.
|
|
269
|
+
pub const MoveSlot = extern struct {
|
|
270
|
+
/// The identifier for the move.
|
|
242
271
|
id: Move = .None,
|
|
243
|
-
|
|
244
|
-
pp:
|
|
272
|
+
/// The remaining PP of the move.
|
|
273
|
+
pp: u8 = 0,
|
|
245
274
|
|
|
246
275
|
comptime {
|
|
247
276
|
assert(@sizeOf(MoveSlot) == 2);
|
|
@@ -250,14 +279,19 @@ const MoveSlot = packed struct {
|
|
|
250
279
|
|
|
251
280
|
pub const Status = gen1.Status;
|
|
252
281
|
|
|
253
|
-
|
|
282
|
+
/// TODO
|
|
283
|
+
pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
|
|
284
|
+
|
|
285
|
+
pub const Volatiles = packed struct(u128) {
|
|
254
286
|
Bide: bool = false,
|
|
255
287
|
Thrashing: bool = false,
|
|
288
|
+
BeatUp: bool = false,
|
|
256
289
|
Flinch: bool = false,
|
|
257
290
|
Charging: bool = false,
|
|
258
291
|
Underground: bool = false,
|
|
259
292
|
Flying: bool = false,
|
|
260
293
|
Confusion: bool = false,
|
|
294
|
+
|
|
261
295
|
Mist: bool = false,
|
|
262
296
|
FocusEnergy: bool = false,
|
|
263
297
|
Substitute: bool = false,
|
|
@@ -268,52 +302,55 @@ const Volatile = packed struct {
|
|
|
268
302
|
Transform: bool = false,
|
|
269
303
|
|
|
270
304
|
Nightmare: bool = false,
|
|
271
|
-
|
|
305
|
+
Curse: bool = false,
|
|
272
306
|
Protect: bool = false,
|
|
273
307
|
Foresight: bool = false,
|
|
274
308
|
PerishSong: bool = false,
|
|
275
309
|
Endure: bool = false,
|
|
276
310
|
Rollout: bool = false,
|
|
277
311
|
Attract: bool = false,
|
|
312
|
+
|
|
278
313
|
DefenseCurl: bool = false,
|
|
279
314
|
Encore: bool = false,
|
|
280
315
|
LockOn: bool = false,
|
|
281
316
|
DestinyBond: bool = false,
|
|
282
|
-
|
|
317
|
+
Trapped: bool = false,
|
|
283
318
|
|
|
284
|
-
trapped: bool = false,
|
|
285
319
|
switched: bool = false,
|
|
320
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
286
321
|
switching: bool = false,
|
|
322
|
+
// TODO: simply store both last moves on side
|
|
323
|
+
dirty: bool = false,
|
|
287
324
|
|
|
288
|
-
|
|
325
|
+
frozen: bool = false,
|
|
326
|
+
minimized: bool = false,
|
|
327
|
+
_: u10 = 0,
|
|
328
|
+
// TODO: is this needed for unmodified stats?
|
|
329
|
+
transform: u4 = 0,
|
|
289
330
|
|
|
290
|
-
bind: u4 = 0,
|
|
291
|
-
future_sight: FutureSight = .{},
|
|
292
331
|
bide: u16 = 0,
|
|
293
|
-
|
|
332
|
+
bind: Bind = .{},
|
|
333
|
+
disable: Disable = .{},
|
|
294
334
|
rage: u8 = 0,
|
|
295
335
|
substitute: u8 = 0,
|
|
296
336
|
toxic: u8 = 0,
|
|
297
337
|
confusion: u4 = 0,
|
|
298
338
|
encore: u4 = 0,
|
|
339
|
+
// TODO merge with attacks (ie rollout/thrashing)? need to be zeroed at same time
|
|
299
340
|
fury_cutter: u4 = 0,
|
|
300
341
|
perish_song: u4 = 0,
|
|
301
342
|
protect: u4 = 0,
|
|
302
|
-
|
|
343
|
+
attacks: u4 = 0, // bide/thrashing/rollout turns
|
|
303
344
|
|
|
304
|
-
const
|
|
305
|
-
move: u4 = 0,
|
|
345
|
+
const Bind = packed struct(u8) {
|
|
306
346
|
duration: u4 = 0,
|
|
347
|
+
reason: u4 = 0,
|
|
307
348
|
};
|
|
308
349
|
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
350
|
+
const Disable = packed struct(u8) {
|
|
351
|
+
move: u4 = 0,
|
|
352
|
+
duration: u4 = 0,
|
|
312
353
|
};
|
|
313
|
-
|
|
314
|
-
comptime {
|
|
315
|
-
assert(@sizeOf(Volatile) == 16);
|
|
316
|
-
}
|
|
317
354
|
};
|
|
318
355
|
|
|
319
356
|
pub fn Stats(comptime T: type) type {
|
|
@@ -327,10 +364,11 @@ pub fn Stats(comptime T: type) type {
|
|
|
327
364
|
|
|
328
365
|
pub fn calc(comptime stat: []const u8, base: T, dv: u4, exp: u16, level: u8) T {
|
|
329
366
|
assert(level > 0 and level <= 100);
|
|
330
|
-
const
|
|
367
|
+
const float: f32 = @floatFromInt(exp);
|
|
368
|
+
const evs: u16 = @min(255, @as(u16, @intFromFloat(@ceil(@sqrt(float)))));
|
|
331
369
|
const core: u32 = (2 *% (@as(u32, base) +% dv)) +% (evs / 4);
|
|
332
370
|
const factor: u32 = if (std.mem.eql(u8, stat, "hp")) level + 10 else 5;
|
|
333
|
-
return @intCast(
|
|
371
|
+
return @intCast(core *% @as(u32, level) / 100 +% factor);
|
|
334
372
|
}
|
|
335
373
|
};
|
|
336
374
|
}
|
|
@@ -347,7 +385,7 @@ test Stats {
|
|
|
347
385
|
try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
348
386
|
}
|
|
349
387
|
|
|
350
|
-
pub const Boosts = packed struct {
|
|
388
|
+
pub const Boosts = packed struct(u32) {
|
|
351
389
|
atk: i4 = 0,
|
|
352
390
|
def: i4 = 0,
|
|
353
391
|
spe: i4 = 0,
|
|
@@ -363,7 +401,7 @@ pub const Boosts = packed struct {
|
|
|
363
401
|
};
|
|
364
402
|
|
|
365
403
|
test Boosts {
|
|
366
|
-
const boosts =
|
|
404
|
+
const boosts: Boosts = .{ .spd = -6 };
|
|
367
405
|
try expectEqual(0, boosts.atk);
|
|
368
406
|
try expectEqual(-6, boosts.spd);
|
|
369
407
|
}
|
|
@@ -376,31 +414,31 @@ test Item {
|
|
|
376
414
|
try expectEqual(Type.Normal, Item.boost(.PolkadotBow).?);
|
|
377
415
|
try expectEqual(Type.Dark, Item.boost(.BlackGlasses).?);
|
|
378
416
|
|
|
379
|
-
try expect(!Item.
|
|
380
|
-
try expect(Item.
|
|
381
|
-
try expect(Item.
|
|
382
|
-
try expect(!Item.
|
|
383
|
-
|
|
384
|
-
try expect(!Item.berry(.LightBall));
|
|
385
|
-
try expect(Item.berry(.PSNCureBerry));
|
|
386
|
-
try expect(Item.berry(.GoldBerry));
|
|
387
|
-
try expect(!Item.berry(.MasterBall));
|
|
417
|
+
try expect(!Item.isMail(.UpGrade));
|
|
418
|
+
try expect(Item.isMail(.FlowerMail));
|
|
419
|
+
try expect(Item.isMail(.MirageMail));
|
|
420
|
+
try expect(!Item.isMail(.TownMap));
|
|
388
421
|
}
|
|
389
422
|
|
|
390
423
|
pub const Move = moves.Move;
|
|
391
424
|
|
|
392
425
|
test Move {
|
|
393
|
-
try expectEqual(251, @
|
|
426
|
+
try expectEqual(251, @intFromEnum(Move.BeatUp));
|
|
394
427
|
const move = Move.get(.DynamicPunch);
|
|
395
428
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
396
|
-
try expectEqual(
|
|
397
|
-
try expectEqual(
|
|
429
|
+
try expectEqual(rng.Gen12.percent(50), move.accuracy);
|
|
430
|
+
try expectEqual(rng.Gen12.percent(100), move.chance);
|
|
431
|
+
try expectEqual(@as(u8, 5), Move.pp(.DynamicPunch));
|
|
432
|
+
try expectEqual(@as(i8, -1), Move.get(.Counter).priority);
|
|
433
|
+
try expect(!move.effect.isHighCritical());
|
|
434
|
+
try expect(Move.get(.KarateChop).effect.isHighCritical());
|
|
435
|
+
try expect(Move.get(.RazorWind).effect.isHighCritical());
|
|
398
436
|
}
|
|
399
437
|
|
|
400
438
|
pub const Species = species.Species;
|
|
401
439
|
|
|
402
440
|
test Species {
|
|
403
|
-
try expectEqual(152, @
|
|
441
|
+
try expectEqual(152, @intFromEnum(Species.Chikorita));
|
|
404
442
|
try expectEqual(@as(u8, 100), Species.get(.Celebi).stats.spd);
|
|
405
443
|
}
|
|
406
444
|
|
|
@@ -409,7 +447,7 @@ pub const Types = types.Types;
|
|
|
409
447
|
pub const Effectiveness = gen1.Effectiveness;
|
|
410
448
|
|
|
411
449
|
test Types {
|
|
412
|
-
try expectEqual(13, @
|
|
450
|
+
try expectEqual(13, @intFromEnum(Type.Electric));
|
|
413
451
|
|
|
414
452
|
try expect(!Type.Steel.special());
|
|
415
453
|
try expect(Type.Dark.special());
|