diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index a15dd459f5..6ba63f916f 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1877,6 +1877,10 @@ .2byte \species .4byte \ptr .endm + + .macro tryendneutralizinggas battler:req + various \battler, VARIOUS_TRY_END_NEUTRALIZING_GAS + .endm .macro trytoapplymimicry battler:req, ptr:req various \battler, VARIOUS_TRY_TO_APPLY_MIMICRY diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index ee859f0e03..e9d019e430 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2187,6 +2187,7 @@ BattleScript_EffectSimpleBeam: trytoclearprimalweather printstring STRINGID_EMPTYSTRING3 waitmessage 1 + tryendneutralizinggas BS_TARGET goto BattleScript_MoveEnd BattleScript_EffectSuckerPunch: @@ -2409,6 +2410,7 @@ BattleScript_EffectGastroAcid: trytoclearprimalweather printstring STRINGID_EMPTYSTRING3 waitmessage 1 + tryendneutralizinggas BS_TARGET goto BattleScript_MoveEnd BattleScript_EffectToxicSpikes: @@ -8378,6 +8380,12 @@ BattleScript_SwitchInAbilityMsg:: waitmessage B_WAIT_TIME_LONG end3 +BattleScript_SwitchInAbilityMsgRet:: + call BattleScript_AbilityPopUp + printfromtable gSwitchInAbilityStringIds + waitmessage B_WAIT_TIME_LONG + return + BattleScript_ActivateAsOne:: call BattleScript_AbilityPopUp printfromtable gSwitchInAbilityStringIds @@ -9231,3 +9239,19 @@ BattleScript_PastelVeilLoopIncrement: goto BattleScript_PastelVeilEnd BattleScript_PastelVeilEnd: end3 + +sByteFour: +.byte MAX_BATTLERS_COUNT + +BattleScript_NeutralizingGasExits:: + savetarget + pause B_WAIT_TIME_SHORT + printstring STRINGID_NEUTRALIZINGGASOVER + waitmessage B_WAIT_TIME_LONG + setbyte gBattlerTarget, 0 +BattleScript_NeutralizingGasExitsLoop: + switchinabilities BS_TARGET + addbyte gBattlerTarget, 1 + jumpifbytenotequal gBattlerTarget, sByteFour, BattleScript_NeutralizingGasExitsLoop @ SOMEHOW, comparing to gBattlersCount is problematic. + restoretarget + return diff --git a/include/battle.h b/include/battle.h index f1262b128e..b587e482db 100644 --- a/include/battle.h +++ b/include/battle.h @@ -62,12 +62,13 @@ struct ResourceFlags u32 flags[4]; }; -#define RESOURCE_FLAG_FLASH_FIRE 0x1 -#define RESOURCE_FLAG_ROOST 0x2 -#define RESOURCE_FLAG_UNBURDEN 0x4 -#define RESOURCE_FLAG_INTIMIDATED 0x8 -#define RESOURCE_FLAG_TRACED 0x10 -#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20 +#define RESOURCE_FLAG_FLASH_FIRE 0x1 +#define RESOURCE_FLAG_ROOST 0x2 +#define RESOURCE_FLAG_UNBURDEN 0x4 +#define RESOURCE_FLAG_INTIMIDATED 0x8 +#define RESOURCE_FLAG_TRACED 0x10 +#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20 +#define RESOURCE_FLAG_NEUTRALIZING_GAS 0x40 struct DisableStruct { @@ -184,6 +185,8 @@ struct SpecialStatus u8 damagedMons:4; // Mons that have been damaged directly by using a move, includes substitute. u8 dancerUsedMove:1; u8 dancerOriginalTarget:3; + u8 announceNeutralizingGas:1; // See Cmd_switchineffects + u8 neutralizingGasRemoved:1; // See VARIOUS_TRY_END_NEUTRALIZING_GAS s32 dmg; s32 physicalDmg; s32 specialDmg; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 41d4ee91d9..415eaa6bb4 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -261,6 +261,7 @@ extern const u8 BattleScript_AttackerAbilityStatRaiseEnd3[]; extern const u8 BattleScript_PoisonHealActivates[]; extern const u8 BattleScript_BadDreamsActivates[]; extern const u8 BattleScript_SwitchInAbilityMsg[]; +extern const u8 BattleScript_SwitchInAbilityMsgRet[]; extern const u8 BattleScript_ToxicSpikesPoisoned[]; extern const u8 BattleScript_ToxicSpikesAbsorbed[]; extern const u8 BattleScript_StickyWebOnSwitchIn[]; @@ -413,5 +414,6 @@ extern const u8 BattleScript_AttackerFormChangeEnd3NoPopup[]; extern const u8 BattleScript_AttackerFormChangeMoveEffect[]; extern const u8 BattleScript_BothCanNoLongerEscape[]; extern const u8 BattleScript_OctolockEndTurn[]; +extern const u8 BattleScript_NeutralizingGasExits[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index d3b930feda..b1a2a15347 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -8,21 +8,23 @@ #define MOVE_LIMITATION_TAUNT (1 << 4) #define MOVE_LIMITATION_IMPRISON (1 << 5) -#define ABILITYEFFECT_ON_SWITCHIN 0x0 -#define ABILITYEFFECT_ENDTURN 0x1 -#define ABILITYEFFECT_MOVES_BLOCK 0x2 -#define ABILITYEFFECT_ABSORBING 0x3 -#define ABILITYEFFECT_MOVE_END_ATTACKER 0x4 -#define ABILITYEFFECT_MOVE_END 0x5 -#define ABILITYEFFECT_IMMUNITY 0x6 -#define ABILITYEFFECT_FORECAST 0x7 -#define ABILITYEFFECT_SYNCHRONIZE 0x8 -#define ABILITYEFFECT_ATK_SYNCHRONIZE 0x9 -#define ABILITYEFFECT_INTIMIDATE1 0xA -#define ABILITYEFFECT_INTIMIDATE2 0xB -#define ABILITYEFFECT_TRACE1 0xC -#define ABILITYEFFECT_TRACE2 0xD -#define ABILITYEFFECT_MOVE_END_OTHER 0xE +#define ABILITYEFFECT_ON_SWITCHIN 0 +#define ABILITYEFFECT_ENDTURN 1 +#define ABILITYEFFECT_MOVES_BLOCK 2 +#define ABILITYEFFECT_ABSORBING 3 +#define ABILITYEFFECT_MOVE_END_ATTACKER 4 +#define ABILITYEFFECT_MOVE_END 5 +#define ABILITYEFFECT_IMMUNITY 6 +#define ABILITYEFFECT_FORECAST 7 +#define ABILITYEFFECT_SYNCHRONIZE 8 +#define ABILITYEFFECT_ATK_SYNCHRONIZE 9 +#define ABILITYEFFECT_INTIMIDATE1 10 +#define ABILITYEFFECT_INTIMIDATE2 11 +#define ABILITYEFFECT_TRACE1 12 +#define ABILITYEFFECT_TRACE2 13 +#define ABILITYEFFECT_MOVE_END_OTHER 14 +#define ABILITYEFFECT_NEUTRALIZINGGAS 15 +// Special cases #define ABILITYEFFECT_SWITCH_IN_TERRAIN 0xFE #define ABILITYEFFECT_SWITCH_IN_WEATHER 0xFF diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 7ceb1d64bf..bd16f741be 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -207,6 +207,7 @@ #define VARIOUS_CHECK_POLTERGEIST 134 #define VARIOUS_SET_OCTOLOCK 135 #define VARIOUS_CUT_1_3_HP_RAISE_STATS 136 +#define VARIOUS_TRY_END_NEUTRALIZING_GAS 137 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index d439e3e7f1..7846fa5218 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -607,8 +607,10 @@ #define STRINGID_PKMNBECAMEWEAKERTOFIRE 604 #define STRINGID_ABOUTTOUSEPOLTERGEIST 605 #define STRINGID_CANTESCAPEBECAUSEOFCURRENTMOVE 606 +#define STRINGID_NEUTRALIZINGGASENTERS 607 +#define STRINGID_NEUTRALIZINGGASOVER 608 -#define BATTLESTRINGS_COUNT 607 +#define BATTLESTRINGS_COUNT 609 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. @@ -844,6 +846,7 @@ #define B_MSG_SWITCHIN_ASONE 13 #define B_MSG_SWITCHIN_CURIOUS_MEDICINE 14 #define B_MSG_SWITCHIN_PASTEL_VEIL 15 +#define B_MSG_SWITCHIN_NEUTRALIZING_GAS 16 // gMentalHerbCureStringIds #define B_MSG_MENTALHERBCURE_INFATUATION 0 diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index e8e3999357..400876cc9b 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -82,7 +82,7 @@ static bool8 ShouldSwitchIfWonderGuard(void) opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(gActiveBattler)); - if (gBattleMons[GetBattlerAtPosition(opposingPosition)].ability != ABILITY_WONDER_GUARD) + if (GetBattlerAbility(GetBattlerAtPosition(opposingPosition)) != ABILITY_WONDER_GUARD) return FALSE; // Check if Pokemon has a super effective move. @@ -176,7 +176,7 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void) else return FALSE; - if (gBattleMons[gActiveBattler].ability == absorbingTypeAbility) + if (AI_GetAbility(gActiveBattler) == absorbingTypeAbility) return FALSE; GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); @@ -228,7 +228,7 @@ static bool8 ShouldSwitchIfNaturalCure(void) { if (!(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)) return FALSE; - if (gBattleMons[gActiveBattler].ability != ABILITY_NATURAL_CURE) + if (AI_GetAbility(gActiveBattler) != ABILITY_NATURAL_CURE) return FALSE; if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 2) return FALSE; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 71dc78d0aa..81450eccbe 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1121,19 +1121,24 @@ bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability) // does NOT include ability suppression checks s32 AI_GetAbility(u32 battlerId) { + u32 knownAbility = GetBattlerAbility(battlerId); + // The AI knows its own ability. if (IsBattlerAIControlled(battlerId)) - return gBattleMons[battlerId].ability; + return knownAbility; + + // Check neutralizing gas, gastro acid + if (knownAbility == ABILITY_NONE) + return knownAbility; if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE) return BATTLE_HISTORY->abilities[battlerId]; - // Abilities that prevent fleeing. - if (gBattleMons[battlerId].ability == ABILITY_SHADOW_TAG - || gBattleMons[battlerId].ability == ABILITY_MAGNET_PULL - || gBattleMons[battlerId].ability == ABILITY_ARENA_TRAP) - return gBattleMons[battlerId].ability; + // Abilities that prevent fleeing - treat as always known + if (knownAbility == ABILITY_SHADOW_TAG || knownAbility == ABILITY_MAGNET_PULL || knownAbility == ABILITY_ARENA_TRAP) + return knownAbility; + // Else, guess the ability if (gBaseStats[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE) { if (gBaseStats[gBattleMons[battlerId].species].abilities[1] != ABILITY_NONE) @@ -1146,6 +1151,7 @@ s32 AI_GetAbility(u32 battlerId) return gBaseStats[gBattleMons[battlerId].species].abilities[0]; // It's definitely ability 1. } } + return ABILITY_NONE; // Unknown. } diff --git a/src/battle_main.c b/src/battle_main.c index 0b96794a60..5277ade1ea 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3548,7 +3548,11 @@ static void TryDoEventsBeforeFirstTurn(void) return; } } - + + // Check neutralizing gas + if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0) + return; + // Check all switch in abilities happening from the fastest mon to slowest. while (gBattleStruct->switchInAbilitiesCounter < gBattlersCount) { diff --git a/src/battle_message.c b/src/battle_message.c index 28bcca187b..d64d02f902 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -733,9 +733,13 @@ static const u8 sText_CantEscapeDueToUsedMove[] = _("{B_ATK_NAME_WITH_PREFIX} ca static const u8 sText_PkmnBecameWeakerToFire[] = _("{B_DEF_NAME_WITH_PREFIX} became\nweaker to fire!"); static const u8 sText_PkmnAboutToBeAttackedByItsItem[] = _("{B_DEF_NAME_WITH_PREFIX} is about\nto be attacked by its {B_BUFF1}!"); static const u8 sText_CantEscapeBecauseOfCurrentMove[] = _("{B_DEF_NAME_WITH_PREFIX} can no longer escape\nbecause of {B_CURRENT_MOVE}!"); +static const u8 sText_NeutralizingGasEnters[] = _("Neutralizing Gas filled the area!"); +static const u8 sText_NeutralizingGasOver[] = _("The effects of Neutralizing\nGas wore off!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_NEUTRALIZINGGASOVER - 12] = sText_NeutralizingGasOver, + [STRINGID_NEUTRALIZINGGASENTERS - 12] = sText_NeutralizingGasEnters, [STRINGID_BATTLERTYPECHANGEDTO - 12] = sText_BattlerTypeChangedTo, [STRINGID_PASTELVEILENTERS - 12] = sText_PastelVeilEnters, [STRINGID_PASTELVEILPROTECTED -12] = sText_PastelVeilProtected, @@ -1392,6 +1396,7 @@ const u16 gSwitchInAbilityStringIds[] = [B_MSG_SWITCHIN_ASONE] = STRINGID_ASONEENTERS, [B_MSG_SWITCHIN_CURIOUS_MEDICINE] = STRINGID_CURIOUSMEDICINEENTERS, [B_MSG_SWITCHIN_PASTEL_VEIL] = STRINGID_PASTELVEILENTERS, + [B_MSG_SWITCHIN_NEUTRALIZING_GAS] = STRINGID_NEUTRALIZINGGASENTERS, }; const u16 gMissStringIds[] = diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index eb9334c4ea..bf17ef436d 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -6159,8 +6159,17 @@ static void Cmd_switchineffects(void) gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler)); gSpecialStatuses[gActiveBattler].flag40 = 0; - - if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED) + + // Neutralizing Gas announces itself before hazards + if (gBattleMons[gActiveBattler].ability == ABILITY_NEUTRALIZING_GAS && gSpecialStatuses[gActiveBattler].announceNeutralizingGas == 0) + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS; + gSpecialStatuses[gActiveBattler].announceNeutralizingGas = TRUE; + gBattlerAbility = gActiveBattler; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SwitchInAbilityMsgRet; + } + else if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED) && (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES) && GetBattlerAbility(gActiveBattler) != ABILITY_MAGIC_GUARD && IsBattlerAffectedByHazards(gActiveBattler, FALSE) @@ -6234,7 +6243,7 @@ static void Cmd_switchineffects(void) { // There is a hack here to ensure the truant counter will be 0 when the battler's next turn starts. // The truant counter is not updated in the case where a mon switches in after a lost judgement in the battle arena. - if (gBattleMons[gActiveBattler].ability == ABILITY_TRUANT + if (GetBattlerAbility(gActiveBattler) == ABILITY_TRUANT && gCurrentActionFuncId != B_ACTION_USE_MOVE && !gDisableStructs[gActiveBattler].truantSwitchInHack) gDisableStructs[gActiveBattler].truantCounter = 1; @@ -7425,7 +7434,7 @@ u32 IsLeafGuardProtected(u32 battler) bool32 IsShieldsDownProtected(u32 battler) { - return (gBattleMons[battler].ability == ABILITY_SHIELDS_DOWN + return (GetBattlerAbility(battler) == ABILITY_SHIELDS_DOWN && GetFormIdFromFormSpeciesId(gBattleMons[battler].species) < GetFormIdFromFormSpeciesId(SPECIES_MINIOR_CORE_RED)); // Minior is not in core form } @@ -7893,6 +7902,7 @@ static void Cmd_various(void) break; case VARIOUS_SWITCHIN_ABILITIES: gBattlescriptCurrInstr += 3; + AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, gActiveBattler, 0, 0, 0); AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBattler, 0, 0, 0); AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE2, gActiveBattler, 0, 0, 0); AbilityBattleEffects(ABILITYEFFECT_TRACE2, gActiveBattler, 0, 0, 0); @@ -8073,6 +8083,9 @@ static void Cmd_various(void) } else { + if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS) + gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE; + gBattleMons[gBattlerTarget].ability = ABILITY_SIMPLE; gBattlescriptCurrInstr += 7; } @@ -8976,6 +8989,15 @@ static void Cmd_various(void) } break; } + case VARIOUS_TRY_END_NEUTRALIZING_GAS: + if (gSpecialStatuses[gActiveBattler].neutralizingGasRemoved) + { + gSpecialStatuses[gActiveBattler].neutralizingGasRemoved = FALSE; + BattleScriptPush(gBattlescriptCurrInstr + 3); + gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits; + return; + } + break; case VARIOUS_GET_ROTOTILLER_TARGETS: // Gets the battlers to be affected by rototiller. If there are none, print 'But it failed!' { @@ -11391,11 +11413,11 @@ static void Cmd_healpartystatus(void) u16 ability; if (gBattlerPartyIndexes[gBattlerAttacker] == i) - ability = gBattleMons[gBattlerAttacker].ability; + ability = GetBattlerAbility(gBattlerAttacker); else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlerPartyIndexes[gActiveBattler] == i && !(gAbsentBattlerFlags & gBitTable[gActiveBattler])) - ability = gBattleMons[gActiveBattler].ability; + ability = GetBattlerAbility(gActiveBattler); else ability = GetAbilityBySpecies(species, abilityNum); @@ -12345,6 +12367,9 @@ static void Cmd_setgastroacid(void) } else { + if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS) + gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE; + gStatuses3[gBattlerTarget] |= STATUS3_GASTRO_ACID; gBattlescriptCurrInstr += 5; } @@ -12625,25 +12650,33 @@ static void Cmd_trygetintimidatetarget(void) static void Cmd_switchoutabilities(void) { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); - - switch (GetBattlerAbility(gActiveBattler)) + if (gBattleMons[gActiveBattler].ability == ABILITY_NEUTRALIZING_GAS) { - case ABILITY_NATURAL_CURE: - gBattleMons[gActiveBattler].status1 = 0; - BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 4, &gBattleMons[gActiveBattler].status1); - MarkBattlerForControllerExec(gActiveBattler); - break; - case ABILITY_REGENERATOR: - gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 3; - gBattleMoveDamage += gBattleMons[gActiveBattler].hp; - if (gBattleMoveDamage > gBattleMons[gActiveBattler].maxHP) - gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP; - BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 2, &gBattleMoveDamage); - MarkBattlerForControllerExec(gActiveBattler); - break; + gBattleMons[gActiveBattler].ability = ABILITY_NONE; + BattleScriptPush(gBattlescriptCurrInstr); + gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits; + } + else + { + switch (GetBattlerAbility(gActiveBattler)) + { + case ABILITY_NATURAL_CURE: + gBattleMons[gActiveBattler].status1 = 0; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 4, &gBattleMons[gActiveBattler].status1); + MarkBattlerForControllerExec(gActiveBattler); + break; + case ABILITY_REGENERATOR: + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 3; + gBattleMoveDamage += gBattleMons[gActiveBattler].hp; + if (gBattleMoveDamage > gBattleMons[gActiveBattler].maxHP) + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP; + BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 2, &gBattleMoveDamage); + MarkBattlerForControllerExec(gActiveBattler); + break; + } + + gBattlescriptCurrInstr += 2; } - - gBattlescriptCurrInstr += 2; } static void Cmd_jumpifhasnohp(void) diff --git a/src/battle_util.c b/src/battle_util.c index 2c2918a004..7e1a5bf4a5 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -317,8 +317,8 @@ void HandleAction_UseMove(void) else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gSideTimers[side].followmeTimer == 0 && (gBattleMoves[gCurrentMove].power != 0 || gBattleMoves[gCurrentMove].target != MOVE_TARGET_USER) - && ((gBattleMons[*(gBattleStruct->moveTarget + gBattlerAttacker)].ability != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) - || (gBattleMons[*(gBattleStruct->moveTarget + gBattlerAttacker)].ability != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) + && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) + || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) { side = GetBattlerSide(gBattlerAttacker); for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) @@ -387,9 +387,9 @@ void HandleAction_UseMove(void) { gActiveBattler = gBattlerByTurnOrder[var]; RecordAbilityBattle(gActiveBattler, gBattleMons[gActiveBattler].ability); - if (gBattleMons[gActiveBattler].ability == ABILITY_LIGHTNING_ROD) + if (GetBattlerAbility(gActiveBattler) == ABILITY_LIGHTNING_ROD) gSpecialStatuses[gActiveBattler].lightningRodRedirected = TRUE; - else if (gBattleMons[gActiveBattler].ability == ABILITY_STORM_DRAIN) + else if (GetBattlerAbility(gActiveBattler) == ABILITY_STORM_DRAIN) gSpecialStatuses[gActiveBattler].stormDrainRedirected = TRUE; gBattlerTarget = gActiveBattler; } @@ -627,7 +627,7 @@ bool8 TryRunFromBattle(u8 battler) effect++; } #endif - else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY) + else if (GetBattlerAbility(battler) == ABILITY_RUN_AWAY) { if (InBattlePyramid()) { @@ -2727,7 +2727,7 @@ u8 DoBattlerEndTurnEffects(void) for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++) { if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) - && gBattleMons[gBattlerAttacker].ability != ABILITY_SOUNDPROOF) + && GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF) { gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP); gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE); @@ -3311,7 +3311,7 @@ u8 AtkCanceller_UnableToUseMove(void) gBattleStruct->atkCancellerTracker++; break; case CANCELLER_TRUANT: // truant - if (gBattleMons[gBattlerAttacker].ability == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) { CancelMultiTurnMoves(gBattlerAttacker); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; @@ -3752,7 +3752,7 @@ u8 TryWeatherFormChange(u8 battler) if (gBattleMons[battler].species == SPECIES_CASTFORM) { - if (gBattleMons[battler].ability != ABILITY_FORECAST || gBattleMons[battler].hp == 0) + if (GetBattlerAbility(battler) != ABILITY_FORECAST || gBattleMons[battler].hp == 0) { ret = 0; } @@ -3788,7 +3788,7 @@ u8 TryWeatherFormChange(u8 battler) } else if (gBattleMons[battler].species == SPECIES_CHERRIM) { - if (gBattleMons[battler].ability != ABILITY_FLOWER_GIFT || gBattleMons[battler].hp == 0) + if (GetBattlerAbility(battler) != ABILITY_FLOWER_GIFT || gBattleMons[battler].hp == 0) ret = 0; else if (gBattleMonForms[battler] == 0 && weatherEffect && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && gBattleWeather & WEATHER_SUN_ANY) ret = 2; @@ -3878,7 +3878,7 @@ static bool32 ShouldChangeFormHpBased(u32 battler) for (i = 0; i < ARRAY_COUNT(forms); i++) { - if (gBattleMons[battler].ability == forms[i][0]) + if (GetBattlerAbility(battler) == forms[i][0]) { if (gBattleMons[battler].species == forms[i][2] && gBattleMons[battler].hp > gBattleMons[battler].maxHP / forms[i][3]) @@ -5373,7 +5373,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move case ABILITYEFFECT_IMMUNITY: // 5 for (battler = 0; battler < gBattlersCount; battler++) { - switch (gBattleMons[battler].ability) + switch (GetBattlerAbility(battler)) { case ABILITY_IMMUNITY: if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER)) @@ -5463,7 +5463,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move case ABILITYEFFECT_FORECAST: // 6 for (battler = 0; battler < gBattlersCount; battler++) { - if (gBattleMons[battler].ability == ABILITY_FORECAST || gBattleMons[battler].ability == ABILITY_FLOWER_GIFT) + if (GetBattlerAbility(battler) == ABILITY_FORECAST || GetBattlerAbility(battler) == ABILITY_FLOWER_GIFT) { effect = TryWeatherFormChange(battler); if (effect) @@ -5524,7 +5524,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move case ABILITYEFFECT_INTIMIDATE2: for (i = 0; i < gBattlersCount; i++) { - if (gBattleMons[i].ability == ABILITY_INTIMIDATE && gBattleResources->flags->flags[i] & RESOURCE_FLAG_INTIMIDATED) + if (GetBattlerAbility(i) == ABILITY_INTIMIDATE && gBattleResources->flags->flags[i] & RESOURCE_FLAG_INTIMIDATED) { gLastUsedAbility = ABILITY_INTIMIDATE; gBattleResources->flags->flags[i] &= ~(RESOURCE_FLAG_INTIMIDATED); @@ -5591,6 +5591,23 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move } } break; + case ABILITYEFFECT_NEUTRALIZINGGAS: + // Prints message only. separate from ABILITYEFFECT_ON_SWITCHIN bc activates before entry hazards + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gBattleResources->flags->flags[i] & RESOURCE_FLAG_NEUTRALIZING_GAS)) + { + gBattleResources->flags->flags[i] |= RESOURCE_FLAG_NEUTRALIZING_GAS; + gBattlerAbility = i; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS; + BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg); + effect++; + } + + if (effect) + break; + } + break; } if (effect && gLastUsedAbility != 0xFF) @@ -5601,11 +5618,51 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move return effect; } +bool32 IsNeutralizingGasBannedAbility(u32 ability) +{ + switch (ability) + { + case ABILITY_MULTITYPE: + case ABILITY_ZEN_MODE: + case ABILITY_STANCE_CHANGE: + case ABILITY_POWER_CONSTRUCT: + case ABILITY_SCHOOLING: + case ABILITY_RKS_SYSTEM: + case ABILITY_SHIELDS_DOWN: + case ABILITY_COMATOSE: + case ABILITY_DISGUISE: + case ABILITY_GULP_MISSILE: + case ABILITY_ICE_FACE: + case ABILITY_AS_ONE_ICE_RIDER: + case ABILITY_AS_ONE_SHADOW_RIDER: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsNeutralizingGasOnField(void) +{ + u32 i; + + for (i = 0; i < gBattlersCount; i++) + { + if (IsBattlerAlive(i) && gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gStatuses3[i] & STATUS3_GASTRO_ACID)) + return TRUE; + } + + return FALSE; +} + u32 GetBattlerAbility(u8 battlerId) { if (gStatuses3[battlerId] & STATUS3_GASTRO_ACID) return ABILITY_NONE; - else if ((((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER + + if (IsNeutralizingGasOnField() && !IsNeutralizingGasBannedAbility(gBattleMons[battlerId].ability)) + return ABILITY_NONE; + + if ((((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER || gBattleMons[gBattlerAttacker].ability == ABILITY_TERAVOLT || gBattleMons[gBattlerAttacker].ability == ABILITY_TURBOBLAZE) && !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID)) @@ -5615,8 +5672,8 @@ u32 GetBattlerAbility(u8 battlerId) && gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE && gCurrentTurnActionNumber < gBattlersCount) return ABILITY_NONE; - else - return gBattleMons[battlerId].ability; + + return gBattleMons[battlerId].ability; } u32 IsAbilityOnSide(u32 battlerId, u32 ability) @@ -5668,7 +5725,7 @@ u32 IsAbilityPreventingEscape(u32 battlerId) return 0; #endif #if B_SHADOW_TAG_ESCAPE >= GEN_4 - if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && gBattleMons[battlerId].ability != ABILITY_SHADOW_TAG) + if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && GetBattlerAbility(battlerId) != ABILITY_SHADOW_TAG) #else if (id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) #endif @@ -7219,7 +7276,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget) targetBattler = SetRandomTarget(gBattlerAttacker); if (gBattleMoves[move].type == TYPE_ELECTRIC && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_LIGHTNING_ROD) - && gBattleMons[targetBattler].ability != ABILITY_LIGHTNING_ROD) + && GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD) { targetBattler ^= BIT_FLANK; RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); @@ -7227,7 +7284,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget) } else if (gBattleMoves[move].type == TYPE_WATER && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_STORM_DRAIN) - && gBattleMons[targetBattler].ability != ABILITY_STORM_DRAIN) + && GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN) { targetBattler ^= BIT_FLANK; RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); @@ -7405,7 +7462,7 @@ u32 GetBattlerHoldEffect(u8 battlerId, bool32 checkNegating) return HOLD_EFFECT_NONE; if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) return HOLD_EFFECT_NONE; - if (gBattleMons[battlerId].ability == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) + if (GetBattlerAbility(battlerId) == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) return HOLD_EFFECT_NONE; } diff --git a/src/battle_util2.c b/src/battle_util2.c index d15700706a..0af19de274 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -142,7 +142,7 @@ u32 sub_805725C(u8 battlerId) { u32 toSub; - if (gBattleMons[battlerId].ability == ABILITY_EARLY_BIRD) + if (GetBattlerAbility(battlerId) == ABILITY_EARLY_BIRD) toSub = 2; else toSub = 1;