@pkmn/engine 0.1.0-dev.f3aaee39 → 0.1.0-dev.f918c3bd
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/build/pkg/data/protocol.json +69 -12
- package/build/pkg/protocol.js +56 -37
- package/build/pkg/protocol.js.map +1 -1
- package/build.zig +2 -2
- package/package.json +20 -11
- package/src/lib/binding/node.zig +1 -1
- package/src/lib/common/data.zig +4 -16
- package/src/lib/common/protocol.zig +514 -66
- package/src/lib/common/rational.zig +1 -1
- package/src/lib/common/rng.zig +6 -6
- package/src/lib/gen1/README.md +3 -1
- package/src/lib/gen1/calc.zig +2 -3
- package/src/lib/gen1/chance.zig +26 -12
- package/src/lib/gen1/data/moves.zig +168 -170
- package/src/lib/gen1/data/types.zig +1 -1
- package/src/lib/gen1/data.zig +11 -23
- package/src/lib/gen1/helpers.zig +12 -12
- package/src/lib/gen1/mechanics.zig +32 -36
- package/src/lib/gen2/README.md +90 -70
- package/src/lib/gen2/data/moves.zig +634 -562
- package/src/lib/gen2/data/types.zig +1 -1
- package/src/lib/gen2/data.zig +74 -52
- package/src/lib/gen2/helpers.zig +8 -12
- package/src/lib/gen2/mechanics.zig +1142 -7
|
@@ -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
|
package/src/lib/gen1/data.zig
CHANGED
|
@@ -214,7 +214,7 @@ pub const Pokemon = extern struct {
|
|
|
214
214
|
}
|
|
215
215
|
};
|
|
216
216
|
|
|
217
|
-
/// Representation of a Generation I
|
|
217
|
+
/// Representation of a Generation I Pokémon's move slot in a battle.
|
|
218
218
|
pub const MoveSlot = extern struct {
|
|
219
219
|
/// The identifier for the move.
|
|
220
220
|
id: Move = .None,
|
|
@@ -222,20 +222,16 @@ pub const MoveSlot = extern struct {
|
|
|
222
222
|
pp: u8 = 0,
|
|
223
223
|
|
|
224
224
|
comptime {
|
|
225
|
-
assert(@sizeOf(MoveSlot) ==
|
|
225
|
+
assert(@sizeOf(MoveSlot) == 2);
|
|
226
226
|
}
|
|
227
227
|
};
|
|
228
228
|
|
|
229
229
|
/// Details required to detect desyncs based on the move last selected/executed by players.
|
|
230
|
-
pub const MoveDetails = packed struct {
|
|
230
|
+
pub const MoveDetails = packed struct(if (showdown) u16 else u8) {
|
|
231
231
|
/// The move slot index of the last move selected in the battle menu.
|
|
232
232
|
index: if (showdown) u8 else u4 = 0,
|
|
233
233
|
/// Whether the last move executed was counterable.
|
|
234
234
|
counterable: if (showdown) u8 else u4 = 0,
|
|
235
|
-
|
|
236
|
-
comptime {
|
|
237
|
-
assert(@sizeOf(MoveDetails) == if (showdown) 2 else 1);
|
|
238
|
-
}
|
|
239
235
|
};
|
|
240
236
|
|
|
241
237
|
/// Bitfield representation of a Generation I & II Pokémon's major status condition.
|
|
@@ -329,7 +325,7 @@ test Status {
|
|
|
329
325
|
}
|
|
330
326
|
|
|
331
327
|
/// Bitfield representation of volatile statuses and associated data in Generation I.
|
|
332
|
-
pub const Volatiles = packed struct {
|
|
328
|
+
pub const Volatiles = packed struct(u64) {
|
|
333
329
|
/// Whether the "Bide" volatile status is present.
|
|
334
330
|
Bide: bool = false,
|
|
335
331
|
/// Whether the "Thrashing" volatile status is present.
|
|
@@ -387,14 +383,10 @@ pub const Volatiles = packed struct {
|
|
|
387
383
|
disabled_move: u3 = 0,
|
|
388
384
|
/// The number of turns toxic damage has been accumulating.
|
|
389
385
|
toxic: u5 = 0,
|
|
390
|
-
|
|
391
|
-
comptime {
|
|
392
|
-
assert(@sizeOf(Volatiles) == 8);
|
|
393
|
-
}
|
|
394
386
|
};
|
|
395
387
|
|
|
396
388
|
test Volatiles {
|
|
397
|
-
var volatiles =
|
|
389
|
+
var volatiles: Volatiles = .{};
|
|
398
390
|
volatiles.Confusion = true;
|
|
399
391
|
volatiles.confusion = 2;
|
|
400
392
|
volatiles.Thrashing = true;
|
|
@@ -456,7 +448,7 @@ test Stats {
|
|
|
456
448
|
}
|
|
457
449
|
|
|
458
450
|
/// Representation of a Pokémon's boosts in Generation I.
|
|
459
|
-
pub const Boosts = packed struct {
|
|
451
|
+
pub const Boosts = packed struct(u32) {
|
|
460
452
|
/// A Pokémon's Attack boosts.
|
|
461
453
|
atk: i4 = 0,
|
|
462
454
|
/// A Pokémon's Defense boosts.
|
|
@@ -471,14 +463,10 @@ pub const Boosts = packed struct {
|
|
|
471
463
|
evasion: i4 = 0,
|
|
472
464
|
|
|
473
465
|
_: u8 = 0,
|
|
474
|
-
|
|
475
|
-
comptime {
|
|
476
|
-
assert(@sizeOf(Boosts) == 4);
|
|
477
|
-
}
|
|
478
466
|
};
|
|
479
467
|
|
|
480
468
|
test Boosts {
|
|
481
|
-
const boosts =
|
|
469
|
+
const boosts: Boosts = .{ .spc = -6 };
|
|
482
470
|
try expectEqual(0, boosts.atk);
|
|
483
471
|
try expectEqual(-6, boosts.spc);
|
|
484
472
|
}
|
|
@@ -490,7 +478,7 @@ test Move {
|
|
|
490
478
|
try expectEqual(2, @intFromEnum(Move.KarateChop));
|
|
491
479
|
const move = Move.get(.Fissure);
|
|
492
480
|
try expectEqual(Move.Effect.OHKO, move.effect);
|
|
493
|
-
try expectEqual(
|
|
481
|
+
try expectEqual(rng.Gen12.percent(30), move.accuracy);
|
|
494
482
|
try expectEqual(Type.Ground, move.type);
|
|
495
483
|
|
|
496
484
|
try expect(!Move.Effect.onBegin(.None));
|
|
@@ -628,16 +616,16 @@ pub const DVs = struct {
|
|
|
628
616
|
};
|
|
629
617
|
|
|
630
618
|
test DVs {
|
|
631
|
-
var dvs =
|
|
619
|
+
var dvs: DVs = .{ .spc = 15, .spe = 15 };
|
|
632
620
|
try expectEqual(@as(u4, 15), dvs.hp());
|
|
633
|
-
dvs =
|
|
621
|
+
dvs = .{
|
|
634
622
|
.atk = 5,
|
|
635
623
|
.def = 15,
|
|
636
624
|
.spe = 13,
|
|
637
625
|
.spc = 13,
|
|
638
626
|
};
|
|
639
627
|
try expectEqual(@as(u4, 15), dvs.hp());
|
|
640
|
-
dvs =
|
|
628
|
+
dvs = .{
|
|
641
629
|
.def = 3,
|
|
642
630
|
.spe = 10,
|
|
643
631
|
.spc = 11,
|
package/src/lib/gen1/helpers.zig
CHANGED
|
@@ -478,13 +478,13 @@ pub const Rolls = struct {
|
|
|
478
478
|
};
|
|
479
479
|
|
|
480
480
|
test "Rolls.speedTie" {
|
|
481
|
-
const actions =
|
|
481
|
+
const actions: Actions = .{ .p1 = .{ .speed_tie = .P2 } };
|
|
482
482
|
try expectEqualSlices(Optional(Player), &.{ .P1, .P2 }, Rolls.speedTie(actions.p1));
|
|
483
483
|
try expectEqualSlices(Optional(Player), &.{.None}, Rolls.speedTie(actions.p2));
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
test "Rolls.damage" {
|
|
487
|
-
const actions =
|
|
487
|
+
const actions: Actions = .{ .p2 = .{ .damage = 221 } };
|
|
488
488
|
try expectEqual(Rolls.Range{ .min = 0, .max = 1 }, Rolls.damage(actions.p1, .None));
|
|
489
489
|
try expectEqual(Rolls.Range{ .min = 217, .max = 256 }, Rolls.damage(actions.p2, .None));
|
|
490
490
|
try expectEqual(Rolls.Range{ .min = 0, .max = 1 }, Rolls.damage(actions.p2, .false));
|
|
@@ -502,7 +502,7 @@ test "Rolls.coalesce" {
|
|
|
502
502
|
}
|
|
503
503
|
|
|
504
504
|
test "Rolls.hit" {
|
|
505
|
-
const actions =
|
|
505
|
+
const actions: Actions = .{ .p2 = .{ .hit = .true } };
|
|
506
506
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.hit(actions.p1, .None));
|
|
507
507
|
try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.hit(actions.p2, .None));
|
|
508
508
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.hit(actions.p2, .true));
|
|
@@ -510,7 +510,7 @@ test "Rolls.hit" {
|
|
|
510
510
|
}
|
|
511
511
|
|
|
512
512
|
test "Rolls.secondaryChance" {
|
|
513
|
-
const actions =
|
|
513
|
+
const actions: Actions = .{ .p1 = .{ .secondary_chance = .true } };
|
|
514
514
|
try expectEqualSlices(
|
|
515
515
|
Optional(bool),
|
|
516
516
|
&.{ .false, .true },
|
|
@@ -521,7 +521,7 @@ test "Rolls.secondaryChance" {
|
|
|
521
521
|
}
|
|
522
522
|
|
|
523
523
|
test "Rolls.criticalHit" {
|
|
524
|
-
const actions =
|
|
524
|
+
const actions: Actions = .{ .p1 = .{ .critical_hit = .true } };
|
|
525
525
|
try expectEqualSlices(
|
|
526
526
|
Optional(bool),
|
|
527
527
|
&.{ .false, .true },
|
|
@@ -532,14 +532,14 @@ test "Rolls.criticalHit" {
|
|
|
532
532
|
}
|
|
533
533
|
|
|
534
534
|
test "Rolls.confused" {
|
|
535
|
-
const actions =
|
|
535
|
+
const actions: Actions = .{ .p2 = .{ .confused = .true } };
|
|
536
536
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.confused(actions.p1, 1));
|
|
537
537
|
try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.confused(actions.p2, 1));
|
|
538
538
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.confused(actions.p2, 0));
|
|
539
539
|
}
|
|
540
540
|
|
|
541
541
|
test "Rolls.paralyzed" {
|
|
542
|
-
const actions =
|
|
542
|
+
const actions: Actions = .{ .p2 = .{ .paralyzed = .true } };
|
|
543
543
|
try expectEqualSlices(Optional(bool), &.{.None}, Rolls.paralyzed(actions.p1, .None));
|
|
544
544
|
try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.paralyzed(actions.p2, .None));
|
|
545
545
|
try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.paralyzed(actions.p2, .false));
|
|
@@ -547,7 +547,7 @@ test "Rolls.paralyzed" {
|
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
test "Rolls.duration" {
|
|
550
|
-
const actions =
|
|
550
|
+
const actions: Actions = .{ .p2 = .{ .duration = 3 } };
|
|
551
551
|
try expectEqualSlices(u1, &.{0}, Rolls.duration(actions.p1, .None));
|
|
552
552
|
try expectEqualSlices(u1, &.{1}, Rolls.duration(actions.p2, .None));
|
|
553
553
|
try expectEqualSlices(u1, &.{0}, Rolls.duration(actions.p2, .false));
|
|
@@ -757,27 +757,27 @@ test "Rolls.binding" {
|
|
|
757
757
|
}
|
|
758
758
|
|
|
759
759
|
test "Rolls.moveSlot" {
|
|
760
|
-
const actions =
|
|
760
|
+
const actions: Actions = .{ .p2 = .{ .move_slot = 3 } };
|
|
761
761
|
try expectEqualSlices(u4, &.{0}, Rolls.moveSlot(actions.p1, .None));
|
|
762
762
|
try expectEqualSlices(u4, &.{ 1, 2, 3, 4 }, Rolls.moveSlot(actions.p2, .None));
|
|
763
763
|
try expectEqualSlices(u4, &.{0}, Rolls.moveSlot(actions.p2, .false));
|
|
764
764
|
}
|
|
765
765
|
|
|
766
766
|
test "Rolls.multiHit" {
|
|
767
|
-
const actions =
|
|
767
|
+
const actions: Actions = .{ .p2 = .{ .multi_hit = 3 } };
|
|
768
768
|
try expectEqualSlices(u4, &.{0}, Rolls.multiHit(actions.p1, .None));
|
|
769
769
|
try expectEqualSlices(u4, &.{ 2, 3, 4, 5 }, Rolls.multiHit(actions.p2, .None));
|
|
770
770
|
try expectEqualSlices(u4, &.{0}, Rolls.multiHit(actions.p2, .false));
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
test "Rolls.metronome" {
|
|
774
|
-
const actions =
|
|
774
|
+
const actions: Actions = .{ .p2 = .{ .metronome = .Surf } };
|
|
775
775
|
try expectEqualSlices(Move, &.{.None}, Rolls.metronome(actions.p1));
|
|
776
776
|
try expectEqual(@as(Move, @enumFromInt(24)), Rolls.metronome(actions.p2)[23]);
|
|
777
777
|
}
|
|
778
778
|
|
|
779
779
|
test "Rolls.psywave" {
|
|
780
|
-
const actions =
|
|
780
|
+
const actions: Actions = .{ .p2 = .{ .psywave = 79 } };
|
|
781
781
|
var side = Side.init(&[_]Pokemon{.{
|
|
782
782
|
.species = .Bulbasaur,
|
|
783
783
|
.level = 100,
|
|
@@ -62,10 +62,6 @@ const MAX_STAT_VALUE = 999;
|
|
|
62
62
|
const DISTRIBUTION = [_]u3{ 2, 2, 2, 3, 3, 3, 4, 5 };
|
|
63
63
|
|
|
64
64
|
pub fn update(battle: anytype, c1: Choice, c2: Choice, options: anytype) !Result {
|
|
65
|
-
// FIXME
|
|
66
|
-
// std.debug.print("\n", .{});
|
|
67
|
-
// DEBUG(battle.turn);
|
|
68
|
-
// std.debug.print("// ", .{});
|
|
69
65
|
assert(c1.type != .Pass or c2.type != .Pass or battle.turn == 0);
|
|
70
66
|
if (battle.turn == 0) return start(battle, options);
|
|
71
67
|
|
|
@@ -214,12 +210,9 @@ fn selectMove(
|
|
|
214
210
|
}
|
|
215
211
|
break :ok true;
|
|
216
212
|
};
|
|
217
|
-
|
|
218
213
|
assert(struggle);
|
|
219
|
-
saveMove(battle, player, choice);
|
|
220
|
-
} else {
|
|
221
|
-
saveMove(battle, player, choice);
|
|
222
214
|
}
|
|
215
|
+
saveMove(battle, player, choice);
|
|
223
216
|
|
|
224
217
|
return null;
|
|
225
218
|
}
|
|
@@ -1438,7 +1431,7 @@ fn moveHit(
|
|
|
1438
1431
|
const overwritten = overwrite and state > 0;
|
|
1439
1432
|
assert(!overwritten or (0 < state and state <= 255 and !side.active.volatiles.Bide));
|
|
1440
1433
|
|
|
1441
|
-
var accuracy = if (overwritten) state else @as(u16,
|
|
1434
|
+
var accuracy = if (overwritten) state else @as(u16, move.accuracy);
|
|
1442
1435
|
var boost = BOOSTS[@as(u4, @intCast(@as(i8, side.active.boosts.accuracy) + 6))];
|
|
1443
1436
|
accuracy = accuracy * boost[0] / boost[1];
|
|
1444
1437
|
boost = BOOSTS[@as(u4, @intCast(@as(i8, -foe.active.boosts.evasion) + 6))];
|
|
@@ -1499,8 +1492,8 @@ fn checkFaint(
|
|
|
1499
1492
|
}
|
|
1500
1493
|
|
|
1501
1494
|
const foe_choice: Choice.Type = if (foe_fainted) .Switch else .Pass;
|
|
1502
|
-
if (player == .P1) return
|
|
1503
|
-
return
|
|
1495
|
+
if (player == .P1) return .{ .p1 = .Switch, .p2 = foe_choice };
|
|
1496
|
+
return .{ .p1 = foe_choice, .p2 = .Switch };
|
|
1504
1497
|
}
|
|
1505
1498
|
|
|
1506
1499
|
fn faint(battle: anytype, player: Player, done: bool, options: anytype) !?Result {
|
|
@@ -1548,21 +1541,19 @@ fn handleResidual(battle: anytype, player: Player, options: anytype) !void {
|
|
|
1548
1541
|
var volatiles = &side.active.volatiles;
|
|
1549
1542
|
|
|
1550
1543
|
const brn = Status.is(stored.status, .BRN);
|
|
1551
|
-
if (brn or Status.is(stored.status, .PSN))
|
|
1544
|
+
if (brn or Status.is(stored.status, .PSN)) {
|
|
1552
1545
|
var damage = @max(stored.stats.hp / 16, 1);
|
|
1553
|
-
|
|
1554
1546
|
if (volatiles.Toxic) {
|
|
1555
1547
|
volatiles.toxic += 1;
|
|
1556
1548
|
damage *= volatiles.toxic;
|
|
1557
1549
|
}
|
|
1550
|
+
damage = @min(damage, stored.hp);
|
|
1558
1551
|
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
// Pokémon Showdown uses damageOf here but its not relevant in Generation I
|
|
1565
|
-
try options.log.damage(ident, stored, if (brn) Damage.Burn else Damage.Poison);
|
|
1552
|
+
if (!showdown or damage > 0) {
|
|
1553
|
+
stored.hp -= damage;
|
|
1554
|
+
// Pokémon Showdown uses damageOf here but its not relevant in Generation I
|
|
1555
|
+
try options.log.damage(ident, stored, if (brn) Damage.Burn else Damage.Poison);
|
|
1556
|
+
}
|
|
1566
1557
|
}
|
|
1567
1558
|
|
|
1568
1559
|
if (volatiles.LeechSeed) {
|
|
@@ -2395,12 +2386,17 @@ pub const Effects = struct {
|
|
|
2395
2386
|
}
|
|
2396
2387
|
|
|
2397
2388
|
fn switchAndTeleport(battle: anytype, player: Player, move: Move.Data, options: anytype) !void {
|
|
2398
|
-
if (!showdown or battle.side(player).last_selected_move == .Teleport) return;
|
|
2399
|
-
|
|
2400
2389
|
// Whirlwind/Roar should not roll to hit/reset damage but Pokémon Showdown does anyway
|
|
2401
|
-
if (
|
|
2402
|
-
|
|
2403
|
-
|
|
2390
|
+
if (showdown) {
|
|
2391
|
+
if (battle.side(player).last_selected_move == .Teleport) return;
|
|
2392
|
+
if (try checkHit(battle, player, move, options)) {
|
|
2393
|
+
try options.chance.commit(player, .hit);
|
|
2394
|
+
}
|
|
2395
|
+
battle.last_damage = 0;
|
|
2396
|
+
} else {
|
|
2397
|
+
try options.log.fail(battle.active(player), .None);
|
|
2398
|
+
try options.log.laststill();
|
|
2399
|
+
}
|
|
2404
2400
|
}
|
|
2405
2401
|
|
|
2406
2402
|
fn thrashing(battle: anytype, player: Player, options: anytype) void {
|
|
@@ -2705,15 +2701,15 @@ fn clearVolatiles(battle: anytype, who: Player, clear: bool, options: anytype) !
|
|
|
2705
2701
|
}
|
|
2706
2702
|
if (volatiles.Mist) {
|
|
2707
2703
|
volatiles.Mist = false;
|
|
2708
|
-
try log.end(ident, .
|
|
2704
|
+
try log.end(ident, .MistSilent);
|
|
2709
2705
|
}
|
|
2710
2706
|
if (volatiles.FocusEnergy) {
|
|
2711
2707
|
volatiles.FocusEnergy = false;
|
|
2712
|
-
try log.end(ident, .
|
|
2708
|
+
try log.end(ident, .FocusEnergySilent);
|
|
2713
2709
|
}
|
|
2714
2710
|
if (volatiles.LeechSeed) {
|
|
2715
2711
|
volatiles.LeechSeed = false;
|
|
2716
|
-
try log.end(ident, .
|
|
2712
|
+
try log.end(ident, .LeechSeedSilent);
|
|
2717
2713
|
}
|
|
2718
2714
|
if (!showdown and volatiles.Toxic) {
|
|
2719
2715
|
volatiles.Toxic = false;
|
|
@@ -2721,17 +2717,17 @@ fn clearVolatiles(battle: anytype, who: Player, clear: bool, options: anytype) !
|
|
|
2721
2717
|
}
|
|
2722
2718
|
if (volatiles.LightScreen) {
|
|
2723
2719
|
volatiles.LightScreen = false;
|
|
2724
|
-
try log.end(ident, .
|
|
2720
|
+
try log.end(ident, .LightScreenSilent);
|
|
2725
2721
|
}
|
|
2726
2722
|
if (volatiles.Reflect) {
|
|
2727
2723
|
volatiles.Reflect = false;
|
|
2728
|
-
try log.end(ident, .
|
|
2724
|
+
try log.end(ident, .ReflectSilent);
|
|
2729
2725
|
}
|
|
2730
2726
|
if (showdown and volatiles.Toxic) {
|
|
2731
2727
|
volatiles.Toxic = false;
|
|
2732
2728
|
// Pokémon Showdown erroneously clears the toxic counter
|
|
2733
2729
|
volatiles.toxic = 0;
|
|
2734
|
-
try log.end(ident, .
|
|
2730
|
+
try log.end(ident, .ToxicSilent);
|
|
2735
2731
|
}
|
|
2736
2732
|
}
|
|
2737
2733
|
|
|
@@ -3039,11 +3035,11 @@ test "RNG agreement" {
|
|
|
3039
3035
|
expected[i] = @intCast(i * 0x1000000);
|
|
3040
3036
|
}
|
|
3041
3037
|
|
|
3042
|
-
var spe
|
|
3043
|
-
var cfz
|
|
3044
|
-
var par
|
|
3045
|
-
var brn
|
|
3046
|
-
var eff
|
|
3038
|
+
var spe: rng.FixedRNG(1, expected.len) = .{ .rolls = expected };
|
|
3039
|
+
var cfz: rng.FixedRNG(1, expected.len) = .{ .rolls = expected };
|
|
3040
|
+
var par: rng.FixedRNG(1, expected.len) = .{ .rolls = expected };
|
|
3041
|
+
var brn: rng.FixedRNG(1, expected.len) = .{ .rolls = expected };
|
|
3042
|
+
var eff: rng.FixedRNG(1, expected.len) = .{ .rolls = expected };
|
|
3047
3043
|
|
|
3048
3044
|
for (0..expected.len) |i| {
|
|
3049
3045
|
try expectEqual(spe.range(u8, 0, 2) == 0, i < Gen12.percent(50) + 1);
|
package/src/lib/gen2/README.md
CHANGED
|
@@ -36,21 +36,21 @@ The following information is required to simulate a Generation II Pokémon battl
|
|
|
36
36
|
| `active.switching` | `PlayerIsSwitching` | `pokemon.switchFlag` |
|
|
37
37
|
| `active.boosts` | `PlayerStatLevels` | `pokemon.boosts` |
|
|
38
38
|
| `active.volatiles` | `PlayerBattleStatus{1,2,3}` | `pokemon.volatiles` |
|
|
39
|
-
| `volatiles.
|
|
40
|
-
| `volatiles.
|
|
41
|
-
| `volatiles.
|
|
42
|
-
| `volatiles.
|
|
43
|
-
| `volatiles.
|
|
44
|
-
| `volatiles.
|
|
45
|
-
| `volatiles.
|
|
46
|
-
| `volatiles.
|
|
47
|
-
| `volatiles.
|
|
48
|
-
| `volatiles.
|
|
49
|
-
| `volatiles.
|
|
50
|
-
| `volatiles.
|
|
51
|
-
| `volatiles.
|
|
39
|
+
| `volatiles.bide` | `PlayerDamageTaken` | `volatiles.bide.totalDamage` |
|
|
40
|
+
| `volatiles.substitute` | `PlayerSubstituteHP` | `volatiles.substitute.hp` |
|
|
41
|
+
| `volatiles.rollout` | `PlayerRolloutCount` | `volatiles.rollout.hitCount` |
|
|
42
|
+
| `volatiles.confusion` | `PlayerConfuseCount` | `volatiles.confusion.duration` |
|
|
43
|
+
| `volatiles.toxic` | `PlayerToxicCount` | `volatiles.residualdmg.counter` |
|
|
44
|
+
| `volatiles.disabled` | `PlayerDisableCount` | `moveSlots.disabled` |
|
|
45
|
+
| `volatiles.encore` | `PlayerEncoreCount` | `volatiles.encore.duration` |
|
|
46
|
+
| `volatiles.perish_song` | `PlayerPerishCount` | `volatiles.perishsong.duration` |
|
|
47
|
+
| `volatiles.fury_cutter` | `PlayerFuryCutterCount` | `volatiles.furycutter.multiplier` |
|
|
48
|
+
| `volatiles.protect` | `PlayerProtectCount` | `volatiles.stall.counter` |
|
|
49
|
+
| `volatiles.future_sight` | `PlayerFutureSight{Damage,Count}` | `slotConditions[i].futuremove` |
|
|
50
|
+
| `volatiles.rage` | `PlayerRageCounter` | **BUG** |
|
|
51
|
+
| `volatiles.bind` | `PlayerWrapCount` | `volatiles.partiallytrapped.duration` |
|
|
52
52
|
| | `PlayerCharging` | |
|
|
53
|
-
|
|
|
53
|
+
| `volatiles.frozen` | `PlayerJustGotFrozen` | `volatiles.frozen` |
|
|
54
54
|
| | | |
|
|
55
55
|
| `active.last_used_move` | `PlayerUsedMove` | `side.lastMove` |
|
|
56
56
|
|
|
@@ -219,6 +219,81 @@ much overhead the preceding representations have after taking into consideration
|
|
|
219
219
|
padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
|
|
220
220
|
[denormalization](https://en.wikipedia.org/wiki/Denormalization):
|
|
221
221
|
|
|
222
|
+
## Details
|
|
223
|
+
|
|
224
|
+
| pkmn | Pokémon Crystal (pret) |
|
|
225
|
+
| ------------------------- | ------------------------------------------------- |
|
|
226
|
+
| `start` | `DoBattle` |
|
|
227
|
+
| `update` | `BattleTurn` |
|
|
228
|
+
| `selectMove` / `saveMove` | `CheckPlayerLockedIn` / `ParsePlayerAction` |
|
|
229
|
+
| `switchIn` | `SwitchPlayerMon` / `SendOutPlayerMon` |
|
|
230
|
+
| `turnOrder` | `DetermineMoveOrder` |
|
|
231
|
+
| `doTurn` | `DoTurn` |
|
|
232
|
+
| `executeMove` | `DoMove` |
|
|
233
|
+
| `beforeMove` | `CheckTurn` |
|
|
234
|
+
| `canMove` | |
|
|
235
|
+
| `decrementPP` | |
|
|
236
|
+
| `doMove` | |
|
|
237
|
+
| `checkCriticalHit` | `BattleCommand_Critical` |
|
|
238
|
+
| `calcDamage` | `BattleCommand_DamageCalc` / `PlayerAttackDamage` |
|
|
239
|
+
| `adjustDamage` | `BattleCommand_Stab` |
|
|
240
|
+
| `randomizeDamage` | `BattleCommand_DamageVariation` |
|
|
241
|
+
| `specialDamage` | `BattleCommand_ConstantDamage` |
|
|
242
|
+
| `applyDamage` | `BattleCommand_ApplyDamage` |
|
|
243
|
+
| `checkHit` | `BattleCommand_CheckHit` |
|
|
244
|
+
| `checkFaint` | `CheckFaint` |
|
|
245
|
+
| `handleResidual` | `ResidualDamage` |
|
|
246
|
+
| `endTurn` | `EndTurn` |
|
|
247
|
+
|
|
248
|
+
DoBattle
|
|
249
|
+
BattleTurn
|
|
250
|
+
- HandleBerserkGene
|
|
251
|
+
- CheckPlayerLockedIn
|
|
252
|
+
- BattleMenu
|
|
253
|
+
- ParsePlayerAction
|
|
254
|
+
- DetermineMoveOrder
|
|
255
|
+
- CompareMovePriority
|
|
256
|
+
- GetMovePriority
|
|
257
|
+
- Battle_*
|
|
258
|
+
- Handle*Switch
|
|
259
|
+
- SwitchPlayerMon
|
|
260
|
+
- BreakAttraction
|
|
261
|
+
- SendOutPlayerMon
|
|
262
|
+
- SpikesDamage
|
|
263
|
+
- *Turn_EndOpponentProtectEndureDestinyBond
|
|
264
|
+
- EndUserDestinyBond
|
|
265
|
+
- Do*Turn
|
|
266
|
+
- EndOpponentProtectEndureDestinyBond
|
|
267
|
+
- ResidualDamage
|
|
268
|
+
- CheckFaint_*
|
|
269
|
+
- HandleBetweenTurnEffects
|
|
270
|
+
- HandleFutureSight
|
|
271
|
+
- HandleWeather
|
|
272
|
+
- HandleWrap
|
|
273
|
+
- HandlePerishSong
|
|
274
|
+
- HandleLeftovers
|
|
275
|
+
- HandleMysteryBerry
|
|
276
|
+
- HandleDefrost
|
|
277
|
+
- HandleSafeguard
|
|
278
|
+
- HandleScreens
|
|
279
|
+
- HandleStatBoostingHeldItems
|
|
280
|
+
- HandleHealingItems
|
|
281
|
+
- HandleEncore
|
|
282
|
+
|
|
283
|
+
DoTurn
|
|
284
|
+
DoMove = executeMove
|
|
285
|
+
CheckTurn = beforeMove
|
|
286
|
+
BattleCommand_Critical = checkCriticalHit
|
|
287
|
+
BattleCommand_Stab = adjustDamage
|
|
288
|
+
BattleCommand_DamageVariation = randomizeDamage
|
|
289
|
+
BattleCommand_CheckHit = checkHit
|
|
290
|
+
BattleCommand_ApplyDamage = applyDamage
|
|
291
|
+
BattleCommand_CheckFaint
|
|
292
|
+
BattleCommand_BuildOpponentRage = buildRage
|
|
293
|
+
BattleCommand_DamageCalc (PlayerAttackDamage / EnemyAttackDamage) = calcDamage
|
|
294
|
+
BattleCommand_ConstantDamage = specialDamage
|
|
295
|
+
DoEnemyDamage / DoPlayerDamage / DoSubstituteDamage
|
|
296
|
+
|
|
222
297
|
==**TODO**==
|
|
223
298
|
|
|
224
299
|
## Protocol
|
|
@@ -226,62 +301,7 @@ padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
|
|
|
226
301
|
TODO
|
|
227
302
|
|
|
228
303
|
```txt
|
|
229
|
-
-activate: _,
|
|
230
|
-
-anim: _
|
|
231
|
-
-block: _
|
|
232
|
-
-boost: _, from, silent
|
|
233
|
-
-clearallboost: _
|
|
234
|
-
-copyboost: from
|
|
235
|
-
-crit: _
|
|
236
|
-
-curestatus: msg
|
|
237
|
-
-cureteam: from
|
|
238
|
-
-damage: _, from, of, partiallytrapped
|
|
239
|
-
-end: _, from, of, partiallytrapped, silent
|
|
240
|
-
-enditem: _, eat
|
|
241
|
-
-fail: _, block, weak
|
|
242
|
-
-fieldactivate: _
|
|
243
|
-
-heal: _, from, of, silent
|
|
244
|
-
-hint: _
|
|
245
|
-
-hitcount: _
|
|
246
|
-
-immune: _, ohko
|
|
247
|
-
-item: from, of
|
|
248
|
-
-miss: _
|
|
249
|
-
-mustrecharge: _
|
|
250
|
-
-ohko: _
|
|
251
|
-
-prepare: _
|
|
252
|
-
-resisted: _
|
|
253
|
-
-setboost: from
|
|
254
|
-
-sethp: from, silent
|
|
255
|
-
-sideend: _, from, of
|
|
256
|
-
-sidestart: _
|
|
257
|
-
-singlemove: _
|
|
258
|
-
-singleturn: _
|
|
259
|
-
-start: _, of, silent
|
|
260
|
-
-status: _, from, silent
|
|
261
|
-
-supereffective: _
|
|
262
|
-
-transform: _
|
|
263
|
-
-unboost: _
|
|
264
|
-
-weather: _, upkeep
|
|
265
|
-
cant: _
|
|
266
|
-
debug: _
|
|
267
|
-
done: _
|
|
268
|
-
drag: _
|
|
269
|
-
faint: _
|
|
270
|
-
gametype: _
|
|
271
|
-
gen: _
|
|
272
|
-
move: _, from, miss, still
|
|
273
|
-
player: _
|
|
274
|
-
request: _
|
|
275
|
-
rule: _
|
|
276
|
-
start: _
|
|
277
|
-
switch: _, from
|
|
278
|
-
t:: _
|
|
279
|
-
teamsize: _
|
|
280
|
-
tie: _
|
|
281
|
-
tier: _
|
|
282
|
-
turn: _
|
|
283
|
-
upkeep: _
|
|
284
|
-
win: _
|
|
304
|
+
-activate: _, move, name, number
|
|
285
305
|
```
|
|
286
306
|
|
|
287
307
|
## Bugs
|