Minor dancer clean up/consolidation (#9417)
Some checks are pending
CI / build (push) Waiting to run
CI / docs_validate (push) Waiting to run
CI / allcontributors (push) Waiting to run

Co-authored-by: PhallenTree <168426989+PhallenTree@users.noreply.github.com>
This commit is contained in:
Alex 2026-03-06 16:15:14 +01:00 committed by GitHub
parent 8f123fb8b7
commit 138a8f90c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 73 additions and 75 deletions

View File

@ -101,7 +101,12 @@ struct ProtectStruct
// Cleared at the start of HandleAction_ActionFinished
struct SpecialStatus
{
u8 changedStatsBattlerId; // Battler that was responsible for the latest stat change. Can be self.
u8 changedStatsBattlerId:3; // Battler that was responsible for the latest stat change. Can be self.
u8 neutralizingGasRemoved:1;
u8 berryReduced:1;
u8 mindBlownRecoil:1;
u8 padding:2;
// End of byte
u8 statLowered:1;
u8 abilityRedirected:1;
u8 restoredBattlerSprite: 1;
@ -111,12 +116,6 @@ struct SpecialStatus
u8 dancerUsedMove:1;
u8 criticalHit:1;
// End of byte
u8 instructedChosenTarget:3;
u8 neutralizingGasRemoved:1;
u8 berryReduced:1;
u8 mindBlownRecoil:1;
u8 padding2:2;
// End of byte
u8 gemParam:7;
u8 gemBoost:1;
// End of byte
@ -124,7 +123,7 @@ struct SpecialStatus
u8 multiHitOn:1;
u8 distortedTypeMatchups:1;
u8 teraShellAbilityDone:1;
u8 dancerOriginalTarget:3;
u8 backUpTarget:3;
// End of byte
};

View File

@ -49,7 +49,7 @@ enum AbilityEffect
ABILITYEFFECT_SYNCHRONIZE,
ABILITYEFFECT_ATK_SYNCHRONIZE,
ABILITYEFFECT_FORM_CHANGE_ON_HIT,
ABILITYEFFECT_MOVE_END_OTHER,
ABILITYEFFECT_DANCER,
ABILITYEFFECT_MOVE_END_FOES_FAINTED, // Moxie-like abilities / Battle Bond / Magician
// On Switch in

View File

@ -1142,11 +1142,11 @@ static enum CancelerResult CancelerMoveFailure(struct BattleContext *ctx)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_FIRST_TURN_ONLY:
if (!gBattleStruct->battlerState[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].instructedChosenTarget)
if (!gBattleStruct->battlerState[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].backUpTarget)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_MAT_BLOCK:
if (!gBattleStruct->battlerState[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].instructedChosenTarget)
if (!gBattleStruct->battlerState[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].backUpTarget)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_FOLLOW_ME:
@ -3689,10 +3689,8 @@ static enum MoveEndResult MoveEndClearBits(void)
if (ShouldSetStompingTantrumTimer())
gBattleStruct->battlerState[gBattlerAttacker].stompingTantrumTimer = 2;
if (gSpecialStatuses[gBattlerAttacker].instructedChosenTarget)
gBattleStruct->moveTarget[gBattlerAttacker] = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3;
if (gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget)
gBattleStruct->moveTarget[gBattlerAttacker] = gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget & 0x3;
if (gSpecialStatuses[gBattlerAttacker].backUpTarget)
gBattleStruct->moveTarget[gBattlerAttacker] = gSpecialStatuses[gBattlerAttacker].backUpTarget - 1;
// If the Pokémon needs to keep track of move usage for its evolutions, do it
if (originallyUsedMove != MOVE_NONE)
@ -3758,35 +3756,8 @@ static enum MoveEndResult MoveEndClearBits(void)
static enum MoveEndResult MoveEndDancer(void)
{
enum MoveEndResult result = MOVEEND_RESULT_CONTINUE;
bool32 anyDancerQueued = FALSE;
enum BattlerId nextDancer = 0;
for (enum BattlerId battler = 0; battler < gBattlersCount; battler++)
{
if (gBattleMons[battler].volatiles.activateDancer && !gSpecialStatuses[battler].dancerUsedMove)
{
if (!anyDancerQueued || (gBattleMons[battler].speed < gBattleMons[nextDancer].speed))
nextDancer = battler;
anyDancerQueued = TRUE;
}
}
if (!anyDancerQueued)
{
gBattleScripting.moveendState++;
return result;
}
// 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;
}
if (AbilityBattleEffects(ABILITYEFFECT_MOVE_END_OTHER, nextDancer, ABILITY_DANCER, gCurrentMove, TRUE))
if (AbilityBattleEffects(ABILITYEFFECT_DANCER, gBattlerAttacker, ABILITY_DANCER, gCurrentMove, TRUE))
result = MOVEEND_RESULT_RUN_SCRIPT;
gBattleScripting.moveendState++;

View File

@ -14175,7 +14175,7 @@ void BS_TryInstruct(void)
}
else
{
gSpecialStatuses[gBattlerTarget].instructedChosenTarget = gBattleStruct->moveTarget[gBattlerTarget] | 0x4;
gSpecialStatuses[gBattlerTarget].backUpTarget = gBattleStruct->moveTarget[gBattlerTarget] + 1;
gCalledMove = move;
u32 moveIndex;
bool32 foundMove = FALSE;

View File

@ -3049,6 +3049,62 @@ static bool32 IsRestrictedAbility(enum BattlerId battler, enum Ability ability)
|| GetSpeciesAbility(gBattleMons[battler].species, 2) == ability;
}
static bool32 TryDancer(void)
{
bool32 anyDancerQueued = FALSE;
enum BattlerId dancerBattler = MAX_BATTLERS_COUNT;
if (!IsDanceMove(gCurrentMove))
return FALSE;
for (enum BattlerId battler = 0; battler < gBattlersCount; battler++)
{
if (gBattleMons[battler].volatiles.activateDancer && !gSpecialStatuses[battler].dancerUsedMove)
{
if (!anyDancerQueued || (gBattleMons[battler].speed < gBattleMons[dancerBattler].speed))
dancerBattler = battler;
anyDancerQueued = TRUE;
}
}
if (!anyDancerQueued)
return FALSE;
// 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;
}
if (IsBattlerAlive(dancerBattler)
&& !gSpecialStatuses[dancerBattler].dancerUsedMove
&& gBattlerAttacker != dancerBattler)
{
gSpecialStatuses[dancerBattler].dancerUsedMove = TRUE;
gSpecialStatuses[dancerBattler].backUpTarget = gBattleStruct->moveTarget[dancerBattler] + 1;
gBattleMons[dancerBattler].volatiles.activateDancer = FALSE;
gBattlerAttacker = gBattlerAbility = dancerBattler;
gCalledMove = gCurrentMove;
gLastUsedAbility = ABILITY_DANCER;
RecordAbilityBattle(gBattlerAttacker, ABILITY_DANCER);
// Set the target to the original target of the mon that first used a Dance move
gBattlerTarget = gBattleScripting.savedBattler & 0x3;
// Make sure that the target isn't an ally - if it is, target the original user
if (IsBattlerAlly(gBattlerTarget, gBattlerAttacker))
gBattlerTarget = (gBattleScripting.savedBattler & 0xF0) >> 4;
BattleScriptExecute(BattleScript_DancerActivates);
return TRUE;
}
return FALSE;
}
u32 AbilityBattleEffects(enum AbilityEffect caseID, enum BattlerId battler, enum Ability ability, enum Move move, bool32 shouldAbilityTrigger)
{
u32 effect = 0;
@ -4424,36 +4480,8 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, enum BattlerId battler, enum
break;
}
break;
case ABILITYEFFECT_MOVE_END_OTHER: // Abilities that activate on *another* battler's moveend: Dancer, Soul-Heart, Receiver, Symbiosis
switch (ability)
{
case ABILITY_DANCER:
if (IsBattlerAlive(battler)
&& IsDanceMove(move)
&& !gSpecialStatuses[battler].dancerUsedMove
&& gBattlerAttacker != battler)
{
// Set bit and save Dancer mon's original target
gSpecialStatuses[battler].dancerUsedMove = TRUE;
gSpecialStatuses[battler].dancerOriginalTarget = gBattleStruct->moveTarget[battler] | 0x4;
gBattleMons[battler].volatiles.activateDancer = FALSE;
gBattlerAttacker = gBattlerAbility = battler;
gCalledMove = move;
// Set the target to the original target of the mon that first used a Dance move
gBattlerTarget = gBattleScripting.savedBattler & 0x3;
// Make sure that the target isn't an ally - if it is, target the original user
if (IsBattlerAlly(gBattlerTarget, gBattlerAttacker))
gBattlerTarget = (gBattleScripting.savedBattler & 0xF0) >> 4;
BattleScriptExecute(BattleScript_DancerActivates);
effect++;
}
break;
default:
break;
}
break;
case ABILITYEFFECT_DANCER:
return TryDancer();
case ABILITYEFFECT_MOVE_END_FOES_FAINTED:
switch (ability)
{
@ -5027,7 +5055,7 @@ u32 IsAbilityPreventingEscape(enum BattlerId battler)
{
if (battler == battlerDef || IsBattlerAlly(battler, battlerDef))
continue;
if (!IsBattlerAlive(battlerDef))
continue;