From 554c9099839920006d274819453400dc2075ccc1 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Tue, 19 Aug 2025 08:56:21 +0200 Subject: [PATCH] Fixes Counter / Mirror Coat / Metal Burst damage assignment (#7538) --- src/battle_script_commands.c | 9 ++- test/battle/move_effect/counter.c | 113 +++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 8 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d9900c26a1..80a5ad664e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -13451,13 +13451,12 @@ static void Cmd_counterdamagecalculator(void) && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBattlerAttacker].physicalBattlerId].hp) { - gBattleStruct->moveDamage[gBattlerTarget] = gProtectStructs[gBattlerAttacker].physicalDmg * 2; - if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget, gCurrentMove)) gBattlerTarget = gSideTimers[sideTarget].followmeTarget; else gBattlerTarget = gProtectStructs[gBattlerAttacker].physicalBattlerId; + gBattleStruct->moveDamage[gBattlerTarget] = gProtectStructs[gBattlerAttacker].physicalDmg * 2; gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -13478,13 +13477,13 @@ static void Cmd_mirrorcoatdamagecalculator(void) && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBattlerAttacker].specialBattlerId].hp) { - gBattleStruct->moveDamage[gBattlerTarget] = gProtectStructs[gBattlerAttacker].specialDmg * 2; if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget, gCurrentMove)) gBattlerTarget = gSideTimers[sideTarget].followmeTarget; else gBattlerTarget = gProtectStructs[gBattlerAttacker].specialBattlerId; + gBattleStruct->moveDamage[gBattlerTarget] = gProtectStructs[gBattlerAttacker].specialDmg * 2; gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -16732,26 +16731,26 @@ void BS_CalcMetalBurstDmg(void) && sideAttacker != (sideTarget = GetBattlerSide(gProtectStructs[gBattlerAttacker].physicalBattlerId)) && gBattleMons[gProtectStructs[gBattlerAttacker].physicalBattlerId].hp) { - gBattleStruct->moveDamage[gBattlerTarget] = gProtectStructs[gBattlerAttacker].physicalDmg * 150 / 100; if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget, gCurrentMove)) gBattlerTarget = gSideTimers[sideTarget].followmeTarget; else gBattlerTarget = gProtectStructs[gBattlerAttacker].physicalBattlerId; + gBattleStruct->moveDamage[gBattlerTarget] = gProtectStructs[gBattlerAttacker].physicalDmg * 150 / 100; gBattlescriptCurrInstr = cmd->nextInstr; } else if (gProtectStructs[gBattlerAttacker].specialDmg && sideAttacker != (sideTarget = GetBattlerSide(gProtectStructs[gBattlerAttacker].specialBattlerId)) && gBattleMons[gProtectStructs[gBattlerAttacker].specialBattlerId].hp) { - gBattleStruct->moveDamage[gBattlerTarget] = gProtectStructs[gBattlerAttacker].specialDmg * 150 / 100; if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget, gCurrentMove)) gBattlerTarget = gSideTimers[sideTarget].followmeTarget; else gBattlerTarget = gProtectStructs[gBattlerAttacker].specialBattlerId; + gBattleStruct->moveDamage[gBattlerTarget] = gProtectStructs[gBattlerAttacker].specialDmg * 150 / 100; gBattlescriptCurrInstr = cmd->nextInstr; } else diff --git a/test/battle/move_effect/counter.c b/test/battle/move_effect/counter.c index d45e75b478..ece0ea9a9f 100644 --- a/test/battle/move_effect/counter.c +++ b/test/battle/move_effect/counter.c @@ -1,6 +1,12 @@ #include "global.h" #include "test/battle.h" +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_COUNTER) == EFFECT_COUNTER); + ASSUME(GetMoveCategory(MOVE_POUND) == DAMAGE_CATEGORY_PHYSICAL); +} + SINGLE_BATTLE_TEST("Counter is not affected by Protect effects") { u32 move; @@ -38,9 +44,110 @@ SINGLE_BATTLE_TEST("Counter is not affected by Protect effects") } } -TO_DO_BATTLE_TEST("Counter will do twice as much damage received from the opponent"); -TO_DO_BATTLE_TEST("Counter cannot affect ally Pokémon"); -TO_DO_BATTLE_TEST("Counter hits the last opponent that hit the user"); //Doubles +SINGLE_BATTLE_TEST("Counter will do twice as much damage received from the opponent") +{ + s16 normalDmg; + s16 counterDmg; + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_POUND); MOVE(player, MOVE_COUNTER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, opponent); + HP_BAR(player, captureDamage: &normalDmg); + ANIMATION(ANIM_TYPE_MOVE, MOVE_COUNTER, player); + HP_BAR(opponent, captureDamage: &counterDmg); + } THEN { + EXPECT_MUL_EQ(normalDmg, Q_4_12(2.0), counterDmg); + } +} + +DOUBLE_BATTLE_TEST("Counter cannot affect ally Pokémon") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(playerLeft, MOVE_POUND, target: playerRight); + MOVE(playerRight, MOVE_COUNTER, target: playerLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerLeft); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_COUNTER, playerRight); + } +} + +DOUBLE_BATTLE_TEST("Counter hits the last opponent that hit the user") +{ + s16 normalDmg; + s16 counterDmg; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_POUND, target: playerLeft); + MOVE(opponentRight, MOVE_SLAM, target: playerLeft); + MOVE(playerLeft, MOVE_COUNTER); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SLAM, opponentRight); + HP_BAR(playerLeft, captureDamage: &normalDmg); + ANIMATION(ANIM_TYPE_MOVE, MOVE_COUNTER, playerLeft); + HP_BAR(opponentRight, captureDamage: &counterDmg); + } THEN { + EXPECT_MUL_EQ(normalDmg, Q_4_12(2.0), counterDmg); + } +} + +DOUBLE_BATTLE_TEST("Counter respects Follow me") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentRight, MOVE_FOLLOW_ME); + MOVE(opponentLeft, MOVE_POUND, target: playerLeft); + MOVE(playerLeft, MOVE_COUNTER, target: opponentLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FOLLOW_ME, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_COUNTER, playerLeft); + HP_BAR(opponentRight); + } +} + +DOUBLE_BATTLE_TEST("Counter fails if mon that damaged counter user is no longer on the field") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); }; + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_POUND, target: playerLeft); + MOVE(playerRight, MOVE_POUND, target: opponentLeft); + MOVE(playerLeft, MOVE_COUNTER, target: opponentLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerRight); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_COUNTER, playerLeft); + } +} // Gen 1 TO_DO_BATTLE_TEST("Counter can only counter Normal and Fighting-type moves (Gen 1)");