@pkmn/engine 0.1.0-dev.90d6c14c → 0.1.0-dev.9257876b
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 +52 -21
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/ids.json +12 -12
- package/build/pkg/data/layout.json +2 -2
- package/build/pkg/data/protocol.json +69 -12
- 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 +57 -38
- 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 +125 -102
- package/package.json +43 -23
- package/src/bin/install-pkmn-engine +27 -19
- package/src/lib/common/data.zig +12 -24
- package/src/lib/common/optional.zig +9 -2
- package/src/lib/common/protocol.zig +805 -327
- package/src/lib/common/rational.zig +12 -8
- package/src/lib/common/rng.zig +26 -17
- package/src/lib/gen1/calc.zig +9 -10
- package/src/lib/gen1/chance.zig +83 -66
- package/src/lib/gen1/data/moves.zig +192 -180
- package/src/lib/gen1/data/species.zig +3 -3
- package/src/lib/gen1/data/types.zig +7 -7
- package/src/lib/gen1/data.zig +60 -67
- package/src/lib/gen1/helpers.zig +261 -123
- package/src/lib/gen1/mechanics.zig +370 -403
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1315 -0
- package/src/lib/gen2/data/items.zig +12 -18
- package/src/lib/gen2/data/moves.zig +663 -569
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +134 -31
- package/src/lib/gen2/data.zig +106 -79
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +8 -12
- package/src/lib/gen2/mechanics.zig +3587 -9
- package/src/lib/{binding/node.zig → node.zig} +10 -13
- package/src/lib/pkmn.zig +26 -3
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
- package/src/lib/gen1/README.md +0 -812
- package/src/lib/gen2/README.md +0 -308
|
@@ -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
|
|
|
@@ -1091,8 +1091,8 @@ pub const Species = enum(u8) {
|
|
|
1091
1091
|
/// The number of Pokémon species in this generation.
|
|
1092
1092
|
pub const size = 151;
|
|
1093
1093
|
|
|
1094
|
-
/// The Pokémon's critical hit
|
|
1095
|
-
pub
|
|
1094
|
+
/// The Pokémon's critical hit ratio out of 256.
|
|
1095
|
+
pub fn chance(id: Species) u8 {
|
|
1096
1096
|
assert(id != .None);
|
|
1097
1097
|
return CHANCES[@intFromEnum(id) - 1];
|
|
1098
1098
|
}
|
|
@@ -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
|
|
|
@@ -30,7 +30,7 @@ pub const Type = enum(u4) {
|
|
|
30
30
|
Ice,
|
|
31
31
|
Dragon,
|
|
32
32
|
|
|
33
|
-
const CHART
|
|
33
|
+
const CHART: [15][15]Effectiveness = .{
|
|
34
34
|
[_]Effectiveness{ N, N, N, N, N, R, N, I, N, N, N, N, N, N, N }, // Normal
|
|
35
35
|
[_]Effectiveness{ S, N, R, R, N, S, R, I, N, N, N, N, R, S, N }, // Fighting
|
|
36
36
|
[_]Effectiveness{ N, S, N, N, N, R, S, N, N, N, S, R, N, N, N }, // Flying
|
|
@@ -90,16 +90,16 @@ pub const Type = enum(u4) {
|
|
|
90
90
|
pub const size = 15;
|
|
91
91
|
|
|
92
92
|
/// Whether or not this type is considered to be special as opposed to physical.
|
|
93
|
-
pub
|
|
93
|
+
pub fn special(self: Type) bool {
|
|
94
94
|
return @intFromEnum(self) >= @intFromEnum(Type.Fire);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/// The `Effectiveness` of type `t2` vs. type `t1`.
|
|
98
|
-
pub
|
|
98
|
+
pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
|
|
99
99
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
/// The precedence order of
|
|
102
|
+
/// The precedence order of Type `t2` vs. Type `t1`.
|
|
103
103
|
pub fn precedence(t1: Type, t2: Type) u8 {
|
|
104
104
|
for (PRECEDENCE, 0..) |matchup, i| {
|
|
105
105
|
if (matchup.type1 == t1 and matchup.type2 == t2) return @intCast(i);
|
|
@@ -120,12 +120,12 @@ pub const Types = packed struct {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/// Whether this typing is immune to type `t`.
|
|
123
|
-
pub
|
|
123
|
+
pub fn immune(self: Types, t: Type) bool {
|
|
124
124
|
return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/// Whether this typing includes type `t`.
|
|
128
|
-
pub
|
|
128
|
+
pub fn includes(self: Types, t: Type) bool {
|
|
129
129
|
return self.type1 == t or self.type2 == t;
|
|
130
130
|
}
|
|
131
131
|
};
|
package/src/lib/gen1/data.zig
CHANGED
|
@@ -65,27 +65,36 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
65
65
|
/// The last damage dealt by either side.
|
|
66
66
|
last_damage: u16 = 0,
|
|
67
67
|
/// Details about the last move selected/used by each player required to detect desyncs.
|
|
68
|
-
last_moves: MoveDetails = .{},
|
|
68
|
+
last_moves: [2]MoveDetails = [_]MoveDetails{.{}} ** 2,
|
|
69
69
|
/// The pseudo random number generator.
|
|
70
70
|
rng: RNG,
|
|
71
71
|
|
|
72
72
|
/// Returns the `Side` for the given `player`.
|
|
73
|
-
pub
|
|
73
|
+
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
74
74
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
75
75
|
return &self.sides[@intFromEnum(player)];
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/// Returns the `Side` of the opponent for the given `player`
|
|
79
|
-
pub
|
|
79
|
+
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
80
80
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
81
81
|
return &self.sides[@intFromEnum(player.foe())];
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/// Returns an identifier for the active Pokémon of `player`.
|
|
85
|
-
pub
|
|
85
|
+
pub fn active(self: *const Self, player: Player) ID {
|
|
86
86
|
return player.ident(@intCast(self.side(player).order[0]));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/// Returns the `MoveDetails` for the given `player`.
|
|
90
|
+
pub fn lastMove(
|
|
91
|
+
self: anytype,
|
|
92
|
+
player: Player,
|
|
93
|
+
) PointerType(@TypeOf(self), MoveDetails) {
|
|
94
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
95
|
+
return &self.last_moves[@intFromEnum(player)];
|
|
96
|
+
}
|
|
97
|
+
|
|
89
98
|
/// Returns the result of applying Player 1's choice `c1` and Player 2's choice `c2` to the
|
|
90
99
|
/// battle, optionally writing protocol message logs to `options.log` if `pkmn.options.log`
|
|
91
100
|
/// is enabled.
|
|
@@ -103,7 +112,7 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
103
112
|
/// make (i.e. on the cartridge a soft-lock occurs).
|
|
104
113
|
///
|
|
105
114
|
/// This function will always return choices > 0 if `pkmn.options.showdown` is true.
|
|
106
|
-
pub fn choices(self: *Self, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
115
|
+
pub fn choices(self: *const Self, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
107
116
|
return mechanics.choices(self, player, request, out);
|
|
108
117
|
}
|
|
109
118
|
};
|
|
@@ -132,7 +141,7 @@ pub const Side = extern struct {
|
|
|
132
141
|
}
|
|
133
142
|
|
|
134
143
|
/// Returns the stored `Pokemon` corresponding to the one-indexed party `slot`.
|
|
135
|
-
pub
|
|
144
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
136
145
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
137
146
|
assert(slot > 0 and slot <= 6);
|
|
138
147
|
const id = self.order[slot - 1];
|
|
@@ -141,7 +150,7 @@ pub const Side = extern struct {
|
|
|
141
150
|
}
|
|
142
151
|
|
|
143
152
|
/// Returns the stored `Pokemon` corresponding to the `active` Pokémon (slot 1).
|
|
144
|
-
pub
|
|
153
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
145
154
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
146
155
|
return self.get(1);
|
|
147
156
|
}
|
|
@@ -167,7 +176,7 @@ pub const ActivePokemon = extern struct {
|
|
|
167
176
|
}
|
|
168
177
|
|
|
169
178
|
/// Returns the active Pokémon's current move slot located at the one-indexed `mslot`.
|
|
170
|
-
pub
|
|
179
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
171
180
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == ActivePokemon);
|
|
172
181
|
assert(mslot > 0 and mslot <= 4);
|
|
173
182
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -197,7 +206,7 @@ pub const Pokemon = extern struct {
|
|
|
197
206
|
}
|
|
198
207
|
|
|
199
208
|
/// Returns the Pokémon's original move slot located at the one-indexed `mslot`.
|
|
200
|
-
pub
|
|
209
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
201
210
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
202
211
|
assert(mslot > 0 and mslot <= 4);
|
|
203
212
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -205,7 +214,7 @@ pub const Pokemon = extern struct {
|
|
|
205
214
|
}
|
|
206
215
|
};
|
|
207
216
|
|
|
208
|
-
/// Representation of a Generation I
|
|
217
|
+
/// Representation of a Generation I Pokémon's move slot in a battle.
|
|
209
218
|
pub const MoveSlot = extern struct {
|
|
210
219
|
/// The identifier for the move.
|
|
211
220
|
id: Move = .None,
|
|
@@ -213,24 +222,16 @@ pub const MoveSlot = extern struct {
|
|
|
213
222
|
pp: u8 = 0,
|
|
214
223
|
|
|
215
224
|
comptime {
|
|
216
|
-
assert(@sizeOf(MoveSlot) ==
|
|
225
|
+
assert(@sizeOf(MoveSlot) == 2);
|
|
217
226
|
}
|
|
218
227
|
};
|
|
219
228
|
|
|
220
229
|
/// Details required to detect desyncs based on the move last selected/executed by players.
|
|
221
|
-
pub const MoveDetails = packed struct {
|
|
222
|
-
/// The move slot index of the last move selected in the battle menu
|
|
223
|
-
|
|
224
|
-
/// Whether the last move executed
|
|
225
|
-
|
|
226
|
-
/// The move slot index of the last move selected in the battle menu by Player 2
|
|
227
|
-
p2_index: if (showdown) u8 else u4 = 0,
|
|
228
|
-
/// Whether the last move executed by Player 2 was counterable.
|
|
229
|
-
p2_counterable: if (showdown) u8 else u4 = 0,
|
|
230
|
-
|
|
231
|
-
comptime {
|
|
232
|
-
assert(@sizeOf(MoveDetails) == if (showdown) 4 else 2);
|
|
233
|
-
}
|
|
230
|
+
pub const MoveDetails = packed struct(if (showdown) u16 else u8) {
|
|
231
|
+
/// The move slot index of the last move selected in the battle menu.
|
|
232
|
+
index: if (showdown) u8 else u4 = 0,
|
|
233
|
+
/// Whether the last move executed was counterable.
|
|
234
|
+
counterable: if (showdown) u8 else u4 = 0,
|
|
234
235
|
};
|
|
235
236
|
|
|
236
237
|
/// Bitfield representation of a Generation I & II Pokémon's major status condition.
|
|
@@ -257,36 +258,36 @@ pub const Status = enum(u8) {
|
|
|
257
258
|
const SLP = 0b111;
|
|
258
259
|
|
|
259
260
|
/// Whether or not the status `num` is the same as `status`.
|
|
260
|
-
pub
|
|
261
|
+
pub fn is(num: u8, status: Status) bool {
|
|
261
262
|
if (status == .SLP) return Status.duration(num) > 0;
|
|
262
263
|
return ((num >> @intCast(@intFromEnum(status))) & 1) != 0;
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
/// Initializes a non-sleep `status`. Use `slp` or `slf` to initialize a sleep status.
|
|
266
|
-
pub
|
|
267
|
+
pub fn init(status: Status) u8 {
|
|
267
268
|
assert(status != .SLP and status != .EXT);
|
|
268
269
|
return @as(u8, 1) << @intCast(@intFromEnum(status));
|
|
269
270
|
}
|
|
270
271
|
|
|
271
272
|
/// Initializes a non self-inflicted sleep status with duration `dur`.
|
|
272
|
-
pub
|
|
273
|
+
pub fn slp(dur: u3) u8 {
|
|
273
274
|
assert(dur > 0);
|
|
274
275
|
return @as(u8, dur);
|
|
275
276
|
}
|
|
276
277
|
|
|
277
278
|
/// Initializes a self-inflicted sleep status with duration `dur`.
|
|
278
|
-
pub
|
|
279
|
+
pub fn slf(dur: u3) u8 {
|
|
279
280
|
assert(dur > 0);
|
|
280
281
|
return 0x80 | slp(dur);
|
|
281
282
|
}
|
|
282
283
|
|
|
283
284
|
/// Returns the duration of a sleep status.
|
|
284
|
-
pub
|
|
285
|
+
pub fn duration(num: u8) u3 {
|
|
285
286
|
return @intCast(num & SLP);
|
|
286
287
|
}
|
|
287
288
|
|
|
288
289
|
/// Returns whether `num` reflects any status.
|
|
289
|
-
pub
|
|
290
|
+
pub fn any(num: u8) bool {
|
|
290
291
|
return num > 0;
|
|
291
292
|
}
|
|
292
293
|
|
|
@@ -315,16 +316,16 @@ test Status {
|
|
|
315
316
|
try expect(Status.is(Status.slp(5), .SLP));
|
|
316
317
|
try expect(!Status.is(Status.slp(5), .EXT));
|
|
317
318
|
try expect(!Status.is(Status.slp(7), .PSN));
|
|
318
|
-
try expectEqual(
|
|
319
|
+
try expectEqual(5, Status.duration(Status.slp(5)));
|
|
319
320
|
try expect(Status.is(Status.slf(2), .SLP));
|
|
320
321
|
try expect(Status.is(Status.slf(2), .EXT));
|
|
321
322
|
try expect(Status.is(Status.TOX, .PSN));
|
|
322
323
|
try expect(Status.is(Status.TOX, .EXT));
|
|
323
|
-
try expectEqual(
|
|
324
|
+
try expectEqual(1, Status.duration(Status.slp(1)));
|
|
324
325
|
}
|
|
325
326
|
|
|
326
327
|
/// Bitfield representation of volatile statuses and associated data in Generation I.
|
|
327
|
-
pub const Volatiles = packed struct {
|
|
328
|
+
pub const Volatiles = packed struct(u64) {
|
|
328
329
|
/// Whether the "Bide" volatile status is present.
|
|
329
330
|
Bide: bool = false,
|
|
330
331
|
/// Whether the "Thrashing" volatile status is present.
|
|
@@ -377,19 +378,15 @@ pub const Volatiles = packed struct {
|
|
|
377
378
|
/// The identity of whom the active Pokémon is transformed into.
|
|
378
379
|
transform: u4 = 0,
|
|
379
380
|
/// The remaining turns the move is disabled.
|
|
380
|
-
|
|
381
|
+
disable_duration: u4 = 0,
|
|
381
382
|
/// The move slot (1-4) that is disabled.
|
|
382
|
-
|
|
383
|
+
disable_move: u3 = 0,
|
|
383
384
|
/// The number of turns toxic damage has been accumulating.
|
|
384
385
|
toxic: u5 = 0,
|
|
385
|
-
|
|
386
|
-
comptime {
|
|
387
|
-
assert(@sizeOf(Volatiles) == 8);
|
|
388
|
-
}
|
|
389
386
|
};
|
|
390
387
|
|
|
391
388
|
test Volatiles {
|
|
392
|
-
var volatiles =
|
|
389
|
+
var volatiles: Volatiles = .{};
|
|
393
390
|
volatiles.Confusion = true;
|
|
394
391
|
volatiles.confusion = 2;
|
|
395
392
|
volatiles.Thrashing = true;
|
|
@@ -398,8 +395,8 @@ test Volatiles {
|
|
|
398
395
|
volatiles.Substitute = true;
|
|
399
396
|
volatiles.substitute = 42;
|
|
400
397
|
volatiles.toxic = 4;
|
|
401
|
-
volatiles.
|
|
402
|
-
volatiles.
|
|
398
|
+
volatiles.disable_move = 2;
|
|
399
|
+
volatiles.disable_duration = 4;
|
|
403
400
|
|
|
404
401
|
try expect(volatiles.Confusion);
|
|
405
402
|
try expect(volatiles.Thrashing);
|
|
@@ -408,13 +405,13 @@ test Volatiles {
|
|
|
408
405
|
try expect(!volatiles.Transform);
|
|
409
406
|
try expect(!volatiles.MultiHit);
|
|
410
407
|
|
|
411
|
-
try expectEqual(
|
|
412
|
-
try expectEqual(
|
|
413
|
-
try expectEqual(
|
|
414
|
-
try expectEqual(
|
|
415
|
-
try expectEqual(
|
|
416
|
-
try expectEqual(
|
|
417
|
-
try expectEqual(
|
|
408
|
+
try expectEqual(235, volatiles.state);
|
|
409
|
+
try expectEqual(42, volatiles.substitute);
|
|
410
|
+
try expectEqual(2, volatiles.disable_move);
|
|
411
|
+
try expectEqual(4, volatiles.disable_duration);
|
|
412
|
+
try expectEqual(2, volatiles.confusion);
|
|
413
|
+
try expectEqual(4, volatiles.toxic);
|
|
414
|
+
try expectEqual(3, volatiles.attacks);
|
|
418
415
|
}
|
|
419
416
|
|
|
420
417
|
/// Representaiton of a Pokémon's stats in Generation I.
|
|
@@ -445,13 +442,13 @@ test Stats {
|
|
|
445
442
|
try expectEqual(0, stats.def);
|
|
446
443
|
|
|
447
444
|
var base = Species.get(.Gyarados).stats;
|
|
448
|
-
try expectEqual(
|
|
445
|
+
try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
449
446
|
base = Species.get(.Pidgeot).stats;
|
|
450
|
-
try expectEqual(
|
|
447
|
+
try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
451
448
|
}
|
|
452
449
|
|
|
453
450
|
/// Representation of a Pokémon's boosts in Generation I.
|
|
454
|
-
pub const Boosts = packed struct {
|
|
451
|
+
pub const Boosts = packed struct(u32) {
|
|
455
452
|
/// A Pokémon's Attack boosts.
|
|
456
453
|
atk: i4 = 0,
|
|
457
454
|
/// A Pokémon's Defense boosts.
|
|
@@ -466,14 +463,10 @@ pub const Boosts = packed struct {
|
|
|
466
463
|
evasion: i4 = 0,
|
|
467
464
|
|
|
468
465
|
_: u8 = 0,
|
|
469
|
-
|
|
470
|
-
comptime {
|
|
471
|
-
assert(@sizeOf(Boosts) == 4);
|
|
472
|
-
}
|
|
473
466
|
};
|
|
474
467
|
|
|
475
468
|
test Boosts {
|
|
476
|
-
const boosts =
|
|
469
|
+
const boosts: Boosts = .{ .spc = -6 };
|
|
477
470
|
try expectEqual(0, boosts.atk);
|
|
478
471
|
try expectEqual(-6, boosts.spc);
|
|
479
472
|
}
|
|
@@ -485,7 +478,7 @@ test Move {
|
|
|
485
478
|
try expectEqual(2, @intFromEnum(Move.KarateChop));
|
|
486
479
|
const move = Move.get(.Fissure);
|
|
487
480
|
try expectEqual(Move.Effect.OHKO, move.effect);
|
|
488
|
-
try expectEqual(
|
|
481
|
+
try expectEqual(rng.Gen12.percent(30), move.accuracy);
|
|
489
482
|
try expectEqual(Type.Ground, move.type);
|
|
490
483
|
|
|
491
484
|
try expect(!Move.Effect.onBegin(.None));
|
|
@@ -544,7 +537,7 @@ pub const Species = species.Species;
|
|
|
544
537
|
|
|
545
538
|
test Species {
|
|
546
539
|
try expectEqual(2, @intFromEnum(Species.Ivysaur));
|
|
547
|
-
try expectEqual(
|
|
540
|
+
try expectEqual(100, Species.get(.Mew).stats.def);
|
|
548
541
|
}
|
|
549
542
|
|
|
550
543
|
/// Representation of a Generation I type in Pokémon.
|
|
@@ -583,8 +576,8 @@ test Types {
|
|
|
583
576
|
try expectEqual(Effectiveness.Resisted, Type.effectiveness(.Fire, .Water));
|
|
584
577
|
try expectEqual(Effectiveness.Neutral, Type.effectiveness(.Normal, .Grass));
|
|
585
578
|
|
|
586
|
-
try expectEqual(
|
|
587
|
-
try expectEqual(
|
|
579
|
+
try expectEqual(3, Type.precedence(.Water, .Water));
|
|
580
|
+
try expectEqual(26, Type.precedence(.Bug, .Ghost));
|
|
588
581
|
try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
|
|
589
582
|
|
|
590
583
|
const t: Types = .{ .type1 = .Rock, .type2 = .Ground };
|
|
@@ -623,19 +616,19 @@ pub const DVs = struct {
|
|
|
623
616
|
};
|
|
624
617
|
|
|
625
618
|
test DVs {
|
|
626
|
-
var dvs =
|
|
627
|
-
try expectEqual(
|
|
628
|
-
dvs =
|
|
619
|
+
var dvs: DVs = .{ .spc = 15, .spe = 15 };
|
|
620
|
+
try expectEqual(15, dvs.hp());
|
|
621
|
+
dvs = .{
|
|
629
622
|
.atk = 5,
|
|
630
623
|
.def = 15,
|
|
631
624
|
.spe = 13,
|
|
632
625
|
.spc = 13,
|
|
633
626
|
};
|
|
634
|
-
try expectEqual(
|
|
635
|
-
dvs =
|
|
627
|
+
try expectEqual(15, dvs.hp());
|
|
628
|
+
dvs = .{
|
|
636
629
|
.def = 3,
|
|
637
630
|
.spe = 10,
|
|
638
631
|
.spc = 11,
|
|
639
632
|
};
|
|
640
|
-
try expectEqual(
|
|
633
|
+
try expectEqual(13, dvs.hp());
|
|
641
634
|
}
|