@pkmn/engine 0.1.0-dev.028ab165 → 0.1.0-dev.047d6e71
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.map +1 -1
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js.map +1 -1
- package/build.zig +65 -57
- 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 +67 -72
- 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 +57 -31
- 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 +132 -51
- 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
- package/src/lib/gen1/README.md +0 -894
- package/src/lib/gen2/README.md +0 -329
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
|
}
|
|
@@ -71,8 +71,8 @@ pub fn update(battle: anytype, c1: Choice, c2: Choice, options: anytype) !Result
|
|
|
71
71
|
var p1 = battle.side(.P1);
|
|
72
72
|
var p2 = battle.side(.P2);
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const r1 = showdown and p1.active.volatiles.Binding and c2.type == .Switch;
|
|
75
|
+
const r2 = showdown and p2.active.volatiles.Binding and c1.type == .Switch;
|
|
76
76
|
|
|
77
77
|
if (try turnOrder(battle, c1, c2, options) == .P1) {
|
|
78
78
|
if (try doTurn(battle, .P1, c1, r1, s1, .P2, c2, r2, s2, options)) |r| return r;
|
|
@@ -90,11 +90,11 @@ fn start(battle: anytype, options: anytype) !Result {
|
|
|
90
90
|
const p1 = battle.side(.P1);
|
|
91
91
|
const p2 = battle.side(.P2);
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
const p1_slot = findFirstAlive(p1);
|
|
94
94
|
assert(!showdown or p1_slot == 1);
|
|
95
95
|
if (p1_slot == 0) return if (findFirstAlive(p2) == 0) Result.Tie else Result.Lose;
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const p2_slot = findFirstAlive(p2);
|
|
98
98
|
assert(!showdown or p2_slot == 1);
|
|
99
99
|
if (p2_slot == 0) return Result.Win;
|
|
100
100
|
|
|
@@ -635,8 +635,6 @@ fn beforeMove(
|
|
|
635
635
|
volatiles.state +%= battle.last_damage;
|
|
636
636
|
}
|
|
637
637
|
|
|
638
|
-
assert(volatiles.attacks > 0);
|
|
639
|
-
|
|
640
638
|
if (options.calc.modify(player, .attacking)) |extend| {
|
|
641
639
|
if (!extend) volatiles.attacks = 0;
|
|
642
640
|
} else {
|
|
@@ -676,8 +674,6 @@ fn beforeMove(
|
|
|
676
674
|
}
|
|
677
675
|
|
|
678
676
|
if (volatiles.Thrashing) {
|
|
679
|
-
assert(volatiles.attacks > 0);
|
|
680
|
-
|
|
681
677
|
if (options.calc.modify(player, .attacking)) |extend| {
|
|
682
678
|
if (!extend) volatiles.attacks = 0;
|
|
683
679
|
} else {
|
|
@@ -701,8 +697,6 @@ fn beforeMove(
|
|
|
701
697
|
}
|
|
702
698
|
|
|
703
699
|
if (volatiles.Binding) {
|
|
704
|
-
assert(volatiles.attacks > 0);
|
|
705
|
-
|
|
706
700
|
if (options.calc.modify(player, .binding)) |extend| {
|
|
707
701
|
if (!extend) volatiles.attacks = 0;
|
|
708
702
|
} else {
|
|
@@ -738,7 +732,6 @@ fn canMove(
|
|
|
738
732
|
const player_ident = battle.active(player);
|
|
739
733
|
const move = Move.get(side.last_selected_move);
|
|
740
734
|
|
|
741
|
-
var skip = skip_pp;
|
|
742
735
|
if (side.active.volatiles.Charging) {
|
|
743
736
|
side.active.volatiles.Charging = false;
|
|
744
737
|
side.active.volatiles.Invulnerable = false;
|
|
@@ -750,7 +743,7 @@ fn canMove(
|
|
|
750
743
|
}
|
|
751
744
|
|
|
752
745
|
side.last_used_move = side.last_selected_move;
|
|
753
|
-
if (!
|
|
746
|
+
if (!skip_pp) decrementPP(side, mslot, auto);
|
|
754
747
|
|
|
755
748
|
const target = if (move.target == .Self) player else player.foe();
|
|
756
749
|
try options.log.move(.{ player_ident, side.last_selected_move, battle.active(target), from });
|
|
@@ -902,7 +895,7 @@ fn doMove(
|
|
|
902
895
|
}
|
|
903
896
|
}
|
|
904
897
|
|
|
905
|
-
|
|
898
|
+
const zero = battle.last_damage == 0;
|
|
906
899
|
miss = if (showdown or skip)
|
|
907
900
|
miss
|
|
908
901
|
else
|
|
@@ -1060,7 +1053,7 @@ fn checkCriticalHit(battle: anytype, player: Player, move: Move.Data, options: a
|
|
|
1060
1053
|
const side = battle.side(player);
|
|
1061
1054
|
|
|
1062
1055
|
// Base speed is used for the critical hit calculation, even when Transform-ed
|
|
1063
|
-
var rate =
|
|
1056
|
+
var rate: u16 = Species.chance(side.stored().species);
|
|
1064
1057
|
// GLITCH: Focus Energy reduces critical hit rate instead of increasing it
|
|
1065
1058
|
rate = if (side.active.volatiles.FocusEnergy) rate / 2 else @min(rate * 2, 255);
|
|
1066
1059
|
rate = if (move.effect == .HighCritical) @min(rate * 4, 255) else rate / 2;
|
|
@@ -1117,9 +1110,9 @@ fn calcDamage(
|
|
|
1117
1110
|
def = @max((def / 4) & 255, if (showdown) 1 else 0);
|
|
1118
1111
|
}
|
|
1119
1112
|
|
|
1120
|
-
const lvl =
|
|
1113
|
+
const lvl: u32 = side.stored().level * @as(u2, if (crit) 2 else 1);
|
|
1121
1114
|
|
|
1122
|
-
def =
|
|
1115
|
+
def = if (move.effect == .Explode) @max(def / 2, 1) else def;
|
|
1123
1116
|
|
|
1124
1117
|
if (def == 0) return false;
|
|
1125
1118
|
|
|
@@ -1402,7 +1395,7 @@ fn moveHit(
|
|
|
1402
1395
|
const overwritten = overwrite and state > 0;
|
|
1403
1396
|
assert(!overwritten or (0 < state and state <= 255 and !side.active.volatiles.Bide));
|
|
1404
1397
|
|
|
1405
|
-
var accuracy = if (overwritten) state else
|
|
1398
|
+
var accuracy: u16 = if (overwritten) state else move.accuracy;
|
|
1406
1399
|
var boost = BOOSTS[@as(u4, @intCast(@as(i8, side.active.boosts.accuracy) + 6))];
|
|
1407
1400
|
accuracy = accuracy * boost[0] / boost[1];
|
|
1408
1401
|
boost = BOOSTS[@as(u4, @intCast(@as(i8, -foe.active.boosts.evasion) + 6))];
|
|
@@ -1679,7 +1672,6 @@ fn onBegin(
|
|
|
1679
1672
|
residual: *bool,
|
|
1680
1673
|
options: anytype,
|
|
1681
1674
|
) !void {
|
|
1682
|
-
assert(move.effect.onBegin());
|
|
1683
1675
|
return switch (move.effect) {
|
|
1684
1676
|
.Confusion => Effects.confusion(battle, player, move, options),
|
|
1685
1677
|
.Conversion => Effects.conversion(battle, player, options),
|
|
@@ -1702,7 +1694,6 @@ fn onBegin(
|
|
|
1702
1694
|
}
|
|
1703
1695
|
|
|
1704
1696
|
fn onEnd(battle: anytype, player: Player, move: Move.Data, options: anytype) !void {
|
|
1705
|
-
assert(move.effect.onEnd());
|
|
1706
1697
|
return switch (move.effect) {
|
|
1707
1698
|
.Bide => Effects.bide(battle, player, options),
|
|
1708
1699
|
// zig fmt: off
|
|
@@ -1724,7 +1715,6 @@ fn alwaysHappens(
|
|
|
1724
1715
|
residual: *bool,
|
|
1725
1716
|
options: anytype,
|
|
1726
1717
|
) !void {
|
|
1727
|
-
assert(move.effect.alwaysHappens());
|
|
1728
1718
|
return switch (move.effect) {
|
|
1729
1719
|
.DrainHP, .DreamEater => Effects.drainHP(battle, player, options),
|
|
1730
1720
|
.Explode => Effects.explode(battle, player),
|
|
@@ -1972,7 +1962,7 @@ pub const Effects = struct {
|
|
|
1972
1962
|
var side = battle.side(player);
|
|
1973
1963
|
var foe = battle.foe(player);
|
|
1974
1964
|
|
|
1975
|
-
|
|
1965
|
+
const side_stored = side.stored();
|
|
1976
1966
|
var foe_stored = foe.stored();
|
|
1977
1967
|
|
|
1978
1968
|
const player_ident = battle.active(player);
|
|
@@ -2441,7 +2431,7 @@ pub const Effects = struct {
|
|
|
2441
2431
|
}
|
|
2442
2432
|
return log.fail(.{ ident, .None });
|
|
2443
2433
|
}
|
|
2444
|
-
|
|
2434
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.atk) + 6))];
|
|
2445
2435
|
const stat = unmodifiedStats(battle, side).atk;
|
|
2446
2436
|
stats.atk = @min(MAX_STAT_VALUE, stat * mod[0] / mod[1]);
|
|
2447
2437
|
try log.boost(.{ ident, reason, n });
|
|
@@ -2461,7 +2451,7 @@ pub const Effects = struct {
|
|
|
2461
2451
|
}
|
|
2462
2452
|
return log.fail(.{ ident, .None });
|
|
2463
2453
|
}
|
|
2464
|
-
|
|
2454
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.def) + 6))];
|
|
2465
2455
|
const stat = unmodifiedStats(battle, side).def;
|
|
2466
2456
|
stats.def = @min(MAX_STAT_VALUE, stat * mod[0] / mod[1]);
|
|
2467
2457
|
try log.boost(.{ ident, .Defense, n });
|
|
@@ -2478,7 +2468,7 @@ pub const Effects = struct {
|
|
|
2478
2468
|
}
|
|
2479
2469
|
return log.fail(.{ ident, .None });
|
|
2480
2470
|
}
|
|
2481
|
-
|
|
2471
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.spe) + 6))];
|
|
2482
2472
|
const stat = unmodifiedStats(battle, side).spe;
|
|
2483
2473
|
stats.spe = @min(MAX_STAT_VALUE, stat * mod[0] / mod[1]);
|
|
2484
2474
|
try log.boost(.{ ident, .Speed, 2 });
|
|
@@ -2498,7 +2488,7 @@ pub const Effects = struct {
|
|
|
2498
2488
|
}
|
|
2499
2489
|
return log.fail(.{ ident, .None });
|
|
2500
2490
|
}
|
|
2501
|
-
|
|
2491
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.spc) + 6))];
|
|
2502
2492
|
const stat = unmodifiedStats(battle, side).spc;
|
|
2503
2493
|
stats.spc = @min(MAX_STAT_VALUE, stat * mod[0] / mod[1]);
|
|
2504
2494
|
try log.boost(.{ ident, .SpecialAttack, n });
|
|
@@ -2551,7 +2541,7 @@ pub const Effects = struct {
|
|
|
2551
2541
|
}
|
|
2552
2542
|
return log.fail(.{ foe_ident, .None });
|
|
2553
2543
|
}
|
|
2554
|
-
|
|
2544
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.atk) + 6))];
|
|
2555
2545
|
const stat = unmodifiedStats(battle, foe).atk;
|
|
2556
2546
|
stats.atk = @max(1, stat * mod[0] / mod[1]);
|
|
2557
2547
|
try log.boost(.{ foe_ident, .Attack, -1 });
|
|
@@ -2569,7 +2559,7 @@ pub const Effects = struct {
|
|
|
2569
2559
|
}
|
|
2570
2560
|
return log.fail(.{ foe_ident, .None });
|
|
2571
2561
|
}
|
|
2572
|
-
|
|
2562
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.def) + 6))];
|
|
2573
2563
|
const stat = unmodifiedStats(battle, foe).def;
|
|
2574
2564
|
stats.def = @max(1, stat * mod[0] / mod[1]);
|
|
2575
2565
|
try log.boost(.{ foe_ident, .Defense, -@as(i8, n) });
|
|
@@ -2586,7 +2576,7 @@ pub const Effects = struct {
|
|
|
2586
2576
|
}
|
|
2587
2577
|
return log.fail(.{ foe_ident, .None });
|
|
2588
2578
|
}
|
|
2589
|
-
|
|
2579
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.spe) + 6))];
|
|
2590
2580
|
const stat = unmodifiedStats(battle, foe).spe;
|
|
2591
2581
|
stats.spe = @max(1, stat * mod[0] / mod[1]);
|
|
2592
2582
|
try log.boost(.{ foe_ident, .Speed, -1 });
|
|
@@ -2606,7 +2596,7 @@ pub const Effects = struct {
|
|
|
2606
2596
|
}
|
|
2607
2597
|
return log.fail(.{ foe_ident, .None });
|
|
2608
2598
|
}
|
|
2609
|
-
|
|
2599
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.spc) + 6))];
|
|
2610
2600
|
const stat = unmodifiedStats(battle, foe).spc;
|
|
2611
2601
|
stats.spc = @max(1, stat * mod[0] / mod[1]);
|
|
2612
2602
|
try log.boost(.{ foe_ident, .SpecialAttack, -1 });
|
|
@@ -2699,6 +2689,8 @@ pub const Rolls = struct {
|
|
|
2699
2689
|
fn speedTie(battle: anytype, options: anytype) !bool {
|
|
2700
2690
|
const p1 = if (options.calc.overridden(.P1, .speed_tie)) |player|
|
|
2701
2691
|
player == .P1
|
|
2692
|
+
else if (@hasDecl(@TypeOf(battle.rng), "speedTie"))
|
|
2693
|
+
battle.rng.speedTie()
|
|
2702
2694
|
else if (showdown)
|
|
2703
2695
|
battle.rng.range(u8, 0, 2) == 0
|
|
2704
2696
|
else
|
|
@@ -2711,6 +2703,8 @@ pub const Rolls = struct {
|
|
|
2711
2703
|
fn criticalHit(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
|
|
2712
2704
|
const crit = if (options.calc.overridden(player, .critical_hit)) |val|
|
|
2713
2705
|
val == .true
|
|
2706
|
+
else if (@hasDecl(@TypeOf(battle.rng), "criticalHit"))
|
|
2707
|
+
battle.rng.criticalHit(player, rate)
|
|
2714
2708
|
else if (showdown)
|
|
2715
2709
|
battle.rng.chance(u8, rate, 256)
|
|
2716
2710
|
else
|
|
@@ -2723,6 +2717,8 @@ pub const Rolls = struct {
|
|
|
2723
2717
|
fn damage(battle: anytype, player: Player, options: anytype) !u8 {
|
|
2724
2718
|
const roll = if (options.calc.overridden(player, .damage)) |val|
|
|
2725
2719
|
val
|
|
2720
|
+
else if (@hasDecl(@TypeOf(battle.rng), "damage"))
|
|
2721
|
+
battle.rng.damage(player)
|
|
2726
2722
|
else roll: {
|
|
2727
2723
|
if (showdown) break :roll battle.rng.range(u8, 217, 256);
|
|
2728
2724
|
while (true) {
|
|
@@ -2739,6 +2735,8 @@ pub const Rolls = struct {
|
|
|
2739
2735
|
fn hit(battle: anytype, player: Player, accuracy: u8, options: anytype) bool {
|
|
2740
2736
|
const ok = if (options.calc.overridden(player, .hit)) |val|
|
|
2741
2737
|
val == .true
|
|
2738
|
+
else if (@hasDecl(@TypeOf(battle.rng), "hit"))
|
|
2739
|
+
battle.rng.hit(player, accuracy)
|
|
2742
2740
|
else if (showdown)
|
|
2743
2741
|
battle.rng.chance(u8, accuracy, 256)
|
|
2744
2742
|
else
|
|
@@ -2751,6 +2749,8 @@ pub const Rolls = struct {
|
|
|
2751
2749
|
fn confused(battle: anytype, player: Player, options: anytype) !bool {
|
|
2752
2750
|
const cfz = if (options.calc.overridden(player, .confused)) |val|
|
|
2753
2751
|
val == .true
|
|
2752
|
+
else if (@hasDecl(@TypeOf(battle.rng), "confused"))
|
|
2753
|
+
battle.rng.confused(player)
|
|
2754
2754
|
else if (showdown)
|
|
2755
2755
|
!battle.rng.chance(u8, 128, 256)
|
|
2756
2756
|
else
|
|
@@ -2763,6 +2763,8 @@ pub const Rolls = struct {
|
|
|
2763
2763
|
fn paralyzed(battle: anytype, player: Player, options: anytype) !bool {
|
|
2764
2764
|
const par = if (options.calc.overridden(player, .paralyzed)) |val|
|
|
2765
2765
|
val == .true
|
|
2766
|
+
else if (@hasDecl(@TypeOf(battle.rng), "paralyzed"))
|
|
2767
|
+
battle.rng.paralyzed(player)
|
|
2766
2768
|
else if (showdown)
|
|
2767
2769
|
battle.rng.chance(u8, 63, 256)
|
|
2768
2770
|
else
|
|
@@ -2775,6 +2777,8 @@ pub const Rolls = struct {
|
|
|
2775
2777
|
fn confusionChance(battle: anytype, player: Player, options: anytype) !bool {
|
|
2776
2778
|
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2777
2779
|
val == .true
|
|
2780
|
+
else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
|
|
2781
|
+
battle.rng.secondaryChance(player, 25)
|
|
2778
2782
|
else if (showdown)
|
|
2779
2783
|
battle.rng.chance(u8, 25, 256)
|
|
2780
2784
|
else
|
|
@@ -2789,6 +2793,8 @@ pub const Rolls = struct {
|
|
|
2789
2793
|
|
|
2790
2794
|
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2791
2795
|
val == .true
|
|
2796
|
+
else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
|
|
2797
|
+
battle.rng.secondaryChance(player, rate)
|
|
2792
2798
|
else if (showdown)
|
|
2793
2799
|
battle.rng.chance(u8, rate, 256)
|
|
2794
2800
|
else
|
|
@@ -2803,6 +2809,8 @@ pub const Rolls = struct {
|
|
|
2803
2809
|
|
|
2804
2810
|
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2805
2811
|
val == .true
|
|
2812
|
+
else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
|
|
2813
|
+
battle.rng.secondaryChance(player, rate)
|
|
2806
2814
|
else if (showdown)
|
|
2807
2815
|
battle.rng.chance(u8, rate, 256)
|
|
2808
2816
|
else
|
|
@@ -2815,6 +2823,8 @@ pub const Rolls = struct {
|
|
|
2815
2823
|
fn unboost(battle: anytype, player: Player, options: anytype) !bool {
|
|
2816
2824
|
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2817
2825
|
val == .true
|
|
2826
|
+
else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
|
|
2827
|
+
battle.rng.secondaryChance(player, 85)
|
|
2818
2828
|
else if (showdown)
|
|
2819
2829
|
battle.rng.chance(u8, 85, 256)
|
|
2820
2830
|
else
|
|
@@ -2827,6 +2837,8 @@ pub const Rolls = struct {
|
|
|
2827
2837
|
fn metronome(battle: anytype, player: Player, options: anytype) !Move {
|
|
2828
2838
|
const move: Move = if (options.calc.overridden(player, .metronome)) |val|
|
|
2829
2839
|
val
|
|
2840
|
+
else if (@hasDecl(@TypeOf(battle.rng), "metronome"))
|
|
2841
|
+
battle.rng.metronome(player)
|
|
2830
2842
|
else if (showdown)
|
|
2831
2843
|
Move.METRONOME[battle.rng.range(u8, 0, Move.METRONOME.len)]
|
|
2832
2844
|
else move: {
|
|
@@ -2845,6 +2857,8 @@ pub const Rolls = struct {
|
|
|
2845
2857
|
fn psywave(battle: anytype, player: Player, max: u8, options: anytype) !u8 {
|
|
2846
2858
|
const power = if (options.calc.overridden(player, .psywave)) |val|
|
|
2847
2859
|
val - 1
|
|
2860
|
+
else if (@hasDecl(@TypeOf(battle.rng), "psywave"))
|
|
2861
|
+
battle.rng.psywave(player)
|
|
2848
2862
|
else if (showdown)
|
|
2849
2863
|
battle.rng.range(u8, 0, max)
|
|
2850
2864
|
else power: {
|
|
@@ -2862,6 +2876,8 @@ pub const Rolls = struct {
|
|
|
2862
2876
|
fn sleepDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
2863
2877
|
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2864
2878
|
@intCast(val)
|
|
2879
|
+
else if (@hasDecl(@TypeOf(battle.rng), "sleepDuration"))
|
|
2880
|
+
battle.rng.sleepDuration(player)
|
|
2865
2881
|
else if (showdown)
|
|
2866
2882
|
battle.rng.range(u3, 1, 8)
|
|
2867
2883
|
else duration: {
|
|
@@ -2879,6 +2895,8 @@ pub const Rolls = struct {
|
|
|
2879
2895
|
fn disableDuration(battle: anytype, player: Player, options: anytype) u4 {
|
|
2880
2896
|
const duration: u4 = if (options.calc.overridden(player, .duration)) |val|
|
|
2881
2897
|
val
|
|
2898
|
+
else if (@hasDecl(@TypeOf(battle.rng), "disableDuration"))
|
|
2899
|
+
battle.rng.disableDuration(player)
|
|
2882
2900
|
else if (showdown)
|
|
2883
2901
|
battle.rng.range(u4, 1, 9)
|
|
2884
2902
|
else
|
|
@@ -2892,6 +2910,8 @@ pub const Rolls = struct {
|
|
|
2892
2910
|
fn confusionDuration(battle: anytype, player: Player, self: bool, options: anytype) u3 {
|
|
2893
2911
|
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2894
2912
|
@intCast(val)
|
|
2913
|
+
else if (@hasDecl(@TypeOf(battle.rng), "confusionDuration"))
|
|
2914
|
+
battle.rng.confusionDuration(player, self)
|
|
2895
2915
|
else if (showdown)
|
|
2896
2916
|
battle.rng.range(u3, 2, 6)
|
|
2897
2917
|
else
|
|
@@ -2905,6 +2925,8 @@ pub const Rolls = struct {
|
|
|
2905
2925
|
fn attackingDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
2906
2926
|
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2907
2927
|
@intCast(val)
|
|
2928
|
+
else if (@hasDecl(@TypeOf(battle.rng), "attackingDuration"))
|
|
2929
|
+
battle.rng.attackingDuration(player)
|
|
2908
2930
|
else if (showdown)
|
|
2909
2931
|
battle.rng.range(u3, 2, 4)
|
|
2910
2932
|
else
|
|
@@ -2926,6 +2948,8 @@ pub const Rolls = struct {
|
|
|
2926
2948
|
const roll = if (effect == .Binding) .duration else .multi_hit;
|
|
2927
2949
|
const n: u3 = if (options.calc.overridden(player, roll)) |val|
|
|
2928
2950
|
@intCast(val)
|
|
2951
|
+
else if (@hasDecl(@TypeOf(battle.rng), "distribution"))
|
|
2952
|
+
battle.rng.distribution(player)
|
|
2929
2953
|
else if (showdown)
|
|
2930
2954
|
DISTRIBUTION[battle.rng.range(u3, 0, DISTRIBUTION.len)]
|
|
2931
2955
|
else n: {
|
|
@@ -2958,7 +2982,9 @@ pub const Rolls = struct {
|
|
|
2958
2982
|
else
|
|
2959
2983
|
null;
|
|
2960
2984
|
|
|
2961
|
-
const slot: u4 = overridden orelse
|
|
2985
|
+
const slot: u4 = overridden orelse if (@hasDecl(@TypeOf(battle.rng), "moveSlot"))
|
|
2986
|
+
battle.rng.moveSlot(player, moves, check_pp)
|
|
2987
|
+
else slot: {
|
|
2962
2988
|
if (showdown) {
|
|
2963
2989
|
if (check_pp == 0) {
|
|
2964
2990
|
var i: usize = moves.len;
|
|
@@ -3038,7 +3064,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
|
|
|
3038
3064
|
const side = battle.side(player);
|
|
3039
3065
|
const foe = battle.foe(player);
|
|
3040
3066
|
|
|
3041
|
-
|
|
3067
|
+
const active = &side.active;
|
|
3042
3068
|
const stored = side.stored();
|
|
3043
3069
|
|
|
3044
3070
|
// While players are not given any input options on the cartridge in these cases,
|