@pkmn/engine 0.1.0-dev.30c63015 → 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 +32 -9
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +3 -2
- package/build/pkg/data.js.map +1 -1
- 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.map +1 -1
- package/build.zig +60 -56
- package/package.json +29 -21
- package/src/bin/install-pkmn-engine +14 -14
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/protocol.zig +211 -209
- package/src/lib/common/rational.zig +7 -3
- package/src/lib/common/rng.zig +11 -11
- package/src/lib/gen1/calc.zig +5 -5
- package/src/lib/gen1/chance.zig +21 -21
- package/src/lib/gen1/data/species.zig +1 -1
- package/src/lib/gen1/data.zig +18 -18
- package/src/lib/gen1/helpers.zig +7 -7
- package/src/lib/gen1/mechanics.zig +198 -187
- package/src/lib/gen2/chance.zig +27 -27
- package/src/lib/gen2/data.zig +9 -9
- package/src/lib/gen2/generated.zig +1 -3
- package/src/lib/gen2/mechanics.zig +171 -198
- 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
|
@@ -192,9 +192,9 @@ pub fn Rational(comptime T: type) type {
|
|
|
192
192
|
|
|
193
193
|
fn addition(r: *Self, p: anytype, q: anytype) !void {
|
|
194
194
|
// (a/b) + (c/d) = (ad+bc)/(bd)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
const d = try std.math.mul(T, r.q, q);
|
|
196
|
+
const n1 = try std.math.mul(T, r.p, q);
|
|
197
|
+
const n2 = try std.math.mul(T, r.q, p);
|
|
198
198
|
|
|
199
199
|
r.p = try std.math.add(T, n1, n2);
|
|
200
200
|
r.q = d;
|
|
@@ -234,6 +234,8 @@ test Rational {
|
|
|
234
234
|
var r: Rational(t) = .{};
|
|
235
235
|
|
|
236
236
|
var c: t = 128;
|
|
237
|
+
_ = &c;
|
|
238
|
+
|
|
237
239
|
try r.update(c, 256);
|
|
238
240
|
try doTurn(&r);
|
|
239
241
|
|
|
@@ -320,6 +322,8 @@ test BigRational {
|
|
|
320
322
|
try r.reset();
|
|
321
323
|
|
|
322
324
|
var c: u8 = 128;
|
|
325
|
+
_ = &c;
|
|
326
|
+
|
|
323
327
|
try r.update(c, 256);
|
|
324
328
|
try doTurn(&r);
|
|
325
329
|
|
package/src/lib/common/rng.zig
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
|
|
3
|
-
const options = @import("
|
|
3
|
+
const options = @import("options.zig");
|
|
4
4
|
|
|
5
5
|
const assert = std.debug.assert;
|
|
6
6
|
const expectEqual = std.testing.expectEqual;
|
|
@@ -66,11 +66,15 @@ pub const PSRNG = extern struct {
|
|
|
66
66
|
(@as(u64, self.range(u16, 0, 0x10000)) << 16) |
|
|
67
67
|
(@as(u64, self.range(u16, 0, 0x10000)));
|
|
68
68
|
}
|
|
69
|
+
|
|
70
|
+
pub fn Bound(comptime T: type) type {
|
|
71
|
+
return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
|
|
72
|
+
}
|
|
69
73
|
};
|
|
70
74
|
|
|
71
75
|
test PSRNG {
|
|
72
76
|
var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
|
|
73
|
-
try expectEqual(
|
|
77
|
+
try expectEqual(121, psrng.range(u8, 0, 256));
|
|
74
78
|
try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -107,9 +111,9 @@ test Gen12 {
|
|
|
107
111
|
try expectEqual(e, rng.next());
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
try expectEqual(
|
|
111
|
-
try expectEqual(
|
|
112
|
-
try expectEqual(
|
|
114
|
+
try expectEqual(16, Gen12.percent(6) + 1);
|
|
115
|
+
try expectEqual(16, Gen12.percent(7) - 1);
|
|
116
|
+
try expectEqual(128, Gen12.percent(50) + 1);
|
|
113
117
|
}
|
|
114
118
|
|
|
115
119
|
// https://pkmn.cc/pokeemerald/src/random.c
|
|
@@ -197,7 +201,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
197
201
|
for (0..n) |_| _ = self.next();
|
|
198
202
|
}
|
|
199
203
|
|
|
200
|
-
pub fn range(self: *Self, comptime T: type, from: T, to: Bound(T)) T {
|
|
204
|
+
pub fn range(self: *Self, comptime T: type, from: T, to: PSRNG.Bound(T)) T {
|
|
201
205
|
assert(showdown);
|
|
202
206
|
return @intCast(@as(u64, self.next()) * (to - from) / divisor + from);
|
|
203
207
|
}
|
|
@@ -206,7 +210,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
206
210
|
self: *Self,
|
|
207
211
|
comptime T: type,
|
|
208
212
|
numerator: T,
|
|
209
|
-
denominator: Bound(T),
|
|
213
|
+
denominator: PSRNG.Bound(T),
|
|
210
214
|
) bool {
|
|
211
215
|
assert(showdown);
|
|
212
216
|
assert(denominator > 0);
|
|
@@ -237,7 +241,3 @@ fn Output(comptime gen: comptime_int) type {
|
|
|
237
241
|
else => unreachable,
|
|
238
242
|
};
|
|
239
243
|
}
|
|
240
|
-
|
|
241
|
-
fn Bound(comptime T: type) type {
|
|
242
|
-
return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
|
|
243
|
-
}
|
package/src/lib/gen1/calc.zig
CHANGED
|
@@ -211,8 +211,8 @@ pub fn transitions(
|
|
|
211
211
|
) !?Stats {
|
|
212
212
|
var stats: Stats = .{};
|
|
213
213
|
|
|
214
|
-
|
|
215
|
-
|
|
214
|
+
const actions = options.actions;
|
|
215
|
+
const cap = options.cap;
|
|
216
216
|
|
|
217
217
|
var seen = std.AutoHashMap(Actions, void).init(allocator);
|
|
218
218
|
defer seen.deinit();
|
|
@@ -232,8 +232,8 @@ pub fn transitions(
|
|
|
232
232
|
_ = try b.update(c1, c2, &opts);
|
|
233
233
|
stats.updates += 1;
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
const p1 = b.side(.P1);
|
|
236
|
+
const p2 = b.side(.P2);
|
|
237
237
|
|
|
238
238
|
var p: Rational(u128) = .{ .p = 0, .q = 1 };
|
|
239
239
|
try frontier.append(opts.chance.actions);
|
|
@@ -247,7 +247,7 @@ pub fn transitions(
|
|
|
247
247
|
var i: usize = 0;
|
|
248
248
|
assert(frontier.items.len == 1);
|
|
249
249
|
while (i < frontier.items.len) : (i += 1) {
|
|
250
|
-
|
|
250
|
+
const template = frontier.items[i];
|
|
251
251
|
opts.calc.overrides.durations = .{
|
|
252
252
|
.p1 = template.p1.durations,
|
|
253
253
|
.p2 = template.p2.durations,
|
package/src/lib/gen1/chance.zig
CHANGED
|
@@ -14,7 +14,7 @@ const util = @import("../common/util.zig");
|
|
|
14
14
|
const Player = @import("../common/data.zig").Player;
|
|
15
15
|
const Optional = @import("../common/optional.zig").Optional;
|
|
16
16
|
|
|
17
|
-
const data = @import("
|
|
17
|
+
const data = @import("data.zig");
|
|
18
18
|
|
|
19
19
|
const enabled = options.chance;
|
|
20
20
|
const showdown = options.showdown;
|
|
@@ -706,19 +706,19 @@ test "Chance.damage" {
|
|
|
706
706
|
|
|
707
707
|
try chance.damage(.P1, 217);
|
|
708
708
|
if (showdown) {
|
|
709
|
-
try expectValue(
|
|
709
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
710
710
|
try expectProbability(&chance.probability, 1, 39);
|
|
711
711
|
} else {
|
|
712
712
|
try expectProbability(&chance.probability, 1, 1);
|
|
713
|
-
try expectValue(
|
|
713
|
+
try expectValue(0, chance.actions.p1.damage);
|
|
714
714
|
|
|
715
715
|
try chance.commit(.P1, .miss);
|
|
716
716
|
try expectProbability(&chance.probability, 1, 1);
|
|
717
|
-
try expectValue(
|
|
717
|
+
try expectValue(0, chance.actions.p1.damage);
|
|
718
718
|
|
|
719
719
|
try chance.commit(.P1, .hit);
|
|
720
720
|
try expectProbability(&chance.probability, 1, 39);
|
|
721
|
-
try expectValue(
|
|
721
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
724
|
|
|
@@ -770,13 +770,13 @@ test "Chance.moveSlot" {
|
|
|
770
770
|
|
|
771
771
|
try chance.moveSlot(.P2, 2, &ms, 2);
|
|
772
772
|
try expectProbability(&chance.probability, 1, 2);
|
|
773
|
-
try expectValue(
|
|
773
|
+
try expectValue(2, chance.actions.p2.move_slot);
|
|
774
774
|
|
|
775
775
|
chance.reset();
|
|
776
776
|
|
|
777
777
|
try chance.moveSlot(.P1, 1, &ms, 0);
|
|
778
778
|
try expectProbability(&chance.probability, 1, 3);
|
|
779
|
-
try expectValue(
|
|
779
|
+
try expectValue(1, chance.actions.p1.move_slot);
|
|
780
780
|
}
|
|
781
781
|
|
|
782
782
|
test "Chance.multiHit" {
|
|
@@ -784,32 +784,32 @@ test "Chance.multiHit" {
|
|
|
784
784
|
|
|
785
785
|
try chance.multiHit(.P1, 3);
|
|
786
786
|
try expectProbability(&chance.probability, 3, 8);
|
|
787
|
-
try expectValue(
|
|
787
|
+
try expectValue(3, chance.actions.p1.multi_hit);
|
|
788
788
|
|
|
789
789
|
chance.reset();
|
|
790
790
|
|
|
791
791
|
try chance.multiHit(.P2, 5);
|
|
792
792
|
try expectProbability(&chance.probability, 1, 8);
|
|
793
|
-
try expectValue(
|
|
793
|
+
try expectValue(5, chance.actions.p2.multi_hit);
|
|
794
794
|
}
|
|
795
795
|
|
|
796
796
|
test "Chance.duration" {
|
|
797
797
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
798
798
|
|
|
799
799
|
chance.duration(.sleep, .P1, .P2, 2);
|
|
800
|
-
try expectValue(
|
|
801
|
-
try expectValue(
|
|
800
|
+
try expectValue(2, chance.actions.p1.duration);
|
|
801
|
+
try expectValue(1, chance.actions.p2.durations.sleep);
|
|
802
802
|
|
|
803
803
|
chance.reset();
|
|
804
804
|
|
|
805
805
|
chance.duration(.binding, .P2, .P2, 4);
|
|
806
806
|
if (!showdown) {
|
|
807
|
-
try expectValue(
|
|
808
|
-
try expectValue(
|
|
807
|
+
try expectValue(0, chance.actions.p2.duration);
|
|
808
|
+
try expectValue(0, chance.actions.p2.durations.binding);
|
|
809
809
|
try chance.commit(.P2, .hit);
|
|
810
810
|
}
|
|
811
|
-
try expectValue(
|
|
812
|
-
try expectValue(
|
|
811
|
+
try expectValue(4, chance.actions.p2.duration);
|
|
812
|
+
try expectValue(1, chance.actions.p2.durations.binding);
|
|
813
813
|
}
|
|
814
814
|
|
|
815
815
|
test "Chance.sleep" {
|
|
@@ -819,7 +819,7 @@ test "Chance.sleep" {
|
|
|
819
819
|
chance.actions.p1.durations.sleep = @intCast(i);
|
|
820
820
|
try chance.sleep(.P1, 0);
|
|
821
821
|
try expectProbability(&chance.probability, 1, d);
|
|
822
|
-
try expectValue(
|
|
822
|
+
try expectValue(0, chance.actions.p1.durations.sleep);
|
|
823
823
|
|
|
824
824
|
chance.reset();
|
|
825
825
|
|
|
@@ -842,7 +842,7 @@ test "Chance.confusion" {
|
|
|
842
842
|
chance.actions.p2.durations.confusion = @intCast(i);
|
|
843
843
|
try chance.confusion(.P2, 0);
|
|
844
844
|
try expectProbability(&chance.probability, 1, d);
|
|
845
|
-
try expectValue(
|
|
845
|
+
try expectValue(0, chance.actions.p2.durations.confusion);
|
|
846
846
|
|
|
847
847
|
chance.reset();
|
|
848
848
|
}
|
|
@@ -865,7 +865,7 @@ test "Chance.disable" {
|
|
|
865
865
|
chance.actions.p1.durations.disable = @intCast(i);
|
|
866
866
|
try chance.disable(.P1, 0);
|
|
867
867
|
try expectProbability(&chance.probability, 1, d);
|
|
868
|
-
try expectValue(
|
|
868
|
+
try expectValue(0, chance.actions.p1.durations.disable);
|
|
869
869
|
|
|
870
870
|
chance.reset();
|
|
871
871
|
|
|
@@ -888,7 +888,7 @@ test "Chance.attacking" {
|
|
|
888
888
|
chance.actions.p2.durations.attacking = @intCast(i);
|
|
889
889
|
try chance.attacking(.P2, 0);
|
|
890
890
|
try expectProbability(&chance.probability, 1, d);
|
|
891
|
-
try expectValue(
|
|
891
|
+
try expectValue(0, chance.actions.p2.durations.attacking);
|
|
892
892
|
|
|
893
893
|
chance.reset();
|
|
894
894
|
}
|
|
@@ -914,7 +914,7 @@ test "Chance.binding" {
|
|
|
914
914
|
chance.actions.p1.durations.binding = @intCast(i);
|
|
915
915
|
try chance.binding(.P1, 0);
|
|
916
916
|
try expectProbability(&chance.probability, p, q);
|
|
917
|
-
try expectValue(
|
|
917
|
+
try expectValue(0, chance.actions.p1.durations.binding);
|
|
918
918
|
|
|
919
919
|
chance.reset();
|
|
920
920
|
|
|
@@ -934,7 +934,7 @@ test "Chance.psywave" {
|
|
|
934
934
|
|
|
935
935
|
try chance.psywave(.P2, 100, 150);
|
|
936
936
|
try expectProbability(&chance.probability, 1, 150);
|
|
937
|
-
try expectValue(
|
|
937
|
+
try expectValue(101, chance.actions.p2.psywave);
|
|
938
938
|
}
|
|
939
939
|
|
|
940
940
|
test "Chance.metronome" {
|
|
@@ -1091,7 +1091,7 @@ 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
|
|
1094
|
+
/// The Pokémon's critical hit ratio out of 256.
|
|
1095
1095
|
pub fn chance(id: Species) u8 {
|
|
1096
1096
|
assert(id != .None);
|
|
1097
1097
|
return CHANCES[@intFromEnum(id) - 1];
|
package/src/lib/gen1/data.zig
CHANGED
|
@@ -112,7 +112,7 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
112
112
|
/// make (i.e. on the cartridge a soft-lock occurs).
|
|
113
113
|
///
|
|
114
114
|
/// This function will always return choices > 0 if `pkmn.options.showdown` is true.
|
|
115
|
-
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 {
|
|
116
116
|
return mechanics.choices(self, player, request, out);
|
|
117
117
|
}
|
|
118
118
|
};
|
|
@@ -316,12 +316,12 @@ test Status {
|
|
|
316
316
|
try expect(Status.is(Status.slp(5), .SLP));
|
|
317
317
|
try expect(!Status.is(Status.slp(5), .EXT));
|
|
318
318
|
try expect(!Status.is(Status.slp(7), .PSN));
|
|
319
|
-
try expectEqual(
|
|
319
|
+
try expectEqual(5, Status.duration(Status.slp(5)));
|
|
320
320
|
try expect(Status.is(Status.slf(2), .SLP));
|
|
321
321
|
try expect(Status.is(Status.slf(2), .EXT));
|
|
322
322
|
try expect(Status.is(Status.TOX, .PSN));
|
|
323
323
|
try expect(Status.is(Status.TOX, .EXT));
|
|
324
|
-
try expectEqual(
|
|
324
|
+
try expectEqual(1, Status.duration(Status.slp(1)));
|
|
325
325
|
}
|
|
326
326
|
|
|
327
327
|
/// Bitfield representation of volatile statuses and associated data in Generation I.
|
|
@@ -405,13 +405,13 @@ test Volatiles {
|
|
|
405
405
|
try expect(!volatiles.Transform);
|
|
406
406
|
try expect(!volatiles.MultiHit);
|
|
407
407
|
|
|
408
|
-
try expectEqual(
|
|
409
|
-
try expectEqual(
|
|
410
|
-
try expectEqual(
|
|
411
|
-
try expectEqual(
|
|
412
|
-
try expectEqual(
|
|
413
|
-
try expectEqual(
|
|
414
|
-
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);
|
|
415
415
|
}
|
|
416
416
|
|
|
417
417
|
/// Representaiton of a Pokémon's stats in Generation I.
|
|
@@ -442,9 +442,9 @@ test Stats {
|
|
|
442
442
|
try expectEqual(0, stats.def);
|
|
443
443
|
|
|
444
444
|
var base = Species.get(.Gyarados).stats;
|
|
445
|
-
try expectEqual(
|
|
445
|
+
try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
446
446
|
base = Species.get(.Pidgeot).stats;
|
|
447
|
-
try expectEqual(
|
|
447
|
+
try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
/// Representation of a Pokémon's boosts in Generation I.
|
|
@@ -537,7 +537,7 @@ pub const Species = species.Species;
|
|
|
537
537
|
|
|
538
538
|
test Species {
|
|
539
539
|
try expectEqual(2, @intFromEnum(Species.Ivysaur));
|
|
540
|
-
try expectEqual(
|
|
540
|
+
try expectEqual(100, Species.get(.Mew).stats.def);
|
|
541
541
|
}
|
|
542
542
|
|
|
543
543
|
/// Representation of a Generation I type in Pokémon.
|
|
@@ -576,8 +576,8 @@ test Types {
|
|
|
576
576
|
try expectEqual(Effectiveness.Resisted, Type.effectiveness(.Fire, .Water));
|
|
577
577
|
try expectEqual(Effectiveness.Neutral, Type.effectiveness(.Normal, .Grass));
|
|
578
578
|
|
|
579
|
-
try expectEqual(
|
|
580
|
-
try expectEqual(
|
|
579
|
+
try expectEqual(3, Type.precedence(.Water, .Water));
|
|
580
|
+
try expectEqual(26, Type.precedence(.Bug, .Ghost));
|
|
581
581
|
try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
|
|
582
582
|
|
|
583
583
|
const t: Types = .{ .type1 = .Rock, .type2 = .Ground };
|
|
@@ -617,18 +617,18 @@ pub const DVs = struct {
|
|
|
617
617
|
|
|
618
618
|
test DVs {
|
|
619
619
|
var dvs: DVs = .{ .spc = 15, .spe = 15 };
|
|
620
|
-
try expectEqual(
|
|
620
|
+
try expectEqual(15, dvs.hp());
|
|
621
621
|
dvs = .{
|
|
622
622
|
.atk = 5,
|
|
623
623
|
.def = 15,
|
|
624
624
|
.spe = 13,
|
|
625
625
|
.spc = 13,
|
|
626
626
|
};
|
|
627
|
-
try expectEqual(
|
|
627
|
+
try expectEqual(15, dvs.hp());
|
|
628
628
|
dvs = .{
|
|
629
629
|
.def = 3,
|
|
630
630
|
.spe = 10,
|
|
631
631
|
.spc = 11,
|
|
632
632
|
};
|
|
633
|
-
try expectEqual(
|
|
633
|
+
try expectEqual(13, dvs.hp());
|
|
634
634
|
}
|
package/src/lib/gen1/helpers.zig
CHANGED
|
@@ -478,12 +478,12 @@ test "Rolls.damage" {
|
|
|
478
478
|
test "Rolls.coalesce" {
|
|
479
479
|
var summaries =
|
|
480
480
|
calc.Summaries{ .p1 = .{ .damage = .{ .base = 74, .final = 69, .capped = true } } };
|
|
481
|
-
try expectEqual(
|
|
482
|
-
try expectEqual(
|
|
483
|
-
try expectEqual(
|
|
481
|
+
try expectEqual(0, try Rolls.coalesce(.P2, 0, &summaries, false));
|
|
482
|
+
try expectEqual(241, try Rolls.coalesce(.P2, 238, &summaries, false));
|
|
483
|
+
try expectEqual(255, try Rolls.coalesce(.P2, 238, &summaries, true));
|
|
484
484
|
summaries.p1.damage.final = 74;
|
|
485
|
-
try expectEqual(
|
|
486
|
-
try expectEqual(
|
|
485
|
+
try expectEqual(217, try Rolls.coalesce(.P2, 217, &summaries, false));
|
|
486
|
+
try expectEqual(255, try Rolls.coalesce(.P2, 217, &summaries, true));
|
|
487
487
|
}
|
|
488
488
|
|
|
489
489
|
test "Rolls.hit" {
|
|
@@ -771,9 +771,9 @@ test "Rolls.psywave" {
|
|
|
771
771
|
|
|
772
772
|
try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p1, &side, .None));
|
|
773
773
|
var rolls = Rolls.psywave(actions.p2, &side, .None);
|
|
774
|
-
try expectEqual(
|
|
774
|
+
try expectEqual(150, rolls[rolls.len - 1]);
|
|
775
775
|
side.stored().level = 81;
|
|
776
776
|
rolls = Rolls.psywave(actions.p2, &side, .None);
|
|
777
|
-
try expectEqual(
|
|
777
|
+
try expectEqual(121, rolls[rolls.len - 1]);
|
|
778
778
|
try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p2, &side, .false));
|
|
779
779
|
}
|