Add damage context to effectiveness multiplier (#7111)

This commit is contained in:
Alex 2025-06-14 11:05:14 +02:00 committed by GitHub
parent e1b542944f
commit d4146afcae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 245 additions and 160 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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));

View File

@ -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);