Fix switch-in abilities not triggering on revive (#8293)

This commit is contained in:
FosterProgramming 2025-11-23 17:04:01 +01:00 committed by GitHub
parent 935817bf37
commit 7fd0745766
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 163 additions and 6 deletions

View File

@ -75,6 +75,10 @@ BattleScript_ItemRestoreHP_Party::
return
BattleScript_ItemRestoreHP_SendOutRevivedBattler:
switchhandleorder BS_SCRIPTING, 0
getswitchedmondata BS_SCRIPTING
switchindataupdate BS_SCRIPTING
trytoclearprimalweather
switchinanim BS_SCRIPTING, FALSE, FALSE
waitstate
switchineffects BS_SCRIPTING

View File

@ -4862,8 +4862,6 @@ static void Cmd_getexp(void)
// not sure why gf clears the item and ability here
gBattleStruct->expOrderId = 0;
gBattleStruct->teamGotExpMsgPrinted = FALSE;
gBattleMons[gBattlerFainted].item = ITEM_NONE;
gBattleMons[gBattlerFainted].ability = ABILITY_NONE;
gBattlescriptCurrInstr = cmd->nextInstr;
}
break;
@ -15192,12 +15190,14 @@ void BS_ItemRestoreHP(void)
hp += healAmount;
SetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_HP, &hp);
// Revived battlers on the field need to be brought back.
if (IsDoubleBattle() && battler != MAX_BATTLERS_COUNT)
u32 partner = BATTLE_PARTNER(gBattlerAttacker);
// Absent battlers on the field need to be replaced
if (IsDoubleBattle() && (gAbsentBattlerFlags & (1u << partner)))
{
gAbsentBattlerFlags &= ~(1u << battler);
gBattleMons[battler].hp = hp;
gAbsentBattlerFlags &= ~(1u << partner);
gBattleCommunication[MULTIUSE_STATE] = TRUE;
gBattleScripting.battler = partner;
BtlController_EmitChosenMonReturnValue(partner, B_COMM_TO_ENGINE, gBattleStruct->itemPartyIndex[gBattlerAttacker], NULL);
}
gBattlescriptCurrInstr = cmd->nextInstr;
}

View File

@ -5195,6 +5195,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITYEFFECT_ON_WEATHER: // For ability effects that activate when the battle weather changes.
if (!IsBattlerAlive(battler))
return effect;
gLastUsedAbility = GetBattlerAbility(battler);
switch (gLastUsedAbility)
{
@ -5249,6 +5251,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITYEFFECT_ON_TERRAIN: // For ability effects that activate when the field terrain changes.
if (!IsBattlerAlive(battler))
return effect;
gLastUsedAbility = GetBattlerAbility(battler);
switch (gLastUsedAbility)
{

View File

@ -99,3 +99,28 @@ SINGLE_BATTLE_TEST("Unnerve activates only once per switch-in")
}
}
DOUBLE_BATTLE_TEST("Unnerve stops applying on death but applies on revive")
{
u16 mon;
u16 ability;
PARAMETRIZE { mon = SPECIES_JOLTIK, ability = ABILITY_UNNERVE;}
PARAMETRIZE { mon = SPECIES_CALYREX_ICE, ability = ABILITY_AS_ONE_ICE_RIDER; }
GIVEN {
ASSUME(gItemsInfo[ITEM_RAWST_BERRY].holdEffect == HOLD_EFFECT_CURE_BRN);
ASSUME(gItemsInfo[ITEM_REVIVE].battleUsage == EFFECT_ITEM_REVIVE);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(mon) { Ability(ability); HP(1); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RAWST_BERRY); Status1(STATUS1_BURN); }
OPPONENT(SPECIES_WYNAUT) { Item(ITEM_RAWST_BERRY); }
} WHEN {
TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight); }
TURN { USE_ITEM(playerLeft, ITEM_REVIVE, partyIndex: 1); SKIP_TURN(playerRight); MOVE(opponentLeft, MOVE_WILL_O_WISP, target: opponentRight); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, opponentRight);
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
}
}

View File

@ -99,4 +99,128 @@ DOUBLE_BATTLE_TEST("Revive works for a partner in a double battle")
}
}
DOUBLE_BATTLE_TEST("Revive can trigger switch-in abilities")
{
GIVEN {
PLAYER(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); HP(1); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft); }
TURN { USE_ITEM(playerRight, ITEM_REVIVE, partyIndex: 0); SKIP_TURN(playerLeft); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
} THEN {
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 2);
EXPECT_EQ(opponentRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 2);
}
}
DOUBLE_BATTLE_TEST("Revive does reset abilities")
{
GIVEN {
PLAYER(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); HP(1); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponentRight, MOVE_WORRY_SEED, target: playerLeft); MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft); }
TURN { USE_ITEM(playerRight, ITEM_REVIVE, partyIndex: 0); SKIP_TURN(playerLeft); MOVE(opponentRight, MOVE_SPORE, target: playerLeft);}
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
} THEN {
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 2);
EXPECT_EQ(opponentRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 2);
}
}
DOUBLE_BATTLE_TEST("Revive does not grant a mon its pre-death status condition")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT) { Status1(STATUS1_SLEEP); HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight); }
TURN { USE_ITEM(playerLeft, ITEM_REVIVE, partyIndex: 1); SKIP_TURN(playerRight); }
} THEN {
EXPECT_EQ(opponentRight->status1, 0);
}
}
DOUBLE_BATTLE_TEST("Revive does not grant a mon its pre-death stat change")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerRight, MOVE_SWORDS_DANCE); MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight); }
TURN { USE_ITEM(playerLeft, ITEM_REVIVE, partyIndex: 1); SKIP_TURN(playerRight); }
} THEN {
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
}
}
DOUBLE_BATTLE_TEST("Revive does not grant a mon its pre-death types")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_POOCHYENA);
} WHEN {
TURN { MOVE(playerRight, MOVE_REFLECT_TYPE, target: opponentRight); MOVE(opponentLeft, MOVE_PSYSHOCK, target: playerRight); MOVE(opponentRight, MOVE_SCRATCH, target: playerRight); }
TURN { USE_ITEM(playerLeft, ITEM_MAX_REVIVE, partyIndex: 1); SKIP_TURN(playerRight); MOVE(opponentLeft, MOVE_PSYCHIC, target: playerRight);}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, playerRight);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYSHOCK, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHIC, opponentLeft);
} THEN {
EXPECT_LT(playerRight->hp, playerRight->maxHP);
}
}
DOUBLE_BATTLE_TEST("Revive force revived pokemon to replace absent battler immediately", s16 damage)
{
u32 ability;
PARAMETRIZE { ability = ABILITY_INTIMIDATE; }
PARAMETRIZE { ability = ABILITY_SHED_SKIN; }
GIVEN {
PLAYER(SPECIES_WYNAUT) { HP(1); }
PLAYER(SPECIES_WOBBUFFET) { };
PLAYER(SPECIES_ARBOK) { Ability(ability); HP(0) ;} ;
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft);}
TURN { USE_ITEM(playerRight, ITEM_REVIVE, partyIndex: 2); SKIP_TURN(playerLeft); MOVE(opponentRight, MOVE_SCRATCH, target: playerRight); }
} SCENE {
if (ability == ABILITY_INTIMIDATE)
{
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentRight);
HP_BAR(playerRight, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
}
}
TO_DO_BATTLE_TEST("Revive won't restore a battler's HP if it hasn't fainted")