Fixes Ruin abilities / gastro acid interaction (#9880)

This commit is contained in:
Alex 2026-05-01 15:18:43 +02:00 committed by GitHub
parent 84e02096fc
commit cfb4f864e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 158 additions and 19 deletions

View File

@ -7775,23 +7775,19 @@ BattleScript_PastelVeilEnd:
return
BattleScript_NeutralizingGasExits::
saveattacker
savetarget
pause B_WAIT_TIME_SHORT
printstring STRINGID_NEUTRALIZINGGASOVER
waitmessage B_WAIT_TIME_LONG
setbyte gBattlerAttacker, 0
setbyte gBattlerTarget, 0
sortbattlers
BattleScript_NeutralizingGasExitsLoop:
copyarraywithindex gBattlerTarget, gBattlersBySpeed, gBattlerAttacker, 1
jumpifabilitycantbereactivated BS_TARGET, BattleScript_NeutralizingGasExitsLoopIncrement
saveattacker
switchinabilities BS_TARGET
restoreattacker
copyarraywithindex gEffectBattler, gBattlersBySpeed, gBattlerTarget, 1
jumpifabilitycantbereactivated BS_EFFECT_BATTLER, BattleScript_NeutralizingGasExitsLoopIncrement
switchinabilities BS_EFFECT_BATTLER
BattleScript_NeutralizingGasExitsLoopIncrement:
addbyte gBattlerAttacker, 1
jumpifbytenotequal gBattlerAttacker, gBattlersCount, BattleScript_NeutralizingGasExitsLoop
restoreattacker
addbyte gBattlerTarget, 1
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_NeutralizingGasExitsLoop
restoretarget
return

View File

@ -408,6 +408,7 @@ bool32 HasPartnerTrainer(enum BattlerId battler);
bool32 IsAffectedByPowderMove(enum BattlerId battler, enum Ability ability, enum HoldEffect holdEffect);
enum Move GetNaturePowerMove(void);
void RemoveAbilityFlags(enum BattlerId battler);
void RemoveRuinAbilityFlags(enum BattlerId battler);
void CheckSetUnburden(enum BattlerId battler);
bool32 IsDazzlingAbility(enum Ability ability);
bool32 IsAllowedToUseBag(void);

View File

@ -9943,6 +9943,7 @@ static void Cmd_setgastroacid(void)
if (gBattleMons[gBattlerTarget].volatiles.neutralizingGas)
gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE;
RemoveRuinAbilityFlags(gBattlerTarget);
gBattleMons[gBattlerTarget].volatiles.gastroAcid = TRUE;
gBattlescriptCurrInstr = cmd->nextInstr;
}

View File

