@pkmn/engine 0.1.0-dev.21e728d9 → 0.1.0-dev.29e0e9e1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/package.json +3 -3
- package/src/lib/common/protocol.zig +325 -344
- package/src/lib/gen1/mechanics.zig +199 -199
- package/src/lib/gen2/generated.zig +3 -3
- package/src/lib/gen2/mechanics.zig +271 -251
|
@@ -26,9 +26,9 @@ const Result = common.Result;
|
|
|
26
26
|
|
|
27
27
|
const Activate = protocol.Activate;
|
|
28
28
|
const Boost = protocol.Boost;
|
|
29
|
-
const Cant = protocol.Cant;
|
|
30
29
|
const Damage = protocol.Damage;
|
|
31
30
|
const End = protocol.End;
|
|
31
|
+
const Fail = protocol.Fail;
|
|
32
32
|
const Heal = protocol.Heal;
|
|
33
33
|
const Start = protocol.Start;
|
|
34
34
|
|
|
@@ -252,15 +252,15 @@ fn switchIn(battle: anytype, player: Player, slot: u8, kind: SwitchIn, options:
|
|
|
252
252
|
statusModify(incoming.status, &active.stats);
|
|
253
253
|
|
|
254
254
|
if (kind == .Drag) {
|
|
255
|
-
try options.log.drag(battle.active(player), incoming);
|
|
255
|
+
try options.log.drag(.{ battle.active(player), incoming });
|
|
256
256
|
} else {
|
|
257
|
-
try options.log.switched(battle.active(player), incoming);
|
|
257
|
+
try options.log.switched(.{ battle.active(player), incoming });
|
|
258
258
|
}
|
|
259
259
|
options.chance.switched(player, side.pokemon[0].position, out);
|
|
260
260
|
|
|
261
261
|
if (side.conditions.Spikes and !active.types.includes(.Flying)) {
|
|
262
262
|
incoming.hp -|= @max(incoming.stats.hp / 8, 1);
|
|
263
|
-
try options.log.damage(battle.active(player), incoming, .Spikes);
|
|
263
|
+
try options.log.damage(.{ battle.active(player), incoming, .Spikes });
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
|
|
@@ -433,7 +433,7 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
433
433
|
if (volatiles.Recharging) {
|
|
434
434
|
volatiles.Recharging = false;
|
|
435
435
|
resetCant(volatiles);
|
|
436
|
-
try log.cant(ident, .Recharge);
|
|
436
|
+
try log.cant(.{ ident, .Recharge });
|
|
437
437
|
return false;
|
|
438
438
|
}
|
|
439
439
|
|
|
@@ -452,12 +452,12 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
if (duration == 0) {
|
|
455
|
-
try log.curestatus(ident, before, .Message);
|
|
455
|
+
try log.curestatus(.{ ident, before, .Message });
|
|
456
456
|
stored.status = 0; // clears EXT if present
|
|
457
457
|
resetCant(volatiles);
|
|
458
458
|
volatiles.Nightmare = false;
|
|
459
459
|
} else {
|
|
460
|
-
try log.cant(ident, .Sleep);
|
|
460
|
+
try log.cant(.{ ident, .Sleep });
|
|
461
461
|
if (move == .Snore or move == .SleepTalk) break :slp;
|
|
462
462
|
resetCant(volatiles);
|
|
463
463
|
return false;
|
|
@@ -466,7 +466,7 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
466
466
|
|
|
467
467
|
if (Status.is(stored.status, .FRZ) and !(move == .FlameWheel or move == .SacredFire)) {
|
|
468
468
|
resetCant(volatiles);
|
|
469
|
-
try log.cant(ident, .Freeze);
|
|
469
|
+
try log.cant(.{ ident, .Freeze });
|
|
470
470
|
return false;
|
|
471
471
|
}
|
|
472
472
|
|
|
@@ -476,7 +476,7 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
476
476
|
// if (!showdown) volatiles.Flinch = false;
|
|
477
477
|
volatiles.Flinch = false;
|
|
478
478
|
resetCant(volatiles);
|
|
479
|
-
try log.cant(ident, .Flinch);
|
|
479
|
+
try log.cant(.{ ident, .Flinch });
|
|
480
480
|
return false;
|
|
481
481
|
}
|
|
482
482
|
|
|
@@ -490,7 +490,7 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
490
490
|
|
|
491
491
|
if (volatiles.disable.duration == 0) {
|
|
492
492
|
volatiles.disable.move = 0;
|
|
493
|
-
try log.end(ident, .Disable);
|
|
493
|
+
try log.end(.{ ident, .Disable });
|
|
494
494
|
}
|
|
495
495
|
}
|
|
496
496
|
|
|
@@ -506,9 +506,9 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
506
506
|
|
|
507
507
|
if (volatiles.confusion == 0) {
|
|
508
508
|
volatiles.Confusion = false;
|
|
509
|
-
try log.end(ident, .Confusion);
|
|
509
|
+
try log.end(.{ ident, .Confusion });
|
|
510
510
|
} else {
|
|
511
|
-
try log.activate(ident, .Confusion);
|
|
511
|
+
try log.activate(.{ ident, .Confusion });
|
|
512
512
|
|
|
513
513
|
if (try Rolls.confused(battle, player, options)) {
|
|
514
514
|
volatiles.BeatUp = false;
|
|
@@ -523,11 +523,11 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
if (volatiles.Attract) {
|
|
526
|
-
try log.activate(ident, .Attract);
|
|
526
|
+
try log.activate(.{ ident, .Attract });
|
|
527
527
|
|
|
528
528
|
if (try Rolls.attract(battle, player, options)) {
|
|
529
529
|
resetCant(volatiles);
|
|
530
|
-
try log.cant(ident, .Attract);
|
|
530
|
+
try log.cant(.{ ident, .Attract });
|
|
531
531
|
return false;
|
|
532
532
|
}
|
|
533
533
|
}
|
|
@@ -538,14 +538,14 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
538
538
|
if (m != .None and m == move) {
|
|
539
539
|
side.active.volatiles.Charging = false;
|
|
540
540
|
resetCant(volatiles);
|
|
541
|
-
try options.log.
|
|
541
|
+
try options.log.cant(.{ ident, .Disable, move });
|
|
542
542
|
return false;
|
|
543
543
|
}
|
|
544
544
|
}
|
|
545
545
|
|
|
546
546
|
if (Status.is(stored.status, .PAR) and try Rolls.paralyzed(battle, player, options)) {
|
|
547
547
|
resetCant(volatiles);
|
|
548
|
-
try log.cant(ident, .Paralysis);
|
|
548
|
+
try log.cant(.{ ident, .Paralysis });
|
|
549
549
|
return false;
|
|
550
550
|
}
|
|
551
551
|
|
|
@@ -569,7 +569,7 @@ pub fn canMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
569
569
|
|
|
570
570
|
// FIXME: pass in target to avoid lookup?
|
|
571
571
|
const target = if (Move.get(state.move).target == .Self) player else player.foe();
|
|
572
|
-
try options.log.
|
|
572
|
+
try options.log.move(.{ battle.active(player), state.move, battle.active(target), state.from });
|
|
573
573
|
|
|
574
574
|
const charging = false; // TODO charging uses doUse
|
|
575
575
|
const skip_pp = charging or state.move == .Struggle or
|
|
@@ -849,13 +849,13 @@ fn checkFaint(
|
|
|
849
849
|
if (foe_fainted) try faint(battle, player.foe(), !more, options);
|
|
850
850
|
|
|
851
851
|
if (player_out and foe_out) {
|
|
852
|
-
try options.log.tie();
|
|
852
|
+
try options.log.tie(.{});
|
|
853
853
|
return Result.Tie;
|
|
854
854
|
} else if (player_out) {
|
|
855
|
-
try options.log.win(player.foe());
|
|
855
|
+
try options.log.win(.{player.foe()});
|
|
856
856
|
return if (player == .P1) Result.Lose else Result.Win;
|
|
857
857
|
} else if (foe_out) {
|
|
858
|
-
try options.log.win(player);
|
|
858
|
+
try options.log.win(.{player});
|
|
859
859
|
return if (player == .P1) Result.Win else Result.Lose;
|
|
860
860
|
}
|
|
861
861
|
|
|
@@ -885,19 +885,19 @@ fn faint(battle: anytype, player: Player, done: bool, options: anytype) !void {
|
|
|
885
885
|
side.stored().stats.spe;
|
|
886
886
|
}
|
|
887
887
|
|
|
888
|
-
try options.log.faint(battle.active(player), done);
|
|
888
|
+
try options.log.faint(.{ battle.active(player), done });
|
|
889
889
|
options.calc.capped(player);
|
|
890
890
|
}
|
|
891
891
|
|
|
892
892
|
// TODO: see if we can move *before* applyDamage and include failuretext logic
|
|
893
893
|
pub fn reportOutcome(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
894
894
|
const foe_ident = battle.active(player.foe());
|
|
895
|
-
if (state.crit) try options.log.crit(foe_ident);
|
|
895
|
+
if (state.crit) try options.log.crit(.{foe_ident});
|
|
896
896
|
if (!state.immune()) {
|
|
897
897
|
if (state.effectiveness > Effectiveness.neutral) {
|
|
898
|
-
try options.log.supereffective(foe_ident);
|
|
898
|
+
try options.log.supereffective(.{foe_ident});
|
|
899
899
|
} else if (state.effectiveness < Effectiveness.neutral) {
|
|
900
|
-
try options.log.resisted(foe_ident);
|
|
900
|
+
try options.log.resisted(.{foe_ident});
|
|
901
901
|
}
|
|
902
902
|
}
|
|
903
903
|
}
|
|
@@ -930,8 +930,8 @@ fn handleResidual(battle: anytype, player: Player, options: anytype) !bool {
|
|
|
930
930
|
}
|
|
931
931
|
|
|
932
932
|
stored.hp -|= damage;
|
|
933
|
-
// Pokémon Showdown uses
|
|
934
|
-
try options.log.damage(ident, stored, if (brn) Damage.Burn else Damage.Poison);
|
|
933
|
+
// Pokémon Showdown uses damage [of] here but its not relevant in Generation II
|
|
934
|
+
try options.log.damage(.{ ident, stored, if (brn) Damage.Burn else Damage.Poison });
|
|
935
935
|
if (stored.hp == 0) return true;
|
|
936
936
|
}
|
|
937
937
|
|
|
@@ -947,27 +947,27 @@ fn handleResidual(battle: anytype, player: Player, options: anytype) !bool {
|
|
|
947
947
|
|
|
948
948
|
const damage = @max(stored.stats.hp / 8, 1);
|
|
949
949
|
stored.hp -|= damage;
|
|
950
|
-
// As above, Pokémon Showdown uses
|
|
951
|
-
try options.log.damage(ident, stored, .LeechSeed);
|
|
950
|
+
// As above, Pokémon Showdown uses damage [of] but its not relevant
|
|
951
|
+
try options.log.damage(.{ ident, stored, .LeechSeed });
|
|
952
952
|
|
|
953
953
|
const before = foe_stored.hp;
|
|
954
954
|
foe_stored.hp = @min(foe_stored.hp + damage, foe_stored.stats.hp);
|
|
955
955
|
// Pokémon Showdown uses the less specific heal here instead of drain... because reasons?
|
|
956
|
-
if (foe_stored.hp > before) try options.log.heal(foe_ident, foe_stored, .Silent);
|
|
956
|
+
if (foe_stored.hp > before) try options.log.heal(.{ foe_ident, foe_stored, .Silent });
|
|
957
957
|
if (stored.hp == 0) return true;
|
|
958
958
|
}
|
|
959
959
|
|
|
960
960
|
if (volatiles.Nightmare) {
|
|
961
961
|
stored.hp -= @max(stored.stats.hp / 4, 1);
|
|
962
962
|
// ibid
|
|
963
|
-
try options.log.damage(ident, stored, .Nightmare);
|
|
963
|
+
try options.log.damage(.{ ident, stored, .Nightmare });
|
|
964
964
|
if (stored.hp == 0) return true;
|
|
965
965
|
}
|
|
966
966
|
|
|
967
967
|
if (volatiles.Curse) {
|
|
968
968
|
stored.hp -= @max(stored.stats.hp / 4, 1);
|
|
969
969
|
// ibid
|
|
970
|
-
try options.log.damage(ident, stored, .Curse);
|
|
970
|
+
try options.log.damage(.{ ident, stored, .Curse });
|
|
971
971
|
if (stored.hp == 0) return true;
|
|
972
972
|
}
|
|
973
973
|
|
|
@@ -988,7 +988,7 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
988
988
|
future_sight.count -= 1;
|
|
989
989
|
assert(future_sight.count != 0);
|
|
990
990
|
if (future_sight.count == 1) {
|
|
991
|
-
try options.log.end(battle.active(player), .FutureSight);
|
|
991
|
+
try options.log.end(.{ battle.active(player), .FutureSight });
|
|
992
992
|
// TODO doMove
|
|
993
993
|
}
|
|
994
994
|
}
|
|
@@ -1002,16 +1002,20 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1002
1002
|
|
|
1003
1003
|
if (battle.field.weather_duration == 0) {
|
|
1004
1004
|
battle.field.weather = .None;
|
|
1005
|
-
try options.log.weather(battle.field.weather, .None);
|
|
1005
|
+
try options.log.weather(.{ battle.field.weather, protocol.Weather.None });
|
|
1006
1006
|
} else {
|
|
1007
|
-
try options.log.weather(battle.field.weather, .Upkeep);
|
|
1007
|
+
try options.log.weather(.{ battle.field.weather, protocol.Weather.Upkeep });
|
|
1008
1008
|
if (battle.field.weather == .Sandstorm) {
|
|
1009
1009
|
inline for (players) |player| {
|
|
1010
1010
|
var side = battle.side(player);
|
|
1011
1011
|
const active = side.active;
|
|
1012
1012
|
if (!(active.volatiles.Underground or active.types.sandstormImmune())) {
|
|
1013
1013
|
side.stored().hp -|= @max(side.stored().stats.hp / 8, 1);
|
|
1014
|
-
try options.log.damage(
|
|
1014
|
+
try options.log.damage(.{
|
|
1015
|
+
battle.active(player),
|
|
1016
|
+
side.stored(),
|
|
1017
|
+
.Sandstorm,
|
|
1018
|
+
});
|
|
1015
1019
|
}
|
|
1016
1020
|
}
|
|
1017
1021
|
if (try checkFaint(battle, .P1, options)) |r| return r;
|
|
@@ -1023,19 +1027,24 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1023
1027
|
inline for (players) |player| {
|
|
1024
1028
|
var side = battle.side(player);
|
|
1025
1029
|
var volatiles = &side.active.volatiles;
|
|
1030
|
+
const ident = battle.active(player);
|
|
1026
1031
|
|
|
1027
1032
|
if (volatiles.bind.duration > 0 and !volatiles.Substitute) {
|
|
1028
1033
|
volatiles.bind.duration -= 1;
|
|
1029
1034
|
if (volatiles.bind.duration == 0) {
|
|
1030
1035
|
const reason = @intFromEnum(End.Bind) + volatiles.bind.reason - 1;
|
|
1031
|
-
try options.log.end(
|
|
1036
|
+
try options.log.end(.{ ident, @as(End, @enumFromInt(reason)) });
|
|
1032
1037
|
} else {
|
|
1033
1038
|
var reason = @intFromEnum(Activate.Bind) + volatiles.bind.reason - 1;
|
|
1034
|
-
try options.log.activate(
|
|
1039
|
+
try options.log.activate(.{ ident, @as(Activate, @enumFromInt(reason)) });
|
|
1035
1040
|
|
|
1036
1041
|
reason = @intFromEnum(Damage.Bind) + volatiles.bind.reason - 1;
|
|
1037
1042
|
side.stored().hp -|= @max(side.stored().stats.hp / 16, 1);
|
|
1038
|
-
try options.log.damage(
|
|
1043
|
+
try options.log.damage(.{
|
|
1044
|
+
ident,
|
|
1045
|
+
side.stored(),
|
|
1046
|
+
@as(Damage, @enumFromInt(reason)),
|
|
1047
|
+
});
|
|
1039
1048
|
}
|
|
1040
1049
|
}
|
|
1041
1050
|
}
|
|
@@ -1052,7 +1061,7 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1052
1061
|
|
|
1053
1062
|
assert(volatiles.perish_song < 3);
|
|
1054
1063
|
const reason = @intFromEnum(Start.PerishSong0) + volatiles.perish_song;
|
|
1055
|
-
try options.log.start(battle.active(player), @enumFromInt(reason));
|
|
1064
|
+
try options.log.start(.{ battle.active(player), @as(Start, @enumFromInt(reason)) });
|
|
1056
1065
|
|
|
1057
1066
|
if (volatiles.perish_song == 0) {
|
|
1058
1067
|
volatiles.PerishSong = false;
|
|
@@ -1069,7 +1078,9 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1069
1078
|
if (stored.item == .Leftovers) {
|
|
1070
1079
|
const before = stored.hp;
|
|
1071
1080
|
stored.hp = @min(stored.hp + @max(stored.stats.hp / 16, 1), stored.stats.hp);
|
|
1072
|
-
if (stored.hp > before)
|
|
1081
|
+
if (stored.hp > before) {
|
|
1082
|
+
try options.log.heal(.{ battle.active(player), stored, .Leftovers });
|
|
1083
|
+
}
|
|
1073
1084
|
}
|
|
1074
1085
|
}
|
|
1075
1086
|
|
|
@@ -1090,7 +1101,7 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1090
1101
|
!side.active.volatiles.frozen and
|
|
1091
1102
|
try Rolls.defrost(battle, player, options))
|
|
1092
1103
|
{
|
|
1093
|
-
try options.log.curestatus(battle.active(player), side.stored().status, .Message);
|
|
1104
|
+
try options.log.curestatus(.{ battle.active(player), side.stored().status, .Message });
|
|
1094
1105
|
side.stored().status = 0;
|
|
1095
1106
|
}
|
|
1096
1107
|
}
|
|
@@ -1131,14 +1142,14 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1131
1142
|
stored.hp < stored.stats.hp;
|
|
1132
1143
|
if (proc) {
|
|
1133
1144
|
assert(stored.hp != 0);
|
|
1134
|
-
try options.log.enditem(ident, stored.item, .Eat);
|
|
1145
|
+
try options.log.enditem(.{ ident, stored.item, .Eat });
|
|
1135
1146
|
stored.item = .None;
|
|
1136
1147
|
|
|
1137
1148
|
const offset = num - @intFromEnum(Item.Berry);
|
|
1138
1149
|
assert(offset < 3);
|
|
1139
1150
|
stored.hp = @min(stored.hp + ((offset + 1) * 10), stored.stats.hp);
|
|
1140
1151
|
const reason: Heal = @enumFromInt(@intFromEnum(Heal.Berry) + offset);
|
|
1141
|
-
try options.log.heal(ident, stored, reason);
|
|
1152
|
+
try options.log.heal(.{ ident, stored, reason });
|
|
1142
1153
|
}
|
|
1143
1154
|
} else if (num < @intFromEnum(Item.BitterBerry)) {
|
|
1144
1155
|
const proc = if (stored.item == .MiracleBerry)
|
|
@@ -1148,7 +1159,7 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1148
1159
|
|
|
1149
1160
|
if (proc) {
|
|
1150
1161
|
assert(Status.any(stored.status));
|
|
1151
|
-
try options.log.enditem(ident, stored.item, .Eat);
|
|
1162
|
+
try options.log.enditem(.{ ident, stored.item, .Eat });
|
|
1152
1163
|
stored.item = .None;
|
|
1153
1164
|
|
|
1154
1165
|
// FIXME wtf?
|
|
@@ -1156,21 +1167,21 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1156
1167
|
// side.active.volatiles.Nightmare = false;
|
|
1157
1168
|
if (stored.item == .MiracleBerry) {
|
|
1158
1169
|
side.active.volatiles.Confusion = false;
|
|
1159
|
-
try options.log.end(ident, .Confusion);
|
|
1170
|
+
try options.log.end(.{ ident, .Confusion });
|
|
1160
1171
|
}
|
|
1161
1172
|
stored.status = 0;
|
|
1162
1173
|
|
|
1163
1174
|
// FIXME recalc stats
|
|
1164
1175
|
|
|
1165
|
-
try options.log.curestatus(ident, stored.status, .Message);
|
|
1176
|
+
try options.log.curestatus(.{ ident, stored.status, .Message });
|
|
1166
1177
|
}
|
|
1167
1178
|
} else if (num == @intFromEnum(Item.BitterBerry)) {
|
|
1168
1179
|
if (side.active.volatiles.Confusion) {
|
|
1169
|
-
try options.log.enditem(ident, stored.item, .Eat);
|
|
1180
|
+
try options.log.enditem(.{ ident, stored.item, .Eat });
|
|
1170
1181
|
stored.item = .None;
|
|
1171
1182
|
|
|
1172
1183
|
side.active.volatiles.Confusion = false;
|
|
1173
|
-
try options.log.end(ident, .Confusion);
|
|
1184
|
+
try options.log.end(.{ ident, .Confusion });
|
|
1174
1185
|
}
|
|
1175
1186
|
}
|
|
1176
1187
|
}
|
|
@@ -1187,7 +1198,7 @@ fn betweenTurns(battle: anytype, mslot: u4, options: anytype) !?Result {
|
|
|
1187
1198
|
|
|
1188
1199
|
if (volatiles.encore == 0 or side.active.move(mslot).pp == 0) {
|
|
1189
1200
|
volatiles.Encore = false;
|
|
1190
|
-
try options.log.end(battle.active(player), .Encore);
|
|
1201
|
+
try options.log.end(.{ battle.active(player), .Encore });
|
|
1191
1202
|
}
|
|
1192
1203
|
}
|
|
1193
1204
|
}
|
|
@@ -1209,7 +1220,7 @@ fn updateSideCondition(
|
|
|
1209
1220
|
|
|
1210
1221
|
if (@field(side.conditions, value) == 0) {
|
|
1211
1222
|
@field(side.conditions, key) = false;
|
|
1212
|
-
try options.log.sideend(player, @field(protocol.Side, key));
|
|
1223
|
+
try options.log.sideend(.{ player, @field(protocol.Side, key) });
|
|
1213
1224
|
}
|
|
1214
1225
|
}
|
|
1215
1226
|
}
|
|
@@ -1218,13 +1229,13 @@ fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result
|
|
|
1218
1229
|
battle.turn += 1;
|
|
1219
1230
|
|
|
1220
1231
|
if (showdown and battle.turn >= 1000) {
|
|
1221
|
-
try options.log.tie();
|
|
1232
|
+
try options.log.tie(.{});
|
|
1222
1233
|
return Result.Tie;
|
|
1223
1234
|
} else if (battle.turn >= 65535) {
|
|
1224
1235
|
return Result.Error;
|
|
1225
1236
|
}
|
|
1226
1237
|
|
|
1227
|
-
try options.log.turn(battle.turn);
|
|
1238
|
+
try options.log.turn(.{battle.turn});
|
|
1228
1239
|
|
|
1229
1240
|
return Result.Default;
|
|
1230
1241
|
}
|
|
@@ -1240,7 +1251,7 @@ pub fn buildRage(battle: anytype, player: Player, state: *State, options: anytyp
|
|
|
1240
1251
|
}
|
|
1241
1252
|
} else {
|
|
1242
1253
|
foe.active.volatiles.rage +|= 1;
|
|
1243
|
-
try options.log.activate(battle.active(player), .Rage);
|
|
1254
|
+
try options.log.activate(.{ battle.active(player), .Rage });
|
|
1244
1255
|
}
|
|
1245
1256
|
}
|
|
1246
1257
|
}
|
|
@@ -1263,7 +1274,7 @@ pub fn destinyBond(battle: anytype, player: Player, _: *State, options: anytype)
|
|
|
1263
1274
|
|
|
1264
1275
|
if (foe.active.volatiles.DestinyBond) {
|
|
1265
1276
|
battle.side(player).stored().hp = 0;
|
|
1266
|
-
try options.log.activate(battle.active(player.foe()), .DestinyBond);
|
|
1277
|
+
try options.log.activate(.{ battle.active(player.foe()), .DestinyBond });
|
|
1267
1278
|
}
|
|
1268
1279
|
return true;
|
|
1269
1280
|
}
|
|
@@ -1276,14 +1287,14 @@ pub const Effects = struct {
|
|
|
1276
1287
|
const gender: u8 = @intFromEnum(side.stored().dvs.gender);
|
|
1277
1288
|
const foe_gender: u8 = @intFromEnum(foe.stored().dvs.gender);
|
|
1278
1289
|
if (gender + foe_gender != 1) {
|
|
1279
|
-
return options.log.immune(battle.active(player.foe()), .None);
|
|
1290
|
+
return options.log.immune(.{ battle.active(player.foe()), .None });
|
|
1280
1291
|
} else if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
1281
|
-
try options.log.lastmiss();
|
|
1282
|
-
return options.log.miss(battle.active(player));
|
|
1292
|
+
try options.log.lastmiss(.{});
|
|
1293
|
+
return options.log.miss(.{battle.active(player)});
|
|
1283
1294
|
}
|
|
1284
1295
|
|
|
1285
1296
|
foe.active.volatiles.Attract = true;
|
|
1286
|
-
try options.log.start(battle.active(player.foe()), .Attract);
|
|
1297
|
+
try options.log.start(.{ battle.active(player.foe()), .Attract });
|
|
1287
1298
|
}
|
|
1288
1299
|
|
|
1289
1300
|
pub fn batonPass(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -1322,10 +1333,10 @@ pub const Effects = struct {
|
|
|
1322
1333
|
// }
|
|
1323
1334
|
try options.chance.attacking(player, volatiles.attacks);
|
|
1324
1335
|
|
|
1325
|
-
if (volatiles.attacks != 0) return options.log.activate(ident, .Bide);
|
|
1336
|
+
if (volatiles.attacks != 0) return options.log.activate(.{ ident, .Bide });
|
|
1326
1337
|
|
|
1327
1338
|
volatiles.Bide = false;
|
|
1328
|
-
try options.log.end(ident, .Bide);
|
|
1339
|
+
try options.log.end(.{ ident, .Bide });
|
|
1329
1340
|
|
|
1330
1341
|
state.damage = volatiles.bide *% 2;
|
|
1331
1342
|
volatiles.bide = 0;
|
|
@@ -1359,11 +1370,11 @@ pub const Effects = struct {
|
|
|
1359
1370
|
if (Status.any(foe_stored.status)) {
|
|
1360
1371
|
if (Status.is(foe_stored.status, .FRZ)) {
|
|
1361
1372
|
assert(Move.get(state.move).type == .Fire or state.move == .TriAttack);
|
|
1362
|
-
try options.log.curestatus(
|
|
1373
|
+
try options.log.curestatus(.{
|
|
1363
1374
|
battle.active(player.foe()),
|
|
1364
1375
|
foe_stored.status,
|
|
1365
1376
|
.Message,
|
|
1366
|
-
);
|
|
1377
|
+
});
|
|
1367
1378
|
foe_stored.status = 0;
|
|
1368
1379
|
}
|
|
1369
1380
|
return;
|
|
@@ -1378,7 +1389,8 @@ pub const Effects = struct {
|
|
|
1378
1389
|
|
|
1379
1390
|
foe_stored.status = Status.init(.BRN);
|
|
1380
1391
|
foe.active.stats.atk = @max(foe.active.stats.atk / 2, 1);
|
|
1381
|
-
|
|
1392
|
+
|
|
1393
|
+
try options.log.status(.{ battle.active(player.foe()), foe_stored.status, .None });
|
|
1382
1394
|
|
|
1383
1395
|
// TODO: check for status berry
|
|
1384
1396
|
}
|
|
@@ -1398,7 +1410,7 @@ pub const Effects = struct {
|
|
|
1398
1410
|
for (side.active.moves) |m| {
|
|
1399
1411
|
if (convertible(side.active, m.id)) n += 1;
|
|
1400
1412
|
}
|
|
1401
|
-
if (n == 0) return options.log.fail(battle.active(player), .None);
|
|
1413
|
+
if (n == 0) return options.log.fail(.{ battle.active(player), .None });
|
|
1402
1414
|
|
|
1403
1415
|
side.active.types.type1 = try Rolls.conversion(battle, player, n, options);
|
|
1404
1416
|
side.active.types.type2 = side.active.types.type1;
|
|
@@ -1408,9 +1420,9 @@ pub const Effects = struct {
|
|
|
1408
1420
|
var side = battle.side(player);
|
|
1409
1421
|
|
|
1410
1422
|
const last = battle.foe(player).lastMove(false);
|
|
1411
|
-
if (last == .None) return options.log.fail(battle.active(player), .None);
|
|
1423
|
+
if (last == .None) return options.log.fail(.{ battle.active(player), .None });
|
|
1412
1424
|
const move = Move.get(last);
|
|
1413
|
-
if (move.type == .@"???") return options.log.fail(battle.active(player), .None);
|
|
1425
|
+
if (move.type == .@"???") return options.log.fail(.{ battle.active(player), .None });
|
|
1414
1426
|
|
|
1415
1427
|
side.active.types.type1 = try Rolls.conversion2(battle, player, move.type, options);
|
|
1416
1428
|
side.active.types.type2 = side.active.types.type1;
|
|
@@ -1452,41 +1464,41 @@ pub const Effects = struct {
|
|
|
1452
1464
|
|
|
1453
1465
|
if (side.active.types.includes(.Ghost)) {
|
|
1454
1466
|
if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
1455
|
-
try options.log.lastmiss();
|
|
1456
|
-
return options.log.miss(battle.active(player));
|
|
1467
|
+
try options.log.lastmiss(.{});
|
|
1468
|
+
return options.log.miss(.{battle.active(player)});
|
|
1457
1469
|
} else if (foe.active.volatiles.Substitute) {
|
|
1458
|
-
return options.log.
|
|
1470
|
+
return options.log.activate(.{ foe_ident, .SubstituteBlock, state.move });
|
|
1459
1471
|
} else if (foe.active.volatiles.Curse) {
|
|
1460
|
-
return options.log.fail(foe_ident, .None);
|
|
1472
|
+
return options.log.fail(.{ foe_ident, .None });
|
|
1461
1473
|
}
|
|
1462
1474
|
|
|
1463
1475
|
foe.active.volatiles.Curse = true;
|
|
1464
|
-
try options.log.start(foe_ident, .Curse);
|
|
1476
|
+
try options.log.start(.{ foe_ident, .Curse });
|
|
1465
1477
|
|
|
1466
1478
|
side.stored().hp -= @max(side.stored().stats.hp / 2, 1);
|
|
1467
|
-
try options.log.damage(ident, side.stored(), .Curse);
|
|
1479
|
+
try options.log.damage(.{ ident, side.stored(), .Curse });
|
|
1468
1480
|
} else {
|
|
1469
1481
|
var stats = &side.active.stats;
|
|
1470
1482
|
var boosts = &side.active.boosts;
|
|
1471
1483
|
|
|
1472
1484
|
const max_atk = boosts.atk == 6 or stats.atk == MAX_STAT_VALUE;
|
|
1473
1485
|
const max_def = boosts.def == 6 or stats.def == MAX_STAT_VALUE;
|
|
1474
|
-
if (max_atk and max_def) return options.log.fail(ident, .None);
|
|
1486
|
+
if (max_atk and max_def) return options.log.fail(.{ ident, .None });
|
|
1475
1487
|
|
|
1476
1488
|
if (!(boosts.spe == -6 or stats.spe == 1)) {
|
|
1477
1489
|
assert(boosts.spe >= -6 and boosts.spe <= 6);
|
|
1478
1490
|
try unboostStat(battle, side, stats, boosts, "spe", 1);
|
|
1479
|
-
try options.log.boost(ident, .Speed, @as(i8, -1));
|
|
1491
|
+
try options.log.boost(.{ ident, .Speed, @as(i8, -1) });
|
|
1480
1492
|
}
|
|
1481
1493
|
if (!max_atk) {
|
|
1482
1494
|
assert(boosts.atk >= -6 and boosts.atk <= 6);
|
|
1483
1495
|
try boostStat(battle, side, stats, boosts, "atk", 1);
|
|
1484
|
-
try options.log.boost(ident, .Attack, @as(i8, 1));
|
|
1496
|
+
try options.log.boost(.{ ident, .Attack, @as(i8, 1) });
|
|
1485
1497
|
}
|
|
1486
1498
|
if (!max_def) {
|
|
1487
1499
|
assert(boosts.def >= -6 and boosts.def <= 6);
|
|
1488
1500
|
try boostStat(battle, side, stats, boosts, "def", 1);
|
|
1489
|
-
try options.log.boost(ident, .Defense, @as(i8, 1));
|
|
1501
|
+
try options.log.boost(.{ ident, .Defense, @as(i8, 1) });
|
|
1490
1502
|
}
|
|
1491
1503
|
}
|
|
1492
1504
|
}
|
|
@@ -1498,14 +1510,13 @@ pub const Effects = struct {
|
|
|
1498
1510
|
pub fn defrost(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1499
1511
|
var side = battle.side(player);
|
|
1500
1512
|
assert(Status.is(side.stored().status, .FRZ));
|
|
1501
|
-
|
|
1502
|
-
try options.log.curestatus(battle.active(player), side.stored().status, .Message);
|
|
1513
|
+
try options.log.curestatus(.{ battle.active(player), side.stored().status, .Message });
|
|
1503
1514
|
side.stored().status = 0;
|
|
1504
1515
|
}
|
|
1505
1516
|
|
|
1506
1517
|
pub fn destinyBond(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1507
1518
|
battle.side(player).active.volatiles.DestinyBond = true;
|
|
1508
|
-
try options.log.singlemove(battle.active(player), Move.DestinyBond);
|
|
1519
|
+
try options.log.singlemove(.{ battle.active(player), Move.DestinyBond });
|
|
1509
1520
|
}
|
|
1510
1521
|
|
|
1511
1522
|
pub fn disable(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
@@ -1513,14 +1524,10 @@ pub const Effects = struct {
|
|
|
1513
1524
|
var volatiles = &foe.active.volatiles;
|
|
1514
1525
|
const foe_ident = battle.active(player.foe());
|
|
1515
1526
|
|
|
1516
|
-
if (volatiles.disable.move != 0) {
|
|
1517
|
-
return options.log.fail(foe_ident, .None);
|
|
1518
|
-
}
|
|
1527
|
+
if (volatiles.disable.move != 0) return options.log.fail(.{ foe_ident, .None });
|
|
1519
1528
|
|
|
1520
1529
|
const last = battle.foe(player).lastMove(false);
|
|
1521
|
-
if (last == .None or last == .Struggle) {
|
|
1522
|
-
return options.log.fail(foe_ident, .None);
|
|
1523
|
-
}
|
|
1530
|
+
if (last == .None or last == .Struggle) return options.log.fail(.{ foe_ident, .None });
|
|
1524
1531
|
|
|
1525
1532
|
var slot: u3 = 0;
|
|
1526
1533
|
for (foe.active.moves) |m| {
|
|
@@ -1529,12 +1536,12 @@ pub const Effects = struct {
|
|
|
1529
1536
|
if (m.id == last) break;
|
|
1530
1537
|
}
|
|
1531
1538
|
const move = foe.active.move(slot);
|
|
1532
|
-
if (move.pp == 0) return options.log.fail(foe_ident, .None);
|
|
1539
|
+
if (move.pp == 0) return options.log.fail(.{ foe_ident, .None });
|
|
1533
1540
|
|
|
1534
1541
|
volatiles.disable.move = slot;
|
|
1535
1542
|
volatiles.disable.duration = Rolls.disableDuration(battle, player, options);
|
|
1536
1543
|
|
|
1537
|
-
try options.log.
|
|
1544
|
+
try options.log.start(.{ foe_ident, .Disable, move.id });
|
|
1538
1545
|
}
|
|
1539
1546
|
|
|
1540
1547
|
pub const double = struct {
|
|
@@ -1553,13 +1560,14 @@ pub const Effects = struct {
|
|
|
1553
1560
|
|
|
1554
1561
|
pub fn drainHP(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1555
1562
|
var stored = battle.side(player).stored();
|
|
1563
|
+
const ident = battle.active(player);
|
|
1556
1564
|
|
|
1557
1565
|
assert(state.damage != 0);
|
|
1558
1566
|
|
|
1559
1567
|
if (stored.hp == stored.stats.hp) return;
|
|
1560
1568
|
stored.hp = @min(stored.stats.hp, stored.hp + @max(state.damage / 2, 1));
|
|
1561
1569
|
|
|
1562
|
-
try options.log.
|
|
1570
|
+
try options.log.heal(.{ ident, stored, .Drain, battle.active(player.foe()) });
|
|
1563
1571
|
}
|
|
1564
1572
|
|
|
1565
1573
|
pub fn encore(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -1571,7 +1579,7 @@ pub const Effects = struct {
|
|
|
1571
1579
|
const failed = volatiles.Encore or
|
|
1572
1580
|
(last == .None or last == .Struggle or
|
|
1573
1581
|
last == .Encore or .last == .MirrorMove);
|
|
1574
|
-
if (failed) return options.log.fail(foe_ident, .None);
|
|
1582
|
+
if (failed) return options.log.fail(.{ foe_ident, .None });
|
|
1575
1583
|
|
|
1576
1584
|
var slot: u3 = 0;
|
|
1577
1585
|
for (foe.active.moves) |m| {
|
|
@@ -1580,7 +1588,7 @@ pub const Effects = struct {
|
|
|
1580
1588
|
if (m.id == last) break;
|
|
1581
1589
|
}
|
|
1582
1590
|
const move = foe.active.move(slot);
|
|
1583
|
-
if (move.pp == 0) return options.log.fail(foe_ident, .None);
|
|
1591
|
+
if (move.pp == 0) return options.log.fail(.{ foe_ident, .None });
|
|
1584
1592
|
|
|
1585
1593
|
volatiles.Encore = true;
|
|
1586
1594
|
volatiles.encore = Rolls.encoreDuration(battle, player, options);
|
|
@@ -1588,7 +1596,7 @@ pub const Effects = struct {
|
|
|
1588
1596
|
// TODO ???
|
|
1589
1597
|
_ = state;
|
|
1590
1598
|
|
|
1591
|
-
try options.log.
|
|
1599
|
+
try options.log.start(.{ foe_ident, .Encore, move.id });
|
|
1592
1600
|
}
|
|
1593
1601
|
|
|
1594
1602
|
pub fn explode(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -1642,12 +1650,11 @@ pub const Effects = struct {
|
|
|
1642
1650
|
var side = battle.side(player);
|
|
1643
1651
|
|
|
1644
1652
|
if (side.active.volatiles.FocusEnergy) {
|
|
1645
|
-
if (!showdown) try options.log.fail(battle.active(player), .None);
|
|
1646
|
-
return;
|
|
1653
|
+
return if (!showdown) try options.log.fail(.{ battle.active(player), .None });
|
|
1647
1654
|
}
|
|
1648
1655
|
|
|
1649
1656
|
side.active.volatiles.FocusEnergy = true;
|
|
1650
|
-
try options.log.start(battle.active(player), .FocusEnergy);
|
|
1657
|
+
try options.log.start(.{ battle.active(player), .FocusEnergy });
|
|
1651
1658
|
}
|
|
1652
1659
|
|
|
1653
1660
|
var SLOTS: [5]u4 = .{ 0, 0, 0, 0, 0 };
|
|
@@ -1657,7 +1664,7 @@ pub const Effects = struct {
|
|
|
1657
1664
|
|
|
1658
1665
|
const foe = battle.foe(player);
|
|
1659
1666
|
|
|
1660
|
-
if (state.first) return options.log.fail(battle.active(player), .None);
|
|
1667
|
+
if (state.first) return options.log.fail(.{ battle.active(player), .None });
|
|
1661
1668
|
|
|
1662
1669
|
var n: u4 = 0;
|
|
1663
1670
|
var i: u4 = 0;
|
|
@@ -1671,7 +1678,7 @@ pub const Effects = struct {
|
|
|
1671
1678
|
}
|
|
1672
1679
|
}
|
|
1673
1680
|
|
|
1674
|
-
if (n == 0) return options.log.fail(battle.active(player), .None);
|
|
1681
|
+
if (n == 0) return options.log.fail(.{ battle.active(player), .None });
|
|
1675
1682
|
|
|
1676
1683
|
const slot = try Rolls.forceSwitch(battle, player, SLOTS[0..i], n, options);
|
|
1677
1684
|
try switchIn(battle, player.foe(), slot, .Drag, options);
|
|
@@ -1681,14 +1688,14 @@ pub const Effects = struct {
|
|
|
1681
1688
|
var foe = battle.foe(player);
|
|
1682
1689
|
|
|
1683
1690
|
if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
1684
|
-
try options.log.lastmiss();
|
|
1685
|
-
return options.log.miss(battle.active(player));
|
|
1691
|
+
try options.log.lastmiss(.{});
|
|
1692
|
+
return options.log.miss(.{battle.active(player)});
|
|
1686
1693
|
} else if (foe.active.volatiles.Foresight) {
|
|
1687
|
-
return options.log.fail(battle.active(player), .None);
|
|
1694
|
+
return options.log.fail(.{ battle.active(player), .None });
|
|
1688
1695
|
}
|
|
1689
1696
|
|
|
1690
1697
|
foe.active.volatiles.Foresight = true;
|
|
1691
|
-
try options.log.start(battle.active(player.foe()), .FocusEnergy);
|
|
1698
|
+
try options.log.start(.{ battle.active(player.foe()), .FocusEnergy });
|
|
1692
1699
|
}
|
|
1693
1700
|
|
|
1694
1701
|
pub fn freezeChance(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -1711,7 +1718,7 @@ pub const Effects = struct {
|
|
|
1711
1718
|
if (showdown) for (foe.pokemon) |p| if (Status.is(p.status, .FRZ)) return;
|
|
1712
1719
|
|
|
1713
1720
|
foe_stored.status = Status.init(.FRZ);
|
|
1714
|
-
try options.log.status(foe_ident, foe_stored.status, .None);
|
|
1721
|
+
try options.log.status(.{ foe_ident, foe_stored.status, .None });
|
|
1715
1722
|
|
|
1716
1723
|
// TODO: check for status berry
|
|
1717
1724
|
|
|
@@ -1746,7 +1753,7 @@ pub const Effects = struct {
|
|
|
1746
1753
|
inline for (STATS) |s| @field(foe.active.stats, s) = @field(stats, s);
|
|
1747
1754
|
statusModify(foe.stored().status, &foe.active.stats);
|
|
1748
1755
|
|
|
1749
|
-
try options.log.clearallboost();
|
|
1756
|
+
try options.log.clearallboost(.{});
|
|
1750
1757
|
}
|
|
1751
1758
|
|
|
1752
1759
|
pub fn heal(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -1754,7 +1761,7 @@ pub const Effects = struct {
|
|
|
1754
1761
|
var stored = side.stored();
|
|
1755
1762
|
const ident = battle.active(player);
|
|
1756
1763
|
|
|
1757
|
-
if (stored.stats.hp == stored.hp) return options.log.fail(ident, .None);
|
|
1764
|
+
if (stored.stats.hp == stored.hp) return options.log.fail(.{ ident, .None });
|
|
1758
1765
|
|
|
1759
1766
|
const rest = state.move == .Rest;
|
|
1760
1767
|
if (rest) {
|
|
@@ -1763,19 +1770,19 @@ pub const Effects = struct {
|
|
|
1763
1770
|
side.active.volatiles.Toxic = false;
|
|
1764
1771
|
stored.status = Status.slf(2);
|
|
1765
1772
|
recomputeStats(battle, side);
|
|
1766
|
-
try options.log.
|
|
1773
|
+
try options.log.status(.{ ident, stored.status, .From, Move.Rest });
|
|
1767
1774
|
stored.hp = stored.stats.hp;
|
|
1768
1775
|
} else {
|
|
1769
1776
|
stored.hp = @min(stored.stats.hp, stored.hp + (stored.stats.hp / 2));
|
|
1770
1777
|
}
|
|
1771
|
-
try options.log.heal(ident, stored, if (rest) Heal.Silent else Heal.None);
|
|
1778
|
+
try options.log.heal(.{ ident, stored, if (rest) Heal.Silent else Heal.None });
|
|
1772
1779
|
}
|
|
1773
1780
|
|
|
1774
1781
|
pub fn healBell(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1775
1782
|
var side = battle.side(player);
|
|
1776
1783
|
side.active.volatiles.Nightmare = false;
|
|
1777
1784
|
|
|
1778
|
-
try options.log.cureteam(battle.active(player));
|
|
1785
|
+
try options.log.cureteam(.{battle.active(player)});
|
|
1779
1786
|
for (&side.pokemon) |*p| p.status = 0;
|
|
1780
1787
|
|
|
1781
1788
|
// We technically only need to recompute stats if the active Pokémon was burned/paralyzed,
|
|
@@ -1791,7 +1798,7 @@ pub const Effects = struct {
|
|
|
1791
1798
|
|
|
1792
1799
|
pub fn hyperBeam(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1793
1800
|
battle.side(player).active.volatiles.Recharging = true;
|
|
1794
|
-
try options.log.mustrecharge(battle.active(player));
|
|
1801
|
+
try options.log.mustrecharge(.{battle.active(player)});
|
|
1795
1802
|
}
|
|
1796
1803
|
|
|
1797
1804
|
pub fn leechSeed(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -1801,12 +1808,12 @@ pub const Effects = struct {
|
|
|
1801
1808
|
// Invulnerability trumps type immunity on Pokémon Showdown
|
|
1802
1809
|
const invulnerable = foe.active.volatiles.Underground or foe.active.volatiles.Flying;
|
|
1803
1810
|
if (!invulnerable and foe.active.types.includes(.Grass)) {
|
|
1804
|
-
return options.log.immune(battle.active(player.foe()), .None);
|
|
1811
|
+
return options.log.immune(.{ battle.active(player.foe()), .None });
|
|
1805
1812
|
}
|
|
1806
1813
|
try checkHit(battle, player, state, options);
|
|
1807
1814
|
if (state.miss) {
|
|
1808
|
-
try options.log.lastmiss();
|
|
1809
|
-
return options.log.miss(battle.active(player));
|
|
1815
|
+
try options.log.lastmiss(.{});
|
|
1816
|
+
return options.log.miss(.{battle.active(player)});
|
|
1810
1817
|
}
|
|
1811
1818
|
if (foe.active.volatiles.LeechSeed) return;
|
|
1812
1819
|
} else {
|
|
@@ -1814,14 +1821,14 @@ pub const Effects = struct {
|
|
|
1814
1821
|
const miss =
|
|
1815
1822
|
state.miss or foe.active.types.includes(.Grass) or foe.active.volatiles.LeechSeed;
|
|
1816
1823
|
if (miss) {
|
|
1817
|
-
try options.log.lastmiss();
|
|
1818
|
-
return options.log.miss(battle.active(player));
|
|
1824
|
+
try options.log.lastmiss(.{});
|
|
1825
|
+
return options.log.miss(.{battle.active(player)});
|
|
1819
1826
|
}
|
|
1820
1827
|
}
|
|
1821
1828
|
|
|
1822
1829
|
foe.active.volatiles.LeechSeed = true;
|
|
1823
1830
|
|
|
1824
|
-
try options.log.start(battle.active(player.foe()), .LeechSeed);
|
|
1831
|
+
try options.log.start(.{ battle.active(player.foe()), .LeechSeed });
|
|
1825
1832
|
}
|
|
1826
1833
|
|
|
1827
1834
|
pub fn lockOn(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -1829,20 +1836,20 @@ pub const Effects = struct {
|
|
|
1829
1836
|
const foe_ident = battle.active(player.foe());
|
|
1830
1837
|
|
|
1831
1838
|
if (foe.active.volatiles.Substitute) {
|
|
1832
|
-
return options.log.
|
|
1839
|
+
return options.log.activate(.{ foe_ident, .SubstituteBlock, state.move });
|
|
1833
1840
|
} else if (state.miss) {
|
|
1834
|
-
return options.log.fail(foe_ident, .None);
|
|
1841
|
+
return options.log.fail(.{ foe_ident, .None });
|
|
1835
1842
|
}
|
|
1836
1843
|
|
|
1837
1844
|
foe.active.volatiles.LockOn = true;
|
|
1838
|
-
try options.log.activate(battle.active(player), .LockOn);
|
|
1845
|
+
try options.log.activate(.{ battle.active(player), .LockOn });
|
|
1839
1846
|
}
|
|
1840
1847
|
|
|
1841
1848
|
const MAGNITUDE_POWER = [_]u8{ 10, 30, 50, 70, 90, 110, 150 };
|
|
1842
1849
|
|
|
1843
1850
|
pub fn magnitude(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
1844
1851
|
const num = try Rolls.magnitude(battle, player, options);
|
|
1845
|
-
try options.log.
|
|
1852
|
+
try options.log.activate(.{ battle.active(player), .Magnitude, num });
|
|
1846
1853
|
state.bp = MAGNITUDE_POWER[num - 4];
|
|
1847
1854
|
}
|
|
1848
1855
|
|
|
@@ -1850,11 +1857,11 @@ pub const Effects = struct {
|
|
|
1850
1857
|
var foe = battle.foe(player);
|
|
1851
1858
|
|
|
1852
1859
|
if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
1853
|
-
if (!showdown) return options.log.fail(battle.active(player.foe()), .None);
|
|
1854
|
-
try options.log.lastmiss();
|
|
1855
|
-
return options.log.miss(battle.active(player));
|
|
1860
|
+
if (!showdown) return options.log.fail(.{ battle.active(player.foe()), .None });
|
|
1861
|
+
try options.log.lastmiss(.{});
|
|
1862
|
+
return options.log.miss(.{battle.active(player)});
|
|
1856
1863
|
} else if (foe.active.volatiles.Trapped) {
|
|
1857
|
-
return options.log.fail(battle.active(player.foe()), .None);
|
|
1864
|
+
return options.log.fail(.{ battle.active(player.foe()), .None });
|
|
1858
1865
|
}
|
|
1859
1866
|
|
|
1860
1867
|
foe.active.volatiles.Trapped = true;
|
|
@@ -1898,11 +1905,11 @@ pub const Effects = struct {
|
|
|
1898
1905
|
|
|
1899
1906
|
const last = foe.lastMove(false);
|
|
1900
1907
|
|
|
1901
|
-
if (last == .None) return options.log.fail(battle.active(player), .None);
|
|
1908
|
+
if (last == .None) return options.log.fail(.{ battle.active(player), .None });
|
|
1902
1909
|
const knows = knows: for (side.active.moves) |m| {
|
|
1903
1910
|
if (last == m.id) break :knows true;
|
|
1904
1911
|
} else false;
|
|
1905
|
-
if (knows) return options.log.fail(battle.active(player), .None);
|
|
1912
|
+
if (knows) return options.log.fail(.{ battle.active(player), .None });
|
|
1906
1913
|
|
|
1907
1914
|
// if (wPlayerCharging) ???
|
|
1908
1915
|
// wPlayerCharging = 1
|
|
@@ -1916,17 +1923,17 @@ pub const Effects = struct {
|
|
|
1916
1923
|
pub fn mist(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1917
1924
|
var side = battle.side(player);
|
|
1918
1925
|
|
|
1919
|
-
if (side.active.volatiles.Mist) return options.log.fail(battle.active(player), .None);
|
|
1926
|
+
if (side.active.volatiles.Mist) return options.log.fail(.{ battle.active(player), .None });
|
|
1920
1927
|
side.active.volatiles.Mist = true;
|
|
1921
1928
|
|
|
1922
|
-
try options.log.start(battle.active(player), .Mist);
|
|
1929
|
+
try options.log.start(.{ battle.active(player), .Mist });
|
|
1923
1930
|
}
|
|
1924
1931
|
|
|
1925
1932
|
pub fn weatherHeal(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
1926
1933
|
var stored = battle.side(player).stored();
|
|
1927
1934
|
const ident = battle.active(player);
|
|
1928
1935
|
|
|
1929
|
-
if (stored.hp == stored.stats.hp) return options.log.fail(ident, .None);
|
|
1936
|
+
if (stored.hp == stored.stats.hp) return options.log.fail(.{ ident, .None });
|
|
1930
1937
|
|
|
1931
1938
|
stored.hp = switch (battle.field.weather) {
|
|
1932
1939
|
.Sun => stored.stats.hp,
|
|
@@ -1934,7 +1941,7 @@ pub const Effects = struct {
|
|
|
1934
1941
|
else => @min(stored.stats.hp, stored.hp + (stored.stats.hp / 4)),
|
|
1935
1942
|
};
|
|
1936
1943
|
|
|
1937
|
-
try options.log.heal(ident, stored,
|
|
1944
|
+
try options.log.heal(.{ ident, stored, .None });
|
|
1938
1945
|
}
|
|
1939
1946
|
|
|
1940
1947
|
pub fn multiHit(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -1947,17 +1954,17 @@ pub const Effects = struct {
|
|
|
1947
1954
|
const foe_ident = battle.active(player.foe());
|
|
1948
1955
|
|
|
1949
1956
|
if (foe_volatiles.Flying or foe_volatiles.Underground) {
|
|
1950
|
-
if (!showdown) return options.log.fail(battle.active(player.foe()), .None);
|
|
1951
|
-
try options.log.lastmiss();
|
|
1952
|
-
return options.log.miss(battle.active(player));
|
|
1957
|
+
if (!showdown) return options.log.fail(.{ battle.active(player.foe()), .None });
|
|
1958
|
+
try options.log.lastmiss(.{});
|
|
1959
|
+
return options.log.miss(.{battle.active(player)});
|
|
1953
1960
|
} else if (foe_volatiles.Substitute) {
|
|
1954
|
-
return options.log.
|
|
1961
|
+
return options.log.activate(.{ foe_ident, .SubstituteBlock, state.move });
|
|
1955
1962
|
} else if (!Status.is(foe.stored().status, .SLP) or foe_volatiles.Nightmare) {
|
|
1956
|
-
return options.log.fail(foe_ident, .None);
|
|
1963
|
+
return options.log.fail(.{ foe_ident, .None });
|
|
1957
1964
|
}
|
|
1958
1965
|
|
|
1959
1966
|
foe_volatiles.Nightmare = true;
|
|
1960
|
-
try options.log.start(battle.active(player.foe()), .Nightmare);
|
|
1967
|
+
try options.log.start(.{ battle.active(player.foe()), .Nightmare });
|
|
1961
1968
|
}
|
|
1962
1969
|
|
|
1963
1970
|
pub const ohko = struct {
|
|
@@ -1981,9 +1988,9 @@ pub const Effects = struct {
|
|
|
1981
1988
|
const foe_ident = battle.active(player.foe());
|
|
1982
1989
|
|
|
1983
1990
|
state.damage = 0;
|
|
1984
|
-
if (state.immune()) return options.log.immune(foe_ident, .None);
|
|
1991
|
+
if (state.immune()) return options.log.immune(.{ foe_ident, .None });
|
|
1985
1992
|
const delta = side.stored().level -| foe.stored().level;
|
|
1986
|
-
if (delta == 0) return options.log.immune(foe_ident, .OHKO);
|
|
1993
|
+
if (delta == 0) return options.log.immune(.{ foe_ident, .OHKO });
|
|
1987
1994
|
|
|
1988
1995
|
state.accuracy = 2 * delta +| Gen12.percent(30);
|
|
1989
1996
|
try checkHit(battle, player, state, options);
|
|
@@ -1999,37 +2006,39 @@ pub const Effects = struct {
|
|
|
1999
2006
|
const ident = battle.active(player);
|
|
2000
2007
|
const foe_ident = battle.active(player.foe());
|
|
2001
2008
|
|
|
2002
|
-
if (state.miss) return options.log.fail(foe_ident, .None);
|
|
2009
|
+
if (state.miss) return options.log.fail(.{ foe_ident, .None });
|
|
2003
2010
|
if (foe.active.volatiles.Substitute) {
|
|
2004
|
-
return options.log.
|
|
2011
|
+
return options.log.activate(.{ foe_ident, .SubstituteBlock, state.move });
|
|
2005
2012
|
}
|
|
2006
2013
|
|
|
2007
2014
|
const avg = @max((foe.stored().hp + side.stored().hp) / 2, 1);
|
|
2008
2015
|
foe.stored().hp -= avg;
|
|
2009
2016
|
side.stored().hp = avg;
|
|
2010
2017
|
|
|
2011
|
-
try options.log.sethp(foe_ident, foe.stored(), .Silent);
|
|
2012
|
-
try options.log.sethp(ident, side.stored(), .None);
|
|
2018
|
+
try options.log.sethp(.{ foe_ident, foe.stored(), .Silent });
|
|
2019
|
+
try options.log.sethp(.{ ident, side.stored(), .None });
|
|
2013
2020
|
}
|
|
2014
2021
|
|
|
2015
2022
|
pub fn paralyze(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
2016
2023
|
var foe = battle.foe(player);
|
|
2017
2024
|
const foe_ident = battle.active(player.foe());
|
|
2018
2025
|
|
|
2019
|
-
if (Status.is(foe.stored().status, .PAR))
|
|
2020
|
-
|
|
2021
|
-
|
|
2026
|
+
if (Status.is(foe.stored().status, .PAR)) {
|
|
2027
|
+
return options.log.fail(.{ foe_ident, .Paralysis });
|
|
2028
|
+
}
|
|
2029
|
+
if (state.immune()) return options.log.immune(.{ foe_ident, .None });
|
|
2030
|
+
if (Status.any(foe.stored().status)) return options.log.fail(.{ foe_ident, .None });
|
|
2022
2031
|
if (state.miss) {
|
|
2023
|
-
try options.log.lastmiss();
|
|
2024
|
-
return options.log.miss(battle.active(player));
|
|
2032
|
+
try options.log.lastmiss(.{});
|
|
2033
|
+
return options.log.miss(.{battle.active(player)});
|
|
2025
2034
|
} else if (foe.active.volatiles.Substitute) {
|
|
2026
|
-
return options.log.
|
|
2035
|
+
return options.log.activate(.{ foe_ident, .SubstituteBlock, state.move });
|
|
2027
2036
|
}
|
|
2028
2037
|
|
|
2029
2038
|
foe.stored().status = Status.init(.PAR);
|
|
2030
2039
|
foe.active.stats.spe = @max(foe.active.stats.spe / 4, 1);
|
|
2031
2040
|
|
|
2032
|
-
try options.log.status(foe_ident, foe.stored().status, .None);
|
|
2041
|
+
try options.log.status(.{ foe_ident, foe.stored().status, .None });
|
|
2033
2042
|
}
|
|
2034
2043
|
|
|
2035
2044
|
pub fn paralyzeChance(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -2044,14 +2053,15 @@ pub const Effects = struct {
|
|
|
2044
2053
|
|
|
2045
2054
|
foe_stored.status = Status.init(.PAR);
|
|
2046
2055
|
foe.active.stats.spe = @max(foe.active.stats.spe / 4, 1);
|
|
2047
|
-
|
|
2056
|
+
|
|
2057
|
+
try options.log.status(.{ battle.active(player.foe()), foe_stored.status, .None });
|
|
2048
2058
|
|
|
2049
2059
|
// TODO: check for status berry
|
|
2050
2060
|
}
|
|
2051
2061
|
|
|
2052
2062
|
pub fn payDay(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
2053
2063
|
if (!showdown or !battle.foe(player).active.volatiles.Substitute) {
|
|
2054
|
-
try options.log.fieldactivate(); // FIXME .PayDay
|
|
2064
|
+
try options.log.fieldactivate(.{}); // FIXME .PayDay
|
|
2055
2065
|
}
|
|
2056
2066
|
}
|
|
2057
2067
|
|
|
@@ -2060,17 +2070,17 @@ pub const Effects = struct {
|
|
|
2060
2070
|
var foe = battle.foe(player);
|
|
2061
2071
|
|
|
2062
2072
|
if (foe.active.volatiles.PerishSong) {
|
|
2063
|
-
return options.log.fail(battle.active(player.foe()), .None);
|
|
2073
|
+
return options.log.fail(.{ battle.active(player.foe()), .None });
|
|
2064
2074
|
} else if (!side.active.volatiles.PerishSong) {
|
|
2065
2075
|
side.active.volatiles.PerishSong = true;
|
|
2066
2076
|
side.active.volatiles.perish_song = 4;
|
|
2067
|
-
try options.log.start(battle.active(player), .PerishSong3Silent);
|
|
2077
|
+
try options.log.start(.{ battle.active(player), .PerishSong3Silent });
|
|
2068
2078
|
}
|
|
2069
2079
|
foe.active.volatiles.PerishSong = true;
|
|
2070
2080
|
foe.active.volatiles.perish_song = 4;
|
|
2071
|
-
try options.log.start(battle.active(player.foe()), .PerishSong3Silent);
|
|
2081
|
+
try options.log.start(.{ battle.active(player.foe()), .PerishSong3Silent });
|
|
2072
2082
|
|
|
2073
|
-
try options.log.fieldactivate(); // FIXME .PerishSong
|
|
2083
|
+
try options.log.fieldactivate(.{}); // FIXME .PerishSong
|
|
2074
2084
|
}
|
|
2075
2085
|
|
|
2076
2086
|
pub fn poison(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -2080,24 +2090,24 @@ pub const Effects = struct {
|
|
|
2080
2090
|
|
|
2081
2091
|
const toxic = state.move == .Toxic;
|
|
2082
2092
|
if (state.immune() or foe.active.types.includes(.Poison)) {
|
|
2083
|
-
return options.log.immune(foe_ident, .None);
|
|
2093
|
+
return options.log.immune(.{ foe_ident, .None });
|
|
2084
2094
|
} else if (Status.any(foe_stored.status)) {
|
|
2085
2095
|
// Pokémon Showdown considers Toxic to be a status even in Generation II and so
|
|
2086
2096
|
// will not include a fail reason for Toxic vs. Poison or vice-versa...
|
|
2087
|
-
return options.log.fail(foe_ident, if (Status.is(foe_stored.status, .PSN))
|
|
2097
|
+
return options.log.fail(.{ foe_ident, if (Status.is(foe_stored.status, .PSN))
|
|
2088
2098
|
if (!showdown)
|
|
2089
|
-
.Poison
|
|
2099
|
+
Fail.Poison
|
|
2090
2100
|
else if (toxic == (foe_stored.status == Status.TOX))
|
|
2091
|
-
if (toxic) .Toxic else .Poison
|
|
2101
|
+
if (toxic) Fail.Toxic else Fail.Poison
|
|
2092
2102
|
else
|
|
2093
|
-
.None
|
|
2103
|
+
Fail.None
|
|
2094
2104
|
else
|
|
2095
|
-
.None);
|
|
2105
|
+
Fail.None });
|
|
2096
2106
|
} else if (foe.active.volatiles.Substitute) {
|
|
2097
|
-
return options.log.
|
|
2107
|
+
return options.log.activate(.{ foe_ident, .SubstituteBlock, state.move });
|
|
2098
2108
|
} else if (state.miss) {
|
|
2099
|
-
try options.log.lastmiss();
|
|
2100
|
-
return options.log.miss(battle.active(player));
|
|
2109
|
+
try options.log.lastmiss(.{});
|
|
2110
|
+
return options.log.miss(.{battle.active(player)});
|
|
2101
2111
|
}
|
|
2102
2112
|
|
|
2103
2113
|
foe_stored.status = Status.init(.PSN);
|
|
@@ -2107,7 +2117,7 @@ pub const Effects = struct {
|
|
|
2107
2117
|
foe.active.volatiles.toxic = 0;
|
|
2108
2118
|
}
|
|
2109
2119
|
|
|
2110
|
-
try options.log.status(foe_ident, foe_stored.status, .None);
|
|
2120
|
+
try options.log.status(.{ foe_ident, foe_stored.status, .None });
|
|
2111
2121
|
|
|
2112
2122
|
// TODO: check for status berry
|
|
2113
2123
|
}
|
|
@@ -2123,7 +2133,8 @@ pub const Effects = struct {
|
|
|
2123
2133
|
if (foe.conditions.Safeguard) return;
|
|
2124
2134
|
|
|
2125
2135
|
foe_stored.status = Status.init(.PSN);
|
|
2126
|
-
|
|
2136
|
+
|
|
2137
|
+
try options.log.status(.{ battle.active(player.foe()), foe_stored.status, .None });
|
|
2127
2138
|
|
|
2128
2139
|
// TODO: check for status berry
|
|
2129
2140
|
}
|
|
@@ -2138,9 +2149,7 @@ pub const Effects = struct {
|
|
|
2138
2149
|
|
|
2139
2150
|
const failed = !state.first or volatiles.Substitute or
|
|
2140
2151
|
!try Rolls.protect(battle, player, volatiles.protect, options);
|
|
2141
|
-
if (failed) {
|
|
2142
|
-
return options.log.fail(battle.active(player), .None);
|
|
2143
|
-
}
|
|
2152
|
+
if (failed) return options.log.fail(.{ battle.active(player), .None });
|
|
2144
2153
|
|
|
2145
2154
|
volatiles.protect = @max(8, volatiles.protect + 1);
|
|
2146
2155
|
if (state.move == .Endure) {
|
|
@@ -2148,7 +2157,7 @@ pub const Effects = struct {
|
|
|
2148
2157
|
} else {
|
|
2149
2158
|
volatiles.Protect = true;
|
|
2150
2159
|
}
|
|
2151
|
-
try options.log.singleturn(battle.active(player), state.move);
|
|
2160
|
+
try options.log.singleturn(.{ battle.active(player), state.move });
|
|
2152
2161
|
}
|
|
2153
2162
|
|
|
2154
2163
|
pub fn psychUp(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
@@ -2157,11 +2166,11 @@ pub const Effects = struct {
|
|
|
2157
2166
|
|
|
2158
2167
|
// Pokémon Showdown should fail when the enemy has no boosts/unboosts but doesn't
|
|
2159
2168
|
if (!showdown and @as(u32, @bitCast(foe.active.boosts)) == 0) {
|
|
2160
|
-
return options.log.fail(battle.active(player), .None);
|
|
2169
|
+
return options.log.fail(.{ battle.active(player), .None });
|
|
2161
2170
|
}
|
|
2162
2171
|
|
|
2163
2172
|
side.active.boosts = foe.active.boosts;
|
|
2164
|
-
try options.log.copyboost(battle.active(player), battle.active(player.foe()));
|
|
2173
|
+
try options.log.copyboost(.{ battle.active(player), battle.active(player.foe()) });
|
|
2165
2174
|
}
|
|
2166
2175
|
|
|
2167
2176
|
pub fn pursuit(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
@@ -2172,7 +2181,7 @@ pub const Effects = struct {
|
|
|
2172
2181
|
pub const rage = struct {
|
|
2173
2182
|
pub fn start(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
2174
2183
|
battle.side(player).active.volatiles.Rage = true;
|
|
2175
|
-
try options.log.singlemove(battle.active(player), Move.Rage);
|
|
2184
|
+
try options.log.singlemove(.{ battle.active(player), Move.Rage });
|
|
2176
2185
|
}
|
|
2177
2186
|
|
|
2178
2187
|
pub fn damage(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
@@ -2192,18 +2201,18 @@ pub const Effects = struct {
|
|
|
2192
2201
|
var side = battle.side(player);
|
|
2193
2202
|
|
|
2194
2203
|
if (side.active.volatiles.LeechSeed) {
|
|
2195
|
-
try options.log.end(battle.active(player), .LeechSeedFrom);
|
|
2204
|
+
try options.log.end(.{ battle.active(player), .LeechSeedFrom });
|
|
2196
2205
|
side.active.volatiles.LeechSeed = false;
|
|
2197
2206
|
}
|
|
2198
2207
|
|
|
2199
2208
|
if (side.conditions.Spikes) {
|
|
2200
|
-
try options.log.
|
|
2209
|
+
try options.log.sideend(.{ player, protocol.Side.Spikes, battle.active(player) });
|
|
2201
2210
|
side.conditions.Spikes = false;
|
|
2202
2211
|
}
|
|
2203
2212
|
|
|
2204
2213
|
if (side.active.volatiles.bind.duration > 0) {
|
|
2205
2214
|
const reason = @intFromEnum(End.Bind) + side.active.volatiles.bind.reason - 1;
|
|
2206
|
-
try options.log.end(battle.active(player), @enumFromInt(reason));
|
|
2215
|
+
try options.log.end(.{ battle.active(player), @as(End, @enumFromInt(reason)) });
|
|
2207
2216
|
side.active.volatiles.bind = .{};
|
|
2208
2217
|
}
|
|
2209
2218
|
}
|
|
@@ -2211,18 +2220,14 @@ pub const Effects = struct {
|
|
|
2211
2220
|
pub fn recoil(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
2212
2221
|
var side = battle.side(player);
|
|
2213
2222
|
var stored = side.stored();
|
|
2223
|
+
const ident = battle.active(player);
|
|
2214
2224
|
|
|
2215
2225
|
assert(state.damage > 0);
|
|
2216
2226
|
|
|
2217
2227
|
const damage: i16 = @intCast(@max(state.damage / 4, 1));
|
|
2218
2228
|
stored.hp = @intCast(@max(@as(i16, @intCast(stored.hp)) - damage, 0));
|
|
2219
2229
|
|
|
2220
|
-
try options.log.
|
|
2221
|
-
battle.active(player),
|
|
2222
|
-
stored,
|
|
2223
|
-
.RecoilOf,
|
|
2224
|
-
battle.active(player.foe()),
|
|
2225
|
-
);
|
|
2230
|
+
try options.log.damage(.{ ident, stored, .RecoilOf, battle.active(player.foe()) });
|
|
2226
2231
|
}
|
|
2227
2232
|
|
|
2228
2233
|
pub fn reversal(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -2285,7 +2290,7 @@ pub const Effects = struct {
|
|
|
2285
2290
|
|
|
2286
2291
|
pub fn sandstorm(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
2287
2292
|
if (battle.field.weather != .Sandstorm) return weather(battle, .Sandstorm, options);
|
|
2288
|
-
return options.log.fail(battle.active(player), .None);
|
|
2293
|
+
return options.log.fail(.{ battle.active(player), .None });
|
|
2289
2294
|
}
|
|
2290
2295
|
|
|
2291
2296
|
pub fn safeguard(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
@@ -2309,11 +2314,13 @@ pub const Effects = struct {
|
|
|
2309
2314
|
) !void {
|
|
2310
2315
|
var side = battle.side(player);
|
|
2311
2316
|
|
|
2312
|
-
if (@field(side.conditions, key))
|
|
2317
|
+
if (@field(side.conditions, key)) {
|
|
2318
|
+
return options.log.fail(.{ battle.active(player), .None });
|
|
2319
|
+
}
|
|
2313
2320
|
|
|
2314
2321
|
@field(side.conditions, key) = true;
|
|
2315
2322
|
@field(side.conditions, value) = 5;
|
|
2316
|
-
try options.log.sidestart(player, @field(protocol.Side, key));
|
|
2323
|
+
try options.log.sidestart(.{ player, @field(protocol.Side, key) });
|
|
2317
2324
|
}
|
|
2318
2325
|
|
|
2319
2326
|
pub fn sketch(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
@@ -2324,9 +2331,9 @@ pub const Effects = struct {
|
|
|
2324
2331
|
|
|
2325
2332
|
if (showdown) {
|
|
2326
2333
|
// yes, actually "Splash". '|nothing' gets blindly mapped to '|-activate||move:Splash'
|
|
2327
|
-
try options.log.activate(battle.active(player), .Splash);
|
|
2334
|
+
try options.log.activate(.{ battle.active(player), .Splash });
|
|
2328
2335
|
} else {
|
|
2329
|
-
try options.log.fail(battle.active(player), .None);
|
|
2336
|
+
try options.log.fail(.{ battle.active(player), .None });
|
|
2330
2337
|
}
|
|
2331
2338
|
}
|
|
2332
2339
|
|
|
@@ -2336,14 +2343,14 @@ pub const Effects = struct {
|
|
|
2336
2343
|
const foe_ident = battle.active(player.foe());
|
|
2337
2344
|
|
|
2338
2345
|
if (Status.any(foe_stored.status)) {
|
|
2339
|
-
return options.log.fail(
|
|
2346
|
+
return options.log.fail(.{
|
|
2340
2347
|
foe_ident,
|
|
2341
|
-
if (Status.is(foe_stored.status, .SLP)) .Sleep else .None,
|
|
2342
|
-
);
|
|
2348
|
+
if (Status.is(foe_stored.status, .SLP)) Fail.Sleep else Fail.None,
|
|
2349
|
+
});
|
|
2343
2350
|
}
|
|
2344
2351
|
|
|
2345
2352
|
if (foe.active.volatiles.Substitute) {
|
|
2346
|
-
return options.log.
|
|
2353
|
+
return options.log.activate(.{ foe_ident, .SubstituteBlock, state.move });
|
|
2347
2354
|
}
|
|
2348
2355
|
|
|
2349
2356
|
// Sleep Clause Mod
|
|
@@ -2354,22 +2361,21 @@ pub const Effects = struct {
|
|
|
2354
2361
|
}
|
|
2355
2362
|
|
|
2356
2363
|
foe_stored.status = Status.slp(Rolls.sleepDuration(battle, player, options));
|
|
2357
|
-
try options.log.
|
|
2364
|
+
try options.log.status(.{ foe_ident, foe_stored.status, .From, state.move });
|
|
2358
2365
|
}
|
|
2359
2366
|
|
|
2360
2367
|
pub fn sleepTalk(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
2361
2368
|
const side = battle.side(player);
|
|
2362
2369
|
|
|
2363
2370
|
if (!Status.is(side.stored().status, .SLP)) {
|
|
2364
|
-
if (!showdown) try options.log.fail(battle.active(player), .None);
|
|
2365
|
-
return;
|
|
2371
|
+
return if (!showdown) try options.log.fail(.{ battle.active(player), .None });
|
|
2366
2372
|
}
|
|
2367
2373
|
|
|
2368
2374
|
var n: u3 = 0;
|
|
2369
2375
|
for (side.active.moves, 0..) |m, i| {
|
|
2370
2376
|
if (state.mslot - 1 != i and Move.get(m.id).extra.sleep_talk) n += 1;
|
|
2371
2377
|
}
|
|
2372
|
-
if (n == 0) return options.log.fail(battle.active(player), .None);
|
|
2378
|
+
if (n == 0) return options.log.fail(.{ battle.active(player), .None });
|
|
2373
2379
|
|
|
2374
2380
|
_ = try Rolls.sleepTalk(battle, player, n, state.mslot, options); // TODO
|
|
2375
2381
|
}
|
|
@@ -2378,23 +2384,23 @@ pub const Effects = struct {
|
|
|
2378
2384
|
if (Status.is(battle.side(player).stored().status, .SLP)) return true;
|
|
2379
2385
|
state.damage = 0;
|
|
2380
2386
|
state.miss = true; // TODO is this necessary?
|
|
2381
|
-
if (!showdown) try options.log.fail(battle.active(player), .None);
|
|
2387
|
+
if (!showdown) try options.log.fail(.{ battle.active(player), .None });
|
|
2382
2388
|
return false;
|
|
2383
2389
|
}
|
|
2384
2390
|
|
|
2385
2391
|
pub fn spikes(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
2386
2392
|
var foe = battle.foe(player);
|
|
2387
|
-
if (foe.conditions.Spikes) return options.log.fail(battle.active(player), .None);
|
|
2393
|
+
if (foe.conditions.Spikes) return options.log.fail(.{ battle.active(player), .None });
|
|
2388
2394
|
|
|
2389
2395
|
foe.conditions.Spikes = true;
|
|
2390
|
-
try options.log.sidestart(player.foe(), .Spikes);
|
|
2396
|
+
try options.log.sidestart(.{ player.foe(), protocol.Side.Spikes });
|
|
2391
2397
|
}
|
|
2392
2398
|
|
|
2393
2399
|
pub fn spite(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
2394
2400
|
_ = .{ battle, player, state, options }; // TODO
|
|
2395
2401
|
// var foe = battle.foe(player);
|
|
2396
2402
|
|
|
2397
|
-
// if (state.miss) return options.log.fail(battle.active(player), .None);
|
|
2403
|
+
// if (state.miss) return options.log.fail(.{ battle.active(player), .None });
|
|
2398
2404
|
|
|
2399
2405
|
// const last = foe.lastMove(false);
|
|
2400
2406
|
// if (showdown) {
|
|
@@ -2405,28 +2411,28 @@ pub const Effects = struct {
|
|
|
2405
2411
|
}
|
|
2406
2412
|
|
|
2407
2413
|
pub fn splash(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
2408
|
-
try options.log.activate(battle.active(player), .Splash);
|
|
2414
|
+
try options.log.activate(.{ battle.active(player), .Splash });
|
|
2409
2415
|
}
|
|
2410
2416
|
|
|
2411
2417
|
pub fn substitute(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
2412
2418
|
var side = battle.side(player);
|
|
2413
2419
|
if (side.active.volatiles.Substitute) {
|
|
2414
|
-
return options.log.fail(battle.active(player), .Substitute);
|
|
2420
|
+
return options.log.fail(.{ battle.active(player), .Substitute });
|
|
2415
2421
|
}
|
|
2416
2422
|
|
|
2417
2423
|
assert(side.stored().stats.hp <= 1023);
|
|
2418
2424
|
const hp: u8 = @intCast(side.stored().stats.hp / 4);
|
|
2419
2425
|
|
|
2420
2426
|
if (hp == 0 or side.stored().hp <= hp) {
|
|
2421
|
-
return options.log.fail(battle.active(player), .Weak);
|
|
2427
|
+
return options.log.fail(.{ battle.active(player), .Weak });
|
|
2422
2428
|
}
|
|
2423
2429
|
|
|
2424
2430
|
side.stored().hp -= hp;
|
|
2425
2431
|
side.active.volatiles.substitute = hp;
|
|
2426
2432
|
side.active.volatiles.Substitute = true;
|
|
2427
2433
|
side.active.volatiles.bind = .{};
|
|
2428
|
-
try options.log.start(battle.active(player), .Substitute);
|
|
2429
|
-
try options.log.damage(battle.active(player), side.stored(), .None);
|
|
2434
|
+
try options.log.start(.{ battle.active(player), .Substitute });
|
|
2435
|
+
try options.log.damage(.{ battle.active(player), side.stored(), .None });
|
|
2430
2436
|
}
|
|
2431
2437
|
|
|
2432
2438
|
pub fn sunnyDay(battle: anytype, _: Player, _: *State, options: anytype) !void {
|
|
@@ -2436,14 +2442,14 @@ pub const Effects = struct {
|
|
|
2436
2442
|
fn weather(battle: anytype, w: Weather, options: anytype) !void {
|
|
2437
2443
|
battle.field.weather = w;
|
|
2438
2444
|
battle.field.weather_duration = 5;
|
|
2439
|
-
try options.log.weather(w, .None);
|
|
2445
|
+
try options.log.weather(.{ w, protocol.Weather.None });
|
|
2440
2446
|
}
|
|
2441
2447
|
|
|
2442
2448
|
pub fn teleport(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
2443
2449
|
if (showdown) return;
|
|
2444
2450
|
|
|
2445
|
-
try options.log.fail(battle.active(player), .None);
|
|
2446
|
-
try options.log.laststill();
|
|
2451
|
+
try options.log.fail(.{ battle.active(player), .None });
|
|
2452
|
+
try options.log.laststill(.{});
|
|
2447
2453
|
}
|
|
2448
2454
|
|
|
2449
2455
|
pub fn thief(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -2458,11 +2464,11 @@ pub const Effects = struct {
|
|
|
2458
2464
|
side.stored().item = foe.stored().item;
|
|
2459
2465
|
foe.stored().item = .None;
|
|
2460
2466
|
|
|
2461
|
-
try options.log.item(
|
|
2467
|
+
try options.log.item(.{
|
|
2462
2468
|
battle.active(player),
|
|
2463
2469
|
side.stored().item,
|
|
2464
2470
|
battle.active(player.foe()),
|
|
2465
|
-
);
|
|
2471
|
+
});
|
|
2466
2472
|
}
|
|
2467
2473
|
|
|
2468
2474
|
pub fn thrashing(battle: anytype, player: Player, _: *State, options: anytype) !void {
|
|
@@ -2484,11 +2490,11 @@ pub const Effects = struct {
|
|
|
2484
2490
|
side.active.volatiles.dirty = false;
|
|
2485
2491
|
|
|
2486
2492
|
if (foe.active.volatiles.Transform) {
|
|
2487
|
-
return options.log.fail(battle.active(player), .None);
|
|
2493
|
+
return options.log.fail(.{ battle.active(player), .None });
|
|
2488
2494
|
} else if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
2489
|
-
if (!showdown) return options.log.fail(battle.active(player), .None);
|
|
2490
|
-
try options.log.lastmiss();
|
|
2491
|
-
return options.log.miss(battle.active(player));
|
|
2495
|
+
if (!showdown) return options.log.fail(.{ battle.active(player), .None });
|
|
2496
|
+
try options.log.lastmiss(.{});
|
|
2497
|
+
return options.log.miss(.{battle.active(player)});
|
|
2492
2498
|
}
|
|
2493
2499
|
|
|
2494
2500
|
side.active.volatiles.Transform = true;
|
|
@@ -2510,7 +2516,7 @@ pub const Effects = struct {
|
|
|
2510
2516
|
side.active.moves[i].pp = if (m.id != .None) if (m.id == .Sketch) 1 else 5 else 0;
|
|
2511
2517
|
}
|
|
2512
2518
|
|
|
2513
|
-
try options.log.transform(battle.active(player), foe_ident);
|
|
2519
|
+
try options.log.transform(.{ battle.active(player), foe_ident });
|
|
2514
2520
|
}
|
|
2515
2521
|
|
|
2516
2522
|
pub fn triAttack(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
@@ -2542,10 +2548,10 @@ pub const Effects = struct {
|
|
|
2542
2548
|
inline for (STATS, STAT_UP_REASONS) |s, r| {
|
|
2543
2549
|
assert(@field(boosts, s) >= -6 and @field(boosts, s) <= 6);
|
|
2544
2550
|
if (@field(boosts, s) == 6 or @field(stats, s) == MAX_STAT_VALUE) {
|
|
2545
|
-
try options.log.boost(battle.active(player), r, 0);
|
|
2551
|
+
try options.log.boost(.{ battle.active(player), r, 0 });
|
|
2546
2552
|
} else {
|
|
2547
2553
|
try boostStat(battle, side, stats, boosts, s, 1);
|
|
2548
|
-
try options.log.boost(battle.active(player), r, 1);
|
|
2554
|
+
try options.log.boost(.{ battle.active(player), r, 1 });
|
|
2549
2555
|
}
|
|
2550
2556
|
}
|
|
2551
2557
|
}
|
|
@@ -2555,7 +2561,7 @@ pub const Effects = struct {
|
|
|
2555
2561
|
var side = battle.side(player);
|
|
2556
2562
|
const ident = battle.active(player);
|
|
2557
2563
|
|
|
2558
|
-
if (state.miss) return log.fail(ident, .None);
|
|
2564
|
+
if (state.miss) return log.fail(.{ ident, .None });
|
|
2559
2565
|
|
|
2560
2566
|
var stats = &side.active.stats;
|
|
2561
2567
|
var boosts = &side.active.boosts;
|
|
@@ -2564,42 +2570,52 @@ pub const Effects = struct {
|
|
|
2564
2570
|
switch (move.effect) {
|
|
2565
2571
|
.AttackUp1, .AttackUp2, .Rage, .Swagger => {
|
|
2566
2572
|
assert(boosts.atk >= -6 and boosts.atk <= 6);
|
|
2567
|
-
if (boosts.atk == 6 or stats.atk == MAX_STAT_VALUE)
|
|
2573
|
+
if (boosts.atk == 6 or stats.atk == MAX_STAT_VALUE) {
|
|
2574
|
+
return log.fail(.{ ident, .None });
|
|
2575
|
+
}
|
|
2568
2576
|
const n: u2 = if (move.effect == .AttackUp2 or move.effect == .Swagger) 2 else 1;
|
|
2569
2577
|
try boostStat(battle, side, stats, boosts, "atk", n);
|
|
2570
2578
|
const reason = if (showdown and move.effect == .Rage) Boost.Rage else Boost.Attack;
|
|
2571
|
-
try log.boost(ident, reason, n);
|
|
2579
|
+
try log.boost(.{ ident, reason, n });
|
|
2572
2580
|
},
|
|
2573
2581
|
.DefenseUp1, .DefenseUp2, .SkullBash => {
|
|
2574
2582
|
assert(boosts.def >= -6 and boosts.def <= 6);
|
|
2575
|
-
if (boosts.def == 6 or stats.def == MAX_STAT_VALUE)
|
|
2583
|
+
if (boosts.def == 6 or stats.def == MAX_STAT_VALUE) {
|
|
2584
|
+
return log.fail(.{ ident, .None });
|
|
2585
|
+
}
|
|
2576
2586
|
const n: u2 = if (move.effect == .DefenseUp2) 2 else 1;
|
|
2577
2587
|
try boostStat(battle, side, stats, boosts, "def", n);
|
|
2578
|
-
try log.boost(ident, .Defense, n);
|
|
2588
|
+
try log.boost(.{ ident, .Defense, n });
|
|
2579
2589
|
},
|
|
2580
2590
|
.SpeedUp2 => {
|
|
2581
2591
|
assert(boosts.spe >= -6 and boosts.spe <= 6);
|
|
2582
|
-
if (boosts.spe == 6 or stats.spe == MAX_STAT_VALUE)
|
|
2592
|
+
if (boosts.spe == 6 or stats.spe == MAX_STAT_VALUE) {
|
|
2593
|
+
return log.fail(.{ ident, .None });
|
|
2594
|
+
}
|
|
2583
2595
|
try boostStat(battle, side, stats, boosts, "spe", 2);
|
|
2584
|
-
try log.boost(ident, .Speed, 2);
|
|
2596
|
+
try log.boost(.{ ident, .Speed, 2 });
|
|
2585
2597
|
},
|
|
2586
2598
|
.SpAtkUp1 => {
|
|
2587
2599
|
assert(boosts.spa >= -6 and boosts.spa <= 6);
|
|
2588
|
-
if (boosts.spa == 6 or stats.spa == MAX_STAT_VALUE)
|
|
2600
|
+
if (boosts.spa == 6 or stats.spa == MAX_STAT_VALUE) {
|
|
2601
|
+
return log.fail(.{ ident, .None });
|
|
2602
|
+
}
|
|
2589
2603
|
try boostStat(battle, side, stats, boosts, "spa", 1);
|
|
2590
|
-
try log.boost(ident, .SpecialAttack, 1);
|
|
2604
|
+
try log.boost(.{ ident, .SpecialAttack, 1 });
|
|
2591
2605
|
},
|
|
2592
2606
|
.SpDefUp2 => {
|
|
2593
2607
|
assert(boosts.spd >= -6 and boosts.spd <= 6);
|
|
2594
|
-
if (boosts.spd == 6 or stats.spd == MAX_STAT_VALUE)
|
|
2608
|
+
if (boosts.spd == 6 or stats.spd == MAX_STAT_VALUE) {
|
|
2609
|
+
return log.fail(.{ ident, .None });
|
|
2610
|
+
}
|
|
2595
2611
|
try boostStat(battle, side, stats, boosts, "spd", 2);
|
|
2596
|
-
try log.boost(ident, .SpecialDefense, 2);
|
|
2612
|
+
try log.boost(.{ ident, .SpecialDefense, 2 });
|
|
2597
2613
|
},
|
|
2598
2614
|
.EvasionUp1 => {
|
|
2599
2615
|
assert(boosts.evasion >= -6 and boosts.evasion <= 6);
|
|
2600
|
-
if (boosts.evasion == 6) return log.fail(ident, .None);
|
|
2616
|
+
if (boosts.evasion == 6) return log.fail(.{ ident, .None });
|
|
2601
2617
|
boosts.evasion = @intCast(@min(6, @as(i8, boosts.evasion) + 1));
|
|
2602
|
-
try log.boost(ident, .Evasion, 1);
|
|
2618
|
+
try log.boost(.{ ident, .Evasion, 1 });
|
|
2603
2619
|
if (state.move == .Minimize) side.active.volatiles.minimized = true;
|
|
2604
2620
|
},
|
|
2605
2621
|
else => unreachable,
|
|
@@ -2612,8 +2628,8 @@ pub const Effects = struct {
|
|
|
2612
2628
|
const foe_ident = battle.active(player.foe());
|
|
2613
2629
|
|
|
2614
2630
|
if (foe.active.volatiles.Mist) {
|
|
2615
|
-
try log.activate(foe_ident, .Mist);
|
|
2616
|
-
return log.fail(foe_ident, .None);
|
|
2631
|
+
try log.activate(.{ foe_ident, .Mist });
|
|
2632
|
+
return log.fail(.{ foe_ident, .None });
|
|
2617
2633
|
}
|
|
2618
2634
|
|
|
2619
2635
|
const fail = foe.active.volatiles.Substitute or state.miss or !state.proc;
|
|
@@ -2622,69 +2638,73 @@ pub const Effects = struct {
|
|
|
2622
2638
|
var boosts = &foe.active.boosts;
|
|
2623
2639
|
|
|
2624
2640
|
const move = Move.get(state.move);
|
|
2641
|
+
const none: Fail = .None;
|
|
2625
2642
|
switch (move.effect) {
|
|
2626
2643
|
.AttackDown1, .AttackDown2, .AttackDownChance => {
|
|
2627
2644
|
assert(boosts.atk >= -6 and boosts.atk <= 6);
|
|
2628
2645
|
if (fail or boosts.atk == -6) {
|
|
2629
|
-
return if (move.effect != .AttackDownChance) try log.fail(foe_ident,
|
|
2646
|
+
return if (move.effect != .AttackDownChance) try log.fail(.{ foe_ident, none });
|
|
2630
2647
|
} else if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
2631
|
-
try options.log.lastmiss();
|
|
2632
|
-
return options.log.miss(battle.active(player));
|
|
2648
|
+
try options.log.lastmiss(.{});
|
|
2649
|
+
return options.log.miss(.{battle.active(player)});
|
|
2633
2650
|
} else if (stats.atk == 1) {
|
|
2634
|
-
return if (move.effect != .AttackDownChance) try log.fail(foe_ident,
|
|
2651
|
+
return if (move.effect != .AttackDownChance) try log.fail(.{ foe_ident, none });
|
|
2635
2652
|
}
|
|
2636
2653
|
const n: u2 = if (move.effect == .AttackDown2) 2 else 1;
|
|
2637
2654
|
try unboostStat(battle, foe, stats, boosts, "atk", n);
|
|
2638
|
-
try log.boost(foe_ident, .Attack, -@as(i8, n));
|
|
2655
|
+
try log.boost(.{ foe_ident, .Attack, -@as(i8, n) });
|
|
2639
2656
|
},
|
|
2640
2657
|
.DefenseDown1, .DefenseDown2, .DefenseDownChance => {
|
|
2641
2658
|
assert(boosts.def >= -6 and boosts.def <= 6);
|
|
2642
2659
|
if (fail or boosts.def == -6) {
|
|
2643
|
-
|
|
2660
|
+
if (move.effect != .DefenseDownChance) try log.fail(.{ foe_ident, none });
|
|
2661
|
+
return;
|
|
2644
2662
|
} else if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
2645
|
-
try options.log.lastmiss();
|
|
2646
|
-
return options.log.miss(battle.active(player));
|
|
2663
|
+
try options.log.lastmiss(.{});
|
|
2664
|
+
return options.log.miss(.{battle.active(player)});
|
|
2647
2665
|
} else if (stats.def == 1) {
|
|
2648
|
-
|
|
2666
|
+
if (move.effect != .DefenseDownChance) try log.fail(.{ foe_ident, none });
|
|
2667
|
+
return;
|
|
2649
2668
|
}
|
|
2650
2669
|
const n: u2 = if (move.effect == .DefenseDown2) 2 else 1;
|
|
2651
2670
|
try unboostStat(battle, foe, stats, boosts, "def", n);
|
|
2652
|
-
try log.boost(foe_ident, .Defense, -@as(i8, n));
|
|
2671
|
+
try log.boost(.{ foe_ident, .Defense, -@as(i8, n) });
|
|
2653
2672
|
},
|
|
2654
2673
|
.SpeedDown1, .SpeedDown2, .SpeedDownChance => {
|
|
2655
2674
|
assert(boosts.spe >= -6 and boosts.spe <= 6);
|
|
2656
2675
|
if (fail or boosts.spe == -6) {
|
|
2657
|
-
return if (move.effect != .SpeedDownChance) try log.fail(foe_ident,
|
|
2676
|
+
return if (move.effect != .SpeedDownChance) try log.fail(.{ foe_ident, none });
|
|
2658
2677
|
} else if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
2659
|
-
try options.log.lastmiss();
|
|
2660
|
-
return options.log.miss(battle.active(player));
|
|
2678
|
+
try options.log.lastmiss(.{});
|
|
2679
|
+
return options.log.miss(.{battle.active(player)});
|
|
2661
2680
|
} else if (stats.spe == 1) {
|
|
2662
|
-
return if (move.effect != .SpeedDownChance) try log.fail(foe_ident,
|
|
2681
|
+
return if (move.effect != .SpeedDownChance) try log.fail(.{ foe_ident, none });
|
|
2663
2682
|
}
|
|
2664
2683
|
const n: u2 = if (move.effect == .SpeedDown2) 2 else 1;
|
|
2665
2684
|
try unboostStat(battle, foe, stats, boosts, "spe", n);
|
|
2666
|
-
try log.boost(foe_ident, .Speed, -@as(i8, n));
|
|
2685
|
+
try log.boost(.{ foe_ident, .Speed, -@as(i8, n) });
|
|
2667
2686
|
},
|
|
2668
2687
|
.SpDefDownChance => {
|
|
2669
2688
|
assert(boosts.spd >= -6 and boosts.spd <= 6);
|
|
2670
2689
|
if (fail or boosts.spd == -6) return;
|
|
2671
2690
|
if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
2672
|
-
try options.log.lastmiss();
|
|
2673
|
-
return options.log.miss(battle.active(player));
|
|
2691
|
+
try options.log.lastmiss(.{});
|
|
2692
|
+
return options.log.miss(.{battle.active(player)});
|
|
2674
2693
|
} else if (stats.spd == 1) return;
|
|
2675
2694
|
try unboostStat(battle, foe, stats, boosts, "spd", 1);
|
|
2676
|
-
try log.boost(foe_ident, .SpecialDefense, -1);
|
|
2695
|
+
try log.boost(.{ foe_ident, .SpecialDefense, -1 });
|
|
2677
2696
|
},
|
|
2678
2697
|
.AccuracyDown1, .AccuracyDownChance => {
|
|
2679
2698
|
assert(boosts.accuracy >= -6 and boosts.accuracy <= 6);
|
|
2680
2699
|
if (fail or boosts.accuracy == -6) {
|
|
2681
|
-
|
|
2700
|
+
if (move.effect != .AccuracyDownChance) try log.fail(.{ foe_ident, none });
|
|
2701
|
+
return;
|
|
2682
2702
|
} else if (foe.active.volatiles.Flying or foe.active.volatiles.Underground) {
|
|
2683
|
-
try options.log.lastmiss();
|
|
2684
|
-
return options.log.miss(battle.active(player));
|
|
2703
|
+
try options.log.lastmiss(.{});
|
|
2704
|
+
return options.log.miss(.{battle.active(player)});
|
|
2685
2705
|
}
|
|
2686
2706
|
boosts.accuracy = @intCast(@max(-6, @as(i8, boosts.accuracy) - 1));
|
|
2687
|
-
try log.boost(foe_ident, .Accuracy, -1);
|
|
2707
|
+
try log.boost(.{ foe_ident, .Accuracy, -1 });
|
|
2688
2708
|
},
|
|
2689
2709
|
else => unreachable,
|
|
2690
2710
|
}
|
|
@@ -3224,7 +3244,7 @@ pub const Rolls = struct {
|
|
|
3224
3244
|
|
|
3225
3245
|
const move: Move = overridden orelse move: {
|
|
3226
3246
|
if (showdown) {
|
|
3227
|
-
var r = battle.rng.range(u8, 0, @intCast(Move.METRONOME.len - n));
|
|
3247
|
+
var r = battle.rng.range(u8, 0, @as(u8, @intCast(Move.METRONOME.len - n)));
|
|
3228
3248
|
for (moves) |m| {
|
|
3229
3249
|
if (m.id == .None) break;
|
|
3230
3250
|
if (@intFromEnum(m.id) > @intFromEnum(Move.METRONOME[r])) break;
|