@pkmn/engine 0.1.0-dev.a324c50f → 0.1.0-dev.a93847b2
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 +45 -37
- 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 +2 -2
- package/build/pkg/gen1.js +2 -2
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/protocol.js +56 -37
- package/build/pkg/protocol.js.map +1 -1
- package/build.zig +53 -44
- package/package.json +40 -19
- package/src/bin/install-pkmn-engine +2 -2
- package/src/lib/binding/node.zig +1 -1
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/data.zig +4 -16
- package/src/lib/common/js.zig +118 -0
- package/src/lib/common/optional.zig +67 -0
- package/src/lib/common/protocol.zig +561 -80
- package/src/lib/common/rational.zig +353 -0
- package/src/lib/common/rng.zig +6 -6
- package/src/lib/common/util.zig +12 -0
- package/src/lib/gen1/README.md +273 -193
- package/src/lib/gen1/calc.zig +426 -0
- package/src/lib/gen1/chance.zig +1060 -0
- package/src/lib/gen1/data/moves.zig +183 -171
- package/src/lib/gen1/data/species.zig +1 -1
- package/src/lib/gen1/data/types.zig +3 -3
- package/src/lib/gen1/data.zig +31 -38
- package/src/lib/gen1/helpers.zig +241 -103
- package/src/lib/gen1/mechanics.zig +111 -166
- package/src/lib/gen2/README.md +106 -85
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1314 -0
- package/src/lib/gen2/data/items.zig +11 -17
- package/src/lib/gen2/data/moves.zig +662 -568
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +129 -26
- package/src/lib/gen2/data.zig +89 -64
- package/src/lib/gen2/generated.zig +857 -0
- package/src/lib/gen2/helpers.zig +8 -12
- package/src/lib/gen2/mechanics.zig +2994 -9
|
@@ -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
|
|
@@ -99,7 +99,7 @@ pub const Type = enum(u4) {
|
|
|
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);
|
package/src/lib/gen1/data.zig
CHANGED
|
@@ -65,7 +65,7 @@ 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
|
|
|
@@ -86,6 +86,15 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
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 inline 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.
|
|
@@ -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.
|
|
@@ -324,7 +325,7 @@ test Status {
|
|
|
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);
|
|
@@ -410,8 +407,8 @@ test Volatiles {
|
|
|
410
407
|
|
|
411
408
|
try expectEqual(@as(u16, 235), volatiles.state);
|
|
412
409
|
try expectEqual(@as(u8, 42), volatiles.substitute);
|
|
413
|
-
try expectEqual(@as(u4, 2), volatiles.
|
|
414
|
-
try expectEqual(@as(u4, 4), volatiles.
|
|
410
|
+
try expectEqual(@as(u4, 2), volatiles.disable_move);
|
|
411
|
+
try expectEqual(@as(u4, 4), volatiles.disable_duration);
|
|
415
412
|
try expectEqual(@as(u4, 2), volatiles.confusion);
|
|
416
413
|
try expectEqual(@as(u5, 4), volatiles.toxic);
|
|
417
414
|
try expectEqual(@as(u4, 3), volatiles.attacks);
|
|
@@ -451,7 +448,7 @@ test Stats {
|
|
|
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));
|
|
@@ -623,16 +616,16 @@ pub const DVs = struct {
|
|
|
623
616
|
};
|
|
624
617
|
|
|
625
618
|
test DVs {
|
|
626
|
-
var dvs =
|
|
619
|
+
var dvs: DVs = .{ .spc = 15, .spe = 15 };
|
|
627
620
|
try expectEqual(@as(u4, 15), dvs.hp());
|
|
628
|
-
dvs =
|
|
621
|
+
dvs = .{
|
|
629
622
|
.atk = 5,
|
|
630
623
|
.def = 15,
|
|
631
624
|
.spe = 13,
|
|
632
625
|
.spc = 13,
|
|
633
626
|
};
|
|
634
627
|
try expectEqual(@as(u4, 15), dvs.hp());
|
|
635
|
-
dvs =
|
|
628
|
+
dvs = .{
|
|
636
629
|
.def = 3,
|
|
637
630
|
.spe = 10,
|
|
638
631
|
.spc = 11,
|
package/src/lib/gen1/helpers.zig
CHANGED
|
@@ -350,47 +350,65 @@ pub const Rolls = struct {
|
|
|
350
350
|
const U3_NONE = [_]u3{0};
|
|
351
351
|
const U3_FORCED = [_]u3{1};
|
|
352
352
|
|
|
353
|
-
/// Returns a slice with a range of values for sleep given the `action`
|
|
353
|
+
/// Returns a slice with a range of values for sleep given the `action` and `origin` states.
|
|
354
354
|
pub inline fn sleep(action: Action, origin: Action) []const u3 {
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
355
|
+
const a = @field(action.durations, "sleep");
|
|
356
|
+
const o = @field(origin.durations, "sleep");
|
|
357
|
+
if (o == a) return if (o == 0) &U3_NONE else &[_]u3{o};
|
|
358
|
+
assert(a == 0 or a == o + 1);
|
|
359
|
+
return if (o >= 7) &U3_NONE else &[_]u3{ 0, o + 1 };
|
|
358
360
|
}
|
|
359
361
|
|
|
360
362
|
const DISABLE_NONE = [_]u4{0};
|
|
361
363
|
|
|
362
|
-
/// Returns a slice with a range of values for disable given the `action`
|
|
364
|
+
/// Returns a slice with a range of values for disable given the `action` and `origin` states
|
|
363
365
|
/// and the state of the `parent` (the player's Pokémon's remaining sleep turns).
|
|
364
366
|
pub inline fn disable(action: Action, origin: Action, parent: u4) []const u4 {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
367
|
+
if (parent > 0) return &DISABLE_NONE;
|
|
368
|
+
const a = @field(action.durations, "disable");
|
|
369
|
+
const o = @field(origin.durations, "disable");
|
|
370
|
+
if (o == a) return if (o == 0) &DISABLE_NONE else &[_]u4{o};
|
|
371
|
+
assert(a == 0 or a == o + 1);
|
|
372
|
+
return if (o >= 8) &DISABLE_NONE else &[_]u4{ 0, o + 1 };
|
|
368
373
|
}
|
|
369
374
|
|
|
370
|
-
/// Returns a slice with a range of values for confusion given the `action`
|
|
375
|
+
/// Returns a slice with a range of values for confusion given the `action` and `origin` states
|
|
371
376
|
/// and the state of the `parent` (the player's remaining sleep turns).
|
|
372
377
|
pub inline fn confusion(action: Action, origin: Action, parent: u4) []const u3 {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
return if (
|
|
378
|
+
if (parent > 0) return &U3_NONE;
|
|
379
|
+
const a = @field(action.durations, "confusion");
|
|
380
|
+
const o = @field(origin.durations, "confusion");
|
|
381
|
+
if (o == a) return if (o == 0) &U3_NONE else &[_]u3{o};
|
|
382
|
+
assert(a == 0 or a == o + 1);
|
|
383
|
+
return if (o >= 5) &U3_NONE else if (o < 2)
|
|
384
|
+
if (a == 0) &U3_NONE else &U3_FORCED
|
|
385
|
+
else
|
|
386
|
+
&[_]u3{ 0, o + 1 };
|
|
377
387
|
}
|
|
378
388
|
|
|
379
|
-
/// Returns a slice with a range of values for attacking given the `action`
|
|
389
|
+
/// Returns a slice with a range of values for attacking given the `action` and `origin` states
|
|
380
390
|
/// and the state of the `parent` (whether the player's Pokémon was fully paralyzed).
|
|
381
391
|
pub inline fn attacking(action: Action, origin: Action, parent: Optional(bool)) []const u3 {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
return if (
|
|
392
|
+
if (parent == .true) return &U3_NONE;
|
|
393
|
+
const a = @field(action.durations, "attacking");
|
|
394
|
+
const o = @field(origin.durations, "attacking");
|
|
395
|
+
if (o == a) return if (o == 0) &U3_NONE else &[_]u3{o};
|
|
396
|
+
assert(a == 0 or a == o + 1);
|
|
397
|
+
return if (o >= 3) &U3_NONE else if (o < 2)
|
|
398
|
+
if (a == 0) &U3_NONE else &U3_FORCED
|
|
399
|
+
else
|
|
400
|
+
&[_]u3{ 0, o + 1 };
|
|
386
401
|
}
|
|
387
402
|
|
|
388
|
-
/// Returns a slice with a range of values for binding given the `action`
|
|
403
|
+
/// Returns a slice with a range of values for binding given the `action` and `origin` states
|
|
389
404
|
/// and the state of the `parent` (whether the player's Pokémon was fully paralyzed).
|
|
390
405
|
pub inline fn binding(action: Action, origin: Action, parent: Optional(bool)) []const u3 {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
406
|
+
if (parent == .true) return &U3_NONE;
|
|
407
|
+
const a = @field(action.durations, "binding");
|
|
408
|
+
const o = @field(origin.durations, "binding");
|
|
409
|
+
if (o == a) return if (o == 0) &U3_NONE else &[_]u3{o};
|
|
410
|
+
assert(a == 0 or a == o + 1);
|
|
411
|
+
return if (o >= 4) &U3_NONE else &[_]u3{ 0, o + 1 };
|
|
394
412
|
}
|
|
395
413
|
|
|
396
414
|
const SLOT_NONE = [_]u4{0};
|
|
@@ -437,36 +455,21 @@ pub const Rolls = struct {
|
|
|
437
455
|
}
|
|
438
456
|
|
|
439
457
|
const MOVE_NONE = [_]Move{.None};
|
|
440
|
-
const MOVES = init: {
|
|
441
|
-
var moves: [Move.size - 2]Move = undefined;
|
|
442
|
-
var i: usize = 0;
|
|
443
|
-
for (@typeInfo(Move).Enum.fields) |f| {
|
|
444
|
-
if (!(std.mem.eql(u8, f.name, "None") or
|
|
445
|
-
std.mem.eql(u8, f.name, "Metronome") or
|
|
446
|
-
std.mem.eql(u8, f.name, "Struggle") or
|
|
447
|
-
std.mem.eql(u8, f.name, "SKIP_TURN")))
|
|
448
|
-
{
|
|
449
|
-
moves[i] = @field(Move, f.name);
|
|
450
|
-
i += 1;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
break :init moves;
|
|
454
|
-
};
|
|
455
458
|
|
|
456
459
|
/// Returns a slice with the correct range of values for metronome given the `action` state.
|
|
457
460
|
pub inline fn metronome(action: Action) []const Move {
|
|
458
|
-
return if (@field(action, "metronome") == .None) &MOVE_NONE else &
|
|
461
|
+
return if (@field(action, "metronome") == .None) &MOVE_NONE else &Move.METRONOME;
|
|
459
462
|
}
|
|
460
463
|
};
|
|
461
464
|
|
|
462
465
|
test "Rolls.speedTie" {
|
|
463
|
-
const actions =
|
|
466
|
+
const actions: Actions = .{ .p1 = .{ .speed_tie = .P2 } };
|
|
464
467
|
try expectEqualSlices(Optional(Player), &.{ .P1, .P2 }, Rolls.speedTie(actions.p1));
|
|
465
468
|
try expectEqualSlices(Optional(Player), &.{.None}, Rolls.speedTie(actions.p2));
|
|
466
469
|
}
|
|
467
470
|
|
|
468
471
|
test "Rolls.damage" {
|
|
469
|
-
const actions =
|
|
472
|
+
const actions: Actions = .{ .p2 = .{ .damage = 221 } };
|
|
470
473
|
try expectEqual(Rolls.Range{ .min = 0, .max = 1 }, Rolls.damage(actions.p1, .None));
|
|
471
474
|
try expectEqual(Rolls.Range{ .min = 217, .max = 256 }, Rolls.damage(actions.p2, .None));
|
|
472
475
|
try expectEqual(Rolls.Range{ .min = 0, .max = 1 }, Rolls.damage(actions.p2, .false));
|
|
@@ -484,7 +487,7 @@ test "Rolls.coalesce" {
|
|
|
484
487
|
}
|
|
485
488
|
|
|
486
489
|
test "Rolls.hit" {
|
|
487
|
-
const actions =
|
|
490
|
+
const actions: Actions = .{ .p2 = .{ .hit = .true } };
|
|
488
491
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.hit(actions.p1, .None));
|
|
489
492
|
try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.hit(actions.p2, .None));
|
|
490
493
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.hit(actions.p2, .true));
|
|
@@ -492,7 +495,7 @@ test "Rolls.hit" {
|
|
|
492
495
|
}
|
|
493
496
|
|
|
494
497
|
test "Rolls.secondaryChance" {
|
|
495
|
-
const actions =
|
|
498
|
+
const actions: Actions = .{ .p1 = .{ .secondary_chance = .true } };
|
|
496
499
|
try expectEqualSlices(
|
|
497
500
|
Optional(bool),
|
|
498
501
|
&.{ .false, .true },
|
|
@@ -503,7 +506,7 @@ test "Rolls.secondaryChance" {
|
|
|
503
506
|
}
|
|
504
507
|
|
|
505
508
|
test "Rolls.criticalHit" {
|
|
506
|
-
const actions =
|
|
509
|
+
const actions: Actions = .{ .p1 = .{ .critical_hit = .true } };
|
|
507
510
|
try expectEqualSlices(
|
|
508
511
|
Optional(bool),
|
|
509
512
|
&.{ .false, .true },
|
|
@@ -514,14 +517,14 @@ test "Rolls.criticalHit" {
|
|
|
514
517
|
}
|
|
515
518
|
|
|
516
519
|
test "Rolls.confused" {
|
|
517
|
-
const actions =
|
|
520
|
+
const actions: Actions = .{ .p2 = .{ .confused = .true } };
|
|
518
521
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.confused(actions.p1, 1));
|
|
519
522
|
try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.confused(actions.p2, 1));
|
|
520
523
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.confused(actions.p2, 0));
|
|
521
524
|
}
|
|
522
525
|
|
|
523
526
|
test "Rolls.paralyzed" {
|
|
524
|
-
const actions =
|
|
527
|
+
const actions: Actions = .{ .p2 = .{ .paralyzed = .true } };
|
|
525
528
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.paralyzed(actions.p1, .None));
|
|
526
529
|
try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.paralyzed(actions.p2, .None));
|
|
527
530
|
try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.paralyzed(actions.p2, .false));
|
|
@@ -529,102 +532,237 @@ test "Rolls.paralyzed" {
|
|
|
529
532
|
}
|
|
530
533
|
|
|
531
534
|
test "Rolls.duration" {
|
|
532
|
-
const actions =
|
|
535
|
+
const actions: Actions = .{ .p2 = .{ .duration = 3 } };
|
|
533
536
|
try expectEqualSlices(u1, &.{0}, Rolls.duration(actions.p1, .None));
|
|
534
537
|
try expectEqualSlices(u1, &.{1}, Rolls.duration(actions.p2, .None));
|
|
535
538
|
try expectEqualSlices(u1, &.{0}, Rolls.duration(actions.p2, .false));
|
|
536
539
|
}
|
|
537
540
|
|
|
538
|
-
const FIXME: Action = .{};
|
|
539
|
-
|
|
540
541
|
test "Rolls.sleep" {
|
|
541
|
-
try expectEqualSlices(u3, &.{0}, Rolls.sleep(
|
|
542
|
-
|
|
543
|
-
|
|
542
|
+
try expectEqualSlices(u3, &.{0}, Rolls.sleep(
|
|
543
|
+
.{ .durations = .{ .sleep = 0 } },
|
|
544
|
+
.{ .durations = .{ .sleep = 0 } },
|
|
545
|
+
));
|
|
546
|
+
try expectEqualSlices(u3, &.{ 0, 1 }, Rolls.sleep(
|
|
547
|
+
.{ .durations = .{ .sleep = 1 } },
|
|
548
|
+
.{ .durations = .{ .sleep = 0 } },
|
|
549
|
+
));
|
|
550
|
+
try expectEqualSlices(u3, &.{ 0, 2 }, Rolls.sleep(
|
|
551
|
+
.{ .durations = .{ .sleep = 0 } },
|
|
552
|
+
.{ .durations = .{ .sleep = 1 } },
|
|
553
|
+
));
|
|
554
|
+
try expectEqualSlices(u3, &.{1}, Rolls.sleep(
|
|
555
|
+
.{ .durations = .{ .sleep = 1 } },
|
|
556
|
+
.{ .durations = .{ .sleep = 1 } },
|
|
557
|
+
));
|
|
558
|
+
try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.sleep(
|
|
559
|
+
.{ .durations = .{ .sleep = 0 } },
|
|
560
|
+
.{ .durations = .{ .sleep = 2 } },
|
|
561
|
+
));
|
|
562
|
+
try expectEqualSlices(u3, &.{ 0, 7 }, Rolls.sleep(
|
|
563
|
+
.{ .durations = .{ .sleep = 7 } },
|
|
564
|
+
.{ .durations = .{ .sleep = 6 } },
|
|
565
|
+
));
|
|
566
|
+
try expectEqualSlices(u3, &.{0}, Rolls.sleep(
|
|
567
|
+
.{ .durations = .{ .sleep = 0 } },
|
|
568
|
+
.{ .durations = .{ .sleep = 7 } },
|
|
569
|
+
));
|
|
544
570
|
}
|
|
545
571
|
|
|
546
572
|
test "Rolls.disable" {
|
|
547
|
-
try expectEqualSlices(u4, &.{0}, Rolls.disable(
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
573
|
+
try expectEqualSlices(u4, &.{0}, Rolls.disable(
|
|
574
|
+
.{ .durations = .{ .disable = 0 } },
|
|
575
|
+
.{ .durations = .{ .disable = 0 } },
|
|
576
|
+
0,
|
|
577
|
+
));
|
|
578
|
+
try expectEqualSlices(u4, &.{ 0, 1 }, Rolls.disable(
|
|
579
|
+
.{ .durations = .{ .disable = 1 } },
|
|
580
|
+
.{ .durations = .{ .disable = 0 } },
|
|
581
|
+
0,
|
|
582
|
+
));
|
|
583
|
+
try expectEqualSlices(u4, &.{ 0, 2 }, Rolls.disable(
|
|
584
|
+
.{ .durations = .{ .disable = 0 } },
|
|
585
|
+
.{ .durations = .{ .disable = 1 } },
|
|
586
|
+
0,
|
|
587
|
+
));
|
|
588
|
+
try expectEqualSlices(u4, &.{1}, Rolls.disable(
|
|
589
|
+
.{ .durations = .{ .disable = 1 } },
|
|
590
|
+
.{ .durations = .{ .disable = 1 } },
|
|
591
|
+
0,
|
|
592
|
+
));
|
|
593
|
+
try expectEqualSlices(u4, &.{ 0, 3 }, Rolls.disable(
|
|
594
|
+
.{ .durations = .{ .disable = 0 } },
|
|
595
|
+
.{ .durations = .{ .disable = 2 } },
|
|
596
|
+
0,
|
|
597
|
+
));
|
|
598
|
+
try expectEqualSlices(u4, &.{0}, Rolls.disable(
|
|
599
|
+
.{ .durations = .{ .disable = 0 } },
|
|
600
|
+
.{ .durations = .{ .disable = 2 } },
|
|
601
|
+
1,
|
|
602
|
+
));
|
|
603
|
+
try expectEqualSlices(u4, &.{ 0, 8 }, Rolls.disable(
|
|
604
|
+
.{ .durations = .{ .disable = 8 } },
|
|
605
|
+
.{ .durations = .{ .disable = 7 } },
|
|
606
|
+
0,
|
|
607
|
+
));
|
|
608
|
+
try expectEqualSlices(u4, &.{0}, Rolls.disable(
|
|
609
|
+
.{ .durations = .{ .disable = 0 } },
|
|
610
|
+
.{ .durations = .{ .disable = 8 } },
|
|
611
|
+
0,
|
|
612
|
+
));
|
|
553
613
|
}
|
|
554
614
|
|
|
555
615
|
test "Rolls.confusion" {
|
|
556
|
-
try expectEqualSlices(u3, &.{0}, Rolls.confusion(
|
|
557
|
-
.durations = .{ .confusion = 0 },
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
.durations = .{ .confusion =
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
616
|
+
try expectEqualSlices(u3, &.{0}, Rolls.confusion(
|
|
617
|
+
.{ .durations = .{ .confusion = 0 } },
|
|
618
|
+
.{ .durations = .{ .confusion = 0 } },
|
|
619
|
+
0,
|
|
620
|
+
));
|
|
621
|
+
try expectEqualSlices(u3, &.{1}, Rolls.confusion(
|
|
622
|
+
.{ .durations = .{ .confusion = 1 } },
|
|
623
|
+
.{ .durations = .{ .confusion = 0 } },
|
|
624
|
+
0,
|
|
625
|
+
));
|
|
626
|
+
try expectEqualSlices(u3, &.{0}, Rolls.confusion(
|
|
627
|
+
.{ .durations = .{ .confusion = 0 } },
|
|
628
|
+
.{ .durations = .{ .confusion = 1 } },
|
|
629
|
+
0,
|
|
630
|
+
));
|
|
631
|
+
try expectEqualSlices(u3, &.{1}, Rolls.confusion(
|
|
632
|
+
.{ .durations = .{ .confusion = 1 } },
|
|
633
|
+
.{ .durations = .{ .confusion = 1 } },
|
|
634
|
+
0,
|
|
635
|
+
));
|
|
636
|
+
try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.confusion(
|
|
637
|
+
.{ .durations = .{ .confusion = 0 } },
|
|
638
|
+
.{ .durations = .{ .confusion = 2 } },
|
|
639
|
+
0,
|
|
640
|
+
));
|
|
641
|
+
try expectEqualSlices(u3, &.{0}, Rolls.confusion(
|
|
642
|
+
.{ .durations = .{ .confusion = 0 } },
|
|
643
|
+
.{ .durations = .{ .confusion = 2 } },
|
|
644
|
+
1,
|
|
645
|
+
));
|
|
646
|
+
try expectEqualSlices(u3, &.{ 0, 5 }, Rolls.confusion(
|
|
647
|
+
.{ .durations = .{ .confusion = 5 } },
|
|
648
|
+
.{ .durations = .{ .confusion = 4 } },
|
|
649
|
+
0,
|
|
650
|
+
));
|
|
651
|
+
try expectEqualSlices(u3, &.{0}, Rolls.confusion(
|
|
652
|
+
.{ .durations = .{ .confusion = 0 } },
|
|
653
|
+
.{ .durations = .{ .confusion = 5 } },
|
|
654
|
+
0,
|
|
655
|
+
));
|
|
571
656
|
}
|
|
572
657
|
|
|
573
658
|
test "Rolls.attacking" {
|
|
574
|
-
try expectEqualSlices(u3, &.{0}, Rolls.attacking(
|
|
575
|
-
.durations = .{ .attacking = 0 },
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
.durations = .{ .attacking =
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
.
|
|
588
|
-
|
|
659
|
+
try expectEqualSlices(u3, &.{0}, Rolls.attacking(
|
|
660
|
+
.{ .durations = .{ .attacking = 0 } },
|
|
661
|
+
.{ .durations = .{ .attacking = 0 } },
|
|
662
|
+
.false,
|
|
663
|
+
));
|
|
664
|
+
try expectEqualSlices(u3, &.{1}, Rolls.attacking(
|
|
665
|
+
.{ .durations = .{ .attacking = 1 } },
|
|
666
|
+
.{ .durations = .{ .attacking = 0 } },
|
|
667
|
+
.false,
|
|
668
|
+
));
|
|
669
|
+
try expectEqualSlices(u3, &.{0}, Rolls.attacking(
|
|
670
|
+
.{ .durations = .{ .attacking = 0 } },
|
|
671
|
+
.{ .durations = .{ .attacking = 1 } },
|
|
672
|
+
.false,
|
|
673
|
+
));
|
|
674
|
+
try expectEqualSlices(u3, &.{1}, Rolls.attacking(
|
|
675
|
+
.{ .durations = .{ .attacking = 1 } },
|
|
676
|
+
.{ .durations = .{ .attacking = 1 } },
|
|
677
|
+
.false,
|
|
678
|
+
));
|
|
679
|
+
try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.attacking(
|
|
680
|
+
.{ .durations = .{ .attacking = 0 } },
|
|
681
|
+
.{ .durations = .{ .attacking = 2 } },
|
|
682
|
+
.false,
|
|
683
|
+
));
|
|
684
|
+
try expectEqualSlices(u3, &.{0}, Rolls.attacking(
|
|
685
|
+
.{ .durations = .{ .attacking = 0 } },
|
|
686
|
+
.{ .durations = .{ .attacking = 2 } },
|
|
687
|
+
.true,
|
|
688
|
+
));
|
|
689
|
+
try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.attacking(
|
|
690
|
+
.{ .durations = .{ .attacking = 3 } },
|
|
691
|
+
.{ .durations = .{ .attacking = 2 } },
|
|
692
|
+
.false,
|
|
693
|
+
));
|
|
694
|
+
try expectEqualSlices(u3, &.{0}, Rolls.attacking(
|
|
695
|
+
.{ .durations = .{ .attacking = 0 } },
|
|
696
|
+
.{ .durations = .{ .attacking = 3 } },
|
|
697
|
+
.false,
|
|
698
|
+
));
|
|
589
699
|
}
|
|
590
700
|
|
|
591
701
|
test "Rolls.binding" {
|
|
592
|
-
try expectEqualSlices(u3, &.{0}, Rolls.binding(
|
|
593
|
-
.durations = .{ .binding = 0 },
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
.durations = .{ .binding =
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
702
|
+
try expectEqualSlices(u3, &.{0}, Rolls.binding(
|
|
703
|
+
.{ .durations = .{ .binding = 0 } },
|
|
704
|
+
.{ .durations = .{ .binding = 0 } },
|
|
705
|
+
.false,
|
|
706
|
+
));
|
|
707
|
+
try expectEqualSlices(u3, &.{ 0, 1 }, Rolls.binding(
|
|
708
|
+
.{ .durations = .{ .binding = 1 } },
|
|
709
|
+
.{ .durations = .{ .binding = 0 } },
|
|
710
|
+
.false,
|
|
711
|
+
));
|
|
712
|
+
try expectEqualSlices(u3, &.{ 0, 2 }, Rolls.binding(
|
|
713
|
+
.{ .durations = .{ .binding = 0 } },
|
|
714
|
+
.{ .durations = .{ .binding = 1 } },
|
|
715
|
+
.false,
|
|
716
|
+
));
|
|
717
|
+
try expectEqualSlices(u3, &.{1}, Rolls.binding(
|
|
718
|
+
.{ .durations = .{ .binding = 1 } },
|
|
719
|
+
.{ .durations = .{ .binding = 1 } },
|
|
720
|
+
.false,
|
|
721
|
+
));
|
|
722
|
+
try expectEqualSlices(u3, &.{ 0, 3 }, Rolls.binding(
|
|
723
|
+
.{ .durations = .{ .binding = 0 } },
|
|
724
|
+
.{ .durations = .{ .binding = 2 } },
|
|
725
|
+
.false,
|
|
726
|
+
));
|
|
727
|
+
try expectEqualSlices(u3, &.{0}, Rolls.binding(
|
|
728
|
+
.{ .durations = .{ .binding = 0 } },
|
|
729
|
+
.{ .durations = .{ .binding = 2 } },
|
|
730
|
+
.true,
|
|
731
|
+
));
|
|
732
|
+
try expectEqualSlices(u3, &.{ 0, 4 }, Rolls.binding(
|
|
733
|
+
.{ .durations = .{ .binding = 4 } },
|
|
734
|
+
.{ .durations = .{ .binding = 3 } },
|
|
735
|
+
.false,
|
|
736
|
+
));
|
|
737
|
+
try expectEqualSlices(u3, &.{0}, Rolls.binding(
|
|
738
|
+
.{ .durations = .{ .binding = 0 } },
|
|
739
|
+
.{ .durations = .{ .binding = 4 } },
|
|
740
|
+
.false,
|
|
741
|
+
));
|
|
604
742
|
}
|
|
605
743
|
|
|
606
744
|
test "Rolls.moveSlot" {
|
|
607
|
-
const actions =
|
|
745
|
+
const actions: Actions = .{ .p2 = .{ .move_slot = 3 } };
|
|
608
746
|
try expectEqualSlices(u4, &.{0}, Rolls.moveSlot(actions.p1, .None));
|
|
609
747
|
try expectEqualSlices(u4, &.{ 1, 2, 3, 4 }, Rolls.moveSlot(actions.p2, .None));
|
|
610
748
|
try expectEqualSlices(u4, &.{0}, Rolls.moveSlot(actions.p2, .false));
|
|
611
749
|
}
|
|
612
750
|
|
|
613
751
|
test "Rolls.multiHit" {
|
|
614
|
-
const actions =
|
|
752
|
+
const actions: Actions = .{ .p2 = .{ .multi_hit = 3 } };
|
|
615
753
|
try expectEqualSlices(u4, &.{0}, Rolls.multiHit(actions.p1, .None));
|
|
616
754
|
try expectEqualSlices(u4, &.{ 2, 3, 4, 5 }, Rolls.multiHit(actions.p2, .None));
|
|
617
755
|
try expectEqualSlices(u4, &.{0}, Rolls.multiHit(actions.p2, .false));
|
|
618
756
|
}
|
|
619
757
|
|
|
620
758
|
test "Rolls.metronome" {
|
|
621
|
-
const actions =
|
|
759
|
+
const actions: Actions = .{ .p2 = .{ .metronome = .Surf } };
|
|
622
760
|
try expectEqualSlices(Move, &.{.None}, Rolls.metronome(actions.p1));
|
|
623
761
|
try expectEqual(@as(Move, @enumFromInt(24)), Rolls.metronome(actions.p2)[23]);
|
|
624
762
|
}
|
|
625
763
|
|
|
626
764
|
test "Rolls.psywave" {
|
|
627
|
-
const actions =
|
|
765
|
+
const actions: Actions = .{ .p2 = .{ .psywave = 79 } };
|
|
628
766
|
var side = Side.init(&[_]Pokemon{.{
|
|
629
767
|
.species = .Bulbasaur,
|
|
630
768
|
.level = 100,
|