@ -4732,6 +4732,13 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, enum BattlerId battler, enum
case ABILITYEFFECT_NEUTRALIZINGGAS:
if (ability == ABILITY_NEUTRALIZING_GAS && !gBattleMons[battler].volatiles.neutralizingGas)
{
for (enum BattlerId battlerDef = B_BATTLER_0; battlerDef < gBattlersCount; battlerDef++)
{
if (battler == battlerDef || GetBattlerHoldEffectIgnoreAbility(battlerDef) == HOLD_EFFECT_ABILITY_SHIELD)
continue;
RemoveRuinAbilityFlags(battlerDef);
}
gBattleMons[battler].volatiles.neutralizingGas = TRUE;
gBattlerAbility = battler;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS;
@ -6862,17 +6869,8 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct BattleContext *ctx)
static bool32 IsRuinStatusActive(u32 fieldEffect)
{
bool32 isNeutralizingGasOnField = IsNeutralizingGasOnField();
for (enum BattlerId battler = 0; battler < gBattlersCount; battler++)
{
// Mold Breaker doesn't ignore Ruin field status but Gastro Acid and Neutralizing Gas do
if (gBattleMons[battler].volatiles.gastroAcid)
continue;
if (GetBattlerHoldEffectIgnoreAbility(battler) != HOLD_EFFECT_ABILITY_SHIELD
&& isNeutralizingGasOnField
&& gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS)
continue;
if (GetBattlerVolatile(battler, fieldEffect))
return TRUE;
}
@ -10739,6 +10737,27 @@ void RemoveAbilityFlags(enum BattlerId battler)
}
}
void RemoveRuinAbilityFlags(enum BattlerId battler)
{
switch (GetBattlerAbility(battler))
{
case ABILITY_VESSEL_OF_RUIN:
gBattleMons[battler].volatiles.vesselOfRuin = FALSE;
break;
case ABILITY_TABLETS_OF_RUIN:
gBattleMons[battler].volatiles.tabletsOfRuin = FALSE;
break;
case ABILITY_SWORD_OF_RUIN:
gBattleMons[battler].volatiles.swordOfRuin = FALSE;
break;
case ABILITY_BEADS_OF_RUIN:
gBattleMons[battler].volatiles.beadsOfRuin = FALSE;
break;
default:
break;
}
}
void CheckSetUnburden(enum BattlerId battler)
{
if (!(gFieldStatuses & STATUS_FIELD_MAGIC_ROOM)

View File

@ -189,3 +189,100 @@ DOUBLE_BATTLE_TEST("Beads of Ruin's Sp. Def reduction is ignored by Gastro Acid"
EXPECT_LT(results[0].damage, results[1].damage);
}
}
SINGLE_BATTLE_TEST("Beads of Ruin reduces Sp. Def if opposing mon's ability doesn't match (Neutralizing switches in and out)")
{
s16 damage[2];
GIVEN {
ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
} WHEN {
TURN { MOVE(player, MOVE_WATER_GUN); }
TURN { SWITCH(opponent, 1); MOVE(player, MOVE_CELEBRATE); }
TURN { SWITCH(opponent, 0); MOVE(player, MOVE_WATER_GUN); }
} SCENE {
ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
HP_BAR(opponent, captureDamage: &damage[0]);
ABILITY_POPUP(opponent, ABILITY_NEUTRALIZING_GAS);
ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
HP_BAR(opponent, captureDamage: &damage[1]);
} THEN {
EXPECT_EQ(damage[1], damage[0]);
}
}
DOUBLE_BATTLE_TEST("Beads of Ruin will not reactivate after Sunsteel Strike faints Neutralizing Gas target")
{
s16 damage[2];
GIVEN {
ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
ASSUME(MoveIgnoresTargetAbility(MOVE_SUNSTEEL_STRIKE));
PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN {
MOVE(playerLeft, MOVE_WATER_GUN, target: opponentRight);
MOVE(playerRight, MOVE_SUNSTEEL_STRIKE, target: opponentLeft);
SEND_OUT(opponentLeft, 2);
}
TURN { MOVE(playerLeft, MOVE_WATER_GUN, target: opponentRight); }
} SCENE {
ABILITY_POPUP(opponentLeft, ABILITY_NEUTRALIZING_GAS);
NOT ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft);
HP_BAR(opponentRight, captureDamage: &damage[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNSTEEL_STRIKE, playerRight);
HP_BAR(opponentLeft);
MESSAGE("The opposing Weezing fainted!");
NOT ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft);
HP_BAR(opponentRight, captureDamage: &damage[1]);
} THEN {
EXPECT_EQ(damage[1], damage[0]);
}
}
DOUBLE_BATTLE_TEST("Beads of Ruin will not be deactivated with Ability Shield")
{
s16 damage[2];
GIVEN {
ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
ASSUME(gItemsInfo[ITEM_ABILITY_SHIELD].holdEffect == HOLD_EFFECT_ABILITY_SHIELD);
PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); Item(ITEM_ABILITY_SHIELD); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_WATER_GUN, target: opponentRight); }
TURN { SWITCH(opponentLeft, 2); MOVE(playerLeft, MOVE_WATER_GUN, target: opponentRight); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft);
HP_BAR(opponentRight, captureDamage: &damage[0]);
ABILITY_POPUP(opponentLeft, ABILITY_NEUTRALIZING_GAS);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft);
HP_BAR(opponentRight, captureDamage: &damage[1]);
} THEN {
EXPECT_EQ(damage[1], damage[0]);
}
}

View File

@ -146,3 +146,28 @@ DOUBLE_BATTLE_TEST("Vessel of Ruin is active if removed by Mold Breaker Entrainm
EXPECT_EQ(isSwordOfRuinActive, TRUE);
}
}
DOUBLE_BATTLE_TEST("Vessel of Ruin affects a Gastro Acid-suppressed Vessel of Ruin user")
{
s16 damage[2];
GIVEN {
ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID);
PLAYER(SPECIES_TING_LU) { Ability(ABILITY_VESSEL_OF_RUIN); }
PLAYER(SPECIES_TING_LU) { Ability(ABILITY_VESSEL_OF_RUIN); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); }
TURN { MOVE(opponentRight, MOVE_GASTRO_ACID, target: playerRight); }
TURN { MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerRight);
HP_BAR(opponentLeft, captureDamage: &damage[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_GASTRO_ACID, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerRight);
HP_BAR(opponentLeft, captureDamage: &damage[1]);
} THEN {
EXPECT_MUL_EQ(damage[1], Q_4_12(1.33), damage[0]);
}
}