diff --git a/include/battle_util.h b/include/battle_util.h index f22fd8b0ac..d30caadd47 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -165,7 +165,8 @@ struct DamageContext u32 isCrit:1; u32 randomFactor:1; u32 updateFlags:1; - u32 padding1:2; + u32 isAnticipation:1; + u32 padding1:1; u32 weather:16; u32 fixedBasePower:8; u32 padding2:8; diff --git a/src/battle_util.c b/src/battle_util.c index 58349507a7..abf61c1d58 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3690,8 +3690,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_ANTICIPATION: if (!gSpecialStatuses[battler].switchInAbilityDone) { - u32 types[3]; - GetBattlerTypes(battler, FALSE, types); + struct DamageContext ctx = {0}; + uq4_12_t modifier = UQ_4_12(1.0); for (i = 0; i < MAX_BATTLERS_COUNT; i++) { if (IsBattlerAlive(i) && !IsBattlerAlly(i, battler)) @@ -3702,9 +3702,14 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 enum BattleMoveEffects moveEffect = GetMoveEffect(move); moveType = GetBattleMoveType(move); - if (GetTypeModifier(moveType, types[0]) >= UQ_4_12(2.0) - || (types[0] != types[1] && GetTypeModifier(moveType, types[1]) >= UQ_4_12(2.0)) - || (types[2] != TYPE_MYSTERY && GetTypeModifier(moveType, types[2]) >= UQ_4_12(2.0)) + ctx.battlerAtk = i; + ctx.battlerDef = battler; + ctx.move = move; + ctx.moveType = moveType; + ctx.isAnticipation = TRUE; + modifier = CalcTypeEffectivenessMultiplier(&ctx); + + if (modifier >= UQ_4_12(2.0) || moveEffect == EFFECT_OHKO || moveEffect == EFFECT_SHEER_COLD) { @@ -7639,13 +7644,13 @@ enum IronBallCheck }; // Only called directly when calculating damage type effectiveness, and Iron Ball's type effectiveness mechanics -static bool32 IsBattlerGroundedInverseCheck(u32 battler, u32 ability, enum InverseBattleCheck checkInverse, enum IronBallCheck checkIronBall) +static bool32 IsBattlerGroundedInverseCheck(u32 battler, u32 ability, enum InverseBattleCheck checkInverse, enum IronBallCheck checkIronBall, bool32 isAnticipation) { enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); if (!(checkIronBall == IGNORE_IRON_BALL) && holdEffect == HOLD_EFFECT_IRON_BALL) return TRUE; - if (gFieldStatuses & STATUS_FIELD_GRAVITY) + if (gFieldStatuses & STATUS_FIELD_GRAVITY && isAnticipation == FALSE) return TRUE; if (B_ROOTED_GROUNDING >= GEN_4 && gBattleMons[battler].volatiles.root) return TRUE; @@ -7666,7 +7671,7 @@ static bool32 IsBattlerGroundedInverseCheck(u32 battler, u32 ability, enum Inver bool32 IsBattlerGrounded(u32 battler) { - return IsBattlerGroundedInverseCheck(battler, GetBattlerAbility(battler), NOT_INVERSE_BATTLE, CHECK_IRON_BALL); + return IsBattlerGroundedInverseCheck(battler, GetBattlerAbility(battler), NOT_INVERSE_BATTLE, CHECK_IRON_BALL, FALSE); } u32 GetMoveSlot(u16 *moves, u32 move) @@ -9522,7 +9527,7 @@ static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *m if (ctx->moveType == TYPE_PSYCHIC && defType == TYPE_DARK && gBattleMons[ctx->battlerDef].volatiles.miracleEye && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); - if (GetMoveEffect(ctx->move) == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == GetMoveArgType(ctx->move)) + if (GetMoveEffect(ctx->move) == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == GetMoveArgType(ctx->move) && !ctx->isAnticipation) mod = UQ_4_12(2.0); if (ctx->moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(ctx->battlerDef) && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); @@ -9530,7 +9535,7 @@ static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *m mod = UQ_4_12(2.0); // B_WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon - if (gBattleWeather & B_WEATHER_STRONG_WINDS && HasWeatherEffect()) + if (gBattleWeather & B_WEATHER_STRONG_WINDS && HasWeatherEffect() && !ctx->isAnticipation) { if (defType == TYPE_FLYING && mod >= UQ_4_12(2.0)) mod = UQ_4_12(1.0); @@ -9621,7 +9626,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont if (B_GLARE_GHOST < GEN_4 && ctx->move == MOVE_GLARE && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GHOST)) modifier = UQ_4_12(0.0); } - else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, INVERSE_BATTLE, CHECK_IRON_BALL) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move))) + else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, INVERSE_BATTLE, CHECK_IRON_BALL, ctx->isAnticipation) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move))) { modifier = UQ_4_12(0.0); if (ctx->updateFlags && ctx->abilityDef == ABILITY_LEVITATE) @@ -9651,7 +9656,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont && ctx->moveType == TYPE_GROUND && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_FLYING) && GetBattlerHoldEffect(ctx->battlerDef, TRUE) == HOLD_EFFECT_IRON_BALL - && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, NOT_INVERSE_BATTLE, IGNORE_IRON_BALL) + && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, NOT_INVERSE_BATTLE, IGNORE_IRON_BALL, FALSE) && !FlagGet(B_FLAG_INVERSE_BATTLE)) { modifier = UQ_4_12(1.0); @@ -9685,7 +9690,7 @@ uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx) if (ctx->move != MOVE_STRUGGLE && ctx->moveType != TYPE_MYSTERY) { modifier = CalcTypeEffectivenessMultiplierInternal(ctx, modifier); - if (GetMoveEffect(ctx->move) == EFFECT_TWO_TYPED_MOVE) + if (GetMoveEffect(ctx->move) == EFFECT_TWO_TYPED_MOVE && !ctx->isAnticipation) { ctx->moveType = GetMoveArgType(ctx->move); modifier = CalcTypeEffectivenessMultiplierInternal(ctx, modifier); diff --git a/test/battle/ability/anticipation.c b/test/battle/ability/anticipation.c index 223512710f..a4a3bef77f 100644 --- a/test/battle/ability/anticipation.c +++ b/test/battle/ability/anticipation.c @@ -16,6 +16,18 @@ SINGLE_BATTLE_TEST("Anticipation causes notifies if an opponent has a super-effe } } +SINGLE_BATTLE_TEST("Anticipation does not trigger even when a move is super effective on only 1 type") +{ + GIVEN { + PLAYER(SPECIES_WHISCASH) { Ability(ABILITY_ANTICIPATION); } + OPPONENT(SPECIES_PIKACHU) { Moves(MOVE_CELEBRATE, MOVE_THUNDERBOLT); } + } WHEN { + TURN { } + } SCENE { + NOT ABILITY_POPUP(player, ABILITY_ANTICIPATION); + } +} + SINGLE_BATTLE_TEST("Anticipation causes notifies if an opponent has a One-hit KO move") { GIVEN { @@ -59,28 +71,21 @@ SINGLE_BATTLE_TEST("Anticipation doesn't consider Normalize into their effective SINGLE_BATTLE_TEST("Anticipation doesn't consider Scrappy into their effectiveness (Gen5+)") { - KNOWN_FAILING; GIVEN { ASSUME(GetMoveType(MOVE_CLOSE_COMBAT) == TYPE_FIGHTING); - ASSUME(GetSpeciesType(SPECIES_EEVEE, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_EEVEE, 1) == TYPE_NORMAL); - PLAYER(SPECIES_EEVEE) { Ability(ABILITY_ANTICIPATION); } - OPPONENT(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); Moves(MOVE_CLOSE_COMBAT, MOVE_TRICK_OR_TREAT, MOVE_SKILL_SWAP, MOVE_CELEBRATE); } + ASSUME(GetSpeciesType(SPECIES_DOUBLADE, 0) == TYPE_STEEL); + ASSUME(GetSpeciesType(SPECIES_DOUBLADE, 1) == TYPE_GHOST); + PLAYER(SPECIES_DOUBLADE) { Ability(ABILITY_ANTICIPATION); } + OPPONENT(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); Moves(MOVE_CLOSE_COMBAT, MOVE_CELEBRATE); } } WHEN { - TURN { MOVE(opponent, MOVE_TRICK_OR_TREAT); MOVE(player, MOVE_SKILL_SWAP); } - TURN { MOVE(opponent, MOVE_SKILL_SWAP); } + TURN { } } SCENE { - ABILITY_POPUP(player, ABILITY_ANTICIPATION); - ANIMATION(ANIM_TYPE_MOVE, MOVE_TRICK_OR_TREAT, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); NOT ABILITY_POPUP(player, ABILITY_ANTICIPATION); } } SINGLE_BATTLE_TEST("Anticipation doesn't consider Gravity into their effectiveness (Gen5+)") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_SKARMORY); OPPONENT(SPECIES_EEVEE) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_EARTHQUAKE, MOVE_GRAVITY, MOVE_SCRATCH, MOVE_POUND); }