diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 009c3a882f..e104db758e 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -8091,6 +8091,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 @@ -8909,3 +8915,14 @@ BattleScript_DarkTypePreventsPrankster:: waitmessage B_WAIT_TIME_LONG orhalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT goto BattleScript_MoveEnd + +BattleScript_NeutralizingGasExits:: + 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, gBattlersCount, BattleScript_NeutralizingGasExitsLoop + return diff --git a/include/battle.h b/include/battle.h index 5077053e35..68a40c9789 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 { @@ -181,6 +182,7 @@ 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; s32 dmg; s32 physicalDmg; s32 specialDmg; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index ec95a45497..1c48800113 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[]; @@ -402,5 +403,6 @@ extern const u8 BattleScript_BlockedByPrimalWeatherEnd3[]; extern const u8 BattleScript_BlockedByPrimalWeatherRet[]; extern const u8 BattleScript_PrimalReversion[]; extern const u8 BattleScript_HyperspaceFuryRemoveProtect[]; +extern const u8 BattleScript_NeutralizingGasExits[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index ee7337ef2d..32c7a53dc4 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_string_ids.h b/include/constants/battle_string_ids.h index 1d461e2a00..7167296198 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -597,8 +597,10 @@ #define STRINGID_BUTPOKEMONCANTUSETHEMOVE 594 #define STRINGID_BUTHOOPACANTUSEIT 595 #define STRINGID_BROKETHROUGHPROTECTION 596 +#define STRINGID_NEUTRALIZINGGASENTERS 597 +#define STRINGID_NEUTRALIZINGGASOVER 598 -#define BATTLESTRINGS_COUNT 597 +#define BATTLESTRINGS_COUNT 599 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. @@ -833,6 +835,7 @@ #define B_MSG_SWITCHIN_SCREENCLEANER 12 #define B_MSG_SWITCHIN_ASONE 13 #define B_MSG_SWITCHIN_CURIOUS_MEDICINE 14 +#define B_MSG_SWITCHIN_NEUTRALIZING_GAS 15 // gMentalHerbCureStringIds #define B_MSG_MENTALHERBCURE_INFATUATION 0 diff --git a/src/battle_main.c b/src/battle_main.c index 271e977314..19e0d49403 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3533,7 +3533,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 f26726a69a..48e7ab1a43 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -723,9 +723,12 @@ static const u8 sText_PkmnRevertedToPrimal[] = _("{B_ATK_NAME_WITH_PREFIX}'s Pri static const u8 sText_ButPokemonCantUseTheMove[] = _("But {B_ATK_NAME_WITH_PREFIX} can't\nuse the move!"); static const u8 sText_ButHoopaCantUseIt[] = _("But Hoopa can't use it\nthe way it is now!"); static const u8 sText_BrokeThroughProtection[] = _("It broke through the\n{B_DEF_NAME_WITH_PREFIX}'s protection!"); - +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_BROKETHROUGHPROTECTION - 12] = sText_BrokeThroughProtection, [STRINGID_BUTPOKEMONCANTUSETHEMOVE - 12] = sText_ButPokemonCantUseTheMove, [STRINGID_BUTHOOPACANTUSEIT - 12] = sText_ButHoopaCantUseIt, @@ -1371,6 +1374,7 @@ const u16 gSwitchInAbilityStringIds[] = [B_MSG_SWITCHIN_SCREENCLEANER] = STRINGID_SCREENCLEANERENTERS, [B_MSG_SWITCHIN_ASONE] = STRINGID_ASONEENTERS, [B_MSG_SWITCHIN_CURIOUS_MEDICINE] = STRINGID_CURIOUSMEDICINEENTERS, + [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 e41f0982a7..e2c6aff027 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -5416,7 +5416,7 @@ static void Cmd_sethealblock(void) static void Cmd_returnatktoball(void) { - gActiveBattler = gBattlerAttacker; + gActiveBattler = gBattlerAttacker; if (!(gHitMarker & HITMARKER_FAINTED(gActiveBattler))) { BtlController_EmitReturnMonToBall(0, 0); @@ -6077,8 +6077,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) @@ -6240,7 +6249,7 @@ static void Cmd_endlinkbattle(void) } static void Cmd_returntoball(void) -{ +{ gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); BtlController_EmitReturnMonToBall(0, 1); MarkBattlerForControllerExec(gActiveBattler); @@ -12281,25 +12290,34 @@ 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 = 0; + BattleScriptPushCursor(); + 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 275139f4f4..0125d362c1 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -5436,6 +5436,20 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move } } break; + case ABILITYEFFECT_NEUTRALIZINGGAS: + // for the start of battle only. The switch-in message plays in Cmd_switchineffects because it comes before the 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++; + } + } + break; } if (effect && gLastUsedAbility != 0xFF) @@ -5446,11 +5460,51 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move return effect; } +static 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; + } +} + +static bool32 IsNeutralizingGasOnField(void) +{ + u32 i; + + for (i = 0; i < gBattlersCount; i++) + { + if (IsBattlerAlive(i) && gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS) + 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)) @@ -5460,8 +5514,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)