From e750dca08a75e008914b01bb371d809fd4f4c390 Mon Sep 17 00:00:00 2001 From: PhallenTree <168426989+PhallenTree@users.noreply.github.com> Date: Tue, 4 Mar 2025 11:02:33 +0000 Subject: [PATCH] Reorder Dancer activation --- include/constants/battle_script_commands.h | 2 +- src/battle_script_commands.c | 87 ++++++++++------------ src/battle_util.c | 2 + test/battle/ability/dancer.c | 34 +++++++++ 4 files changed, 78 insertions(+), 47 deletions(-) diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 2cbc25b003..2aa5799a9e 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -293,13 +293,13 @@ enum MoveEndEffects MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc MOVEEND_CHANGED_ITEMS, MOVEEND_PICKPOCKET, - MOVEEND_DANCER, MOVEEND_EMERGENCY_EXIT, MOVEEND_SYMBIOSIS, MOVEEND_OPPORTUNIST, // Occurs after other stat change items/abilities to try and copy the boosts MOVEEND_SAME_MOVE_TURNS, MOVEEND_SET_EVOLUTION_TRACKER, MOVEEND_CLEAR_BITS, + MOVEEND_DANCER, MOVEEND_PURSUIT_NEXT_ACTION, MOVEEND_COUNT, }; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 331ff44ff2..fc86c99bf1 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7143,49 +7143,6 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; - case MOVEEND_DANCER: // Special case because it's so annoying - if (IsDanceMove(gCurrentMove) && !gBattleStruct->snatchedMoveIsUsed) - { - u32 battler, nextDancer = 0; - bool32 hasDancerTriggered = FALSE; - - for (battler = 0; battler < gBattlersCount; battler++) - { - if (gSpecialStatuses[battler].dancerUsedMove) - { - // in case a battler fails to act on a Dancer-called move - hasDancerTriggered = TRUE; - break; - } - } - - if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE) - || (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE && !hasDancerTriggered) - || (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove && gBattleStruct->bouncedMoveIsUsed))) - { // Dance move succeeds - // Set target for other Dancer mons; set bit so that mon cannot activate Dancer off of its own move - if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) - { - gBattleScripting.savedBattler = gBattlerTarget | 0x4; - gBattleScripting.savedBattler |= (gBattlerAttacker << 4); - gSpecialStatuses[gBattlerAttacker].dancerUsedMove = TRUE; - } - for (battler = 0; battler < gBattlersCount; battler++) - { - if (GetBattlerAbility(battler) == ABILITY_DANCER && !gSpecialStatuses[battler].dancerUsedMove) - { - if (!nextDancer || (gBattleMons[battler].speed < gBattleMons[nextDancer & 0x3].speed)) - nextDancer = battler | 0x4; - } - } - if (nextDancer && AbilityBattleEffects(ABILITYEFFECT_MOVE_END_OTHER, nextDancer & 0x3, 0, 0, 0)) - effect = TRUE; - - ClearDamageCalcResults(); - } - } - gBattleScripting.moveendState++; - break; case MOVEEND_EMERGENCY_EXIT: // Special case, because moves hitting multiple opponents stop after switching out for (i = 0; i < gBattlersCount; i++) { @@ -7291,8 +7248,6 @@ static void Cmd_moveend(void) gBattleStruct->isAtkCancelerForCalledMove = FALSE; gBattleStruct->swapDamageCategory = FALSE; gBattleStruct->categoryOverride = FALSE; - gBattleStruct->bouncedMoveIsUsed = FALSE; - gBattleStruct->snatchedMoveIsUsed = FALSE; gBattleStruct->additionalEffectsCounter = 0; gBattleStruct->poisonPuppeteerConfusion = FALSE; gBattleStruct->fickleBeamBoosted = FALSE; @@ -7305,7 +7260,6 @@ static void Cmd_moveend(void) if (B_CHARGE >= GEN_9 && moveType == TYPE_ELECTRIC && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) gStatuses3[gBattlerAttacker] &= ~(STATUS3_CHARGED_UP); memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); - ClearDamageCalcResults(); for (i = 0; i < gBattlersCount; i++) { @@ -7320,6 +7274,47 @@ static void Cmd_moveend(void) } } + gBattleScripting.moveendState++; + break; + case MOVEEND_DANCER: // Special case because it's so annoying + if (IsDanceMove(gCurrentMove) && !gBattleStruct->snatchedMoveIsUsed) + { + u32 battler, nextDancer = 0; + bool32 hasDancerTriggered = FALSE; + + for (battler = 0; battler < gBattlersCount; battler++) + { + if (gSpecialStatuses[battler].dancerUsedMove) + { + // in case a battler fails to act on a Dancer-called move + hasDancerTriggered = TRUE; + break; + } + } + + if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE) + || (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE && !hasDancerTriggered) + || (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove && gBattleStruct->bouncedMoveIsUsed))) + { // Dance move succeeds + // Set target for other Dancer mons; set bit so that mon cannot activate Dancer off of its own move + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) + { + gBattleScripting.savedBattler = gBattlerTarget | 0x4; + gBattleScripting.savedBattler |= (gBattlerAttacker << 4); + gSpecialStatuses[gBattlerAttacker].dancerUsedMove = TRUE; + } + for (battler = 0; battler < gBattlersCount; battler++) + { + if (GetBattlerAbility(battler) == ABILITY_DANCER && !gSpecialStatuses[battler].dancerUsedMove) + { + if (!nextDancer || (gBattleMons[battler].speed < gBattleMons[nextDancer & 0x3].speed)) + nextDancer = battler | 0x4; + } + } + if (nextDancer && AbilityBattleEffects(ABILITYEFFECT_MOVE_END_OTHER, nextDancer & 0x3, 0, 0, 0)) + effect = TRUE; + } + } gBattleScripting.moveendState++; break; case MOVEEND_PURSUIT_NEXT_ACTION: diff --git a/src/battle_util.c b/src/battle_util.c index 04f641ddac..4a7a0faf0e 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -811,6 +811,8 @@ void HandleAction_ActionFinished(void) gBattleScripting.animTurn = 0; gBattleScripting.animTargetsHit = 0; gBattleStruct->dynamicMoveType = 0; + gBattleStruct->bouncedMoveIsUsed = FALSE; + gBattleStruct->snatchedMoveIsUsed = FALSE; gBattleScripting.moveendState = 0; gBattleCommunication[3] = 0; gBattleCommunication[4] = 0; diff --git a/test/battle/ability/dancer.c b/test/battle/ability/dancer.c index 1e4c61dba0..b95b79a11f 100644 --- a/test/battle/ability/dancer.c +++ b/test/battle/ability/dancer.c @@ -300,3 +300,37 @@ DOUBLE_BATTLE_TEST("Dancer still activate after Red Card even if blocked by Suct HP_BAR(opponentLeft); } } + +DOUBLE_BATTLE_TEST("Dancer correctly restores move targets") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_REVELATION_DANCE)); + PLAYER(SPECIES_ORICORIO) { Speed(10); } + PLAYER(SPECIES_ORICORIO) { Speed(3); } + OPPONENT(SPECIES_ORICORIO) { Speed(1); } + OPPONENT(SPECIES_ORICORIO) { Speed(5); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_REVELATION_DANCE, target: opponentLeft); + MOVE(opponentRight, MOVE_TACKLE, target: playerRight); + MOVE(playerRight, MOVE_TACKLE, target: opponentRight); + MOVE(opponentLeft, MOVE_TACKLE, target: playerRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, playerLeft); + HP_BAR(opponentLeft); + ABILITY_POPUP(opponentLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, opponentLeft); + HP_BAR(playerLeft); + ABILITY_POPUP(playerRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, playerRight); + HP_BAR(opponentLeft); + ABILITY_POPUP(opponentRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, opponentRight); + HP_BAR(playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight); + HP_BAR(playerRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); + HP_BAR(opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft); + HP_BAR(playerRight); + } +}