@pkmn/engine 0.1.0-dev.6d566713 → 0.1.0-dev.6ebbd3bc
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 +5 -4
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +44 -0
- package/build/pkg/addon/browser.js.map +1 -0
- package/build/pkg/addon/node.d.ts +3 -0
- package/build/pkg/addon/node.js +97 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon/wasm.d.ts +2 -0
- package/build/pkg/addon/wasm.js +53 -0
- package/build/pkg/addon/wasm.js.map +1 -0
- package/build/pkg/addon.d.ts +25 -3
- package/build/pkg/addon.js +34 -65
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/layout.json +15 -2
- package/build/pkg/data/protocol.json +23 -9
- package/build/pkg/data.d.ts +23 -1
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +13 -17
- package/build/pkg/gen1.js +6 -10
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +37 -89
- package/build/pkg/index.js +6 -63
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +20 -1
- package/build/pkg/protocol.js +105 -103
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +35 -69
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +141 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +142 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +349 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +18 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +150 -71
- package/package.json +51 -135
- package/src/bin/install-pkmn-engine +2 -2
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/bindings/c.zig +254 -0
- package/src/lib/bindings/node.zig +121 -0
- package/src/lib/bindings/wasm.zig +59 -0
- package/src/lib/common/array.zig +1 -1
- package/src/lib/common/debug.zig +39 -8
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/options.zig +4 -0
- package/src/lib/common/protocol.zig +4 -8
- package/src/lib/common/rational.zig +7 -5
- package/src/lib/common/rng.zig +1 -3
- package/src/lib/common/util.zig +1 -1
- package/src/lib/gen1/calc.zig +200 -51
- package/src/lib/gen1/chance.zig +40 -22
- package/src/lib/gen1/data/moves.zig +2 -4
- package/src/lib/gen1/data/species.zig +1 -3
- package/src/lib/gen1/data/types.zig +1 -2
- package/src/lib/gen1/data.zig +7 -11
- package/src/lib/gen1/helpers.zig +5 -18
- package/src/lib/gen1/mechanics.zig +107 -79
- package/src/lib/gen2/calc.zig +9 -17
- package/src/lib/gen2/data/items.zig +1 -3
- package/src/lib/gen2/data/moves.zig +2 -4
- package/src/lib/gen2/data/species.zig +1 -3
- package/src/lib/gen2/data/types.zig +1 -2
- package/src/lib/gen2/data.zig +11 -15
- package/src/lib/gen2/generated.zig +18 -23
- package/src/lib/gen2/helpers.zig +5 -12
- package/src/lib/gen2/mechanics.zig +41 -38
- package/src/lib/node.zig +3 -116
- package/src/lib/pkmn.zig +7 -2
- package/src/lib/wasm.zig +13 -9
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +354 -0
- package/build/test/display.js +0 -405
- package/build/test/display.js.map +0 -1
- package/src/test/display/pkmn.html.tmpl +0 -368
|
@@ -1,36 +1,29 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
const pkmn = @import("../pkmn.zig");
|
|
1
|
+
const DEBUG = @import("../common/debug.zig").print;
|
|
4
2
|
|
|
3
|
+
const builtin = @import("builtin");
|
|
4
|
+
const chance = @import("chance.zig");
|
|
5
5
|
const common = @import("../common/data.zig");
|
|
6
|
-
const
|
|
6
|
+
const data = @import("data.zig");
|
|
7
|
+
const pkmn = @import("../pkmn.zig");
|
|
7
8
|
const protocol = @import("../common/protocol.zig");
|
|
8
9
|
const rng = @import("../common/rng.zig");
|
|
9
|
-
|
|
10
|
-
const data = @import("data.zig");
|
|
11
|
-
const chance = @import("chance.zig");
|
|
10
|
+
const std = @import("std");
|
|
12
11
|
|
|
13
12
|
const assert = std.debug.assert;
|
|
14
|
-
|
|
15
|
-
const expectEqual = std.testing.expectEqual;
|
|
16
|
-
|
|
17
|
-
const showdown = pkmn.options.showdown;
|
|
18
|
-
|
|
19
|
-
const Choice = common.Choice;
|
|
20
|
-
const ID = common.ID;
|
|
21
|
-
const Player = common.Player;
|
|
22
|
-
const Result = common.Result;
|
|
23
|
-
|
|
24
13
|
const Boost = protocol.Boost;
|
|
14
|
+
const Choice = common.Choice;
|
|
25
15
|
const Damage = protocol.Damage;
|
|
16
|
+
const Effectiveness = data.Effectiveness;
|
|
17
|
+
const expectEqual = std.testing.expectEqual;
|
|
26
18
|
const Fail = protocol.Fail;
|
|
27
|
-
const Heal = protocol.Heal;
|
|
28
|
-
|
|
29
19
|
const Gen12 = rng.Gen12;
|
|
30
|
-
|
|
31
|
-
const
|
|
20
|
+
const Heal = protocol.Heal;
|
|
21
|
+
const ID = common.ID;
|
|
32
22
|
const Move = data.Move;
|
|
33
23
|
const MoveSlot = data.MoveSlot;
|
|
24
|
+
const Player = common.Player;
|
|
25
|
+
const Result = common.Result;
|
|
26
|
+
const showdown = pkmn.options.showdown;
|
|
34
27
|
const Side = data.Side;
|
|
35
28
|
const Species = data.Species;
|
|
36
29
|
const Stats = data.Stats;
|
|
@@ -173,7 +166,10 @@ fn selectMove(
|
|
|
173
166
|
if (foe_choice.type == .Switch) {
|
|
174
167
|
const last = side.active.move(battle.lastMove(player).index);
|
|
175
168
|
if (last.id == .Metronome) side.last_selected_move = last.id;
|
|
176
|
-
if (last.id == .MirrorMove)
|
|
169
|
+
if (last.id == .MirrorMove) {
|
|
170
|
+
if (!pkmn.options.mod) return Result.Error;
|
|
171
|
+
side.last_selected_move = last.id;
|
|
172
|
+
}
|
|
177
173
|
}
|
|
178
174
|
}
|
|
179
175
|
return null;
|
|
@@ -424,7 +420,7 @@ fn executeMove(
|
|
|
424
420
|
mslot = @intCast(battle.lastMove(player).index);
|
|
425
421
|
const stored = side.stored();
|
|
426
422
|
// GLITCH: Struggle bypass PP underflow via Hyper Beam / Trapping-switch auto selection
|
|
427
|
-
auto = isForced(&side.active) or
|
|
423
|
+
auto = pkmn.options.mod or isForced(&side.active) or
|
|
428
424
|
side.active.volatiles.Binding or side.active.volatiles.Bide or
|
|
429
425
|
side.last_selected_move == .HyperBeam or
|
|
430
426
|
Status.is(stored.status, .FRZ) or Status.is(stored.status, .SLP);
|
|
@@ -457,6 +453,25 @@ fn executeMove(
|
|
|
457
453
|
.err => return @as(?Result, Result.Error),
|
|
458
454
|
}
|
|
459
455
|
|
|
456
|
+
// Pokémon Showdown incorrectly implements PP deduction when handling the Hyper Beam automatic
|
|
457
|
+
// selection glitch - if the move was proced due to Metronome / Mirror Move it either subtracts
|
|
458
|
+
// from the Hyper Beam slot if present or skips PP deduction entirely...
|
|
459
|
+
if (showdown and !skip_pp and side.last_selected_move == .HyperBeam and
|
|
460
|
+
side.last_selected_move != side.active.move(mslot).id)
|
|
461
|
+
{
|
|
462
|
+
assert(mslot == 1);
|
|
463
|
+
const has_beam = has_beam: {
|
|
464
|
+
for (side.active.moves, 0..) |m, i| {
|
|
465
|
+
if (m.id == .HyperBeam) {
|
|
466
|
+
mslot = @intCast(i + 1);
|
|
467
|
+
break :has_beam true;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
break :has_beam false;
|
|
471
|
+
};
|
|
472
|
+
if (!has_beam) skip_pp = true;
|
|
473
|
+
}
|
|
474
|
+
|
|
460
475
|
const can = skip_can or
|
|
461
476
|
try canMove(battle, player, mslot, auto, skip_pp, .None, residual, options);
|
|
462
477
|
if (!can) return null;
|
|
@@ -554,18 +569,17 @@ fn beforeMove(
|
|
|
554
569
|
// This can only happen if a Pokémon started the battle frozen/sleeping and was thawed/woken
|
|
555
570
|
// before the side had a selected a move - we simply need to assume this leads to a desync
|
|
556
571
|
if (side.last_selected_move == .None) {
|
|
557
|
-
assert(!
|
|
572
|
+
assert(!pkmn.options.mod);
|
|
558
573
|
return .err;
|
|
559
574
|
}
|
|
560
575
|
|
|
561
576
|
if (volatiles.Confusion) {
|
|
562
577
|
assert(volatiles.confusion > 0);
|
|
563
578
|
if (options.calc.overridden(player, .confusion)) |obs| switch (obs) {
|
|
564
|
-
.started => volatiles.confusion
|
|
579
|
+
.started, .ended => volatiles.confusion = 0,
|
|
565
580
|
.continuing => if (volatiles.confusion > 1) {
|
|
566
581
|
volatiles.confusion -= 1;
|
|
567
582
|
},
|
|
568
|
-
.ended => volatiles.confusion = 0,
|
|
569
583
|
.overwritten => {},
|
|
570
584
|
else => unreachable,
|
|
571
585
|
} else {
|
|
@@ -704,7 +718,11 @@ fn beforeMove(
|
|
|
704
718
|
// can be expected to recognize this pattern and pass the information only to the
|
|
705
719
|
// correct player)
|
|
706
720
|
try log.start(.{ battle.active(player), .ConfusionSilent });
|
|
707
|
-
options.chance.observe(.confusion, player, if (overwritten)
|
|
721
|
+
options.chance.observe(.confusion, player, if (overwritten)
|
|
722
|
+
if (pkmn.options.overwrite) .overwritten else .continuing
|
|
723
|
+
else
|
|
724
|
+
.started);
|
|
725
|
+
if (!overwritten) options.calc.confusion(player);
|
|
708
726
|
}
|
|
709
727
|
|
|
710
728
|
// This shouldn't actually set last_used_move, but Pokémon Showdown sets last
|
|
@@ -770,9 +788,14 @@ fn canMove(
|
|
|
770
788
|
|
|
771
789
|
if (move.effect == .Thrashing) {
|
|
772
790
|
Effects.thrashing(battle, player, options);
|
|
773
|
-
} else if (
|
|
774
|
-
// Pokémon Showdown handles this after hit/miss checks and damage calculation
|
|
775
|
-
|
|
791
|
+
} else if (move.effect == .Binding) {
|
|
792
|
+
// Pokémon Showdown handles this after hit/miss checks and damage calculation, though clears
|
|
793
|
+
// Recharging in onTryMove (required for the Hyper Beam automatic selection glitch)
|
|
794
|
+
if (showdown) {
|
|
795
|
+
battle.foe(player).active.volatiles.Recharging = false;
|
|
796
|
+
} else {
|
|
797
|
+
try Effects.binding(battle, player, false, options);
|
|
798
|
+
}
|
|
776
799
|
}
|
|
777
800
|
|
|
778
801
|
return true;
|
|
@@ -1032,22 +1055,20 @@ fn doMove(
|
|
|
1032
1055
|
try Effects.poison(battle, player, Move.get(.PoisonSting), options);
|
|
1033
1056
|
}
|
|
1034
1057
|
try log.hitcount(.{ battle.active(player.foe()), hit });
|
|
1035
|
-
} else if (showdown) {
|
|
1058
|
+
} else if (showdown and move.effect == .Binding) {
|
|
1036
1059
|
// This should be handled much earlier but Pokémon Showdown does it here... ¯\_(ツ)_/¯
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
try buildRage(battle, player.foe(), options);
|
|
1048
|
-
}
|
|
1049
|
-
return null;
|
|
1060
|
+
try Effects.binding(battle, player, rewrap, options);
|
|
1061
|
+
if (immune) {
|
|
1062
|
+
battle.last_damage = 0;
|
|
1063
|
+
assert(foe.stored().hp > 0);
|
|
1064
|
+
// Pokémon Showdown logs |-damage| here instead of |-immune| because logic...
|
|
1065
|
+
if (sub) {
|
|
1066
|
+
try log.activate(.{ battle.active(player.foe()), .Substitute });
|
|
1067
|
+
} else {
|
|
1068
|
+
try log.damage(.{ battle.active(player.foe()), foe.stored(), .None });
|
|
1069
|
+
try buildRage(battle, player.foe(), options);
|
|
1050
1070
|
}
|
|
1071
|
+
return null;
|
|
1051
1072
|
}
|
|
1052
1073
|
}
|
|
1053
1074
|
|
|
@@ -1128,7 +1149,7 @@ fn calcDamage(
|
|
|
1128
1149
|
if ((!showdown or !cfz) and (atk > 255 or def > 255)) {
|
|
1129
1150
|
atk = @max((atk / 4) & 255, 1);
|
|
1130
1151
|
// GLITCH: not adjusted to be a min of 1 on cartridge (can lead to division-by-zero freeze)
|
|
1131
|
-
def = @max((def / 4) & 255, if (
|
|
1152
|
+
def = @max((def / 4) & 255, if (pkmn.options.mod) 1 else 0);
|
|
1132
1153
|
}
|
|
1133
1154
|
|
|
1134
1155
|
const lvl: u32 = side.stored().level * @as(u2, if (crit) 2 else 1);
|
|
@@ -1149,7 +1170,7 @@ fn calcDamage(
|
|
|
1149
1170
|
// encountered so we need to make sure that in the event of a miss we commit the status of the
|
|
1150
1171
|
// crit roll. The alternative to doing this extra work is to *always* commit the crit roll but
|
|
1151
1172
|
// that results in counter intuitive probabilities in the common case
|
|
1152
|
-
if (pkmn.options.chance and !
|
|
1173
|
+
if (pkmn.options.chance and !pkmn.options.mod and move.effect != .Explode) {
|
|
1153
1174
|
atk = attack(side, !crit, special);
|
|
1154
1175
|
def = defense(target, !crit, special, false);
|
|
1155
1176
|
if ((atk > 255 or def > 255) and (def / 4) & 255 == 0) options.chance.glitch();
|
|
@@ -1234,13 +1255,13 @@ fn specialDamage(battle: anytype, player: Player, move: Move.Data, options: anyt
|
|
|
1234
1255
|
.Psywave => power: {
|
|
1235
1256
|
const max: u8 = @intCast(@as(u16, side.stored().level) * 3 / 2);
|
|
1236
1257
|
// GLITCH: Psywave infinite glitch loop
|
|
1237
|
-
if (!
|
|
1258
|
+
if (!pkmn.options.mod and max <= 1) return Result.Error;
|
|
1238
1259
|
break :power try Rolls.psywave(battle, player, max, options);
|
|
1239
1260
|
},
|
|
1240
1261
|
else => unreachable,
|
|
1241
1262
|
};
|
|
1242
1263
|
|
|
1243
|
-
if (battle.last_damage == 0) return if (
|
|
1264
|
+
if (battle.last_damage == 0) return if (pkmn.options.mod) null else Result.Error;
|
|
1244
1265
|
|
|
1245
1266
|
const sub = showdown and foe.active.volatiles.Substitute;
|
|
1246
1267
|
_ = try applyDamage(battle, player.foe(), player.foe(), .None, options);
|
|
@@ -1277,12 +1298,16 @@ fn counterDamage(battle: anytype, player: Player, move: Move.Data, options: anyt
|
|
|
1277
1298
|
|
|
1278
1299
|
if (!used or !selected) {
|
|
1279
1300
|
// GLITCH: Counter desync (covered by Desync Clause Mod on Pokémon Showdown)
|
|
1280
|
-
if (!
|
|
1301
|
+
if (!pkmn.options.mod) return Result.Error;
|
|
1281
1302
|
try options.log.fail(.{ battle.active(player), .None });
|
|
1282
1303
|
return null;
|
|
1283
1304
|
}
|
|
1284
1305
|
|
|
1285
|
-
|
|
1306
|
+
// NOTE: llvm/llvm-project#58557
|
|
1307
|
+
battle.last_damage = if (comptime builtin.target.isWasm())
|
|
1308
|
+
@max(battle.last_damage *% 2, std.math.maxInt(u16))
|
|
1309
|
+
else
|
|
1310
|
+
battle.last_damage *| 2;
|
|
1286
1311
|
|
|
1287
1312
|
// Pokémon Showdown calls moveHit before Counter
|
|
1288
1313
|
if (!showdown and !try checkHit(battle, player, move, options)) return null;
|
|
@@ -1314,7 +1339,7 @@ fn applyDamage(
|
|
|
1314
1339
|
subbed.active.volatiles.Substitute = false;
|
|
1315
1340
|
// battle.last_damage is not updated with the amount of HP the Substitute had
|
|
1316
1341
|
try options.log.end(.{ battle.active(sub_player), .Substitute });
|
|
1317
|
-
options.calc.capped(sub_player);
|
|
1342
|
+
if (reason != .Confusion) options.calc.capped(sub_player);
|
|
1318
1343
|
return true;
|
|
1319
1344
|
} else {
|
|
1320
1345
|
// Safe to truncate since less than subbed.volatiles.substitute which is a u8
|
|
@@ -1524,7 +1549,7 @@ fn faint(battle: anytype, player: Player, done: bool, cap: bool, options: anytyp
|
|
|
1524
1549
|
assert(!foe_volatiles.MultiHit);
|
|
1525
1550
|
if (foe_volatiles.Bide) {
|
|
1526
1551
|
assert(!foe_volatiles.Thrashing and !foe_volatiles.Rage);
|
|
1527
|
-
foe_volatiles.state = if (
|
|
1552
|
+
foe_volatiles.state = if (pkmn.options.mod) 0 else foe_volatiles.state & 255;
|
|
1528
1553
|
if (foe_volatiles.state != 0) return Result.Error;
|
|
1529
1554
|
}
|
|
1530
1555
|
|
|
@@ -1615,12 +1640,12 @@ fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result
|
|
|
1615
1640
|
|
|
1616
1641
|
battle.turn += 1;
|
|
1617
1642
|
|
|
1618
|
-
if (
|
|
1643
|
+
if (pkmn.options.mod and pkmn.options.ebc and checkEBC(battle)) {
|
|
1619
1644
|
try options.log.tie(.{});
|
|
1620
1645
|
return Result.Tie;
|
|
1621
1646
|
}
|
|
1622
1647
|
|
|
1623
|
-
if (
|
|
1648
|
+
if (pkmn.options.mod and battle.turn >= 1000) {
|
|
1624
1649
|
try options.log.tie(.{});
|
|
1625
1650
|
return Result.Tie;
|
|
1626
1651
|
} else if (battle.turn >= 65535) {
|
|
@@ -1869,6 +1894,7 @@ pub const Effects = struct {
|
|
|
1869
1894
|
|
|
1870
1895
|
foe.active.volatiles.confusion = Rolls.confusionDuration(battle, player, options);
|
|
1871
1896
|
options.chance.observe(.confusion, player.foe(), .started);
|
|
1897
|
+
options.calc.confusion(player.foe());
|
|
1872
1898
|
|
|
1873
1899
|
try options.log.start(.{ battle.active(player.foe()), .Confusion });
|
|
1874
1900
|
}
|
|
@@ -1914,12 +1940,11 @@ pub const Effects = struct {
|
|
|
1914
1940
|
|
|
1915
1941
|
// Technically this is still considered simply a "miss" on the cartridge,
|
|
1916
1942
|
// but diverging from Pokémon Showdown here would mostly just be pedantic
|
|
1917
|
-
if (n == 0) {
|
|
1943
|
+
if (n == 0 or (pkmn.options.mod and err)) {
|
|
1918
1944
|
try options.log.fail(.{ foe_ident, .None });
|
|
1919
1945
|
return null;
|
|
1920
1946
|
} else if (err) {
|
|
1921
1947
|
// GLITCH: Transform + Mirror Move / Metronome PP softlock
|
|
1922
|
-
assert(!showdown);
|
|
1923
1948
|
return Result.Error;
|
|
1924
1949
|
}
|
|
1925
1950
|
|
|
@@ -1997,7 +2022,7 @@ pub const Effects = struct {
|
|
|
1997
2022
|
if (foe.active.types.includes(move.type)) return;
|
|
1998
2023
|
if (!try Rolls.secondaryChance(battle, player, true, options)) return;
|
|
1999
2024
|
// Freeze Clause Mod
|
|
2000
|
-
if (
|
|
2025
|
+
if (pkmn.options.mod) for (foe.pokemon) |p| if (Status.is(p.status, .FRZ)) return;
|
|
2001
2026
|
|
|
2002
2027
|
foe_stored.status = Status.init(.FRZ);
|
|
2003
2028
|
// GLITCH: Hyper Beam recharging status is not cleared
|
|
@@ -2338,7 +2363,7 @@ pub const Effects = struct {
|
|
|
2338
2363
|
}
|
|
2339
2364
|
|
|
2340
2365
|
// Sleep Clause Mod
|
|
2341
|
-
if (
|
|
2366
|
+
if (pkmn.options.mod) {
|
|
2342
2367
|
for (foe.pokemon) |p| {
|
|
2343
2368
|
if (Status.is(p.status, .SLP) and !Status.is(p.status, .EXT)) return;
|
|
2344
2369
|
}
|
|
@@ -2444,7 +2469,7 @@ pub const Effects = struct {
|
|
|
2444
2469
|
if (side.active.volatiles.Binding) return;
|
|
2445
2470
|
side.active.volatiles.Binding = true;
|
|
2446
2471
|
// GLITCH: Hyper Beam automatic selection glitch if Recharging gets cleared on miss
|
|
2447
|
-
// (Pokémon Showdown
|
|
2472
|
+
// (Pokémon Showdown clears Recharging in onTryMove instead)
|
|
2448
2473
|
if (!showdown) {
|
|
2449
2474
|
foe.active.volatiles.Recharging = false;
|
|
2450
2475
|
} else if (foe.stored().hp == 0) return if (!rewrap) battle.rng.advance(1);
|
|
@@ -2941,9 +2966,10 @@ pub const Rolls = struct {
|
|
|
2941
2966
|
}
|
|
2942
2967
|
|
|
2943
2968
|
fn sleepDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
2944
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2945
|
-
@intCast(val)
|
|
2946
|
-
else
|
|
2969
|
+
const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
|
|
2970
|
+
if (val >= 1 and val <= 7) @as(u3, @intCast(val)) else null
|
|
2971
|
+
else
|
|
2972
|
+
null) orelse if (@hasDecl(@TypeOf(battle.rng), "sleepDuration"))
|
|
2947
2973
|
battle.rng.sleepDuration(player)
|
|
2948
2974
|
else if (showdown)
|
|
2949
2975
|
battle.rng.range(u3, 1, 8)
|
|
@@ -2960,9 +2986,10 @@ pub const Rolls = struct {
|
|
|
2960
2986
|
}
|
|
2961
2987
|
|
|
2962
2988
|
fn disableDuration(battle: anytype, player: Player, options: anytype) u4 {
|
|
2963
|
-
const duration: u4 = if (options.calc.overridden(player, .duration)) |val|
|
|
2964
|
-
val
|
|
2965
|
-
else
|
|
2989
|
+
const duration: u4 = (if (options.calc.overridden(player, .duration)) |val|
|
|
2990
|
+
if (val >= 1 and val <= 8) val else null
|
|
2991
|
+
else
|
|
2992
|
+
null) orelse if (@hasDecl(@TypeOf(battle.rng), "disableDuration"))
|
|
2966
2993
|
battle.rng.disableDuration(player)
|
|
2967
2994
|
else if (showdown)
|
|
2968
2995
|
battle.rng.range(u4, 1, 9)
|
|
@@ -2975,9 +3002,10 @@ pub const Rolls = struct {
|
|
|
2975
3002
|
}
|
|
2976
3003
|
|
|
2977
3004
|
fn confusionDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
2978
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2979
|
-
@intCast(val)
|
|
2980
|
-
else
|
|
3005
|
+
const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
|
|
3006
|
+
if (val >= 2 and val <= 5) @as(u3, @intCast(val)) else null
|
|
3007
|
+
else
|
|
3008
|
+
null) orelse if (@hasDecl(@TypeOf(battle.rng), "confusionDuration"))
|
|
2981
3009
|
battle.rng.confusionDuration(player)
|
|
2982
3010
|
else if (showdown)
|
|
2983
3011
|
battle.rng.range(u3, 2, 6)
|
|
@@ -2990,9 +3018,10 @@ pub const Rolls = struct {
|
|
|
2990
3018
|
}
|
|
2991
3019
|
|
|
2992
3020
|
fn attackingDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
2993
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2994
|
-
@intCast(val)
|
|
2995
|
-
else
|
|
3021
|
+
const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
|
|
3022
|
+
if (val >= 2 and val <= 3) @as(u3, @intCast(val)) else null
|
|
3023
|
+
else
|
|
3024
|
+
null) orelse if (@hasDecl(@TypeOf(battle.rng), "attackingDuration"))
|
|
2996
3025
|
battle.rng.attackingDuration(player)
|
|
2997
3026
|
else if (showdown)
|
|
2998
3027
|
battle.rng.range(u3, 2, 4)
|
|
@@ -3013,9 +3042,10 @@ pub const Rolls = struct {
|
|
|
3013
3042
|
options: anytype,
|
|
3014
3043
|
) !u3 {
|
|
3015
3044
|
const roll = if (effect == .Binding) .duration else .multi_hit;
|
|
3016
|
-
const n: u3 = if (options.calc.overridden(player, roll)) |val|
|
|
3017
|
-
@intCast(val)
|
|
3018
|
-
else
|
|
3045
|
+
const n: u3 = (if (options.calc.overridden(player, roll)) |val|
|
|
3046
|
+
if (val >= 2 and val <= 5) @as(u3, @intCast(val)) else null
|
|
3047
|
+
else
|
|
3048
|
+
null) orelse if (@hasDecl(@TypeOf(battle.rng), "distribution"))
|
|
3019
3049
|
battle.rng.distribution(player)
|
|
3020
3050
|
else if (showdown)
|
|
3021
3051
|
DISTRIBUTION[battle.rng.range(u3, 0, DISTRIBUTION.len)]
|
|
@@ -3041,15 +3071,13 @@ pub const Rolls = struct {
|
|
|
3041
3071
|
options: anytype,
|
|
3042
3072
|
) !u4 {
|
|
3043
3073
|
// TODO: consider throwing error instead of rerolling?
|
|
3044
|
-
const
|
|
3074
|
+
const slot: u4 = (if (options.calc.overridden(player, .move_slot)) |val|
|
|
3045
3075
|
if (moves[val - 1].id != .None and (check_pp == 0 or moves[val - 1].pp > 0))
|
|
3046
3076
|
val
|
|
3047
3077
|
else
|
|
3048
3078
|
null
|
|
3049
3079
|
else
|
|
3050
|
-
null
|
|
3051
|
-
|
|
3052
|
-
const slot: u4 = overridden orelse if (@hasDecl(@TypeOf(battle.rng), "moveSlot"))
|
|
3080
|
+
null) orelse if (@hasDecl(@TypeOf(battle.rng), "moveSlot"))
|
|
3053
3081
|
battle.rng.moveSlot(player, moves, check_pp)
|
|
3054
3082
|
else slot: {
|
|
3055
3083
|
if (showdown) {
|
|
@@ -3207,7 +3235,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
|
|
|
3207
3235
|
// Struggle (Pokémon Showdown would use 'move 1' here)
|
|
3208
3236
|
if (n == before) {
|
|
3209
3237
|
// GLITCH: Transform + Mirror Move / Metronome PP softlock
|
|
3210
|
-
if (!
|
|
3238
|
+
if (!pkmn.options.mod) {
|
|
3211
3239
|
while (slot <= 4) : (slot += 1) {
|
|
3212
3240
|
if (active.moves[slot - 1].pp != 0) return n;
|
|
3213
3241
|
}
|
package/src/lib/gen2/calc.zig
CHANGED
|
@@ -1,27 +1,19 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
const pkmn = @import("../pkmn.zig");
|
|
4
|
-
|
|
1
|
+
const chance = @import("chance.zig");
|
|
5
2
|
const common = @import("../common/data.zig");
|
|
6
|
-
const util = @import("../common/util.zig");
|
|
7
|
-
|
|
8
3
|
const Optional = @import("../common/optional.zig").Optional;
|
|
4
|
+
const pkmn = @import("../pkmn.zig");
|
|
5
|
+
const std = @import("std");
|
|
6
|
+
const util = @import("../common/util.zig");
|
|
9
7
|
|
|
10
|
-
const
|
|
11
|
-
|
|
8
|
+
const Action = chance.Action;
|
|
9
|
+
const Actions = chance.Actions;
|
|
12
10
|
const assert = std.debug.assert;
|
|
13
|
-
|
|
11
|
+
const Criticals = chance.Criticals;
|
|
12
|
+
const Damages = chance.Damages;
|
|
14
13
|
const enabled = pkmn.options.calc;
|
|
15
|
-
|
|
14
|
+
const isPointerTo = util.isPointerTo;
|
|
16
15
|
const Player = common.Player;
|
|
17
|
-
|
|
18
16
|
const PointerType = util.PointerType;
|
|
19
|
-
const isPointerTo = util.isPointerTo;
|
|
20
|
-
|
|
21
|
-
const Actions = chance.Actions;
|
|
22
|
-
const Action = chance.Action;
|
|
23
|
-
const Criticals = chance.Criticals;
|
|
24
|
-
const Damages = chance.Damages;
|
|
25
17
|
|
|
26
18
|
const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
|
|
27
19
|
const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
|
-
const std = @import("std");
|
|
4
|
-
|
|
5
3
|
const data = @import("../../gen2/data.zig");
|
|
4
|
+
const std = @import("std");
|
|
6
5
|
|
|
7
6
|
const assert = std.debug.assert;
|
|
8
|
-
|
|
9
7
|
const Type = data.Type;
|
|
10
8
|
|
|
11
9
|
/// Representation of a held item in Generation II Pokémon.
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
|
-
const std = @import("std");
|
|
4
|
-
|
|
5
|
-
const rng = @import("../../common/rng.zig");
|
|
6
3
|
const gen2 = @import("../../gen2/data.zig");
|
|
4
|
+
const rng = @import("../../common/rng.zig");
|
|
5
|
+
const std = @import("std");
|
|
7
6
|
|
|
8
7
|
const assert = std.debug.assert;
|
|
9
|
-
|
|
10
8
|
const percent = rng.Gen12.percent;
|
|
11
9
|
const Type = gen2.Type;
|
|
12
10
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
|
-
const std = @import("std");
|
|
4
|
-
|
|
5
3
|
const gen2 = @import("../../gen2/data.zig");
|
|
4
|
+
const std = @import("std");
|
|
6
5
|
|
|
7
6
|
const assert = std.debug.assert;
|
|
8
|
-
|
|
9
7
|
const Stats = gen2.Stats;
|
|
10
8
|
const Types = gen2.Types;
|
|
11
9
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
|
-
const std = @import("std");
|
|
4
|
-
|
|
5
3
|
const gen1 = @import("../../gen1/data.zig");
|
|
4
|
+
const std = @import("std");
|
|
6
5
|
|
|
7
6
|
const assert = std.debug.assert;
|
|
8
7
|
const Effectiveness = gen1.Effectiveness;
|
package/src/lib/gen2/data.zig
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const builtin = @import("builtin");
|
|
3
|
-
|
|
4
|
-
const pkmn = @import("../pkmn.zig");
|
|
5
|
-
|
|
6
|
-
const data = @import("../common/data.zig");
|
|
7
1
|
const DEBUG = @import("../common/debug.zig").print;
|
|
8
|
-
const protocol = @import("../common/protocol.zig");
|
|
9
|
-
const rng = @import("../common/rng.zig");
|
|
10
|
-
const util = @import("../common/util.zig");
|
|
11
2
|
|
|
3
|
+
const builtin = @import("builtin");
|
|
4
|
+
const calc = @import("calc.zig");
|
|
5
|
+
const chance = @import("chance.zig");
|
|
6
|
+
const data = @import("../common/data.zig");
|
|
7
|
+
const gen1 = @import("../gen1/data.zig");
|
|
12
8
|
const items = @import("data/items.zig");
|
|
9
|
+
const mechanics = @import("mechanics.zig");
|
|
13
10
|
const moves = @import("data/moves.zig");
|
|
11
|
+
const pkmn = @import("../pkmn.zig");
|
|
12
|
+
const protocol = @import("../common/protocol.zig");
|
|
13
|
+
const rng = @import("../common/rng.zig");
|
|
14
14
|
const species = @import("data/species.zig");
|
|
15
|
+
const std = @import("std");
|
|
15
16
|
const types = @import("data/types.zig");
|
|
16
|
-
|
|
17
|
-
const gen1 = @import("../gen1/data.zig");
|
|
18
|
-
|
|
19
|
-
const calc = @import("calc.zig");
|
|
20
|
-
const chance = @import("chance.zig");
|
|
21
|
-
const mechanics = @import("mechanics.zig");
|
|
17
|
+
const util = @import("../common/util.zig");
|
|
22
18
|
|
|
23
19
|
const assert = std.debug.assert;
|
|
24
20
|
const expectEqual = std.testing.expectEqual;
|
|
@@ -1,37 +1,32 @@
|
|
|
1
1
|
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
|
-
const std = @import("std");
|
|
4
|
-
|
|
5
3
|
const common = @import("../common/data.zig");
|
|
6
|
-
|
|
7
4
|
const data = @import("data.zig");
|
|
8
5
|
const mechanics = @import("mechanics.zig");
|
|
6
|
+
const std = @import("std");
|
|
9
7
|
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const Effects = mechanics.Effects;
|
|
17
|
-
const State = mechanics.State;
|
|
18
|
-
|
|
19
|
-
const canMove = mechanics.canMove;
|
|
8
|
+
const adjustDamage = mechanics.adjustDamage;
|
|
9
|
+
const afterMove = mechanics.afterMove;
|
|
10
|
+
const applyDamage = mechanics.applyDamage;
|
|
11
|
+
const buildRage = mechanics.buildRage;
|
|
12
|
+
const calcDamage = mechanics.calcDamage;
|
|
20
13
|
const canCharge = mechanics.canCharge;
|
|
14
|
+
const canMove = mechanics.canMove;
|
|
15
|
+
const checkCriticalHit = mechanics.checkCriticalHit;
|
|
16
|
+
const checkHit = mechanics.checkHit;
|
|
21
17
|
const decrementPP = mechanics.decrementPP;
|
|
18
|
+
const destinyBond = mechanics.destinyBond;
|
|
22
19
|
const doMove = mechanics.doMove;
|
|
23
|
-
const checkHit = mechanics.checkHit;
|
|
24
|
-
const checkCriticalHit = mechanics.checkCriticalHit;
|
|
25
|
-
const calcDamage = mechanics.calcDamage;
|
|
26
|
-
const adjustDamage = mechanics.adjustDamage;
|
|
27
|
-
const randomizeDamage = mechanics.randomizeDamage;
|
|
28
|
-
const applyDamage = mechanics.applyDamage;
|
|
29
|
-
const reportOutcome = mechanics.reportOutcome;
|
|
30
20
|
const effectChance = mechanics.effectChance;
|
|
31
|
-
const
|
|
32
|
-
const
|
|
21
|
+
const Effectiveness = data.Effectiveness;
|
|
22
|
+
const Effects = mechanics.Effects;
|
|
33
23
|
const kingsRock = mechanics.kingsRock;
|
|
34
|
-
const
|
|
24
|
+
const Move = data.Move;
|
|
25
|
+
const Player = common.Player;
|
|
26
|
+
const randomizeDamage = mechanics.randomizeDamage;
|
|
27
|
+
const reportOutcome = mechanics.reportOutcome;
|
|
28
|
+
const Result = common.Result;
|
|
29
|
+
const State = mechanics.State;
|
|
35
30
|
|
|
36
31
|
const SECONDARY = true;
|
|
37
32
|
const KINGS = true;
|
package/src/lib/gen2/helpers.zig
CHANGED
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
|
|
3
1
|
const common = @import("../common/data.zig");
|
|
2
|
+
const data = @import("data.zig");
|
|
3
|
+
const gen1 = @import("../gen1/data.zig");
|
|
4
4
|
const options = @import("../common/options.zig");
|
|
5
5
|
const rng = @import("../common/rng.zig");
|
|
6
|
-
|
|
7
|
-
const gen1 = @import("../gen1/data.zig");
|
|
8
|
-
|
|
9
|
-
const data = @import("data.zig");
|
|
6
|
+
const std = @import("std");
|
|
10
7
|
|
|
11
8
|
const assert = std.debug.assert;
|
|
12
|
-
|
|
13
9
|
const Choice = common.Choice;
|
|
14
|
-
|
|
15
|
-
const showdown = options.showdown;
|
|
16
|
-
|
|
17
|
-
const PSRNG = rng.PSRNG;
|
|
18
|
-
|
|
19
10
|
const DVs = data.DVs;
|
|
20
11
|
const Item = data.Item;
|
|
21
12
|
const Move = data.Move;
|
|
22
13
|
const MoveSlot = data.MoveSlot;
|
|
14
|
+
const PSRNG = rng.PSRNG;
|
|
15
|
+
const showdown = options.showdown;
|
|
23
16
|
const Species = data.Species;
|
|
24
17
|
const Stats = data.Stats;
|
|
25
18
|
|