@pkmn/engine 0.1.0-dev.1336408 → 0.1.0-dev.14ca6108
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/layout.json +2 -2
- package/build/pkg/gen1.js +2 -2
- package/build/pkg/gen1.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/common/protocol.zig +4 -0
- package/src/lib/gen1/README.md +28 -28
- package/src/lib/gen1/data.zig +6 -6
- package/src/lib/gen1/mechanics.zig +21 -21
- package/src/lib/gen2/README.md +1 -1
- package/src/lib/gen2/data/types.zig +3 -2
- package/src/lib/gen2/data.zig +2 -2
- package/src/lib/gen2/mechanics.zig +462 -634
|
@@ -6,6 +6,7 @@ const common = @import("../common/data.zig");
|
|
|
6
6
|
const DEBUG = @import("../common/debug.zig").print;
|
|
7
7
|
const protocol = @import("../common/protocol.zig");
|
|
8
8
|
const rng = @import("../common/rng.zig");
|
|
9
|
+
const util = @import("../common/util.zig");
|
|
9
10
|
|
|
10
11
|
const data = @import("data.zig");
|
|
11
12
|
|
|
@@ -13,14 +14,15 @@ const assert = std.debug.assert;
|
|
|
13
14
|
|
|
14
15
|
const expectEqual = std.testing.expectEqual;
|
|
15
16
|
const expectEqualSlices = std.testing.expectEqualSlices;
|
|
17
|
+
const expectEqualStrings = std.testing.expectEqualStrings;
|
|
18
|
+
|
|
19
|
+
const showdown = pkmn.options.showdown;
|
|
16
20
|
|
|
17
21
|
const Choice = common.Choice;
|
|
18
22
|
const ID = common.ID;
|
|
19
23
|
const Player = common.Player;
|
|
20
24
|
const Result = common.Result;
|
|
21
25
|
|
|
22
|
-
const showdown = pkmn.options.showdown;
|
|
23
|
-
|
|
24
26
|
const Activate = protocol.Activate;
|
|
25
27
|
const Cant = protocol.Cant;
|
|
26
28
|
const Damage = protocol.Damage;
|
|
@@ -30,6 +32,8 @@ const Start = protocol.Start;
|
|
|
30
32
|
|
|
31
33
|
const Gen12 = rng.Gen12;
|
|
32
34
|
|
|
35
|
+
const PointerType = util.PointerType;
|
|
36
|
+
|
|
33
37
|
const ActivePokemon = data.ActivePokemon;
|
|
34
38
|
const Effectiveness = data.Effectiveness;
|
|
35
39
|
const Item = data.Item;
|
|
@@ -89,6 +93,25 @@ const CRITICAL_HITS = &[_]u8{
|
|
|
89
93
|
|
|
90
94
|
const MAX_STAT_VALUE = 999;
|
|
91
95
|
|
|
96
|
+
const State = struct {
|
|
97
|
+
damage: u16 = 0,
|
|
98
|
+
effectiveness: u16 = Effectiveness.neutral,
|
|
99
|
+
bp: u8 = 0,
|
|
100
|
+
move: Move = .None,
|
|
101
|
+
mslot: u4 = 0,
|
|
102
|
+
first: bool = false,
|
|
103
|
+
miss: bool = false,
|
|
104
|
+
crit: bool = false,
|
|
105
|
+
|
|
106
|
+
comptime {
|
|
107
|
+
assert(@sizeOf(State) == 10);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
inline fn immune(self: *State) bool {
|
|
111
|
+
return self.effectiveness == 0;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
92
115
|
pub fn update(battle: anytype, c1: Choice, c2: Choice, options: anytype) !Result {
|
|
93
116
|
assert(c1.type != .Pass or c2.type != .Pass or battle.turn == 0);
|
|
94
117
|
if (battle.turn == 0) return start(battle, options);
|
|
@@ -167,14 +190,14 @@ fn selectMove(battle: anytype, player: Player, choice: Choice) void {
|
|
|
167
190
|
if (choice.data == 0) {
|
|
168
191
|
const struggle = ok: {
|
|
169
192
|
for (side.active.moves, 0..) |move, i| {
|
|
170
|
-
if (move.pp > 0 and volatiles.
|
|
193
|
+
if (move.pp > 0 and volatiles.disable.move != i + 1) break :ok false;
|
|
171
194
|
}
|
|
172
195
|
break :ok true;
|
|
173
196
|
};
|
|
174
197
|
assert(struggle);
|
|
175
198
|
// TODO wCurPlayerMove = .Struggle;
|
|
176
199
|
} else {
|
|
177
|
-
assert(showdown or side.active.volatiles.
|
|
200
|
+
assert(showdown or side.active.volatiles.disable.move != choice.data);
|
|
178
201
|
const move = side.active.move(choice.data);
|
|
179
202
|
// You cannot *select* a move with 0 PP
|
|
180
203
|
assert(move.pp != 0);
|
|
@@ -326,6 +349,12 @@ fn doTurn(
|
|
|
326
349
|
volatiles.Endure = false;
|
|
327
350
|
volatiles.DestinyBond = false;
|
|
328
351
|
|
|
352
|
+
// FIXME
|
|
353
|
+
try handleResidual(battle, player, options);
|
|
354
|
+
|
|
355
|
+
// FIXME
|
|
356
|
+
try betweenTurns(battle, 0, options);
|
|
357
|
+
|
|
329
358
|
return null;
|
|
330
359
|
}
|
|
331
360
|
|
|
@@ -342,16 +371,16 @@ fn executeMove(
|
|
|
342
371
|
}
|
|
343
372
|
|
|
344
373
|
assert(choice.type == .Move);
|
|
345
|
-
var mslot:
|
|
346
|
-
|
|
347
|
-
// const move = Move.get(side.last_selected_move);
|
|
374
|
+
var mslot: u4 = @intCast(choice.data);
|
|
375
|
+
var move = Move.Pound; // TODO
|
|
348
376
|
|
|
349
|
-
|
|
377
|
+
if (!try beforeMove(battle, player, move, options)) return null;
|
|
350
378
|
|
|
351
|
-
|
|
379
|
+
var state: State = .{ .move = move, .mslot = mslot, .first = first };
|
|
380
|
+
return doMove(battle, player, &state, options);
|
|
352
381
|
}
|
|
353
382
|
|
|
354
|
-
fn beforeMove(battle: anytype, player: Player, options: anytype) !bool {
|
|
383
|
+
fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bool {
|
|
355
384
|
var log = options.log;
|
|
356
385
|
var side = battle.side(player);
|
|
357
386
|
// const foe = battle.foe(player);
|
|
@@ -360,8 +389,6 @@ fn beforeMove(battle: anytype, player: Player, options: anytype) !bool {
|
|
|
360
389
|
const ident = battle.active(player);
|
|
361
390
|
var volatiles = &active.volatiles;
|
|
362
391
|
|
|
363
|
-
const move = Move.Pound; // TODO
|
|
364
|
-
|
|
365
392
|
if (volatiles.Recharging) {
|
|
366
393
|
volatiles.Recharging = false;
|
|
367
394
|
cantMove(volatiles);
|
|
@@ -412,16 +439,16 @@ fn beforeMove(battle: anytype, player: Player, options: anytype) !bool {
|
|
|
412
439
|
return false;
|
|
413
440
|
}
|
|
414
441
|
|
|
415
|
-
if (volatiles.
|
|
442
|
+
if (volatiles.disable.duration > 0) {
|
|
416
443
|
// if (options.calc.modify(player, .disable)) |extend| {
|
|
417
|
-
// if (!extend) volatiles.
|
|
444
|
+
// if (!extend) volatiles.disable.duration = 0;
|
|
418
445
|
// } else {
|
|
419
|
-
volatiles.
|
|
446
|
+
volatiles.disable.duration -= 1;
|
|
420
447
|
// }
|
|
421
|
-
try options.chance.disable(player, volatiles.
|
|
448
|
+
try options.chance.disable(player, volatiles.disable.duration);
|
|
422
449
|
|
|
423
|
-
if (volatiles.
|
|
424
|
-
volatiles.
|
|
450
|
+
if (volatiles.disable.duration == 0) {
|
|
451
|
+
volatiles.disable.move = 0;
|
|
425
452
|
try log.end(ident, .Disable);
|
|
426
453
|
}
|
|
427
454
|
}
|
|
@@ -455,7 +482,7 @@ fn beforeMove(battle: anytype, player: Player, options: anytype) !bool {
|
|
|
455
482
|
}
|
|
456
483
|
|
|
457
484
|
if (volatiles.Attract) {
|
|
458
|
-
try log.
|
|
485
|
+
try log.activate(ident, .Attract);
|
|
459
486
|
|
|
460
487
|
if (try Rolls.attract(battle, player, options)) {
|
|
461
488
|
cantMove(volatiles);
|
|
@@ -464,9 +491,9 @@ fn beforeMove(battle: anytype, player: Player, options: anytype) !bool {
|
|
|
464
491
|
}
|
|
465
492
|
}
|
|
466
493
|
|
|
467
|
-
if (side.active.volatiles.
|
|
468
|
-
// A Pokémon that transforms after being
|
|
469
|
-
const m = side.active.moves[side.active.volatiles.
|
|
494
|
+
if (side.active.volatiles.disable.move != 0) {
|
|
495
|
+
// A Pokémon that transforms after being disable may end up with less move slots
|
|
496
|
+
const m = side.active.moves[side.active.volatiles.disable.move - 1].id;
|
|
470
497
|
if (m != .None and m == move) {
|
|
471
498
|
side.active.volatiles.Charging = false;
|
|
472
499
|
cantMove(volatiles);
|
|
@@ -484,7 +511,7 @@ fn beforeMove(battle: anytype, player: Player, options: anytype) !bool {
|
|
|
484
511
|
return true;
|
|
485
512
|
}
|
|
486
513
|
|
|
487
|
-
fn cantMove(volatiles: *Volatiles) void {
|
|
514
|
+
fn cantMove(volatiles: *align(8) Volatiles) void {
|
|
488
515
|
volatiles.Bide = false;
|
|
489
516
|
volatiles.Thrashing = false;
|
|
490
517
|
volatiles.Charging = false;
|
|
@@ -495,7 +522,7 @@ fn cantMove(volatiles: *Volatiles) void {
|
|
|
495
522
|
volatiles.fury_cutter = 0;
|
|
496
523
|
}
|
|
497
524
|
|
|
498
|
-
fn canMove(battle: anytype, player: Player, options: anytype) !
|
|
525
|
+
fn canMove(battle: anytype, player: Player, options: anytype) !void {
|
|
499
526
|
_ = battle;
|
|
500
527
|
_ = player;
|
|
501
528
|
_ = options;
|
|
@@ -520,325 +547,56 @@ fn decrementPP(side: *Side, mslot: u3) void {
|
|
|
520
547
|
assert(active.move(mslot).pp == side.stored().move(mslot).pp);
|
|
521
548
|
}
|
|
522
549
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
.Curse => {
|
|
568
|
-
try Effects.curse(battle, player, options); // TODO
|
|
569
|
-
},
|
|
570
|
-
.DefenseCurl => {
|
|
571
|
-
try Effects.defenseCurl(battle, player, options); // TODO
|
|
572
|
-
},
|
|
573
|
-
.DestinyBond => {
|
|
574
|
-
try Effects.destinyBond(battle, player, options); // TODO
|
|
575
|
-
},
|
|
576
|
-
.Disable => {
|
|
577
|
-
try Effects.disable(battle, player, options); // TODO
|
|
578
|
-
},
|
|
579
|
-
.DrainHP, .DreamEater => {
|
|
580
|
-
try Effects.drainHP(battle, player, options); // TODO
|
|
581
|
-
},
|
|
582
|
-
.Encore => {
|
|
583
|
-
try Effects.encore(battle, player, first, options); // TODO
|
|
584
|
-
},
|
|
585
|
-
.Endure => {
|
|
586
|
-
try Effects.protect(battle, player, Move.Endure, first, options); // TODO
|
|
587
|
-
},
|
|
588
|
-
.Explode => {
|
|
589
|
-
try Effects.explode(battle, player, options); // TODO
|
|
590
|
-
},
|
|
591
|
-
.FalseSwipe => {
|
|
592
|
-
var damage: u16 = 0; // TODO
|
|
593
|
-
damage = try Effects.falseSwipe(battle, player, damage);
|
|
594
|
-
},
|
|
595
|
-
.FixedDamage, .Psywave, .SuperFang => {
|
|
596
|
-
try Effects.fixedDamage(battle, player, move, options); // TODO
|
|
597
|
-
},
|
|
598
|
-
.FlameWheel => {
|
|
599
|
-
try Effects.flameWheel(battle, player, options); // TODO
|
|
600
|
-
},
|
|
601
|
-
.FlinchChance => {
|
|
602
|
-
try Effects.flinchChance(battle, player, move, options); // TODO
|
|
603
|
-
},
|
|
604
|
-
.FlyDig => {
|
|
605
|
-
try Effects.flyDig(battle, player, move, options); // TODO
|
|
606
|
-
},
|
|
607
|
-
.FocusEnergy => {
|
|
608
|
-
try Effects.focusEnergy(battle, player, options); // TODO
|
|
609
|
-
},
|
|
610
|
-
.ForceSwitch => {
|
|
611
|
-
try Effects.forceSwitch(battle, player, options); // TODO
|
|
612
|
-
},
|
|
613
|
-
.Foresight => {
|
|
614
|
-
try Effects.foresight(battle, player, options); // TODO
|
|
615
|
-
},
|
|
616
|
-
.FreezeChance => {
|
|
617
|
-
try Effects.freezeChance(battle, player, move, options); // TODO
|
|
618
|
-
},
|
|
619
|
-
.FuryCutter => {
|
|
620
|
-
try Effects.furyCutter(battle, player, options); // TODO
|
|
621
|
-
},
|
|
622
|
-
.FutureSight => {
|
|
623
|
-
try Effects.futureSight(battle, player, options); // TODO
|
|
624
|
-
},
|
|
625
|
-
.Return, .Frustration => {
|
|
626
|
-
const bp = try Effects.happiness(battle, player, move); // TODO
|
|
627
|
-
_ = bp;
|
|
628
|
-
},
|
|
629
|
-
.Haze => {
|
|
630
|
-
try Effects.haze(battle, player, options); // TODO
|
|
631
|
-
},
|
|
632
|
-
.Heal => {
|
|
633
|
-
try Effects.heal(battle, player, options); // TODO
|
|
634
|
-
},
|
|
635
|
-
.HealBell => {
|
|
636
|
-
try Effects.healBell(battle, player, options); // TODO
|
|
637
|
-
},
|
|
638
|
-
.HiddenPower => {
|
|
639
|
-
try Effects.hiddenPower(battle, player, options); // TODO
|
|
640
|
-
},
|
|
641
|
-
.HyperBeam => {
|
|
642
|
-
try Effects.hyperBeam(battle, player, options); // TODO
|
|
643
|
-
},
|
|
644
|
-
.JumpKick => {
|
|
645
|
-
try Effects.jumpKick(battle, player, options); // TODO
|
|
646
|
-
},
|
|
647
|
-
.LeechSeed => {
|
|
648
|
-
try Effects.leechSeed(battle, player, options); // TODO
|
|
649
|
-
},
|
|
650
|
-
.LevelDamage => {
|
|
651
|
-
try Effects.levelDamage(battle, player, options); // TODO
|
|
652
|
-
},
|
|
653
|
-
.LightScreen, .Reflect => {
|
|
654
|
-
try Effects.screens(battle, player, move, options); // TODO
|
|
655
|
-
},
|
|
656
|
-
.LockOn => {
|
|
657
|
-
try Effects.lockOn(battle, player, options); // TODO
|
|
658
|
-
},
|
|
659
|
-
.Magnitude => {
|
|
660
|
-
try Effects.magnitude(battle, player, options); // TODO
|
|
661
|
-
},
|
|
662
|
-
.MeanLook => {
|
|
663
|
-
try Effects.meanLook(battle, player, options); // TODO
|
|
664
|
-
},
|
|
665
|
-
.Metronome => {
|
|
666
|
-
try Effects.metronome(battle, player, options); // TODO
|
|
667
|
-
},
|
|
668
|
-
.Mimic => {
|
|
669
|
-
try Effects.mimic(battle, player, options); // TODO
|
|
670
|
-
},
|
|
671
|
-
.MirrorCoat => {
|
|
672
|
-
try Effects.mirrorCoat(battle, player, options); // TODO
|
|
673
|
-
},
|
|
674
|
-
.MirrorMove => {
|
|
675
|
-
try Effects.mirrorMove(battle, player, options); // TODO
|
|
676
|
-
},
|
|
677
|
-
.Mist => {
|
|
678
|
-
try Effects.mist(battle, player, options); // TODO
|
|
679
|
-
},
|
|
680
|
-
.Moonlight, .MorningSun => {
|
|
681
|
-
try Effects.weatherHeal(battle, player, options); // TODO
|
|
682
|
-
},
|
|
683
|
-
.MultiHit, .DoubleHit, .Twineedle => {
|
|
684
|
-
try Effects.multiHit(battle, player, options); // TODO
|
|
685
|
-
},
|
|
686
|
-
.Nightmare => {
|
|
687
|
-
try Effects.nightmare(battle, player, options); // TODO
|
|
688
|
-
},
|
|
689
|
-
.OHKO => {
|
|
690
|
-
try Effects.ohko(battle, player, options); // TODO
|
|
691
|
-
},
|
|
692
|
-
.PainSplit => {
|
|
693
|
-
try Effects.painSplit(battle, player, options); // TODO
|
|
694
|
-
},
|
|
695
|
-
.Paralyze => {
|
|
696
|
-
try Effects.paralyze(battle, player, options); // TODO
|
|
697
|
-
},
|
|
698
|
-
.ParalyzeChance, .Thunder => {
|
|
699
|
-
try Effects.paralyzeChance(battle, player, options); // TODO
|
|
700
|
-
},
|
|
701
|
-
.PayDay => {
|
|
702
|
-
try Effects.payDay(battle, player, options); // TODO
|
|
703
|
-
},
|
|
704
|
-
.PerishSong => {
|
|
705
|
-
try Effects.perishSong(battle, player, options); // TODO
|
|
706
|
-
},
|
|
707
|
-
.Poison, .PoisonChance, .Toxic => {
|
|
708
|
-
try Effects.poison(battle, player, move, options); // TODO
|
|
709
|
-
},
|
|
710
|
-
.Present => {
|
|
711
|
-
try Effects.present(battle, player, options); // TODO
|
|
712
|
-
},
|
|
713
|
-
.Protect => {
|
|
714
|
-
try Effects.protect(battle, player, Move.Protect, first, options); // TODO Detect?
|
|
715
|
-
},
|
|
716
|
-
.PsychUp => {
|
|
717
|
-
try Effects.psychUp(battle, player, options); // TODO
|
|
718
|
-
},
|
|
719
|
-
.Pursuit => {
|
|
720
|
-
try Effects.pursuit(battle, player, options); // TODO
|
|
721
|
-
},
|
|
722
|
-
.Rage => {
|
|
723
|
-
try Effects.rage(battle, player, options); // TODO
|
|
724
|
-
},
|
|
725
|
-
.RainDance => {
|
|
726
|
-
try Effects.rainDance(battle, player, options); // TODOq
|
|
727
|
-
},
|
|
728
|
-
.RapidSpin => {
|
|
729
|
-
try Effects.rapidSpin(battle, player, options); // TODO
|
|
730
|
-
},
|
|
731
|
-
.RazorWind => {
|
|
732
|
-
try Effects.razorWind(battle, player, options); // TODO
|
|
733
|
-
},
|
|
734
|
-
.Recoil => {
|
|
735
|
-
try Effects.recoil(battle, player, options); // TODO
|
|
736
|
-
},
|
|
737
|
-
.Reversal => {
|
|
738
|
-
try Effects.reversal(battle, player, options); // TODO
|
|
739
|
-
},
|
|
740
|
-
.Rollout => {
|
|
741
|
-
try Effects.rollout(battle, player, options); // TODO
|
|
742
|
-
},
|
|
743
|
-
.SacredFire => {
|
|
744
|
-
try Effects.sacredFire(battle, player, options); // TODO
|
|
745
|
-
},
|
|
746
|
-
.Safeguard => {
|
|
747
|
-
try Effects.safeguard(battle, player, options); // TODO
|
|
748
|
-
},
|
|
749
|
-
.Sandstorm => {
|
|
750
|
-
try Effects.sandstorm(battle, player, options); // TODO
|
|
751
|
-
},
|
|
752
|
-
.Sketch => {
|
|
753
|
-
try Effects.sketch(battle, player, options); // TODO
|
|
754
|
-
},
|
|
755
|
-
.SkullBash => {
|
|
756
|
-
try Effects.skullBash(battle, player, options); // TODO
|
|
757
|
-
},
|
|
758
|
-
.SkyAttack => {
|
|
759
|
-
try Effects.skyAttack(battle, player, options); // TODO
|
|
760
|
-
},
|
|
761
|
-
.Sleep => {
|
|
762
|
-
try Effects.sleep(battle, player, options); // TODO
|
|
763
|
-
},
|
|
764
|
-
.SleepTalk => {
|
|
765
|
-
try Effects.sleepTalk(battle, player, mslot, options); // TODO
|
|
766
|
-
},
|
|
767
|
-
.Snore => {
|
|
768
|
-
try Effects.snore(battle, player, options); // TODO
|
|
769
|
-
},
|
|
770
|
-
.Solarbeam => {
|
|
771
|
-
try Effects.solarBeam(battle, player, options); // TODO
|
|
772
|
-
},
|
|
773
|
-
.Spikes => {
|
|
774
|
-
try Effects.spikes(battle, player, options); // TODO
|
|
775
|
-
},
|
|
776
|
-
.Spite => {
|
|
777
|
-
try Effects.spite(battle, player, options); // TODO
|
|
778
|
-
},
|
|
779
|
-
.Splash => {
|
|
780
|
-
try Effects.splash(battle, player, options); // TODO
|
|
781
|
-
},
|
|
782
|
-
.Stomp => {
|
|
783
|
-
try Effects.stomp(battle, player, options); // TODO
|
|
784
|
-
},
|
|
785
|
-
.Substitute => {
|
|
786
|
-
try Effects.substitute(battle, player, options); // TODO
|
|
787
|
-
},
|
|
788
|
-
.SunnyDay => {
|
|
789
|
-
try Effects.sunnyDay(battle, player, options); // TODO
|
|
790
|
-
},
|
|
791
|
-
.Swagger => {
|
|
792
|
-
try Effects.swagger(battle, player, options); // TODO
|
|
793
|
-
},
|
|
794
|
-
.Synthesis => {
|
|
795
|
-
try Effects.synthesis(battle, player, options); // TODO
|
|
796
|
-
},
|
|
797
|
-
.Teleport => {
|
|
798
|
-
try Effects.teleport(battle, player, options); // TODO
|
|
799
|
-
},
|
|
800
|
-
.Thief => {
|
|
801
|
-
try Effects.thief(battle, player, options); // TODO
|
|
802
|
-
},
|
|
803
|
-
.Thrashing => {
|
|
804
|
-
try Effects.thrashing(battle, player, options); // TODO
|
|
805
|
-
},
|
|
806
|
-
.Transform => {
|
|
807
|
-
try Effects.transform(battle, player, options); // TODO
|
|
808
|
-
},
|
|
809
|
-
.TripleKick => {
|
|
810
|
-
try Effects.tripleKick(battle, player, options); // TODO
|
|
811
|
-
},
|
|
812
|
-
.Twister => {
|
|
813
|
-
try Effects.twister(battle, player, options); // TODO
|
|
814
|
-
},
|
|
815
|
-
// zig fmt: off
|
|
816
|
-
.AllStatUpChance,
|
|
817
|
-
.AttackUp1, .AttackUp2, .AttackUpChance,
|
|
818
|
-
.DefenseUp1, .DefenseUp2, .DefenseUpChance,
|
|
819
|
-
.EvasionUp1,
|
|
820
|
-
.SpAtkUp1,
|
|
821
|
-
.SpDefUp2,
|
|
822
|
-
.SpeedUp2 => {
|
|
823
|
-
// zig fmt: on
|
|
824
|
-
try Effects.boost(battle, player, move, options); // TODO
|
|
825
|
-
},
|
|
826
|
-
// zig fmt: off
|
|
827
|
-
.AccuracyDown1, .AccuracyDownChance,
|
|
828
|
-
.AttackDown1, .AttackDown2, .AttackDownChance,
|
|
829
|
-
.DefenseDown1, .DefenseDown2, .DefenseDownChance,
|
|
830
|
-
.EvasionDown1,
|
|
831
|
-
.SpDefDownChance,
|
|
832
|
-
.SpeedDown1, .SpeedDown2, .SpeedDownChance => {
|
|
833
|
-
// zig fmt: on
|
|
834
|
-
try Effects.unboost(battle, player, move, options); // TODO
|
|
835
|
-
},
|
|
836
|
-
}
|
|
550
|
+
const Command: type =
|
|
551
|
+
fn (battle: anytype, player: Player, state: *State, options: anytype) anyerror!void;
|
|
552
|
+
|
|
553
|
+
// zig fmt: off
|
|
554
|
+
// const COMMANDS = [_][]Command{
|
|
555
|
+
// // None
|
|
556
|
+
// (if (showdown) &[_]Command{
|
|
557
|
+
// // checkHit, checkCriticalHit, calcDamage, adjustDamage, randomizeDamage,
|
|
558
|
+
// // applyDamage, buildRage, kingsRock,
|
|
559
|
+
// } else &[_]Command{
|
|
560
|
+
// // checkCriticalHit, calcDamage, adjustDamage, randomizeDamage,
|
|
561
|
+
// // checkHit, applyDamage, buildRage, kingsRock,
|
|
562
|
+
// }),
|
|
563
|
+
// };
|
|
564
|
+
// zig fmt: on
|
|
565
|
+
|
|
566
|
+
fn doMove(battle: anytype, player: Player, state: *State, options: anytype) !?Result {
|
|
567
|
+
// FIXME
|
|
568
|
+
// const commands = COMMANDS[@intFromEnum(Move.get(state.move).effect)];
|
|
569
|
+
// for (commands) |command| {
|
|
570
|
+
// if (!try command(battle, player, state, options)) return null;
|
|
571
|
+
// }
|
|
572
|
+
// return null;
|
|
573
|
+
try checkCriticalHit(battle, player, state, options);
|
|
574
|
+
try calcDamage(battle, player, state, options);
|
|
575
|
+
try adjustDamage(battle, player, state, options);
|
|
576
|
+
try randomizeDamage(battle, player, state, options);
|
|
577
|
+
try applyDamage(battle, player, state, options);
|
|
578
|
+
try buildRage(battle, player, state, options);
|
|
579
|
+
try kingsRock(battle, player, state, options);
|
|
580
|
+
|
|
581
|
+
try Effects.attract(battle, player, state, options);
|
|
582
|
+
try Effects.conversion(battle, player, state, options);
|
|
583
|
+
try Effects.conversion2(battle, player, state, options);
|
|
584
|
+
try Effects.destinyBond(battle, player, state, options);
|
|
585
|
+
try Effects.disable(battle, player, state, options);
|
|
586
|
+
try Effects.encore(battle, player, state, options);
|
|
587
|
+
try Effects.falseSwipe(battle, player, state, options);
|
|
588
|
+
try Effects.focusEnergy(battle, player, state, options);
|
|
589
|
+
try Effects.forceSwitch(battle, player, state, options);
|
|
590
|
+
try Effects.foresight(battle, player, state, options);
|
|
591
|
+
try Effects.happiness(battle, player, state, options);
|
|
592
|
+
try Effects.protect(battle, player, state, options);
|
|
593
|
+
|
|
837
594
|
return null;
|
|
838
595
|
}
|
|
839
596
|
|
|
840
|
-
fn checkCriticalHit(battle: anytype, player: Player,
|
|
841
|
-
|
|
597
|
+
fn checkCriticalHit(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
598
|
+
const move = Move.get(state.move);
|
|
599
|
+
if (move.bp == 0) return;
|
|
842
600
|
|
|
843
601
|
const side = battle.side(player);
|
|
844
602
|
const pokemon = side.stored();
|
|
@@ -853,41 +611,38 @@ fn checkCriticalHit(battle: anytype, player: Player, move: Move.Data, options: a
|
|
|
853
611
|
}
|
|
854
612
|
assert(stage <= 4);
|
|
855
613
|
|
|
856
|
-
|
|
614
|
+
state.crit = try Rolls.criticalHit(battle, player, CRITICAL_HITS[stage], options);
|
|
857
615
|
}
|
|
858
616
|
|
|
859
617
|
fn calcDamage(
|
|
860
618
|
battle: anytype,
|
|
861
619
|
player: Player,
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
) u16 {
|
|
620
|
+
state: *State,
|
|
621
|
+
options: anytype,
|
|
622
|
+
) !void {
|
|
866
623
|
_ = battle;
|
|
867
624
|
_ = player;
|
|
868
|
-
_ =
|
|
869
|
-
_ =
|
|
870
|
-
_ = crit;
|
|
871
|
-
return 0;
|
|
625
|
+
_ = state;
|
|
626
|
+
_ = options;
|
|
872
627
|
}
|
|
873
628
|
|
|
874
629
|
const FORESIGHT: Types = .{ .type1 = .Normal, .type2 = .Fighting };
|
|
875
630
|
|
|
876
|
-
fn adjustDamage(battle: anytype, player: Player,
|
|
877
|
-
if (
|
|
631
|
+
fn adjustDamage(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
632
|
+
if (state.move == .Struggle) return;
|
|
878
633
|
|
|
879
634
|
const side = battle.side(player);
|
|
880
635
|
const foe = battle.foe(player);
|
|
881
636
|
const types = foe.active.types;
|
|
882
|
-
const move = Move.get(
|
|
637
|
+
const move = Move.get(state.move);
|
|
883
638
|
|
|
884
|
-
var d = damage;
|
|
639
|
+
var d = state.damage;
|
|
885
640
|
if ((move.type == .Water and battle.field.weather == .Rain) or
|
|
886
641
|
(move.type == .Fire and battle.field.weather == .Sun))
|
|
887
642
|
{
|
|
888
643
|
d = d *% @intFromEnum(Effectiveness.Super) / 10;
|
|
889
644
|
} else if ((move.type == .Water and battle.field.weather == .Sun) or
|
|
890
|
-
((move.type == .Fire or
|
|
645
|
+
((move.type == .Fire or state.move == .SolarBeam) and battle.field.weather == .Rain))
|
|
891
646
|
{
|
|
892
647
|
d = d *% @intFromEnum(Effectiveness.Resisted) / 10;
|
|
893
648
|
}
|
|
@@ -897,17 +652,17 @@ fn adjustDamage(battle: anytype, player: Player, m: Move, damage: u16, effective
|
|
|
897
652
|
const neutral = @intFromEnum(Effectiveness.Neutral);
|
|
898
653
|
const foresight = foe.active.volatiles.Foresight and FORESIGHT.includes(move.type);
|
|
899
654
|
const eff1: u16 = if (foresight and types.type1 == .Ghost)
|
|
900
|
-
|
|
655
|
+
neutral
|
|
901
656
|
else
|
|
902
657
|
@intFromEnum(move.type.effectiveness(types.type1));
|
|
903
658
|
const eff2: u16 = if (foresight and types.type2 == .Ghost)
|
|
904
|
-
|
|
659
|
+
neutral
|
|
905
660
|
else
|
|
906
661
|
@intFromEnum(move.type.effectiveness(types.type2));
|
|
907
662
|
|
|
908
663
|
// Type effectiveness matchup precedence only matters with (NVE, SE)
|
|
909
664
|
if (!showdown and (eff1 + eff2) == Effectiveness.mismatch and
|
|
910
|
-
|
|
665
|
+
types.type1.precedence() > types.type2.precedence())
|
|
911
666
|
{
|
|
912
667
|
assert(eff2 != neutral);
|
|
913
668
|
d = d *% eff2 / 10;
|
|
@@ -919,65 +674,79 @@ fn adjustDamage(battle: anytype, player: Player, m: Move, damage: u16, effective
|
|
|
919
674
|
if (types.type1 != types.type2 and eff2 != neutral) d = d *% eff2 / 10;
|
|
920
675
|
}
|
|
921
676
|
|
|
922
|
-
effectiveness
|
|
923
|
-
|
|
677
|
+
state.effectiveness = if (types.type1 == types.type2) eff1 * neutral else eff1 * eff2;
|
|
678
|
+
state.damage = d;
|
|
924
679
|
}
|
|
925
680
|
|
|
926
|
-
fn randomizeDamage(battle: anytype, player: Player,
|
|
927
|
-
if (damage <= 1) return;
|
|
681
|
+
fn randomizeDamage(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
682
|
+
if (state.damage <= 1) return;
|
|
928
683
|
const random = try Rolls.damage(battle, player, options);
|
|
929
|
-
options.calc.base(player.foe(), damage);
|
|
930
|
-
damage = @intCast(@as(u32, damage) *% random / 255);
|
|
931
|
-
options.calc.final(player.foe(), damage);
|
|
932
|
-
return damage;
|
|
684
|
+
options.calc.base(player.foe(), state.damage);
|
|
685
|
+
state.damage = @intCast(@as(u32, state.damage) *% random / 255);
|
|
686
|
+
options.calc.final(player.foe(), state.damage);
|
|
933
687
|
}
|
|
934
688
|
|
|
935
689
|
fn applyDamage(
|
|
936
690
|
battle: anytype,
|
|
937
691
|
player: Player,
|
|
692
|
+
state: *State,
|
|
938
693
|
options: anytype,
|
|
939
|
-
) !
|
|
694
|
+
) !void {
|
|
940
695
|
_ = battle;
|
|
941
696
|
_ = player;
|
|
697
|
+
_ = state;
|
|
942
698
|
_ = options;
|
|
943
|
-
return false;
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
fn checkHit(battle: anytype, player: Player, move: Move.Data, options: anytype) !bool {
|
|
947
|
-
if (try moveHit(battle, player, move, options)) return true;
|
|
948
|
-
|
|
949
|
-
// try options.chance.commit(player, .miss);
|
|
950
|
-
// try options.log.lastmiss();
|
|
951
|
-
// try options.log.miss(battle.active(player));
|
|
952
|
-
|
|
953
|
-
return false;
|
|
954
699
|
}
|
|
955
700
|
|
|
956
701
|
// TODO: set damage = 0 if missed and not (High) Jump Kick
|
|
957
|
-
fn
|
|
702
|
+
fn checkHit(
|
|
958
703
|
battle: anytype,
|
|
959
704
|
player: Player,
|
|
960
|
-
|
|
705
|
+
state: *State,
|
|
961
706
|
options: anytype,
|
|
962
|
-
) !
|
|
707
|
+
) !void {
|
|
963
708
|
const side = battle.side(player);
|
|
964
709
|
const foe = battle.foe(player);
|
|
965
710
|
|
|
966
|
-
|
|
967
|
-
|
|
711
|
+
const move = Move.get(state.move);
|
|
712
|
+
|
|
713
|
+
if (move.effect == .DreamEater and !Status.is(foe.stored().status, .SLP)) {
|
|
714
|
+
state.miss = true;
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
if (foe.active.volatiles.Protect) {
|
|
718
|
+
state.miss = true;
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
968
721
|
const drain = move.effect == .DrainHP or move.effect == .DreamEater;
|
|
969
|
-
if (drain and foe.active.volatiles.Substitute)
|
|
722
|
+
if (drain and foe.active.volatiles.Substitute) {
|
|
723
|
+
state.miss = true;
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
970
726
|
if (side.active.volatiles.LockOn) {
|
|
971
|
-
|
|
727
|
+
state.miss = !(foe.active.volatiles.Flying and move.extra.undeground);
|
|
728
|
+
return;
|
|
972
729
|
}
|
|
973
730
|
assert(!(foe.active.volatiles.Flying and foe.active.volatiles.Underground));
|
|
974
731
|
if (foe.active.volatiles.Flying) {
|
|
975
|
-
if (!move.extra.flying)
|
|
732
|
+
if (!move.extra.flying) {
|
|
733
|
+
state.miss = true;
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
976
736
|
} else if (foe.active.volatiles.Underground) {
|
|
977
|
-
if (!move.extra.underground)
|
|
737
|
+
if (!move.extra.underground) {
|
|
738
|
+
state.miss = true;
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (move.effect == .Thunder and battle.field.weather == .Rain) {
|
|
743
|
+
state.miss = false;
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
if (move.effect == .AlwaysHit) {
|
|
747
|
+
state.miss = false;
|
|
748
|
+
return;
|
|
978
749
|
}
|
|
979
|
-
if (move.effect == .Thunder and battle.field.weather == .Rain) return true;
|
|
980
|
-
if (move.effect == .AlwaysHit) return true;
|
|
981
750
|
|
|
982
751
|
var accuracy: u16 = move.accuracy;
|
|
983
752
|
if (foe.active.boosts.evasion <= side.active.boosts.accuracy or
|
|
@@ -995,17 +764,21 @@ fn moveHit(
|
|
|
995
764
|
}
|
|
996
765
|
|
|
997
766
|
// The accuracy roll is skipped entirely if maxed
|
|
998
|
-
if (accuracy == 255)
|
|
999
|
-
|
|
767
|
+
state.miss = if (accuracy == 255)
|
|
768
|
+
false
|
|
769
|
+
else
|
|
770
|
+
!try Rolls.hit(battle, player, @intCast(accuracy), options);
|
|
1000
771
|
}
|
|
1001
772
|
|
|
1002
773
|
fn checkFaint(
|
|
1003
774
|
battle: anytype,
|
|
1004
775
|
player: Player,
|
|
776
|
+
state: *State,
|
|
1005
777
|
options: anytype,
|
|
1006
778
|
) @TypeOf(options.log).Error!?Result {
|
|
1007
779
|
_ = battle;
|
|
1008
780
|
_ = player;
|
|
781
|
+
_ = state;
|
|
1009
782
|
return null;
|
|
1010
783
|
}
|
|
1011
784
|
|
|
@@ -1067,20 +840,20 @@ fn handleResidual(battle: anytype, player: Player, options: anytype) !void {
|
|
|
1067
840
|
if (volatiles.Nightmare) {
|
|
1068
841
|
stored.hp -= @max(stored.stats.hp / 4, 1);
|
|
1069
842
|
// ibid
|
|
1070
|
-
try options.log.damage(ident, stored,
|
|
843
|
+
try options.log.damage(ident, stored, .Nightmare);
|
|
1071
844
|
if (stored.hp == 0) return;
|
|
1072
845
|
}
|
|
1073
846
|
|
|
1074
847
|
if (volatiles.Curse) {
|
|
1075
848
|
stored.hp -= @max(stored.stats.hp / 4, 1);
|
|
1076
849
|
// ibid
|
|
1077
|
-
try options.log.damage(ident, stored,
|
|
850
|
+
try options.log.damage(ident, stored, .Curse);
|
|
1078
851
|
if (stored.hp == 0) return;
|
|
1079
852
|
}
|
|
1080
853
|
}
|
|
1081
854
|
|
|
1082
|
-
fn betweenTurns(battle: anytype, mslot:
|
|
1083
|
-
const players = std.enums.values(Player);
|
|
855
|
+
fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !void {
|
|
856
|
+
const players = comptime std.enums.values(Player);
|
|
1084
857
|
|
|
1085
858
|
// TODO checkFaintThen(p1, p2);
|
|
1086
859
|
|
|
@@ -1114,7 +887,7 @@ fn betweenTurns(battle: anytype, mslot: u3, options: anytype) !void {
|
|
|
1114
887
|
inline for (players) |player| {
|
|
1115
888
|
var side = battle.side(player);
|
|
1116
889
|
const active = side.active;
|
|
1117
|
-
if (!(active.volatiles.
|
|
890
|
+
if (!(active.volatiles.Underground or active.types.sandstormImmune())) {
|
|
1118
891
|
side.stored().hp -|= @max(side.stored().stats.hp / 8, 1);
|
|
1119
892
|
try options.log.damage(battle.active(player), side.stored(), .Sandstorm);
|
|
1120
893
|
}
|
|
@@ -1129,18 +902,18 @@ fn betweenTurns(battle: anytype, mslot: u3, options: anytype) !void {
|
|
|
1129
902
|
var side = battle.side(player);
|
|
1130
903
|
var volatiles = &side.active.volatiles;
|
|
1131
904
|
|
|
1132
|
-
if (volatiles.bind > 0 and !volatiles.Substitute) {
|
|
1133
|
-
volatiles.bind -= 1;
|
|
1134
|
-
if (volatiles.bind == 0) {
|
|
1135
|
-
const reason = @intFromEnum(End.Bind) + volatiles.
|
|
905
|
+
if (volatiles.bind.duration > 0 and !volatiles.Substitute) {
|
|
906
|
+
volatiles.bind.duration -= 1;
|
|
907
|
+
if (volatiles.bind.duration == 0) {
|
|
908
|
+
const reason = @intFromEnum(End.Bind) + volatiles.bind.reason - 1;
|
|
1136
909
|
try options.log.end(battle.active(player), @enumFromInt(reason));
|
|
1137
910
|
} else {
|
|
1138
|
-
var reason = @intFromEnum(Activate.Bind) + volatiles.
|
|
911
|
+
var reason = @intFromEnum(Activate.Bind) + volatiles.bind.reason - 1;
|
|
1139
912
|
try options.log.activate(battle.active(player), @enumFromInt(reason));
|
|
1140
913
|
|
|
1141
|
-
reason = @intFromEnum(
|
|
914
|
+
reason = @intFromEnum(Damage.Bind) + volatiles.bind.reason - 1;
|
|
1142
915
|
side.stored().hp -|= @max(side.stored().stats.hp / 16, 1);
|
|
1143
|
-
try options.log.damage(battle.active(player), side.stored(), reason);
|
|
916
|
+
try options.log.damage(battle.active(player), side.stored(), @enumFromInt(reason));
|
|
1144
917
|
}
|
|
1145
918
|
}
|
|
1146
919
|
}
|
|
@@ -1157,7 +930,7 @@ fn betweenTurns(battle: anytype, mslot: u3, options: anytype) !void {
|
|
|
1157
930
|
|
|
1158
931
|
assert(volatiles.perish_song < 3);
|
|
1159
932
|
const reason = @intFromEnum(Start.PerishSong0) + volatiles.perish_song;
|
|
1160
|
-
try options.log.start(battle.active(player), reason);
|
|
933
|
+
try options.log.start(battle.active(player), @enumFromInt(reason));
|
|
1161
934
|
|
|
1162
935
|
if (volatiles.perish_song == 0) {
|
|
1163
936
|
volatiles.PerishSong = false;
|
|
@@ -1203,22 +976,21 @@ fn betweenTurns(battle: anytype, mslot: u3, options: anytype) !void {
|
|
|
1203
976
|
// Side Conditions
|
|
1204
977
|
if (showdown) {
|
|
1205
978
|
inline for (players) |player| {
|
|
1206
|
-
updateSideCondition(battle, player, "Reflect", "reflect");
|
|
979
|
+
try updateSideCondition(battle, player, "Reflect", "reflect", options);
|
|
1207
980
|
}
|
|
1208
981
|
inline for (players) |player| {
|
|
1209
|
-
updateSideCondition(battle, player, "LightScreen", "light_screen");
|
|
982
|
+
try updateSideCondition(battle, player, "LightScreen", "light_screen", options);
|
|
1210
983
|
}
|
|
1211
984
|
inline for (players) |player| {
|
|
1212
|
-
updateSideCondition(battle, player, "Safeguard", "safeguard");
|
|
985
|
+
try updateSideCondition(battle, player, "Safeguard", "safeguard", options);
|
|
1213
986
|
}
|
|
1214
987
|
} else {
|
|
1215
988
|
inline for (players) |player| {
|
|
1216
|
-
updateSideCondition(battle, player, "Safeguard", "safeguard");
|
|
989
|
+
try updateSideCondition(battle, player, "Safeguard", "safeguard", options);
|
|
1217
990
|
}
|
|
1218
|
-
|
|
1219
991
|
inline for (players) |player| {
|
|
1220
|
-
updateSideCondition(battle, player, "LightScreen", "light_screen");
|
|
1221
|
-
updateSideCondition(battle, player, "Reflect", "reflect");
|
|
992
|
+
try updateSideCondition(battle, player, "LightScreen", "light_screen", options);
|
|
993
|
+
try updateSideCondition(battle, player, "Reflect", "reflect", options);
|
|
1222
994
|
}
|
|
1223
995
|
}
|
|
1224
996
|
|
|
@@ -1291,7 +1063,7 @@ fn betweenTurns(battle: anytype, mslot: u3, options: anytype) !void {
|
|
|
1291
1063
|
assert(volatiles.encore > 0);
|
|
1292
1064
|
volatiles.encore -= 1;
|
|
1293
1065
|
|
|
1294
|
-
if (volatiles.encore == 0 or side.active.
|
|
1066
|
+
if (volatiles.encore == 0 or side.active.move(mslot).pp == 0) {
|
|
1295
1067
|
volatiles.Encore = false;
|
|
1296
1068
|
try options.log.end(battle.active(player), .Encore);
|
|
1297
1069
|
}
|
|
@@ -1313,7 +1085,7 @@ inline fn updateSideCondition(
|
|
|
1313
1085
|
|
|
1314
1086
|
if (@field(side.conditions, value) == 0) {
|
|
1315
1087
|
@field(side.conditions, key) = false;
|
|
1316
|
-
try options.log.sideend(
|
|
1088
|
+
try options.log.sideend(player, @field(protocol.Side, key));
|
|
1317
1089
|
}
|
|
1318
1090
|
}
|
|
1319
1091
|
}
|
|
@@ -1333,133 +1105,150 @@ fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result
|
|
|
1333
1105
|
return Result.Default;
|
|
1334
1106
|
}
|
|
1335
1107
|
|
|
1336
|
-
fn buildRage(battle: anytype, player: Player, options: anytype) !void {
|
|
1108
|
+
fn buildRage(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1337
1109
|
var foe = battle.foe(player);
|
|
1338
1110
|
if (foe.active.volatiles.Rage) {
|
|
1339
1111
|
if (showdown) {
|
|
1340
1112
|
// TODO if showdown boost
|
|
1341
1113
|
if (foe.active.boosts.atk < 6) {
|
|
1342
|
-
try Effects.boost(battle, player,
|
|
1114
|
+
try Effects.boost(battle, player, state, options);
|
|
1343
1115
|
}
|
|
1344
1116
|
} else {
|
|
1345
1117
|
foe.active.volatiles.rage +|= 1;
|
|
1346
|
-
try options.log.activate(battle.active(player, .Rage)
|
|
1118
|
+
try options.log.activate(battle.active(player), .Rage);
|
|
1347
1119
|
}
|
|
1348
1120
|
}
|
|
1349
1121
|
}
|
|
1350
1122
|
|
|
1351
|
-
fn kingsRock(battle: anytype, player: Player, options: anytype) !void {
|
|
1123
|
+
fn kingsRock(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1352
1124
|
var foe = battle.foe(player);
|
|
1353
1125
|
const flinch = battle.side(player).stored().item == .KingsRock and
|
|
1354
1126
|
!foe.active.volatiles.Substitute and
|
|
1355
|
-
try
|
|
1127
|
+
try Rolls.item(battle, player, options);
|
|
1356
1128
|
if (flinch) {
|
|
1357
|
-
foe.active.volatiles.
|
|
1129
|
+
foe.active.volatiles.Recharging = false;
|
|
1358
1130
|
foe.active.volatiles.Flinch = true;
|
|
1359
1131
|
}
|
|
1360
1132
|
}
|
|
1361
1133
|
|
|
1362
1134
|
pub const Effects = struct {
|
|
1363
|
-
fn alwaysHit(battle: anytype, player: Player, options: anytype) !void {
|
|
1364
|
-
_ = .{ battle, player, options }; // TODO
|
|
1135
|
+
fn alwaysHit(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1136
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1365
1137
|
}
|
|
1366
1138
|
|
|
1367
|
-
fn attract(battle: anytype, player: Player, options: anytype) !void {
|
|
1139
|
+
fn attract(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1368
1140
|
const side = battle.side(player);
|
|
1369
1141
|
var foe = battle.foe(player);
|
|
1370
1142
|
|
|
1371
1143
|
const gender: u8 = @intFromEnum(side.stored().dvs.gender);
|
|
1372
1144
|
const foe_gender: u8 = @intFromEnum(foe.stored().dvs.gender);
|
|
1373
1145
|
if (gender + foe_gender != 1) {
|
|
1374
|
-
|
|
1146
|
+
try options.log.immune(battle.active(player.foe()), .None);
|
|
1147
|
+
return;
|
|
1375
1148
|
} else if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
1376
1149
|
try options.log.lastmiss();
|
|
1377
|
-
|
|
1150
|
+
try options.log.miss(battle.active(player));
|
|
1151
|
+
return;
|
|
1378
1152
|
}
|
|
1379
1153
|
|
|
1380
1154
|
foe.active.volatiles.Attract = true;
|
|
1381
1155
|
try options.log.start(battle.active(player.foe()), .Attract);
|
|
1382
1156
|
}
|
|
1383
1157
|
|
|
1384
|
-
fn batonPass(battle: anytype, player: Player, options: anytype) !void {
|
|
1385
|
-
_ = .{ battle, player, options }; // TODO
|
|
1158
|
+
fn batonPass(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1159
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1386
1160
|
}
|
|
1387
1161
|
|
|
1388
|
-
fn beatUp(battle: anytype, player: Player, options: anytype) !void {
|
|
1389
|
-
_ = .{ battle, player, options }; // TODO
|
|
1162
|
+
fn beatUp(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1163
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1390
1164
|
}
|
|
1391
1165
|
|
|
1392
|
-
fn bellyDrum(battle: anytype, player: Player, options: anytype) !void {
|
|
1393
|
-
_ = .{ battle, player, options }; // TODO
|
|
1166
|
+
fn bellyDrum(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1167
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1394
1168
|
}
|
|
1395
1169
|
|
|
1396
|
-
fn bide(battle: anytype, player: Player, options: anytype) !void {
|
|
1397
|
-
_ = .{ battle, player, options }; // TODO
|
|
1170
|
+
fn bide(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1171
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1398
1172
|
}
|
|
1399
1173
|
|
|
1400
|
-
fn binding(battle: anytype, player: Player, options: anytype) !void {
|
|
1401
|
-
_ = .{ battle, player, options }; // TODO
|
|
1174
|
+
fn binding(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1175
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1402
1176
|
}
|
|
1403
1177
|
|
|
1404
|
-
fn burnChance(battle: anytype, player: Player,
|
|
1405
|
-
_ = .{ battle, player,
|
|
1178
|
+
fn burnChance(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1179
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1406
1180
|
}
|
|
1407
1181
|
|
|
1408
|
-
fn confusion(battle: anytype, player: Player,
|
|
1409
|
-
_ = .{ battle, player,
|
|
1182
|
+
fn confusion(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1183
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1410
1184
|
}
|
|
1411
1185
|
|
|
1412
|
-
fn conversion(battle: anytype, player: Player, options: anytype) !void {
|
|
1186
|
+
fn conversion(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1413
1187
|
var side = battle.side(player);
|
|
1414
1188
|
|
|
1415
1189
|
var n: u3 = 0;
|
|
1416
1190
|
for (side.active.moves) |m| {
|
|
1417
1191
|
if (convertible(side.active, m.id)) n += 1;
|
|
1418
1192
|
}
|
|
1419
|
-
if (n == 0)
|
|
1193
|
+
if (n == 0) {
|
|
1194
|
+
try options.log.fail(battle.active(player), .None);
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1420
1197
|
|
|
1421
1198
|
side.active.types.type1 = try Rolls.conversion(battle, player, n, options);
|
|
1422
1199
|
side.active.types.type2 = side.active.types.type1;
|
|
1423
1200
|
}
|
|
1424
1201
|
|
|
1425
|
-
fn conversion2(battle: anytype, player: Player, options: anytype) !void {
|
|
1202
|
+
fn conversion2(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1426
1203
|
var side = battle.side(player);
|
|
1427
1204
|
|
|
1428
1205
|
const last = battle.foe(player).lastMove(false);
|
|
1429
|
-
if (last == .None)
|
|
1206
|
+
if (last == .None) {
|
|
1207
|
+
try options.log.fail(battle.active(player), .None);
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1430
1210
|
const move = Move.get(last);
|
|
1431
|
-
if (move.type == .@"???")
|
|
1211
|
+
if (move.type == .@"???") {
|
|
1212
|
+
try options.log.fail(battle.active(player), .None);
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1432
1215
|
|
|
1433
1216
|
side.active.types.type1 = try Rolls.conversion2(battle, player, move.type, options);
|
|
1434
1217
|
side.active.types.type2 = side.active.types.type1;
|
|
1435
1218
|
}
|
|
1436
1219
|
|
|
1437
|
-
fn counter(battle: anytype, player: Player,
|
|
1438
|
-
_ = .{ battle, player,
|
|
1220
|
+
fn counter(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1221
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1439
1222
|
}
|
|
1440
1223
|
|
|
1441
|
-
fn curse(battle: anytype, player: Player, options: anytype) !void {
|
|
1442
|
-
_ = .{ battle, player, options }; // TODO
|
|
1224
|
+
fn curse(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1225
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1443
1226
|
}
|
|
1444
1227
|
|
|
1445
|
-
fn defenseCurl(battle: anytype, player: Player, options: anytype) !void {
|
|
1446
|
-
_ = .{ battle, player, options }; // TODO
|
|
1228
|
+
fn defenseCurl(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1229
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1447
1230
|
}
|
|
1448
1231
|
|
|
1449
|
-
fn destinyBond(battle: anytype, player: Player, options: anytype) !void {
|
|
1232
|
+
fn destinyBond(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1450
1233
|
battle.side(player).active.volatiles.DestinyBond = true;
|
|
1451
1234
|
try options.log.singlemove(battle.active(player), Move.DestinyBond);
|
|
1452
1235
|
}
|
|
1453
1236
|
|
|
1454
|
-
fn disable(battle: anytype, player: Player, options: anytype) !void {
|
|
1237
|
+
fn disable(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1455
1238
|
var foe = battle.foe(player);
|
|
1456
1239
|
var volatiles = &foe.active.volatiles;
|
|
1457
1240
|
const foe_ident = battle.active(player.foe());
|
|
1458
1241
|
|
|
1459
|
-
if (volatiles.
|
|
1242
|
+
if (volatiles.disable.move != 0) {
|
|
1243
|
+
try options.log.fail(foe_ident, .None);
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1460
1246
|
|
|
1461
1247
|
const last = battle.foe(player).lastMove(false);
|
|
1462
|
-
if (last == .None or last == .Struggle)
|
|
1248
|
+
if (last == .None or last == .Struggle) {
|
|
1249
|
+
try options.log.fail(foe_ident, .None);
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1463
1252
|
|
|
1464
1253
|
var slot: u3 = 0;
|
|
1465
1254
|
for (foe.active.moves) |m| {
|
|
@@ -1468,23 +1257,26 @@ pub const Effects = struct {
|
|
|
1468
1257
|
if (m.id == last) break;
|
|
1469
1258
|
}
|
|
1470
1259
|
const move = foe.active.move(slot);
|
|
1471
|
-
if (move.pp == 0)
|
|
1260
|
+
if (move.pp == 0) {
|
|
1261
|
+
try options.log.fail(foe_ident, .None);
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1472
1264
|
|
|
1473
|
-
volatiles.
|
|
1474
|
-
volatiles.
|
|
1265
|
+
volatiles.disable.move = slot;
|
|
1266
|
+
volatiles.disable.duration = Rolls.disableDuration(battle, player, options);
|
|
1475
1267
|
|
|
1476
1268
|
try options.log.startEffect(foe_ident, .Disable, move.id);
|
|
1477
1269
|
}
|
|
1478
1270
|
|
|
1479
|
-
fn doubleHit(battle: anytype, player: Player, options: anytype) !void {
|
|
1480
|
-
_ = .{ battle, player, options }; // TODO
|
|
1271
|
+
fn doubleHit(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1272
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1481
1273
|
}
|
|
1482
1274
|
|
|
1483
|
-
fn drainHP(battle: anytype, player: Player, options: anytype) !void {
|
|
1484
|
-
_ = .{ battle, player, options }; // TODO
|
|
1275
|
+
fn drainHP(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1276
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1485
1277
|
}
|
|
1486
1278
|
|
|
1487
|
-
fn encore(battle: anytype, player: Player,
|
|
1279
|
+
fn encore(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1488
1280
|
var foe = battle.foe(player);
|
|
1489
1281
|
var volatiles = &foe.active.volatiles;
|
|
1490
1282
|
const foe_ident = battle.active(player.foe());
|
|
@@ -1493,7 +1285,10 @@ pub const Effects = struct {
|
|
|
1493
1285
|
const failed = volatiles.Encore or
|
|
1494
1286
|
(last == .None or last == .Struggle or
|
|
1495
1287
|
last == .Encore or .last == .MirrorMove);
|
|
1496
|
-
if (failed)
|
|
1288
|
+
if (failed) {
|
|
1289
|
+
try options.log.fail(foe_ident, .None);
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1497
1292
|
|
|
1498
1293
|
var slot: u3 = 0;
|
|
1499
1294
|
for (foe.active.moves) |m| {
|
|
@@ -1502,49 +1297,53 @@ pub const Effects = struct {
|
|
|
1502
1297
|
if (m.id == last) break;
|
|
1503
1298
|
}
|
|
1504
1299
|
const move = foe.active.move(slot);
|
|
1505
|
-
if (move.pp == 0)
|
|
1300
|
+
if (move.pp == 0) {
|
|
1301
|
+
try options.log.fail(foe_ident, .None);
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1506
1304
|
|
|
1507
1305
|
volatiles.Encore = true;
|
|
1508
1306
|
volatiles.encore = Rolls.encoreDuration(battle, player, options);
|
|
1509
1307
|
|
|
1510
1308
|
// TODO ???
|
|
1511
|
-
_ =
|
|
1309
|
+
_ = state;
|
|
1512
1310
|
|
|
1513
1311
|
try options.log.startEffect(foe_ident, .Encore, move.id);
|
|
1514
1312
|
}
|
|
1515
1313
|
|
|
1516
|
-
fn explode(battle: anytype, player: Player, options: anytype) !void {
|
|
1517
|
-
_ = .{ battle, player, options }; // TODO
|
|
1314
|
+
fn explode(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1315
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1518
1316
|
}
|
|
1519
1317
|
|
|
1520
|
-
fn falseSwipe(battle: anytype, player: Player,
|
|
1318
|
+
fn falseSwipe(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
1521
1319
|
const foe = battle.foe(player);
|
|
1522
1320
|
assert(foe.stored().hp > 0);
|
|
1523
1321
|
// FIXME crit?
|
|
1524
|
-
|
|
1322
|
+
if (state.damage > foe.stored().hp) state.damage = foe.stored().hp - 1;
|
|
1525
1323
|
}
|
|
1526
1324
|
|
|
1527
|
-
fn fixedDamage(battle: anytype, player: Player,
|
|
1528
|
-
_ = .{ battle, player,
|
|
1325
|
+
fn fixedDamage(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1326
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1529
1327
|
}
|
|
1530
1328
|
|
|
1531
|
-
fn flameWheel(battle: anytype, player: Player, options: anytype) !void {
|
|
1532
|
-
_ = .{ battle, player, options }; // TODO
|
|
1329
|
+
fn flameWheel(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1330
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1533
1331
|
}
|
|
1534
1332
|
|
|
1535
|
-
fn flinchChance(battle: anytype, player: Player,
|
|
1536
|
-
_ = .{ battle, player,
|
|
1333
|
+
fn flinchChance(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1334
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1537
1335
|
}
|
|
1538
1336
|
|
|
1539
|
-
fn flyDig(battle: anytype, player: Player,
|
|
1540
|
-
_ = .{ battle, player,
|
|
1337
|
+
fn flyDig(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1338
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1541
1339
|
}
|
|
1542
1340
|
|
|
1543
|
-
fn focusEnergy(battle: anytype, player: Player, options: anytype) !void {
|
|
1341
|
+
fn focusEnergy(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1544
1342
|
var side = battle.side(player);
|
|
1545
1343
|
|
|
1546
1344
|
if (side.active.volatiles.FocusEnergy) {
|
|
1547
|
-
|
|
1345
|
+
if (!showdown) try options.log.fail(battle.active(player), .None);
|
|
1346
|
+
return;
|
|
1548
1347
|
}
|
|
1549
1348
|
|
|
1550
1349
|
side.active.volatiles.FocusEnergy = true;
|
|
@@ -1553,7 +1352,7 @@ pub const Effects = struct {
|
|
|
1553
1352
|
|
|
1554
1353
|
var SLOTS: [5]u4 = .{ 0, 0, 0, 0, 0 };
|
|
1555
1354
|
|
|
1556
|
-
fn forceSwitch(battle: anytype, player: Player, options: anytype) !void {
|
|
1355
|
+
fn forceSwitch(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1557
1356
|
const foe = battle.foe(player);
|
|
1558
1357
|
|
|
1559
1358
|
var n: u4 = 0;
|
|
@@ -1568,334 +1367,341 @@ pub const Effects = struct {
|
|
|
1568
1367
|
}
|
|
1569
1368
|
}
|
|
1570
1369
|
|
|
1571
|
-
if (n == 0)
|
|
1370
|
+
if (n == 0) {
|
|
1371
|
+
try options.log.fail(battle.active(player), .None);
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1572
1374
|
|
|
1573
1375
|
_ = try Rolls.forceSwitch(battle, player, SLOTS[0..i], n, options); // TODO
|
|
1574
1376
|
}
|
|
1575
1377
|
|
|
1576
|
-
fn foresight(battle: anytype, player: Player, options: anytype) !void {
|
|
1378
|
+
fn foresight(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1577
1379
|
var foe = battle.foe(player);
|
|
1578
1380
|
|
|
1579
1381
|
if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
1580
1382
|
try options.log.lastmiss();
|
|
1581
|
-
|
|
1383
|
+
try options.log.miss(battle.active(player));
|
|
1384
|
+
return;
|
|
1582
1385
|
} else if (foe.active.volatiles.Foresight) {
|
|
1583
|
-
|
|
1386
|
+
try options.log.fail(battle.active(player), .None);
|
|
1387
|
+
return;
|
|
1584
1388
|
}
|
|
1585
1389
|
|
|
1586
1390
|
foe.active.volatiles.Foresight = true;
|
|
1587
1391
|
try options.log.start(battle.active(player.foe()), .FocusEnergy);
|
|
1588
1392
|
}
|
|
1589
1393
|
|
|
1590
|
-
fn freezeChance(battle: anytype, player: Player,
|
|
1591
|
-
_ = .{ battle, player,
|
|
1394
|
+
fn freezeChance(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1395
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1592
1396
|
}
|
|
1593
1397
|
|
|
1594
|
-
fn furyCutter(battle: anytype, player: Player, options: anytype) !void {
|
|
1595
|
-
_ = .{ battle, player, options }; // TODO
|
|
1398
|
+
fn furyCutter(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1399
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1596
1400
|
}
|
|
1597
1401
|
|
|
1598
|
-
fn futureSight(battle: anytype, player: Player, options: anytype) !void {
|
|
1599
|
-
_ = .{ battle, player, options }; // TODO
|
|
1402
|
+
fn futureSight(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1403
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1600
1404
|
}
|
|
1601
1405
|
|
|
1602
|
-
fn happiness(battle: anytype, player: Player,
|
|
1406
|
+
fn happiness(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
1603
1407
|
const val = battle.side(player).stored().happiness;
|
|
1604
|
-
|
|
1408
|
+
const frustration = Move.get(state.move).effect == .Frustration;
|
|
1409
|
+
state.bp = ((if (frustration) 255 - val else val) * 10) / 25;
|
|
1605
1410
|
}
|
|
1606
1411
|
|
|
1607
|
-
fn haze(battle: anytype, player: Player, options: anytype) !void {
|
|
1608
|
-
_ = .{ battle, player, options }; // TODO
|
|
1412
|
+
fn haze(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1413
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1609
1414
|
}
|
|
1610
1415
|
|
|
1611
|
-
fn heal(battle: anytype, player: Player, options: anytype) !void {
|
|
1612
|
-
_ = .{ battle, player, options }; // TODO
|
|
1416
|
+
fn heal(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1417
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1613
1418
|
}
|
|
1614
1419
|
|
|
1615
|
-
fn healBell(battle: anytype, player: Player, options: anytype) !void {
|
|
1616
|
-
_ = .{ battle, player, options }; // TODO
|
|
1420
|
+
fn healBell(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1421
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1617
1422
|
}
|
|
1618
1423
|
|
|
1619
|
-
fn hiddenPower(battle: anytype, player: Player, options: anytype) !void {
|
|
1620
|
-
_ = .{ battle, player, options }; // TODO
|
|
1424
|
+
fn hiddenPower(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1425
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1621
1426
|
}
|
|
1622
1427
|
|
|
1623
|
-
fn hyperBeam(battle: anytype, player: Player, options: anytype) !void {
|
|
1624
|
-
_ = .{ battle, player, options }; // TODO
|
|
1428
|
+
fn hyperBeam(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1429
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1625
1430
|
}
|
|
1626
1431
|
|
|
1627
|
-
fn jumpKick(battle: anytype, player: Player, options: anytype) !void {
|
|
1628
|
-
_ = .{ battle, player, options }; // TODO
|
|
1432
|
+
fn jumpKick(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1433
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1629
1434
|
}
|
|
1630
1435
|
|
|
1631
|
-
fn leechSeed(battle: anytype, player: Player, options: anytype) !void {
|
|
1632
|
-
_ = .{ battle, player, options }; // TODO
|
|
1436
|
+
fn leechSeed(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1437
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1633
1438
|
}
|
|
1634
1439
|
|
|
1635
|
-
fn levelDamage(battle: anytype, player: Player, options: anytype) !void {
|
|
1636
|
-
_ = .{ battle, player, options }; // TODO
|
|
1440
|
+
fn levelDamage(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1441
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1637
1442
|
}
|
|
1638
1443
|
|
|
1639
|
-
fn lockOn(battle: anytype, player: Player, options: anytype) !void {
|
|
1640
|
-
_ = .{ battle, player, options }; // TODO
|
|
1444
|
+
fn lockOn(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1445
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1641
1446
|
}
|
|
1642
1447
|
|
|
1643
1448
|
const MAGNITUDE_POWER = [_]u8{ 10, 30, 50, 70, 90, 110, 150 };
|
|
1644
1449
|
|
|
1645
|
-
fn magnitude(battle: anytype, player: Player, options: anytype) !void {
|
|
1646
|
-
_ = .{ battle, player, options }; // TODO
|
|
1450
|
+
fn magnitude(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1451
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1647
1452
|
}
|
|
1648
1453
|
|
|
1649
|
-
fn meanLook(battle: anytype, player: Player, options: anytype) !void {
|
|
1650
|
-
_ = .{ battle, player, options }; // TODO
|
|
1454
|
+
fn meanLook(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1455
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1651
1456
|
}
|
|
1652
1457
|
|
|
1653
|
-
fn metronome(battle: anytype, player: Player, options: anytype) !void {
|
|
1654
|
-
_ = .{ battle, player, options }; // TODO
|
|
1458
|
+
fn metronome(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1459
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1655
1460
|
}
|
|
1656
1461
|
|
|
1657
|
-
fn mimic(battle: anytype, player: Player, options: anytype) !void {
|
|
1658
|
-
_ = .{ battle, player, options }; // TODO
|
|
1462
|
+
fn mimic(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1463
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1659
1464
|
}
|
|
1660
1465
|
|
|
1661
|
-
fn mirrorCoat(battle: anytype, player: Player, options: anytype) !void {
|
|
1662
|
-
_ = .{ battle, player, options }; // TODO
|
|
1466
|
+
fn mirrorCoat(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1467
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1663
1468
|
}
|
|
1664
1469
|
|
|
1665
|
-
fn mirrorMove(battle: anytype, player: Player, options: anytype) !void {
|
|
1666
|
-
_ = .{ battle, player, options }; // TODO
|
|
1470
|
+
fn mirrorMove(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1471
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1667
1472
|
}
|
|
1668
1473
|
|
|
1669
|
-
fn mist(battle: anytype, player: Player, options: anytype) !void {
|
|
1670
|
-
_ = .{ battle, player, options }; // TODO
|
|
1474
|
+
fn mist(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1475
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1671
1476
|
}
|
|
1672
1477
|
|
|
1673
|
-
fn weatherHeal(battle: anytype, player: Player, options: anytype) !void {
|
|
1674
|
-
_ = .{ battle, player, options }; // TODO
|
|
1478
|
+
fn weatherHeal(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1479
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1675
1480
|
}
|
|
1676
1481
|
|
|
1677
|
-
fn multiHit(battle: anytype, player: Player, options: anytype) !void {
|
|
1678
|
-
_ = .{ battle, player, options }; // TODO
|
|
1482
|
+
fn multiHit(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1483
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1679
1484
|
}
|
|
1680
1485
|
|
|
1681
|
-
fn nightmare(battle: anytype, player: Player, options: anytype) !void {
|
|
1682
|
-
_ = .{ battle, player, options }; // TODO
|
|
1486
|
+
fn nightmare(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1487
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1683
1488
|
}
|
|
1684
1489
|
|
|
1685
|
-
fn ohko(battle: anytype, player: Player, options: anytype) !void {
|
|
1686
|
-
_ = .{ battle, player, options }; // TODO
|
|
1490
|
+
fn ohko(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1491
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1687
1492
|
}
|
|
1688
1493
|
|
|
1689
|
-
fn painSplit(battle: anytype, player: Player, options: anytype) !void {
|
|
1690
|
-
_ = .{ battle, player, options }; // TODO
|
|
1494
|
+
fn painSplit(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1495
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1691
1496
|
}
|
|
1692
1497
|
|
|
1693
|
-
fn paralyze(battle: anytype, player: Player, options: anytype) !void {
|
|
1694
|
-
_ = .{ battle, player, options }; // TODO
|
|
1498
|
+
fn paralyze(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1499
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1695
1500
|
}
|
|
1696
1501
|
|
|
1697
|
-
fn paralyzeChance(battle: anytype, player: Player, options: anytype) !void {
|
|
1502
|
+
fn paralyzeChance(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1698
1503
|
// TODO: Thunder does acc/checkHit/effectChance before stab + damage variation
|
|
1699
|
-
_ = .{ battle, player, options }; // TODO
|
|
1504
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1700
1505
|
}
|
|
1701
1506
|
|
|
1702
|
-
fn payDay(battle: anytype, player: Player, options: anytype) !void {
|
|
1703
|
-
_ = .{ battle, player, options }; // TODO
|
|
1507
|
+
fn payDay(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1508
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1704
1509
|
}
|
|
1705
1510
|
|
|
1706
|
-
fn perishSong(battle: anytype, player: Player, options: anytype) !void {
|
|
1707
|
-
_ = .{ battle, player, options }; // TODO
|
|
1511
|
+
fn perishSong(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1512
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1708
1513
|
}
|
|
1709
1514
|
|
|
1710
|
-
fn poison(battle: anytype, player: Player,
|
|
1711
|
-
_ = .{ battle, player,
|
|
1515
|
+
fn poison(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1516
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1712
1517
|
}
|
|
1713
1518
|
|
|
1714
|
-
fn present(battle: anytype, player: Player, options: anytype) !void {
|
|
1715
|
-
_ = .{ battle, player, options }; // TODO
|
|
1519
|
+
fn present(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1520
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1716
1521
|
}
|
|
1717
1522
|
|
|
1718
|
-
fn protect(
|
|
1719
|
-
battle: anytype,
|
|
1720
|
-
player: Player,
|
|
1721
|
-
move: Move,
|
|
1722
|
-
first: bool,
|
|
1723
|
-
options: anytype,
|
|
1724
|
-
) !void {
|
|
1523
|
+
fn protect(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1725
1524
|
var side = battle.side(player);
|
|
1726
1525
|
var volatiles = &side.active.volatiles;
|
|
1727
1526
|
|
|
1728
|
-
const failed = !first or volatiles.Substitute or
|
|
1527
|
+
const failed = !state.first or volatiles.Substitute or
|
|
1729
1528
|
!try Rolls.protect(battle, player, volatiles.protect, options);
|
|
1730
|
-
if (failed)
|
|
1529
|
+
if (failed) {
|
|
1530
|
+
try options.log.fail(battle.active(player), .None);
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1731
1533
|
|
|
1732
1534
|
volatiles.protect = @max(8, volatiles.protect + 1);
|
|
1733
|
-
if (move == .Endure) {
|
|
1535
|
+
if (state.move == .Endure) {
|
|
1734
1536
|
volatiles.Endure = true;
|
|
1735
1537
|
} else {
|
|
1736
1538
|
volatiles.Protect = true;
|
|
1737
1539
|
}
|
|
1738
|
-
try options.log.singleturn(battle.active(player), move);
|
|
1540
|
+
try options.log.singleturn(battle.active(player), state.move);
|
|
1739
1541
|
}
|
|
1740
1542
|
|
|
1741
|
-
fn psychUp(battle: anytype, player: Player, options: anytype) !void {
|
|
1742
|
-
_ = .{ battle, player, options }; // TODO
|
|
1543
|
+
fn psychUp(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1544
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1743
1545
|
}
|
|
1744
1546
|
|
|
1745
|
-
fn pursuit(battle: anytype, player: Player, options: anytype) !void {
|
|
1746
|
-
_ = .{ battle, player, options }; // TODO
|
|
1547
|
+
fn pursuit(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1548
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1747
1549
|
}
|
|
1748
1550
|
|
|
1749
|
-
fn rage(battle: anytype, player: Player, options: anytype) !void {
|
|
1750
|
-
_ = .{ battle, player, options }; // TODO
|
|
1551
|
+
fn rage(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1552
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1751
1553
|
}
|
|
1752
1554
|
|
|
1753
|
-
fn rainDance(battle: anytype, player: Player, options: anytype) !void {
|
|
1754
|
-
_ = .{ battle, player, options }; // TODO
|
|
1555
|
+
fn rainDance(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1556
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1755
1557
|
}
|
|
1756
1558
|
|
|
1757
|
-
fn rapidSpin(battle: anytype, player: Player, options: anytype) !void {
|
|
1758
|
-
_ = .{ battle, player, options }; // TODO
|
|
1559
|
+
fn rapidSpin(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1560
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1759
1561
|
}
|
|
1760
1562
|
|
|
1761
|
-
fn razorWind(battle: anytype, player: Player, options: anytype) !void {
|
|
1762
|
-
_ = .{ battle, player, options }; // TODO
|
|
1563
|
+
fn razorWind(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1564
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1763
1565
|
}
|
|
1764
1566
|
|
|
1765
|
-
fn recoil(battle: anytype, player: Player, options: anytype) !void {
|
|
1766
|
-
_ = .{ battle, player, options }; // TODO
|
|
1567
|
+
fn recoil(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1568
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1767
1569
|
}
|
|
1768
1570
|
|
|
1769
|
-
fn reversal(battle: anytype, player: Player, options: anytype) !void {
|
|
1770
|
-
_ = .{ battle, player, options }; // TODO
|
|
1571
|
+
fn reversal(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1572
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1771
1573
|
}
|
|
1772
1574
|
|
|
1773
|
-
fn rollout(battle: anytype, player: Player, options: anytype) !void {
|
|
1774
|
-
_ = .{ battle, player, options }; // TODO
|
|
1575
|
+
fn rollout(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1576
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1775
1577
|
}
|
|
1776
1578
|
|
|
1777
|
-
fn sacredFire(battle: anytype, player: Player, options: anytype) !void {
|
|
1778
|
-
_ = .{ battle, player, options }; // TODO
|
|
1579
|
+
fn sacredFire(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1580
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1779
1581
|
}
|
|
1780
1582
|
|
|
1781
|
-
fn safeguard(battle: anytype, player: Player, options: anytype) !void {
|
|
1782
|
-
_ = .{ battle, player, options }; // TODO
|
|
1583
|
+
fn safeguard(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1584
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1783
1585
|
}
|
|
1784
1586
|
|
|
1785
|
-
fn sandstorm(battle: anytype, player: Player, options: anytype) !void {
|
|
1786
|
-
_ = .{ battle, player, options }; // TODO
|
|
1587
|
+
fn sandstorm(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1588
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1787
1589
|
}
|
|
1788
1590
|
|
|
1789
|
-
fn screens(battle: anytype, player: Player,
|
|
1790
|
-
_ = .{ battle, player,
|
|
1591
|
+
fn screens(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1592
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1791
1593
|
}
|
|
1792
1594
|
|
|
1793
|
-
fn sketch(battle: anytype, player: Player, options: anytype) !void {
|
|
1794
|
-
_ = .{ battle, player, options }; // TODO
|
|
1595
|
+
fn sketch(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1596
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1795
1597
|
}
|
|
1796
1598
|
|
|
1797
|
-
fn skullBash(battle: anytype, player: Player, options: anytype) !void {
|
|
1798
|
-
_ = .{ battle, player, options }; // TODO
|
|
1599
|
+
fn skullBash(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1600
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1799
1601
|
}
|
|
1800
1602
|
|
|
1801
|
-
fn skyAttack(battle: anytype, player: Player, options: anytype) !void {
|
|
1802
|
-
_ = .{ battle, player, options }; // TODO
|
|
1603
|
+
fn skyAttack(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1604
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1803
1605
|
}
|
|
1804
1606
|
|
|
1805
|
-
fn sleep(battle: anytype, player: Player, options: anytype) !void {
|
|
1806
|
-
_ = .{ battle, player, options }; // TODO
|
|
1607
|
+
fn sleep(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1608
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1807
1609
|
}
|
|
1808
1610
|
|
|
1809
|
-
fn sleepTalk(battle: anytype, player: Player,
|
|
1611
|
+
fn sleepTalk(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1810
1612
|
const side = battle.side(player);
|
|
1811
1613
|
|
|
1812
1614
|
if (!Status.is(side.stored().status, .SLP)) {
|
|
1813
|
-
|
|
1615
|
+
if (!showdown) try options.log.fail(battle.active(player), .None);
|
|
1616
|
+
return;
|
|
1814
1617
|
}
|
|
1815
1618
|
|
|
1816
1619
|
var n: u3 = 0;
|
|
1817
1620
|
for (side.active.moves, 0..) |m, i| {
|
|
1818
|
-
if (mslot - 1 != i and Move.get(m.id).extra.sleep_talk) n += 1;
|
|
1621
|
+
if (state.mslot - 1 != i and Move.get(m.id).extra.sleep_talk) n += 1;
|
|
1622
|
+
}
|
|
1623
|
+
if (n == 0) {
|
|
1624
|
+
try options.log.fail(battle.active(player), .None);
|
|
1625
|
+
return;
|
|
1819
1626
|
}
|
|
1820
|
-
if (n == 0) return try options.log.fail(battle.active(player), .None);
|
|
1821
1627
|
|
|
1822
|
-
_ = try Rolls.sleepTalk(battle, player, n, mslot, options); // TODO
|
|
1628
|
+
_ = try Rolls.sleepTalk(battle, player, n, state.mslot, options); // TODO
|
|
1823
1629
|
}
|
|
1824
1630
|
|
|
1825
|
-
fn snore(battle: anytype, player: Player, options: anytype) !void {
|
|
1826
|
-
_ = .{ battle, player, options }; // TODO
|
|
1631
|
+
fn snore(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1632
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1827
1633
|
}
|
|
1828
1634
|
|
|
1829
|
-
fn solarBeam(battle: anytype, player: Player, options: anytype) !void {
|
|
1830
|
-
_ = .{ battle, player, options }; // TODO
|
|
1635
|
+
fn solarBeam(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1636
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1831
1637
|
}
|
|
1832
1638
|
|
|
1833
|
-
fn spikes(battle: anytype, player: Player, options: anytype) !void {
|
|
1834
|
-
_ = .{ battle, player, options }; // TODO
|
|
1639
|
+
fn spikes(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1640
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1835
1641
|
}
|
|
1836
1642
|
|
|
1837
|
-
fn spite(battle: anytype, player: Player, options: anytype) !void {
|
|
1838
|
-
_ = .{ battle, player, options }; // TODO
|
|
1643
|
+
fn spite(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1644
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1839
1645
|
}
|
|
1840
1646
|
|
|
1841
|
-
fn splash(battle: anytype, player: Player, options: anytype) !void {
|
|
1842
|
-
_ = .{ battle, player, options }; // TODO
|
|
1647
|
+
fn splash(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1648
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1843
1649
|
}
|
|
1844
1650
|
|
|
1845
|
-
fn stomp(battle: anytype, player: Player, options: anytype) !void {
|
|
1846
|
-
_ = .{ battle, player, options }; // TODO
|
|
1651
|
+
fn stomp(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1652
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1847
1653
|
}
|
|
1848
1654
|
|
|
1849
|
-
fn substitute(battle: anytype, player: Player, options: anytype) !void {
|
|
1850
|
-
_ = .{ battle, player, options }; // TODO
|
|
1655
|
+
fn substitute(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1656
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1851
1657
|
}
|
|
1852
1658
|
|
|
1853
|
-
fn sunnyDay(battle: anytype, player: Player, options: anytype) !void {
|
|
1854
|
-
_ = .{ battle, player, options }; // TODO
|
|
1659
|
+
fn sunnyDay(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1660
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1855
1661
|
}
|
|
1856
1662
|
|
|
1857
|
-
fn swagger(battle: anytype, player: Player, options: anytype) !void {
|
|
1858
|
-
_ = .{ battle, player, options }; // TODO
|
|
1663
|
+
fn swagger(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1664
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1859
1665
|
}
|
|
1860
1666
|
|
|
1861
|
-
fn synthesis(battle: anytype, player: Player, options: anytype) !void {
|
|
1862
|
-
_ = .{ battle, player, options }; // TODO
|
|
1667
|
+
fn synthesis(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1668
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1863
1669
|
}
|
|
1864
1670
|
|
|
1865
|
-
fn teleport(battle: anytype, player: Player, options: anytype) !void {
|
|
1866
|
-
_ = .{ battle, player, options }; // TODO
|
|
1671
|
+
fn teleport(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1672
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1867
1673
|
}
|
|
1868
1674
|
|
|
1869
|
-
fn thief(battle: anytype, player: Player, options: anytype) !void {
|
|
1870
|
-
_ = .{ battle, player, options }; // TODO
|
|
1675
|
+
fn thief(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1676
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1871
1677
|
}
|
|
1872
1678
|
|
|
1873
|
-
fn thrashing(battle: anytype, player: Player, options: anytype) !void {
|
|
1874
|
-
_ = .{ battle, player, options }; // TODO
|
|
1679
|
+
fn thrashing(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1680
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1875
1681
|
}
|
|
1876
1682
|
|
|
1877
|
-
fn toxic(battle: anytype, player: Player, options: anytype) !void {
|
|
1878
|
-
_ = .{ battle, player, options }; // TODO
|
|
1683
|
+
fn toxic(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1684
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1879
1685
|
}
|
|
1880
1686
|
|
|
1881
|
-
fn transform(battle: anytype, player: Player, options: anytype) !void {
|
|
1882
|
-
_ = .{ battle, player, options }; // TODO
|
|
1687
|
+
fn transform(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1688
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1883
1689
|
}
|
|
1884
1690
|
|
|
1885
|
-
fn tripleKick(battle: anytype, player: Player, options: anytype) !void {
|
|
1886
|
-
_ = .{ battle, player, options }; // TODO
|
|
1691
|
+
fn tripleKick(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1692
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1887
1693
|
}
|
|
1888
1694
|
|
|
1889
|
-
fn twister(battle: anytype, player: Player, options: anytype) !void {
|
|
1890
|
-
_ = .{ battle, player, options }; // TODO
|
|
1695
|
+
fn twister(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1696
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1891
1697
|
}
|
|
1892
1698
|
|
|
1893
|
-
fn boost(battle: anytype, player: Player,
|
|
1894
|
-
_ = .{ battle, player,
|
|
1699
|
+
fn boost(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1700
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1895
1701
|
}
|
|
1896
1702
|
|
|
1897
|
-
fn unboost(battle: anytype, player: Player,
|
|
1898
|
-
_ = .{ battle, player,
|
|
1703
|
+
fn unboost(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1704
|
+
_ = .{ battle, player, state, options }; // TODO
|
|
1899
1705
|
}
|
|
1900
1706
|
};
|
|
1901
1707
|
|
|
@@ -2547,6 +2353,28 @@ test "Roll probabilities" {
|
|
|
2547
2353
|
try expectEqualSlices(u8, &.{ 14, 26, 50, 77, 51, 25, 13 }, &magnitude);
|
|
2548
2354
|
}
|
|
2549
2355
|
|
|
2356
|
+
test "Reasons" {
|
|
2357
|
+
const moves = [_]Move{ .Bind, .Wrap, .FireSpin, .Clamp, .Whirlpool };
|
|
2358
|
+
for (moves) |move| {
|
|
2359
|
+
const reason = Move.get(move).extra.protocol - 1;
|
|
2360
|
+
|
|
2361
|
+
const activate: Activate = @enumFromInt(@intFromEnum(Activate.Bind) + reason);
|
|
2362
|
+
try expectEqualStrings(@tagName(move), @tagName(activate));
|
|
2363
|
+
|
|
2364
|
+
const damage: Damage = @enumFromInt(@intFromEnum(Damage.Bind) + reason);
|
|
2365
|
+
try expectEqualStrings(@tagName(move), @tagName(damage));
|
|
2366
|
+
|
|
2367
|
+
const end: End = @enumFromInt(@intFromEnum(End.Bind) + reason);
|
|
2368
|
+
try expectEqualStrings(@tagName(move), @tagName(end));
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
const perish_song = [_]Start{ .PerishSong0, .PerishSong1, .PerishSong2, .PerishSong3 };
|
|
2372
|
+
for (perish_song, 0..) |ps, i| {
|
|
2373
|
+
const reason: Start = @enumFromInt(@intFromEnum(Start.PerishSong0) + i);
|
|
2374
|
+
try expectEqualStrings(@tagName(ps), @tagName(reason));
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2550
2378
|
pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
2551
2379
|
var n: u8 = 0;
|
|
2552
2380
|
switch (request) {
|
|
@@ -2625,7 +2453,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
|
|
|
2625
2453
|
if (m.id == if (active.volatiles.Bide) .Bide else side.last_selected_move) {
|
|
2626
2454
|
// Pokémon Showdown displays Struggle if limited to Bide but unable to pick
|
|
2627
2455
|
const struggle =
|
|
2628
|
-
m.id == .Bide and (m.pp == 0 or active.volatiles.
|
|
2456
|
+
m.id == .Bide and (m.pp == 0 or active.volatiles.disable.move == slot);
|
|
2629
2457
|
const s = if (struggle) 0 else slot;
|
|
2630
2458
|
out[n] = .{ .type = .Move, .data = s };
|
|
2631
2459
|
n += 1;
|
|
@@ -2640,7 +2468,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
|
|
|
2640
2468
|
const m = active.moves[slot - 1];
|
|
2641
2469
|
if (m.id == .None) break;
|
|
2642
2470
|
if (m.pp == 0) continue;
|
|
2643
|
-
if (active.volatiles.
|
|
2471
|
+
if (active.volatiles.disable.move == slot) continue;
|
|
2644
2472
|
out[n] = .{ .type = .Move, .data = slot };
|
|
2645
2473
|
n += 1;
|
|
2646
2474
|
}
|