Reorder Dancer activation

This commit is contained in:
PhallenTree 2025-03-04 11:02:33 +00:00 committed by GitHub
parent abea5c0486
commit e750dca08a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 47 deletions

View File

@ -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,
};

View File

@ -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:

View File

@ -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;

View File

@ -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);
}
}