diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index ac72666908..7ca6bfa6dc 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1791,6 +1791,12 @@ .4byte \ptr .endm + .macro jumpifterrainaffected battler:req, terrainFlags:req, ptr:req + various \battler, VARIOUS_JUMP_IF_TERRAIN_AFFECTED + .4byte \terrainFlags + .4byte \ptr + .endm + @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 09071b1d85..0a3fafd5b4 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2123,6 +2123,8 @@ BattleScript_EffectSleep:: jumpifleafguard BattleScript_LeafGuardProtects jumpifshieldsdown BS_TARGET, BattleScript_LeafGuardProtects jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed + jumpifterrainaffected BS_TARGET, STATUS_FIELD_ELECTRIC_TERRAIN, BattleScript_ElectricTerrainPrevents + jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsafeguard BattleScript_SafeguardProtected attackanimation @@ -2130,6 +2132,26 @@ BattleScript_EffectSleep:: setmoveeffect MOVE_EFFECT_SLEEP seteffectprimary goto BattleScript_MoveEnd + +BattleScript_TerrainPreventsEnd2:: + pause B_WAIT_TIME_SHORT + printfromtable gTerrainPreventsStringIds + waitmessage B_WAIT_TIME_LONG + end2 + +BattleScript_ElectricTerrainPrevents:: + pause B_WAIT_TIME_SHORT + printstring STRINGID_ELECTRICTERRAINPREVENTS + waitmessage B_WAIT_TIME_LONG + orhalfword gMoveResultFlags, MOVE_RESULT_FAILED + goto BattleScript_MoveEnd + +BattleScript_MistyTerrainPrevents:: + pause B_WAIT_TIME_SHORT + printstring STRINGID_MISTYTERRAINPREVENTS + waitmessage B_WAIT_TIME_LONG + orhalfword gMoveResultFlags, MOVE_RESULT_FAILED + goto BattleScript_MoveEnd BattleScript_FlowerVeilProtectsRet:: pause B_WAIT_TIME_SHORT @@ -2645,6 +2667,7 @@ BattleScript_EffectToxic:: jumpifsubstituteblocks BattleScript_ButItFailed jumpifstatus BS_TARGET, STATUS1_POISON | STATUS1_TOXIC_POISON, BattleScript_AlreadyPoisoned jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed + jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents trypoisontype BS_ATTACKER, BS_TARGET, BattleScript_NotAffected accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsafeguard BattleScript_SafeguardProtected @@ -2869,6 +2892,7 @@ BattleScript_EffectConfuse: jumpifability BS_TARGET, ABILITY_OWN_TEMPO, BattleScript_OwnTempoPrevents jumpifsubstituteblocks BattleScript_ButItFailed jumpifstatus2 BS_TARGET, STATUS2_CONFUSION, BattleScript_AlreadyConfused + jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsafeguard BattleScript_SafeguardProtected attackanimation @@ -2987,6 +3011,7 @@ BattleScript_EffectPoison:: jumpifstatus BS_TARGET, STATUS1_TOXIC_POISON, BattleScript_AlreadyPoisoned trypoisontype BS_ATTACKER, BS_TARGET, BattleScript_NotAffected jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed + jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsafeguard BattleScript_SafeguardProtected attackanimation @@ -3012,6 +3037,7 @@ BattleScript_EffectParalyze: jumpifstatus BS_TARGET, STATUS1_PARALYSIS, BattleScript_AlreadyParalyzed tryparalyzetype BS_ATTACKER, BS_TARGET, BattleScript_NotAffected jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed + jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsafeguard BattleScript_SafeguardProtected bichalfword gMoveResultFlags, MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE @@ -4316,6 +4342,7 @@ BattleScript_EffectWillOWisp:: jumpifleafguard BattleScript_LeafGuardProtects jumpifshieldsdown BS_TARGET, BattleScript_LeafGuardProtects jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed + jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsafeguard BattleScript_SafeguardProtected attackanimation diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index d4df682c63..b8cd53c072 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -119,10 +119,10 @@ bool32 IsUngroundingEffect(u16 effect); bool32 IsSemiInvulnerable(u8 battlerDef, u16 move); // status checks -bool32 CanBeBurned(u8 battler, u16 ability); -bool32 CanBePoisoned(u8 battler, u16 ability); -bool32 CanBeConfused(u8 battler, u16 ability); -bool32 CanSleep(u8 battler, u16 ability); +bool32 AI_CanBeBurned(u8 battler, u16 ability); +bool32 AI_CanBePoisoned(u8 battler, u16 ability); +bool32 AI_CanBeConfused(u8 battler, u16 ability); +bool32 AI_CanSleep(u8 battler, u16 ability); bool32 IsBattlerIncapacitated(u8 battler, u16 ability); bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); bool32 ShouldPoisonSelf(u8 battler, u16 ability); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 98e85184bc..b15ab3aeb3 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -381,5 +381,8 @@ extern const u8 BattleScript_EjectPackActivate_End2[]; extern const u8 BattleScript_EjectPackActivates[]; extern const u8 BattleScript_MentalHerbCureRet[]; extern const u8 BattleScript_MentalHerbCureEnd2[]; +extern const u8 BattleScript_TerrainPreventsEnd2[]; +extern const u8 BattleScript_MistyTerrainPrevents[]; +extern const u8 BattleScript_ElectricTerrainPrevents[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index 4f250c7ea0..4dac63111a 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -161,4 +161,12 @@ bool32 IsGastroAcidBannedAbility(u16 ability); bool32 IsEntrainmentBannedAbilityAttacker(u16 ability); bool32 IsEntrainmentTargetOrSimpleBeamBannedAbility(u16 ability); +bool32 CanSleep(u8 battlerId); +bool32 CanBePoisoned(u8 battlerId); +bool32 CanBeBurned(u8 battlerId); +bool32 CanBeParalyzed(u8 battlerId); +bool32 CanBeFrozen(u8 battlerId); +bool32 CanBeConfused(u8 battlerId); +bool32 IsBattlerTerrainAffected(u8 battlerId, u32 terrainFlag); + #endif // GUARD_BATTLE_UTIL_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 6ab8df3005..66f5925034 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -178,6 +178,7 @@ #define VARIOUS_TERRAIN_SEED 106 #define VARIOUS_MAKE_INVISIBLE 107 #define VARIOUS_ROOM_SERVICE 108 +#define VARIOUS_JUMP_IF_TERRAIN_AFFECTED 109 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 20499ce575..e32fd57780 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -823,4 +823,9 @@ #define B_MSG_MENTALHERBCURE_HEALBLOCK 4 #define B_MSG_MENTALHERBCURE_DISABLE 5 +// gTerrainPreventsStringIds +#define B_MSG_TERRAINPREVENTS_MISTY 0 +#define B_MSG_TERRAINPREVENTS_ELECTRIC 1 +#define B_MSG_TERRAINPREVENTS_PSYCHIC 2 + #endif // GUARD_CONSTANTS_BATTLE_STRING_IDS_H diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index bfd77c5f0a..03472271d1 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1570,7 +1570,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_REST: - if (!CanSleep(battlerAtk, AI_DATA->atkAbility)) + if (!AI_CanSleep(battlerAtk, AI_DATA->atkAbility)) score -= 10; //fallthrough case EFFECT_RESTORE_HP: @@ -2686,7 +2686,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SWAGGER: if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] < MAX_STAT_STAGE && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) - && (!CanBeConfused(battlerAtkPartner, TRUE) + && (!AI_CanBeConfused(battlerAtkPartner, TRUE) || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) { @@ -2696,7 +2696,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_FLATTER: if (gBattleMons[battlerAtkPartner].statStages[STAT_SPATK] < MAX_STAT_STAGE && HasMoveWithSplit(battlerAtkPartner, SPLIT_SPECIAL) - && (!CanBeConfused(battlerAtkPartner, TRUE) + && (!AI_CanBeConfused(battlerAtkPartner, TRUE) || atkPartnerHoldEffect == HOLD_EFFECT_CURE_CONFUSION || atkPartnerHoldEffect == HOLD_EFFECT_CURE_STATUS)) { @@ -3248,7 +3248,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_REST: - if (!(CanSleep(battlerAtk, AI_DATA->atkAbility))) + if (!(AI_CanSleep(battlerAtk, AI_DATA->atkAbility))) { break; } @@ -3937,11 +3937,11 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case HOLD_EFFECT_TOXIC_ORB: - if (!ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility) && CanBePoisoned(battlerDef, AI_DATA->defAbility)) + if (!ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility) && AI_CanBePoisoned(battlerDef, AI_DATA->defAbility)) score += 2; break; case HOLD_EFFECT_FLAME_ORB: - if (!ShouldBurnSelf(battlerAtk, AI_DATA->atkAbility) && CanBeBurned(battlerAtk, AI_DATA->defAbility)) + if (!ShouldBurnSelf(battlerAtk, AI_DATA->atkAbility) && AI_CanBeBurned(battlerAtk, AI_DATA->defAbility)) score += 2; break; case HOLD_EFFECT_BLACK_SLUDGE: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 3fac2ac10f..48d3817c8e 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2589,7 +2589,7 @@ bool32 IsBattlerIncapacitated(u8 battler, u16 ability) return FALSE; } -bool32 CanSleep(u8 battler, u16 ability) +bool32 AI_CanSleep(u8 battler, u16 ability) { if (ability == ABILITY_INSOMNIA || ability == ABILITY_VITAL_SPIRIT @@ -2603,7 +2603,7 @@ bool32 CanSleep(u8 battler, u16 ability) bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { - if (!CanSleep(battlerDef, defAbility) + if (!AI_CanSleep(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) // shouldn't try to sleep mon that partner is trying to make sleep @@ -2611,7 +2611,7 @@ bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, return TRUE; } -bool32 CanBePoisoned(u8 battler, u16 ability) +bool32 AI_CanBePoisoned(u8 battler, u16 ability) { if (ability == ABILITY_IMMUNITY || ability == ABILITY_PASTEL_VEIL @@ -2624,7 +2624,7 @@ bool32 CanBePoisoned(u8 battler, u16 ability) bool32 ShouldPoisonSelf(u8 battler, u16 ability) { - if (CanBePoisoned(battler, ability) && ( + if (AI_CanBePoisoned(battler, ability) && ( ability == ABILITY_MARVEL_SCALE || ability == ABILITY_POISON_HEAL || ability == ABILITY_QUICK_FEET @@ -2639,7 +2639,7 @@ bool32 ShouldPoisonSelf(u8 battler, u16 ability) bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { - if (!CanBePoisoned(battlerDef, defAbility) + if (!AI_CanBePoisoned(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) @@ -2673,7 +2673,7 @@ bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u1 return TRUE; } -bool32 CanBeConfused(u8 battler, u16 ability) +bool32 AI_CanBeConfused(u8 battler, u16 ability) { if ((gBattleMons[battler].status2 & STATUS2_CONFUSION) || (ability == ABILITY_OWN_TEMPO) @@ -2684,7 +2684,7 @@ bool32 CanBeConfused(u8 battler, u16 ability) bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) { - if (!CanBeConfused(battlerDef, defAbility) + if (!AI_CanBeConfused(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) @@ -2696,7 +2696,7 @@ bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtk return TRUE; } -bool32 CanBeBurned(u8 battler, u16 ability) +bool32 AI_CanBeBurned(u8 battler, u16 ability) { if (ability == ABILITY_WATER_VEIL || ability == ABILITY_WATER_BUBBLE @@ -2710,7 +2710,7 @@ bool32 CanBeBurned(u8 battler, u16 ability) bool32 ShouldBurnSelf(u8 battler, u16 ability) { - if (CanBeBurned(battler, ability) && ( + if (AI_CanBeBurned(battler, ability) && ( ability == ABILITY_QUICK_FEET || ability == ABILITY_HEATPROOF || ability == ABILITY_MAGIC_GUARD @@ -2724,7 +2724,7 @@ bool32 ShouldBurnSelf(u8 battler, u16 ability) bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) { - if (!CanBeBurned(battlerDef, defAbility) + if (!AI_CanBeBurned(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove)) diff --git a/src/battle_message.c b/src/battle_message.c index 5126aa2ed2..9d17a2a252 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -1292,7 +1292,9 @@ const u16 gTerrainStringIds[] = const u16 gTerrainPreventsStringIds[] = { - STRINGID_MISTYTERRAINPREVENTS, STRINGID_ELECTRICTERRAINPREVENTS, STRINGID_PSYCHICTERRAINPREVENTS + [B_MSG_TERRAINPREVENTS_MISTY] = STRINGID_MISTYTERRAINPREVENTS, + [B_MSG_TERRAINPREVENTS_ELECTRIC] = STRINGID_ELECTRICTERRAINPREVENTS, + [B_MSG_TERRAINPREVENTS_PSYCHIC] = STRINGID_PSYCHICTERRAINPREVENTS }; const u16 gMagicCoatBounceStringIds[] = diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 98056aff2f..00a52d6c58 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2502,8 +2502,7 @@ void SetMoveEffect(bool32 primary, u32 certain) { s32 i, byTwo, affectsUser = 0; bool32 statusChanged = FALSE; - bool32 noSunCanFreeze = TRUE; - + switch (gBattleScripting.moveEffect) // Set move effects which happen later on { case MOVE_EFFECT_KNOCK_OFF: @@ -2562,15 +2561,9 @@ void SetMoveEffect(bool32 primary, u32 certain) else gActiveBattler = gBattlersCount; - if (gBattleMons[gEffectBattler].status1) - break; if (gActiveBattler != gBattlersCount) break; - if (GetBattlerAbility(gEffectBattler) == ABILITY_VITAL_SPIRIT - || GetBattlerAbility(gEffectBattler) == ABILITY_INSOMNIA - || GetBattlerAbility(gEffectBattler) == ABILITY_COMATOSE - || IsAbilityOnSide(gEffectBattler, ABILITY_SWEET_VEIL) - || IsAbilityStatusProtected(gEffectBattler)) + if (!CanSleep(gEffectBattler)) break; CancelMultiTurnMoves(gEffectBattler); @@ -2609,11 +2602,7 @@ void SetMoveEffect(bool32 primary, u32 certain) } if (!CanPoisonType(gBattleScripting.battler, gEffectBattler)) break; - if (gBattleMons[gEffectBattler].status1) - break; - if (GetBattlerAbility(gEffectBattler) == ABILITY_IMMUNITY - || GetBattlerAbility(gEffectBattler) == ABILITY_COMATOSE - || IsAbilityStatusProtected(gEffectBattler)) + if (!CanBePoisoned(gEffectBattler)) break; statusChanged = TRUE; @@ -2648,30 +2637,14 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STATUS_HAD_NO_EFFECT; RESET_RETURN } - if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_FIRE)) - break; - if (GetBattlerAbility(gEffectBattler) == ABILITY_WATER_VEIL - || GetBattlerAbility(gEffectBattler) == ABILITY_COMATOSE - || GetBattlerAbility(gEffectBattler) == ABILITY_WATER_BUBBLE - || IsAbilityStatusProtected(gEffectBattler)) - break; - if (gBattleMons[gEffectBattler].status1) + + if (!CanBeBurned(gEffectBattler)) break; statusChanged = TRUE; break; case STATUS1_FREEZE: - if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY) - noSunCanFreeze = FALSE; - if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_ICE)) - break; - if (gBattleMons[gEffectBattler].status1) - break; - if (noSunCanFreeze == 0) - break; - if (GetBattlerAbility(gEffectBattler) == ABILITY_MAGMA_ARMOR - || GetBattlerAbility(gEffectBattler) == ABILITY_COMATOSE - || IsAbilityStatusProtected(gEffectBattler)) + if (!CanBeFrozen(gEffectBattler)) break; CancelMultiTurnMoves(gEffectBattler); @@ -2714,11 +2687,7 @@ void SetMoveEffect(bool32 primary, u32 certain) } if (!CanParalyzeType(gBattleScripting.battler, gEffectBattler)) break; - if (GetBattlerAbility(gEffectBattler) == ABILITY_LIMBER - || GetBattlerAbility(gEffectBattler) == ABILITY_COMATOSE - || IsAbilityStatusProtected(gEffectBattler)) - break; - if (gBattleMons[gEffectBattler].status1) + if (!CanBeParalyzed(gEffectBattler)) break; statusChanged = TRUE; @@ -2757,9 +2726,7 @@ void SetMoveEffect(bool32 primary, u32 certain) break; if (CanPoisonType(gBattleScripting.battler, gEffectBattler)) { - if (GetBattlerAbility(gEffectBattler) == ABILITY_IMMUNITY - || GetBattlerAbility(gEffectBattler) == ABILITY_COMATOSE - || IsAbilityStatusProtected(gEffectBattler)) + if (!CanBePoisoned(gEffectBattler)) break; // It's redundant, because at this point we know the status1 value is 0. @@ -2831,8 +2798,7 @@ void SetMoveEffect(bool32 primary, u32 certain) switch (gBattleScripting.moveEffect) { case MOVE_EFFECT_CONFUSION: - if (GetBattlerAbility(gEffectBattler) == ABILITY_OWN_TEMPO - || gBattleMons[gEffectBattler].status2 & STATUS2_CONFUSION) + if (!CanBeConfused(gEffectBattler)) { gBattlescriptCurrInstr++; } @@ -6037,7 +6003,8 @@ static void Cmd_switchineffects(void) if (!(gBattleMons[gActiveBattler].status1 & STATUS1_ANY) && !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL) && GetBattlerAbility(gActiveBattler) != ABILITY_IMMUNITY - && !(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SAFEGUARD)) + && !(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SAFEGUARD) + && !(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) { if (gSideTimers[GetBattlerSide(gActiveBattler)].toxicSpikesAmount >= 2) gBattleMons[gActiveBattler].status1 |= STATUS1_TOXIC_POISON; @@ -8599,6 +8566,15 @@ static void Cmd_various(void) BtlController_EmitSpriteInvisibility(0, TRUE); MarkBattlerForControllerExec(gActiveBattler); break; + case VARIOUS_JUMP_IF_TERRAIN_AFFECTED: + { + u32 flags = T1_READ_32(gBattlescriptCurrInstr + 3); + if (IsBattlerTerrainAffected(gActiveBattler, flags)) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 7); + else + gBattlescriptCurrInstr += 11; + } + return; } gBattlescriptCurrInstr += 3; @@ -8925,6 +8901,14 @@ static void Cmd_trysetrest(void) { gBattlescriptCurrInstr = failJump; } + else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN)) + { + gBattlescriptCurrInstr = BattleScript_ElectricTerrainPrevents; + } + else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_MISTY_TERRAIN)) + { + gBattlescriptCurrInstr = BattleScript_MistyTerrainPrevents; + } else { if (gBattleMons[gBattlerTarget].status1 & ((u8)(~STATUS1_SLEEP))) @@ -11602,6 +11586,18 @@ static void Cmd_setyawn(void) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); } + else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN)) + { + // When Yawn is used while Electric Terrain is set and drowsiness is set from Yawn being used against target in the previous turn: + // "But it failed" will display first. + gBattlescriptCurrInstr = BattleScript_ElectricTerrainPrevents; + } + else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_MISTY_TERRAIN)) + { + // When Yawn is used while Misty Terrain is set and drowsiness is set from Yawn being used against target in the previous turn: + // "But it failed" will display first. + gBattlescriptCurrInstr = BattleScript_MistyTerrainPrevents; + } else { gStatuses3[gBattlerTarget] |= STATUS3_YAWN_TURN(2); diff --git a/src/battle_util.c b/src/battle_util.c index a343dedbeb..ccc0c558a8 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2726,11 +2726,24 @@ u8 DoBattlerEndTurnEffects(void) && !IsLeafGuardProtected(gActiveBattler)) { CancelMultiTurnMoves(gActiveBattler); - gBattleMons[gActiveBattler].status1 |= (Random() & 3) + 2; - BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1); - MarkBattlerForControllerExec(gActiveBattler); gEffectBattler = gActiveBattler; - BattleScriptExecute(BattleScript_YawnMakesAsleep); + if (IsBattlerTerrainAffected(gActiveBattler, STATUS_FIELD_ELECTRIC_TERRAIN)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAINPREVENTS_ELECTRIC; + BattleScriptExecute(BattleScript_TerrainPreventsEnd2); + } + else if (IsBattlerTerrainAffected(gActiveBattler, STATUS_FIELD_MISTY_TERRAIN)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAINPREVENTS_MISTY; + BattleScriptExecute(BattleScript_TerrainPreventsEnd2); + } + else + { + gBattleMons[gActiveBattler].status1 |= (Random() & 3) + 2; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1); + MarkBattlerForControllerExec(gActiveBattler); + BattleScriptExecute(BattleScript_YawnMakesAsleep); + } effect++; } } @@ -4800,10 +4813,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move && gBattleMons[gBattlerAttacker].hp != 0 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED - && GetBattlerAbility(gBattlerAttacker) != ABILITY_INSOMNIA - && GetBattlerAbility(gBattlerAttacker) != ABILITY_VITAL_SPIRIT - && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) - && !IsAbilityStatusProtected(gBattlerAttacker) + && CanSleep(gBattlerAttacker) && IsMoveMakingContact(move, gBattlerAttacker) && (Random() % 3) == 0) { @@ -4822,11 +4832,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move && gBattleMons[gBattlerAttacker].hp != 0 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED - && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_POISON) - && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_STEEL) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_IMMUNITY - && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) - && !IsAbilityStatusProtected(gBattlerAttacker) + && CanBePoisoned(gBattlerAttacker) && IsMoveMakingContact(move, gBattlerAttacker) && (Random() % 3) == 0) { @@ -4844,10 +4850,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move && gBattleMons[gBattlerAttacker].hp != 0 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED - && CanParalyzeType(gBattlerTarget, gBattlerAttacker) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_LIMBER - && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) - && !IsAbilityStatusProtected(gBattlerAttacker) + && CanBeParalyzed(gBattlerAttacker) && IsMoveMakingContact(move, gBattlerAttacker) && (Random() % 3) == 0) { @@ -4864,11 +4867,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) && TARGET_TURN_DAMAGED - && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_WATER_VEIL - && GetBattlerAbility(gBattlerAttacker) != ABILITY_WATER_BUBBLE - && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) - && !IsAbilityStatusProtected(gBattlerAttacker) + && CanBeBurned(gBattlerAttacker) && (Random() % 3) == 0) { gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN; @@ -4976,11 +4975,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && gBattleMons[gBattlerTarget].hp != 0 && !gProtectStructs[gBattlerTarget].confusionSelfDmg - && !IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_POISON) - && !IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_STEEL) - && GetBattlerAbility(gBattlerTarget) != ABILITY_IMMUNITY - && !(gBattleMons[gBattlerTarget].status1 & STATUS1_ANY) - && !IsAbilityStatusProtected(gBattlerTarget) + && CanBePoisoned(gBattlerTarget) && IsMoveMakingContact(move, gBattlerAttacker) && (Random() % 3) == 0) { @@ -5383,6 +5378,100 @@ enum ITEM_STATS_CHANGE, // 5 }; +bool32 IsBattlerTerrainAffected(u8 battlerId, u32 terrainFlag) +{ + if (!(gFieldStatuses & terrainFlag)) + return FALSE; + else if (gStatuses3[battlerId] & STATUS3_SEMI_INVULNERABLE) + return FALSE; + + return IsBattlerGrounded(battlerId); +} + +bool32 CanSleep(u8 battlerId) +{ + u16 ability = GetBattlerAbility(battlerId); + if (ability == ABILITY_INSOMNIA + || ability == ABILITY_VITAL_SPIRIT + || ability == ABILITY_COMATOSE + || gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_SAFEGUARD + || gBattleMons[battlerId].status1 & STATUS1_ANY + || IsAbilityOnSide(battlerId, ABILITY_SWEET_VEIL) + || IsAbilityStatusProtected(battlerId) + || IsBattlerTerrainAffected(battlerId, STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_MISTY_TERRAIN)) + return FALSE; + return TRUE; +} + +bool32 CanBePoisoned(u8 battlerId) +{ + u16 ability = GetBattlerAbility(battlerId); + if (IS_BATTLER_OF_TYPE(battlerId, TYPE_POISON) + || IS_BATTLER_OF_TYPE(battlerId, TYPE_STEEL) + || gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_SAFEGUARD + || gBattleMons[battlerId].status1 & STATUS1_ANY + || ability == ABILITY_IMMUNITY + || ability == ABILITY_COMATOSE + || gBattleMons[battlerId].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerId) + || IsBattlerTerrainAffected(battlerId, STATUS_FIELD_MISTY_TERRAIN)) + return FALSE; + return TRUE; +} + +bool32 CanBeBurned(u8 battlerId) +{ + u16 ability = GetBattlerAbility(battlerId); + if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FIRE) + || gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_SAFEGUARD + || gBattleMons[battlerId].status1 & STATUS1_ANY + || ability == ABILITY_WATER_VEIL + || ability == ABILITY_WATER_BUBBLE + || ability == ABILITY_COMATOSE + || IsAbilityStatusProtected(battlerId) + || IsBattlerTerrainAffected(battlerId, STATUS_FIELD_MISTY_TERRAIN)) + return FALSE; + return TRUE; +} + +bool32 CanBeParalyzed(u8 battlerId) +{ + u16 ability = GetBattlerAbility(battlerId); + if ((B_PARALYZE_ELECTRIC >= GEN_6 && IS_BATTLER_OF_TYPE(battlerId, TYPE_ELECTRIC)) + || gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_SAFEGUARD + || ability == ABILITY_LIMBER + || ability == ABILITY_COMATOSE + || gBattleMons[battlerId].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerId) + || IsBattlerTerrainAffected(battlerId, STATUS_FIELD_MISTY_TERRAIN)) + return FALSE; + return TRUE; +} + +bool32 CanBeFrozen(u8 battlerId) +{ + u16 ability = GetBattlerAbility(battlerId); + if (IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) + || (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY) + || gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_SAFEGUARD + || ability == ABILITY_MAGMA_ARMOR + || ability == ABILITY_COMATOSE + || gBattleMons[battlerId].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerId) + || IsBattlerTerrainAffected(battlerId, STATUS_FIELD_MISTY_TERRAIN)) + return FALSE; + return TRUE; +} + +bool32 CanBeConfused(u8 battlerId) +{ + if (GetBattlerAbility(gEffectBattler) == ABILITY_OWN_TEMPO + || gBattleMons[gEffectBattler].status2 & STATUS2_CONFUSION + || IsBattlerTerrainAffected(battlerId, STATUS_FIELD_MISTY_TERRAIN)) + return FALSE; + return TRUE; +} + // second argument is 1/X of current hp compared to max hp bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId) { @@ -6901,7 +6990,7 @@ u8 IsMonDisobedient(void) obedienceLevel = gBattleMons[gBattlerAttacker].level - obedienceLevel; calc = (Random() & 255); - if (calc < obedienceLevel && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) && gBattleMons[gBattlerAttacker].ability != ABILITY_VITAL_SPIRIT && gBattleMons[gBattlerAttacker].ability != ABILITY_INSOMNIA) + if (calc < obedienceLevel && CanSleep(gBattlerAttacker)) { // try putting asleep int i;