diff --git a/include/battle_util.h b/include/battle_util.h index 71f468996d..963f2288e4 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -282,7 +282,7 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter); s32 CalculateMoveDamage(struct DamageContext *ctx); s32 CalculateMoveDamageVars(struct DamageContext *ctx); s32 ApplyModifiersAfterDmgRoll(struct DamageContext *ctx, s32 dmg); -uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities); +uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx); uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef); uq4_12_t GetTypeModifier(u32 atkType, u32 defType); uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 31807e74ab..091bd6ecf1 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -423,12 +423,20 @@ bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffe // Consider a pokemon boosting their attack against a ghost pokemon having only normal-type physical attacks. bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category) { - s32 i, moveType; u32 usable = 0; u16 *moves = GetMovesArray(attacker); u32 moveLimitations = gAiLogicData->moveLimitations[attacker]; - for (i = 0; i < MAX_MON_MOVES; i++) + struct DamageContext ctx = {0}; + ctx.battlerAtk = attacker; + ctx.battlerDef = target; + ctx.updateFlags = FALSE; + ctx.abilityAtk = gAiLogicData->abilities[attacker]; + ctx.abilityDef = gAiLogicData->abilities[target]; + ctx.holdEffectAtk = gAiLogicData->items[attacker]; + ctx.holdEffectDef = gAiLogicData->items[target]; + + for (u32 i = 0; i < MAX_MON_MOVES; i++) { if (IsMoveUnusable(i, moves[i], moveLimitations)) continue; @@ -436,8 +444,10 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category) if (GetBattleMoveCategory(moves[i]) == category) { SetTypeBeforeUsingMove(moves[i], attacker); - moveType = GetBattleMoveType(moves[i]); - if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, gAiLogicData->abilities[target], FALSE) != 0) + ctx.move = moves[i]; + ctx.moveType = GetBattleMoveType(moves[i]); + + if (CalcTypeEffectivenessMultiplier(&ctx)) usable |= 1u << i; } } @@ -481,83 +491,83 @@ static inline s32 DmgRoll(s32 dmg) return dmg; } -bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveType, uq4_12_t effectiveness, u32 weather) +bool32 IsDamageMoveUnusable(struct DamageContext *ctx) { u32 battlerDefAbility; u32 partnerDefAbility; struct AiLogicData *aiData = gAiLogicData; - if (effectiveness == UQ_4_12(0.0)) + if (ctx->typeEffectivenessModifier == UQ_4_12(0.0)) return TRUE; - if (gBattleStruct->battlerState[battlerDef].commandingDondozo) + if (gBattleStruct->battlerState[ctx->battlerDef].commandingDondozo) return TRUE; // aiData->abilities does not check for Mold Breaker since it happens during combat so it needs to be done manually - if (IsMoldBreakerTypeAbility(battlerAtk, aiData->abilities[battlerAtk]) || MoveIgnoresTargetAbility(move)) + if (IsMoldBreakerTypeAbility(ctx->battlerAtk, ctx->abilityAtk) || MoveIgnoresTargetAbility(ctx->move)) { battlerDefAbility = ABILITY_NONE; partnerDefAbility = ABILITY_NONE; } else { - battlerDefAbility = aiData->abilities[battlerDef]; - partnerDefAbility = aiData->abilities[BATTLE_PARTNER(battlerDef)]; + battlerDefAbility = ctx->abilityDef; + partnerDefAbility = aiData->abilities[BATTLE_PARTNER(ctx->battlerDef)]; } - if (CanAbilityBlockMove(battlerAtk, battlerDef, aiData->abilities[battlerAtk], battlerDefAbility, move, ABILITY_CHECK_TRIGGER)) + if (CanAbilityBlockMove(ctx->battlerAtk, ctx->battlerDef, ctx->abilityAtk, battlerDefAbility, ctx->move, ABILITY_CHECK_TRIGGER)) return TRUE; - if (CanAbilityAbsorbMove(battlerAtk, battlerDef, battlerDefAbility, move, moveType, ABILITY_CHECK_TRIGGER)) + if (CanAbilityAbsorbMove(ctx->battlerAtk, ctx->battlerDef, battlerDefAbility, ctx->move, ctx->moveType, ABILITY_CHECK_TRIGGER)) return TRUE; // Limited to Lighning Rod and Storm Drain because otherwise the AI would consider Water Absorb, etc... if (partnerDefAbility == ABILITY_LIGHTNING_ROD || partnerDefAbility == ABILITY_STORM_DRAIN) { - if (CanAbilityAbsorbMove(battlerAtk, BATTLE_PARTNER(battlerDef), partnerDefAbility, move, moveType, ABILITY_CHECK_TRIGGER)) + if (CanAbilityAbsorbMove(ctx->battlerAtk, BATTLE_PARTNER(ctx->battlerDef), partnerDefAbility, ctx->move, ctx->moveType, ABILITY_CHECK_TRIGGER)) return TRUE; } if (HasWeatherEffect()) { - if (weather & B_WEATHER_SUN_PRIMAL && moveType == TYPE_WATER) + if (ctx->weather & B_WEATHER_SUN_PRIMAL && ctx->moveType == TYPE_WATER) return TRUE; - if (weather & B_WEATHER_RAIN_PRIMAL && moveType == TYPE_FIRE) + if (ctx->weather & B_WEATHER_RAIN_PRIMAL && ctx->moveType == TYPE_FIRE) return TRUE; } - switch (GetMoveEffect(move)) + switch (GetMoveEffect(ctx->move)) { case EFFECT_DREAM_EATER: - if (!AI_IsBattlerAsleepOrComatose(battlerDef)) + if (!AI_IsBattlerAsleepOrComatose(ctx->battlerDef)) return TRUE; break; case EFFECT_BELCH: - if (IsBelchPreventingMove(battlerAtk, move)) + if (IsBelchPreventingMove(ctx->battlerAtk, ctx->move)) return TRUE; break; case EFFECT_LAST_RESORT: - if (!CanUseLastResort(battlerAtk)) + if (!CanUseLastResort(ctx->battlerAtk)) return TRUE; break; case EFFECT_LOW_KICK: case EFFECT_HEAT_CRASH: - if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) + if (GetActiveGimmick(ctx->battlerDef) == GIMMICK_DYNAMAX) return TRUE; break; case EFFECT_FAIL_IF_NOT_ARG_TYPE: - if (!IS_BATTLER_OF_TYPE(battlerAtk, GetMoveArgType(move))) + if (!IS_BATTLER_OF_TYPE(ctx->battlerAtk, GetMoveArgType(ctx->move))) return TRUE; break; case EFFECT_HIT_SET_REMOVE_TERRAIN: - if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && GetMoveEffectArg_MoveProperty(move) == ARG_TRY_REMOVE_TERRAIN_FAIL) + if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && GetMoveEffectArg_MoveProperty(ctx->move) == ARG_TRY_REMOVE_TERRAIN_FAIL) return TRUE; break; case EFFECT_POLTERGEIST: - if (gAiLogicData->items[battlerDef] == ITEM_NONE || !IsBattlerItemEnabled(battlerDef)) + if (gAiLogicData->items[ctx->battlerDef] == ITEM_NONE || !IsBattlerItemEnabled(ctx->battlerDef)) return TRUE; break; case EFFECT_FIRST_TURN_ONLY: - if (!gDisableStructs[battlerAtk].isFirstTurn) + if (!gDisableStructs[ctx->battlerAtk].isFirstTurn) return TRUE; break; case EFFECT_EXPLOSION: @@ -733,9 +743,7 @@ static inline bool32 ShouldCalcCritDamage(u32 battlerAtk, u32 battlerDef, u32 mo struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef, u32 weather) { struct SimulatedDamage simDamage; - s32 moveType; enum BattleMoveEffects moveEffect = GetMoveEffect(move); - uq4_12_t effectivenessMultiplier; bool32 isDamageMoveUnusable = FALSE; bool32 toggledGimmickAtk = FALSE; bool32 toggledGimmickDef = FALSE; @@ -766,36 +774,32 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u SetDynamicMoveCategory(battlerAtk, battlerDef, move); SetTypeBeforeUsingMove(move, battlerAtk); - moveType = GetBattleMoveType(move); - effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, aiData->abilities[battlerDef], FALSE); + + struct DamageContext ctx; + ctx.battlerAtk = battlerAtk; + ctx.battlerDef = battlerDef; + ctx.move = move; + ctx.moveType = GetBattleMoveType(move); + ctx.isCrit = ShouldCalcCritDamage(battlerAtk, battlerDef, move, aiData); + ctx.randomFactor = FALSE; + ctx.updateFlags = FALSE; + ctx.weather = weather; + ctx.fixedBasePower = SetFixedMoveBasePower(battlerAtk, move); + ctx.abilityAtk = aiData->abilities[battlerAtk]; + ctx.abilityDef = aiData->abilities[battlerDef]; + ctx.holdEffectAtk = aiData->holdEffects[battlerAtk]; + ctx.holdEffectDef = aiData->holdEffects[battlerDef]; + ctx.typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(&ctx); u32 movePower = GetMovePower(move); if (movePower) - isDamageMoveUnusable = IsDamageMoveUnusable(battlerAtk, battlerDef, move, moveType, effectivenessMultiplier, weather); + isDamageMoveUnusable = IsDamageMoveUnusable(&ctx); if (movePower && !isDamageMoveUnusable) { u32 types[3]; AI_StoreBattlerTypes(battlerAtk, types); - - ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType); - s32 fixedBasePower = SetFixedMoveBasePower(battlerAtk, move); - - struct DamageContext ctx; - ctx.battlerAtk = battlerAtk; - ctx.battlerDef = battlerDef; - ctx.move = move; - ctx.moveType = moveType; - ctx.isCrit = ShouldCalcCritDamage(battlerAtk, battlerDef, move, aiData); - ctx.randomFactor = FALSE; - ctx.updateFlags = FALSE; - ctx.weather = weather; - ctx.fixedBasePower = fixedBasePower; - ctx.typeEffectivenessModifier = effectivenessMultiplier; - ctx.abilityAtk = aiData->abilities[battlerAtk]; - ctx.abilityDef = aiData->abilities[battlerDef]; - ctx.holdEffectAtk = aiData->holdEffects[battlerAtk]; - ctx.holdEffectDef = aiData->holdEffects[battlerDef]; + ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, ctx.moveType); if (moveEffect == EFFECT_TRIPLE_KICK) { @@ -842,7 +846,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u } // convert multiper to AI_EFFECTIVENESS_xX - *typeEffectiveness = effectivenessMultiplier; + *typeEffectiveness = ctx.typeEffectivenessModifier; // Undo temporary settings gBattleStruct->dynamicMoveType = 0; @@ -1137,7 +1141,6 @@ u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef, enum DamageCalcContex uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) { uq4_12_t typeEffectiveness; - u32 moveType; SaveBattlerData(battlerAtk); SaveBattlerData(battlerDef); @@ -1147,8 +1150,17 @@ uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) gBattleStruct->dynamicMoveType = 0; SetTypeBeforeUsingMove(move, battlerAtk); - moveType = GetBattleMoveType(move); - typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], FALSE); + struct DamageContext ctx = {0}; + ctx.battlerAtk = battlerAtk; + ctx.battlerDef = battlerDef; + ctx.move = move; + ctx.moveType = GetBattleMoveType(move); + ctx.updateFlags = FALSE; + ctx.abilityAtk = gAiLogicData->abilities[battlerAtk]; + ctx.abilityDef = gAiLogicData->abilities[battlerDef]; + ctx.holdEffectAtk = gAiLogicData->items[battlerAtk]; + ctx.holdEffectDef = gAiLogicData->items[battlerDef]; + typeEffectiveness = CalcTypeEffectivenessMultiplier(&ctx); RestoreBattlerData(battlerAtk); RestoreBattlerData(battlerDef); diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 768be59c4a..dfd254e77a 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -100,7 +100,7 @@ static void Task_UpdateLvlInHealthbox(u8); static void PrintLinkStandbyMsg(void); static void ReloadMoveNames(u32 battler); -static u32 CheckTypeEffectiveness(u32 targetId, u32 battler); +static u32 CheckTypeEffectiveness(u32 battlerAtk, u32 battlerDef); static u32 CheckTargetTypeEffectiveness(u32 battler); static void MoveSelectionDisplayMoveEffectiveness(u32 foeEffectiveness, u32 battler); @@ -507,7 +507,7 @@ void HandleInputChooseTarget(u32 battler) break; } if (B_SHOW_EFFECTIVENESS) - MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(GetBattlerPosition(gMultiUsePlayerCursor), battler), battler); + MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(battler, GetBattlerPosition(gMultiUsePlayerCursor)), battler); if (gAbsentBattlerFlags & (1u << gMultiUsePlayerCursor) || !CanTargetBattler(battler, gMultiUsePlayerCursor, move) @@ -558,7 +558,7 @@ void HandleInputChooseTarget(u32 battler) break; } if (B_SHOW_EFFECTIVENESS) - MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(GetBattlerPosition(gMultiUsePlayerCursor), battler), battler); + MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(battler, GetBattlerPosition(gMultiUsePlayerCursor)), battler); if (gAbsentBattlerFlags & (1u << gMultiUsePlayerCursor) || !CanTargetBattler(battler, gMultiUsePlayerCursor, move) @@ -758,7 +758,7 @@ void HandleInputChooseMove(u32 battler) else gMultiUsePlayerCursor = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); if (B_SHOW_EFFECTIVENESS) - MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(GetBattlerPosition(gMultiUsePlayerCursor), battler), battler); + MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(battler, GetBattlerPosition(gMultiUsePlayerCursor)), battler); gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_ShowAsMoveTarget; break; @@ -2435,15 +2435,23 @@ static bool32 ShouldShowTypeEffectiveness(u32 targetId) return TRUE; } -static u32 CheckTypeEffectiveness(u32 targetId, u32 battler) +static u32 CheckTypeEffectiveness(u32 battlerAtk, u32 battlerDef) { - struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); - struct Pokemon *mon = GetBattlerMon(battler); - u32 move = moveInfo->moves[gMoveSelectionCursor[battler]]; - u32 moveType = CheckDynamicMoveType(mon, move, battler, MON_IN_BATTLE); - uq4_12_t modifier = CalcTypeEffectivenessMultiplier(move, moveType, battler, targetId, GetBattlerAbility(targetId), FALSE); + struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battlerAtk][4]); + struct DamageContext ctx = {0}; + ctx.battlerAtk = battlerAtk; + ctx.battlerDef = battlerDef; + ctx.move = moveInfo->moves[gMoveSelectionCursor[battlerAtk]]; + ctx.moveType = CheckDynamicMoveType(GetBattlerMon(battlerAtk), ctx.move, battlerAtk, MON_IN_BATTLE); + ctx.updateFlags = FALSE; + ctx.abilityAtk = GetBattlerAbility(battlerAtk); + ctx.abilityDef = GetBattlerAbility(battlerDef); + ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); + ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); - if (!ShouldShowTypeEffectiveness(targetId)) + uq4_12_t modifier = CalcTypeEffectivenessMultiplier(&ctx); + + if (!ShouldShowTypeEffectiveness(battlerDef)) return EFFECTIVENESS_CANNOT_VIEW; if (modifier == UQ_4_12(0.0)) @@ -2458,12 +2466,12 @@ static u32 CheckTypeEffectiveness(u32 targetId, u32 battler) static u32 CheckTargetTypeEffectiveness(u32 battler) { u32 battlerFoe = BATTLE_OPPOSITE(GetBattlerPosition(battler)); - u32 foeEffectiveness = CheckTypeEffectiveness(battlerFoe, battler); + u32 foeEffectiveness = CheckTypeEffectiveness(battler, battlerFoe); if (IsDoubleBattle()) { u32 partnerFoe = BATTLE_PARTNER(battlerFoe); - u32 partnerFoeEffectiveness = CheckTypeEffectiveness(partnerFoe, battler); + u32 partnerFoeEffectiveness = CheckTypeEffectiveness(battler, partnerFoe); if (!IsBattlerAlive(battlerFoe)) return partnerFoeEffectiveness; if (IsBattlerAlive(battlerFoe) && IsBattlerAlive(partnerFoe) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 048c4d13de..a97c6ee7a5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1715,13 +1715,15 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u if (JumpIfMoveAffectedByProtect(move, battlerDef, FALSE, failInstr) || AccuracyCalcHelper(move, battlerDef)) continue; + u32 abilityDef = GetBattlerAbility(battlerDef); + u32 holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); u32 accuracy = GetTotalAccuracy(gBattlerAttacker, battlerDef, move, abilityAtk, - GetBattlerAbility(battlerDef), + abilityDef, holdEffectAtk, - GetBattlerHoldEffect(battlerDef, TRUE)); + holdEffectDef); if (!RandomPercentage(RNG_ACCURACY, accuracy)) { @@ -1746,7 +1748,20 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u } if (GetMovePower(move) != 0) - CalcTypeEffectivenessMultiplier(move, moveType, gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); + { + struct DamageContext ctx = {0}; + ctx.battlerAtk = gBattlerAttacker; + ctx.battlerDef = battlerDef; + ctx.move = move; + ctx.moveType = moveType; + ctx.updateFlags = TRUE; + ctx.abilityAtk = abilityAtk; + ctx.abilityDef = abilityDef; + ctx.holdEffectAtk = holdEffectAtk; + ctx.holdEffectDef = holdEffectDef; + + CalcTypeEffectivenessMultiplier(&ctx); + } } } @@ -2126,8 +2141,18 @@ static void Cmd_typecalc(void) if (!IsSpreadMove(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove))) // Handled in CANCELLER_MULTI_TARGET_MOVES for Spread Moves { - u32 moveType = GetBattleMoveType(gCurrentMove); - CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE); + struct DamageContext ctx = {0}; + ctx.battlerAtk = gBattlerAttacker; + ctx.battlerDef = gBattlerTarget; + ctx.move = gCurrentMove; + ctx.moveType = GetBattleMoveType(gCurrentMove); + ctx.updateFlags = TRUE; + ctx.abilityAtk = GetBattlerAbility(gBattlerAttacker); + ctx.abilityDef = GetBattlerAbility(gBattlerTarget); + ctx.holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); + ctx.holdEffectDef = GetBattlerHoldEffect(gBattlerTarget, TRUE); + + CalcTypeEffectivenessMultiplier(&ctx); } gBattlescriptCurrInstr = cmd->nextInstr; diff --git a/src/battle_util.c b/src/battle_util.c index b18288763f..750e059612 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -204,6 +204,24 @@ static const struct BattleWeatherInfo sBattleWeatherInfo[BATTLE_WEATHER_COUNT] = }, }; +// Helper function for actual dmg calcs during battle. For simulated AI dmg, CalcTypeEffectivenessMultiplier should be used directly +// This should stay a static function. Ideally everything else is handled through CalcTypeEffectivenessMultiplier just like AI +static uq4_12_t CalcTypeEffectivenessMultiplierHelper(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities) +{ + struct DamageContext ctx = {0}; + ctx.battlerAtk = battlerAtk; + ctx.battlerDef = battlerDef; + ctx.move = move; + ctx.moveType = GetBattleMoveType(gCurrentMove); + ctx.updateFlags = recordAbilities; + ctx.abilityAtk = GetBattlerAbility(battlerAtk); + ctx.abilityDef = defAbility; + ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); + ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); + + return CalcTypeEffectivenessMultiplier(&ctx); +} + u32 GetCurrentBattleWeather(void) { u32 currBattleWeather = 0xFF; @@ -2479,7 +2497,7 @@ static void CancellerMultiTargetMoves(u32 *effect) } else { - CalcTypeEffectivenessMultiplier(gCurrentMove, GetBattleMoveType(gCurrentMove), gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); + CalcTypeEffectivenessMultiplierHelper(gCurrentMove, GetBattleMoveType(gCurrentMove), gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); } } if (moveTarget == MOVE_TARGET_BOTH) @@ -3591,6 +3609,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); for (i = 0; i < MAX_BATTLERS_COUNT; i++) { if (IsBattlerAlive(i) && !IsBattlerAlly(i, battler)) @@ -3598,10 +3618,14 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 for (j = 0; j < MAX_MON_MOVES; j++) { move = gBattleMons[i].moves[j]; - moveType = GetBattleMoveType(move); enum BattleMoveEffects moveEffect = GetMoveEffect(move); - if (CalcTypeEffectivenessMultiplier(move, moveType, i, battler, ABILITY_ANTICIPATION, FALSE) >= UQ_4_12(2.0) - || moveEffect == EFFECT_OHKO || moveEffect == EFFECT_SHEER_COLD) + 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)) + || moveEffect == EFFECT_OHKO + || moveEffect == EFFECT_SHEER_COLD) { effect++; break; @@ -5620,7 +5644,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u battleScript = BattleScript_NotAffected; } else if (option == STATUS_RUN_SCRIPT // Check only important during battle execution for moves - && CalcTypeEffectivenessMultiplier(gCurrentMove, GetBattleMoveType(gCurrentMove), battlerAtk, battlerDef, abilityDef, TRUE) + && CalcTypeEffectivenessMultiplierHelper(gCurrentMove, GetBattleMoveType(gCurrentMove), battlerAtk, battlerDef, abilityDef, TRUE) && gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT) { battleScript = BattleScript_ButItFailed; @@ -9346,10 +9370,10 @@ static inline s32 DoMoveDamageCalc(struct DamageContext *ctx) if (dmg != INT32_MAX) return dmg; - ctx->holdEffectAtk = GetBattlerHoldEffect(ctx->battlerAtk, TRUE); - ctx->holdEffectDef = GetBattlerHoldEffect(ctx->battlerDef, TRUE); ctx->abilityAtk = GetBattlerAbility(ctx->battlerAtk); ctx->abilityDef = GetBattlerAbility(ctx->battlerDef); + ctx->holdEffectDef = GetBattlerHoldEffect(ctx->battlerDef, TRUE); + ctx->holdEffectAtk = GetBattlerHoldEffect(ctx->battlerAtk, TRUE); return DoMoveDamageCalcVars(ctx); } @@ -9435,13 +9459,7 @@ s32 CalculateMoveDamage(struct DamageContext *ctx) ctx->holdEffectAtk = GetItemHoldEffect(ctx->battlerAtk); ctx->holdEffectDef = GetItemHoldEffect(ctx->battlerDef); - ctx->typeEffectivenessModifier = CalcTypeEffectivenessMultiplier( - ctx->move, - ctx->moveType, - ctx->battlerAtk, - ctx->battlerDef, - ctx->abilityDef, - ctx->updateFlags); + ctx->typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(ctx); if (IsFutureSightAttackerInParty(ctx->battlerAtk, ctx->battlerDef, ctx->move)) return DoFutureSightAttackDamageCalc(ctx); @@ -9459,37 +9477,36 @@ s32 CalculateMoveDamageVars(struct DamageContext *ctx) return DoMoveDamageCalcVars(ctx); } -static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 moveType, u32 battlerDef, u32 defAbility, u32 defType, u32 battlerAtk, bool32 recordAbilities) +static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *modifier, u32 defType) { - uq4_12_t mod = GetTypeModifier(moveType, defType); - u32 abilityAtk = GetBattlerAbility(battlerAtk); + uq4_12_t mod = GetTypeModifier(ctx->moveType, defType); - if (mod == UQ_4_12(0.0) && GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_RING_TARGET) + if (mod == UQ_4_12(0.0) && ctx->holdEffectDef == HOLD_EFFECT_RING_TARGET) { mod = UQ_4_12(1.0); - if (recordAbilities) - RecordItemEffectBattle(battlerDef, HOLD_EFFECT_RING_TARGET); + if (ctx->updateFlags) + RecordItemEffectBattle(ctx->battlerDef, HOLD_EFFECT_RING_TARGET); } - else if ((moveType == TYPE_FIGHTING || moveType == TYPE_NORMAL) && defType == TYPE_GHOST && gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT && mod == UQ_4_12(0.0)) + else if ((ctx->moveType == TYPE_FIGHTING || ctx->moveType == TYPE_NORMAL) && defType == TYPE_GHOST && gBattleMons[ctx->battlerDef].status2 & STATUS2_FORESIGHT && mod == UQ_4_12(0.0)) { mod = UQ_4_12(1.0); } - else if ((moveType == TYPE_FIGHTING || moveType == TYPE_NORMAL) && defType == TYPE_GHOST - && (abilityAtk == ABILITY_SCRAPPY || abilityAtk == ABILITY_MINDS_EYE) + else if ((ctx->moveType == TYPE_FIGHTING || ctx->moveType == TYPE_NORMAL) && defType == TYPE_GHOST + && (ctx->abilityAtk == ABILITY_SCRAPPY || ctx->abilityAtk == ABILITY_MINDS_EYE) && mod == UQ_4_12(0.0)) { mod = UQ_4_12(1.0); - if (recordAbilities) - RecordAbilityBattle(battlerAtk, abilityAtk); + if (ctx->updateFlags) + RecordAbilityBattle(ctx->battlerAtk, ctx->abilityAtk); } - if (moveType == TYPE_PSYCHIC && defType == TYPE_DARK && gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED && mod == UQ_4_12(0.0)) + if (ctx->moveType == TYPE_PSYCHIC && defType == TYPE_DARK && gStatuses3[ctx->battlerDef] & STATUS3_MIRACLE_EYED && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); - if (GetMoveEffect(move) == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == GetMoveArgType(move)) + if (GetMoveEffect(ctx->move) == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == GetMoveArgType(ctx->move)) mod = UQ_4_12(2.0); - if (moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(battlerDef) && mod == UQ_4_12(0.0)) + if (ctx->moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(ctx->battlerDef) && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); - if (moveType == TYPE_STELLAR && GetActiveGimmick(battlerDef) == GIMMICK_TERA) + if (ctx->moveType == TYPE_STELLAR && GetActiveGimmick(ctx->battlerDef) == GIMMICK_TERA) mod = UQ_4_12(2.0); // B_WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon @@ -9499,14 +9516,14 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move mod = UQ_4_12(1.0); } - if (gSpecialStatuses[battlerDef].distortedTypeMatchups || (mod > UQ_4_12(0.0) && ShouldTeraShellDistortTypeMatchups(move, battlerDef, defAbility))) + if (gSpecialStatuses[ctx->battlerDef].distortedTypeMatchups || (mod > UQ_4_12(0.0) && ShouldTeraShellDistortTypeMatchups(ctx->move, ctx->battlerDef, ctx->abilityDef))) { mod = UQ_4_12(0.5); - if (recordAbilities) + if (ctx->updateFlags) { - RecordAbilityBattle(battlerDef, defAbility); - gSpecialStatuses[battlerDef].distortedTypeMatchups = TRUE; - gSpecialStatuses[battlerDef].teraShellAbilityDone = TRUE; + RecordAbilityBattle(ctx->battlerDef, ctx->abilityDef); + gSpecialStatuses[ctx->battlerDef].distortedTypeMatchups = TRUE; + gSpecialStatuses[ctx->battlerDef].teraShellAbilityDone = TRUE; } } @@ -9517,12 +9534,24 @@ static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, { // Check if the type effectiveness would've been different if the pokemon really had the types as the disguise. uq4_12_t presumedModifier = UQ_4_12(1.0); - MulByTypeEffectiveness(&presumedModifier, move, moveType, battlerDef, ABILITY_ILLUSION, GetSpeciesType(illusionSpecies, 0), battlerAtk, FALSE); + + struct DamageContext ctx = {0}; + ctx.battlerAtk = battlerAtk; + ctx.battlerDef = battlerDef; + ctx.move = move; + ctx.moveType = moveType; + ctx.updateFlags = FALSE; + ctx.abilityAtk = GetBattlerAbility(battlerAtk); + ctx.abilityDef = ABILITY_ILLUSION; + ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); + ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); + + MulByTypeEffectiveness(&ctx, &presumedModifier, GetSpeciesType(illusionSpecies, 0)); if (GetSpeciesType(illusionSpecies, 1) != GetSpeciesType(illusionSpecies, 0)) - MulByTypeEffectiveness(&presumedModifier, move, moveType, battlerDef, ABILITY_ILLUSION, GetSpeciesType(illusionSpecies, 1), battlerAtk, FALSE); + MulByTypeEffectiveness(&ctx, &presumedModifier, GetSpeciesType(illusionSpecies, 1)); if (presumedModifier != resultingModifier) - RecordAbilityBattle(battlerDef, ABILITY_ILLUSION); + RecordAbilityBattle(ctx.battlerDef, ABILITY_ILLUSION); } void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags) @@ -9549,99 +9578,102 @@ void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags) } } -static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 recordAbilities, uq4_12_t modifier, u32 defAbility) +static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageContext *ctx, uq4_12_t modifier) { u32 illusionSpecies; u32 types[3]; - GetBattlerTypes(battlerDef, FALSE, types); + GetBattlerTypes(ctx->battlerDef, FALSE, types); - MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, defAbility, types[0], battlerAtk, recordAbilities); + MulByTypeEffectiveness(ctx, &modifier, types[0]); if (types[1] != types[0]) - MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, defAbility, types[1], battlerAtk, recordAbilities); + MulByTypeEffectiveness(ctx, &modifier, types[1]); if (types[2] != TYPE_MYSTERY && types[2] != types[1] && types[2] != types[0]) - MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, defAbility, types[2], battlerAtk, recordAbilities); - if (moveType == TYPE_FIRE && gDisableStructs[battlerDef].tarShot) + MulByTypeEffectiveness(ctx, &modifier, types[2]); + if (ctx->moveType == TYPE_FIRE && gDisableStructs[ctx->battlerDef].tarShot) modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); - if (recordAbilities && (illusionSpecies = GetIllusionMonSpecies(battlerDef))) - TryNoticeIllusionInTypeEffectiveness(move, moveType, battlerAtk, battlerDef, modifier, illusionSpecies); + if (ctx->updateFlags && (illusionSpecies = GetIllusionMonSpecies(ctx->battlerDef))) + TryNoticeIllusionInTypeEffectiveness(ctx->move, ctx->moveType, ctx->battlerAtk, ctx->battlerDef, modifier, illusionSpecies); - if (GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS && move != MOVE_THUNDER_WAVE) + if (GetMoveCategory(ctx->move) == DAMAGE_CATEGORY_STATUS && ctx->move != MOVE_THUNDER_WAVE) { modifier = UQ_4_12(1.0); - if (B_GLARE_GHOST < GEN_4 && move == MOVE_GLARE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) + 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 (moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(battlerDef, INVERSE_BATTLE, CHECK_IRON_BALL) && !(MoveIgnoresTypeIfFlyingAndUngrounded(move))) + else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, INVERSE_BATTLE, CHECK_IRON_BALL) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move))) { modifier = UQ_4_12(0.0); - if (recordAbilities && defAbility == ABILITY_LEVITATE) + if (ctx->updateFlags && ctx->abilityDef == ABILITY_LEVITATE) { - gBattleStruct->moveResultFlags[battlerDef] |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE); + gBattleStruct->moveResultFlags[ctx->battlerDef] |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE); gLastUsedAbility = ABILITY_LEVITATE; - gLastLandedMoves[battlerDef] = 0; - gBattleStruct->missStringId[battlerDef] = B_MSG_GROUND_MISS; - RecordAbilityBattle(battlerDef, ABILITY_LEVITATE); + gLastLandedMoves[ctx->battlerDef] = 0; + gBattleStruct->missStringId[ctx->battlerDef] = B_MSG_GROUND_MISS; + RecordAbilityBattle(ctx->battlerDef, ABILITY_LEVITATE); } } - else if (B_SHEER_COLD_IMMUNITY >= GEN_7 && GetMoveEffect(move) == EFFECT_SHEER_COLD && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE)) + else if (B_SHEER_COLD_IMMUNITY >= GEN_7 && GetMoveEffect(ctx->move) == EFFECT_SHEER_COLD && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_ICE)) { modifier = UQ_4_12(0.0); } // Thousand Arrows ignores type modifiers for flying mons - if (!IsBattlerGrounded(battlerDef) - && MoveIgnoresTypeIfFlyingAndUngrounded(move) - && IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING)) + if (!IsBattlerGrounded(ctx->battlerDef) + && MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move) + && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_FLYING)) { modifier = UQ_4_12(1.0); } // Iron Ball ignores type modifiers for flying-type mons if it is the only source of grounding if (B_IRON_BALL >= GEN_5 - && moveType == TYPE_GROUND - && IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING) - && GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_IRON_BALL - && !IsBattlerGroundedInverseCheck(battlerDef, NOT_INVERSE_BATTLE, IGNORE_IRON_BALL) + && ctx->moveType == TYPE_GROUND + && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_FLYING) + && GetBattlerHoldEffect(ctx->battlerDef, TRUE) == HOLD_EFFECT_IRON_BALL + && !IsBattlerGroundedInverseCheck(ctx->battlerDef, NOT_INVERSE_BATTLE, IGNORE_IRON_BALL) && !FlagGet(B_FLAG_INVERSE_BATTLE)) { modifier = UQ_4_12(1.0); } - if (((defAbility == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0)) - || (defAbility == ABILITY_TELEPATHY && battlerDef == BATTLE_PARTNER(battlerAtk))) - && GetMovePower(move) != 0) + if (((ctx->abilityDef == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0)) + || (ctx->abilityDef == ABILITY_TELEPATHY && ctx->battlerDef == BATTLE_PARTNER(ctx->battlerAtk))) + && GetMovePower(ctx->move) != 0) { modifier = UQ_4_12(0.0); - if (recordAbilities) + if (ctx->updateFlags) { - gLastUsedAbility = gBattleMons[battlerDef].ability; - gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_MISSED; - gLastLandedMoves[battlerDef] = 0; - gBattleStruct->missStringId[battlerDef] = B_MSG_AVOIDED_DMG; - RecordAbilityBattle(battlerDef, gBattleMons[battlerDef].ability); + gLastUsedAbility = gBattleMons[ctx->battlerDef].ability; + gBattleStruct->moveResultFlags[ctx->battlerDef] |= MOVE_RESULT_MISSED; + gLastLandedMoves[ctx->battlerDef] = 0; + gBattleStruct->missStringId[ctx->battlerDef] = B_MSG_AVOIDED_DMG; + RecordAbilityBattle(ctx->battlerDef, gBattleMons[ctx->battlerDef].ability); } } - if (recordAbilities) - TryInitializeFirstSTABMoveTrainerSlide(battlerDef, battlerAtk, moveType); + if (ctx->updateFlags) + TryInitializeFirstSTABMoveTrainerSlide(ctx->battlerDef, ctx->battlerAtk, ctx->moveType); return modifier; } -uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities) +uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx) { uq4_12_t modifier = UQ_4_12(1.0); - if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) + if (ctx->move != MOVE_STRUGGLE && ctx->moveType != TYPE_MYSTERY) { - modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); - if (GetMoveEffect(move) == EFFECT_TWO_TYPED_MOVE) - modifier = CalcTypeEffectivenessMultiplierInternal(move, GetMoveArgType(move), battlerAtk, battlerDef, recordAbilities, modifier, defAbility); + modifier = CalcTypeEffectivenessMultiplierInternal(ctx, modifier); + if (GetMoveEffect(ctx->move) == EFFECT_TWO_TYPED_MOVE) + { + ctx->moveType = GetMoveArgType(ctx->move); + modifier = CalcTypeEffectivenessMultiplierInternal(ctx, modifier); + } } - if (recordAbilities) - UpdateMoveResultFlags(modifier, &gBattleStruct->moveResultFlags[battlerDef]); + if (ctx->updateFlags) + UpdateMoveResultFlags(modifier, &gBattleStruct->moveResultFlags[ctx->battlerDef]); return modifier; } @@ -9652,11 +9684,17 @@ uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 a if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) { - MulByTypeEffectiveness(&modifier, move, moveType, 0, 0, GetSpeciesType(speciesDef, 0), 0, FALSE); - if (GetSpeciesType(speciesDef, 1) != GetSpeciesType(speciesDef, 0)) - MulByTypeEffectiveness(&modifier, move, moveType, 0, 0, GetSpeciesType(speciesDef, 1), 0, FALSE); + struct DamageContext ctx = {0}; + ctx.move = move; + ctx.moveType = moveType; + ctx.updateFlags = FALSE; + ctx.abilityDef = abilityDef; - if (moveType == TYPE_GROUND && abilityDef == ABILITY_LEVITATE && !(gFieldStatuses & STATUS_FIELD_GRAVITY)) + MulByTypeEffectiveness(&ctx, &modifier, GetSpeciesType(speciesDef, 0)); + if (GetSpeciesType(speciesDef, 1) != GetSpeciesType(speciesDef, 0)) + MulByTypeEffectiveness(&ctx, &modifier, GetSpeciesType(speciesDef, 1)); + + if (ctx.moveType == TYPE_GROUND && abilityDef == ABILITY_LEVITATE && !(gFieldStatuses & STATUS_FIELD_GRAVITY)) modifier = UQ_4_12(0.0); if (abilityDef == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0) && GetMovePower(move) != 0) modifier = UQ_4_12(0.0); @@ -9690,9 +9728,14 @@ uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType) if (moveType != TYPE_MYSTERY) { - MulByTypeEffectiveness(&modifier, MOVE_POUND, moveType, 0, 0, type1, 0, FALSE); + struct DamageContext ctx = {0}; + ctx.move = MOVE_POUND; + ctx.moveType = moveType; + ctx.updateFlags = FALSE; + + MulByTypeEffectiveness(&ctx, &modifier, type1); if (type2 != type1) - MulByTypeEffectiveness(&modifier, MOVE_POUND, moveType, 0, 0, type2, 0, FALSE); + MulByTypeEffectiveness(&ctx, &modifier, type2); if ((modifier <= UQ_4_12(1.0) && abilityDef == ABILITY_WONDER_GUARD) || (moveType == TYPE_FIRE && abilityDef == ABILITY_FLASH_FIRE) @@ -11103,7 +11146,7 @@ static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerD bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef) { u32 moveType = GetBattleMoveType(gCurrentMove); - return ((CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0)) + return ((CalcTypeEffectivenessMultiplierHelper(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0)) || IsBattlerProtected(battlerAtk, battlerDef, gCurrentMove) || IsSemiInvulnerable(battlerDef, gCurrentMove) || DoesBattlerHaveAbilityImmunity(battlerAtk, battlerDef, moveType)); diff --git a/test/battle/ability/anticipation.c b/test/battle/ability/anticipation.c index e1de10f2ff..223512710f 100644 --- a/test/battle/ability/anticipation.c +++ b/test/battle/ability/anticipation.c @@ -133,7 +133,6 @@ SINGLE_BATTLE_TEST("Anticipation considers Synchronoise as an ordinary Psychic-t SINGLE_BATTLE_TEST("Anticipation considers Freeze-Dry as an ordinary Ice-type move") { - KNOWN_FAILING; GIVEN { ASSUME(GetMoveType(MOVE_FREEZE_DRY) == TYPE_ICE); ASSUME(GetSpeciesType(SPECIES_SQUIRTLE, 0) == TYPE_WATER); @@ -150,7 +149,6 @@ SINGLE_BATTLE_TEST("Anticipation considers Freeze-Dry as an ordinary Ice-type mo SINGLE_BATTLE_TEST("Anticipation considers Flying Press as an ordinary Fighting-type move") { - KNOWN_FAILING; GIVEN { ASSUME(GetMoveType(MOVE_FLYING_PRESS) == TYPE_FIGHTING); ASSUME(GetSpeciesType(SPECIES_TANGELA, 0) == TYPE_GRASS); @@ -280,7 +278,6 @@ SINGLE_BATTLE_TEST("Anticipation treats dynamic move types as their base type (N SINGLE_BATTLE_TEST("Anticipation does not consider Strong Winds on type matchups") { - KNOWN_FAILING; GIVEN { ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 0) == TYPE_DRAGON); ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 1) == TYPE_FLYING);