diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 27c5a86c4..a19c7308d 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1311,6 +1311,13 @@ .4byte \ptr .endm + .macro jumpifholdeffect battler:req, holdEffect:req, ptr:req + callnative BS_JumpIfHoldEffect + .byte \battler + .2byte \holdEffect + .4byte \ptr + .endm + @ various command changed to more readable macros .macro cancelmultiturnmoves battler:req various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 6b8067721..8010d4ee7 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -6996,6 +6996,7 @@ BattleScript_GulpMissileGulping:: tryfaintmon BS_ATTACKER getbattlerfainted BS_ATTACKER jumpifbyte CMP_EQUAL, gBattleCommunication, TRUE, BattleScript_GulpMissileNoSecondEffectGulping + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_CLEAR_AMULET, BattleScript_GulpMissileNoSecondEffectGulping jumpifability BS_ATTACKER, ABILITY_CLEAR_BODY, BattleScript_GulpMissileNoSecondEffectGulping jumpifability BS_ATTACKER, ABILITY_FULL_METAL_BODY, BattleScript_GulpMissileNoSecondEffectGulping jumpifability BS_ATTACKER, ABILITY_WHITE_SMOKE, BattleScript_GulpMissileNoSecondEffectGulping @@ -8211,6 +8212,7 @@ BattleScript_IntimidateActivatesLoop: setstatchanger STAT_ATK, 1, TRUE trygetintimidatetarget BattleScript_IntimidateActivatesReturn jumpifstatus2 BS_TARGET, STATUS2_SUBSTITUTE, BattleScript_IntimidateActivatesLoopIncrement + jumpifholdeffect BS_TARGET, HOLD_EFFECT_CLEAR_AMULET, BattleScript_IntimidatePrevented_Item jumpifability BS_TARGET, ABILITY_CLEAR_BODY, BattleScript_IntimidatePrevented jumpifability BS_TARGET, ABILITY_HYPER_CUTTER, BattleScript_IntimidatePrevented jumpifability BS_TARGET, ABILITY_WHITE_SMOKE, BattleScript_IntimidatePrevented @@ -8235,6 +8237,7 @@ BattleScript_IntimidateActivatesReturn: BattleScript_IntimidatePrevented: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp +BattleScript_IntimidatePrevented_Item: setbyte gBattleCommunication STAT_ATK stattextbuffer BS_ATTACKER printstring STRINGID_STATWASNOTLOWERED diff --git a/include/constants/hold_effects.h b/include/constants/hold_effects.h index e0361795d..cd4256632 100644 --- a/include/constants/hold_effects.h +++ b/include/constants/hold_effects.h @@ -152,6 +152,14 @@ #define HOLD_EFFECT_HEAVY_DUTY_BOOTS 173 #define HOLD_EFFECT_THROAT_SPRAY 174 +// Gen9 hold effects +#define HOLD_EFFECT_ABILITY_SHIELD 175 +#define HOLD_EFFECT_CLEAR_AMULET 176 +#define HOLD_EFFECT_MIRROR_HERB 177 // Not implemented. +#define HOLD_EFFECT_PUNCHING_GLOVE 178 +#define HOLD_EFFECT_COVERT_CLOAK 179 +#define HOLD_EFFECT_LOADED_DICE 180 + #define HOLD_EFFECT_CHOICE(holdEffect)((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS)) // Terrain seed params diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 35b1b3bfd..c624e02e1 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1634,7 +1634,8 @@ bool32 ShouldLowerStat(u8 battler, u16 battlerAbility, u8 stat) if ((gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) || (battlerAbility == ABILITY_CONTRARY && gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE)) { - if (battlerAbility == ABILITY_CLEAR_BODY + if (AI_GetHoldEffect(battler) == HOLD_EFFECT_CLEAR_AMULET + || battlerAbility == ABILITY_CLEAR_BODY || battlerAbility == ABILITY_WHITE_SMOKE || battlerAbility == ABILITY_FULL_METAL_BODY) return FALSE; @@ -1711,7 +1712,8 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_WHITE_SMOKE && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_HYPER_CUTTER) + && defAbility != ABILITY_HYPER_CUTTER + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } @@ -1727,7 +1729,8 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_WHITE_SMOKE && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_BIG_PECKS) + && defAbility != ABILITY_BIG_PECKS + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } @@ -1741,7 +1744,8 @@ bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_WHITE_SMOKE) + && defAbility != ABILITY_WHITE_SMOKE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } @@ -1756,7 +1760,8 @@ bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_WHITE_SMOKE) + && defAbility != ABILITY_WHITE_SMOKE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } @@ -1771,7 +1776,8 @@ bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_WHITE_SMOKE) + && defAbility != ABILITY_WHITE_SMOKE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } @@ -1785,7 +1791,8 @@ bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_WHITE_SMOKE && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_KEEN_EYE) + && defAbility != ABILITY_KEEN_EYE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } @@ -1799,7 +1806,8 @@ bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_WHITE_SMOKE) + && defAbility != ABILITY_WHITE_SMOKE + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 09ef738df..6c207e8d4 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2824,13 +2824,16 @@ void SetMoveEffect(bool32 primary, u32 certain) // Just in case this flag is still set gBattleScripting.moveEffect &= ~MOVE_EFFECT_CERTAIN; - - if (battlerAbility == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && !primary && gBattleScripting.moveEffect <= 9) + + if ((battlerAbility == ABILITY_SHIELD_DUST + || GetBattlerHoldEffect(gEffectBattler, TRUE) == HOLD_EFFECT_COVERT_CLOAK) + && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && !primary + && (gBattleScripting.moveEffect <= MOVE_EFFECT_TRI_ATTACK || gBattleScripting.moveEffect >= MOVE_EFFECT_SMACK_DOWN)) // Exclude stat lowering effects INCREMENT_RESET_RETURN if (gSideStatuses[GET_BATTLER_SIDE(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && !primary && gBattleScripting.moveEffect <= 7) + && !primary && gBattleScripting.moveEffect <= MOVE_EFFECT_CONFUSION) INCREMENT_RESET_RETURN if (TestSheerForceFlag(gBattlerAttacker, gCurrentMove) && affectsUser != MOVE_EFFECT_AFFECTS_USER) @@ -5016,6 +5019,7 @@ static void Cmd_playstatchangeanimation(void) } } else if (!gSideTimers[GET_BATTLER_SIDE(gActiveBattler)].mistTimer + && GetBattlerHoldEffect(gActiveBattler, TRUE) != HOLD_EFFECT_CLEAR_AMULET && ability != ABILITY_CLEAR_BODY && ability != ABILITY_FULL_METAL_BODY && ability != ABILITY_WHITE_SMOKE @@ -8814,7 +8818,8 @@ static void Cmd_various(void) return; case VARIOUS_SET_SIMPLE_BEAM: if (IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gBattlerTarget].ability) - || gBattleMons[gBattlerTarget].ability == ABILITY_SIMPLE) + || gBattleMons[gBattlerTarget].ability == ABILITY_SIMPLE + || GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); } @@ -8829,7 +8834,8 @@ static void Cmd_various(void) return; case VARIOUS_TRY_ENTRAINMENT: if (IsEntrainmentBannedAbilityAttacker(gBattleMons[gBattlerAttacker].ability) - || IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gBattlerTarget].ability)) + || IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gBattlerTarget].ability) + || GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); return; @@ -10748,7 +10754,8 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr gBattlescriptCurrInstr = BattleScript_ButItFailed; return STAT_CHANGE_DIDNT_WORK; } - else if ((activeBattlerAbility == ABILITY_CLEAR_BODY + else if ((GetBattlerHoldEffect(gActiveBattler, TRUE) == HOLD_EFFECT_CLEAR_AMULET + || activeBattlerAbility == ABILITY_CLEAR_BODY || activeBattlerAbility == ABILITY_FULL_METAL_BODY || activeBattlerAbility == ABILITY_WHITE_SMOKE) && !certain && gCurrentMove != MOVE_CURSE) @@ -13362,7 +13369,8 @@ static void Cmd_setroom(void) static void Cmd_tryswapabilities(void) { if (IsSkillSwapBannedAbility(gBattleMons[gBattlerAttacker].ability) - || IsSkillSwapBannedAbility(gBattleMons[gBattlerTarget].ability)) + || IsSkillSwapBannedAbility(gBattleMons[gBattlerTarget].ability) + || GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); return; @@ -14734,7 +14742,8 @@ static void Cmd_unused(void) static void Cmd_tryworryseed(void) { - if (IsWorrySeedBannedAbility(gBattleMons[gBattlerTarget].ability)) + if (IsWorrySeedBannedAbility(gBattleMons[gBattlerTarget].ability) + || GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); } @@ -14790,6 +14799,22 @@ void BS_CalcMetalBurstDmg(void) } } +void BS_JumpIfHoldEffect(void) +{ + u8 battler = gBattlescriptCurrInstr[5]; + u16 holdEffect = T1_READ_16(gBattlescriptCurrInstr + 6); + + if (GetBattlerHoldEffect(battler, TRUE) == holdEffect) + { + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 8); + } + else + { + gLastUsedItem = gBattleMons[battler].item; // For B_LAST_USED_ITEM + gBattlescriptCurrInstr += 12; + } +} + static bool32 CriticalCapture(u32 odds) { #if B_CRITICAL_CAPTURE == TRUE diff --git a/src/battle_util.c b/src/battle_util.c index d8ec3f079..08c0542df 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2946,7 +2946,8 @@ u8 DoBattlerEndTurnEffects(void) { u16 battlerAbility = GetBattlerAbility(gActiveBattler); if (gDisableStructs[gActiveBattler].octolock - && !(battlerAbility == ABILITY_CLEAR_BODY + && !(GetBattlerHoldEffect(gActiveBattler, TRUE) == HOLD_EFFECT_CLEAR_AMULET + || battlerAbility == ABILITY_CLEAR_BODY || battlerAbility == ABILITY_FULL_METAL_BODY || battlerAbility == ABILITY_WHITE_SMOKE)) { @@ -3871,6 +3872,10 @@ u8 AtkCanceller_UnableToUseMove(void) { SetRandomMultiHitCounter(); } + + if (gMultiHitCounter < 4 && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) + gMultiHitCounter = 4; + PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) } else if (gBattleMoves[gCurrentMove].flags & FLAG_TWO_STRIKES) @@ -8011,7 +8016,8 @@ bool32 IsMoveMakingContact(u16 move, u8 battlerAtk) else return FALSE; } - else if (GetBattlerAbility(battlerAtk) == ABILITY_LONG_REACH) + else if (GetBattlerAbility(battlerAtk) == ABILITY_LONG_REACH + || GetBattlerHoldEffect(battlerAtk, TRUE) == HOLD_EFFECT_PUNCHING_GLOVE) { return FALSE; } @@ -8803,6 +8809,10 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe if (moveType == ItemId_GetSecondaryId(gBattleMons[battlerAtk].item)) MulModifier(&modifier, holdEffectModifier); break; + case HOLD_EFFECT_PUNCHING_GLOVE: + if (gBattleMoves[move].flags & FLAG_IRON_FIST_BOOST) + MulModifier(&modifier, UQ_4_12(1.1)); + break; } // move effect