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