Changes AccuracyCalcHelper into CanMoveSkipAccuracyCalc (#7303)
This commit is contained in:
parent
b5a13d5e7f
commit
d15c490223
@ -23,17 +23,12 @@
|
||||
#define MOVE_LIMITATION_PLACEHOLDER (1 << 15)
|
||||
#define MOVE_LIMITATIONS_ALL 0xFFFF
|
||||
|
||||
enum NonVolatileStatus
|
||||
// Switches between simulated battle calc and actual battle combat
|
||||
enum FunctionCallOption
|
||||
{
|
||||
STATUS_CHECK_TRIGGER,
|
||||
STATUS_RUN_SCRIPT,
|
||||
};
|
||||
|
||||
enum AbilityEffectOptions
|
||||
{
|
||||
ABILITY_CHECK_TRIGGER,
|
||||
ABILITY_CHECK_TRIGGER_AI,
|
||||
ABILITY_RUN_SCRIPT,
|
||||
CHECK_TRIGGER, // Check the function without running scripts / setting any flags.
|
||||
AI_CHECK, // Check the function without running scripts / setting any flags. Same as CHECK_TRIGGER but only used when additional data has to be fetched during ai calcs
|
||||
RUN_SCRIPT, // Used during actual combat where a script has to be run / flags need to be set
|
||||
};
|
||||
|
||||
enum MoveAbsorbed
|
||||
@ -245,8 +240,8 @@ enum MoveCanceller AtkCanceller_MoveSuccessOrder(void);
|
||||
void SetAtkCancellerForCalledMove(void);
|
||||
bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2);
|
||||
bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility);
|
||||
bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum AbilityEffectOptions option);
|
||||
bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType, enum AbilityEffectOptions option);
|
||||
bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option);
|
||||
bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType, enum FunctionCallOption option);
|
||||
u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg);
|
||||
bool32 TryPrimalReversion(u32 battler);
|
||||
bool32 IsNeutralizingGasOnField(void);
|
||||
@ -360,7 +355,7 @@ bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, u32 ability);
|
||||
bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
|
||||
bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
|
||||
bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
|
||||
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffects secondaryMoveEffect, enum NonVolatileStatus option);
|
||||
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffects secondaryMoveEffect, enum FunctionCallOption option);
|
||||
bool32 CanBeConfused(u32 battler);
|
||||
bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag);
|
||||
u32 GetBattlerAffectionHearts(u32 battler);
|
||||
@ -406,5 +401,7 @@ bool32 AreAnyHazardsOnSide(u32 side);
|
||||
void RemoveAllHazardsFromField(u32 side);
|
||||
bool32 IsHazardOnSideAndClear(u32 side, enum Hazards hazardType);
|
||||
void RemoveHazardFromField(u32 side, enum Hazards hazardType);
|
||||
bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option);
|
||||
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
||||
@ -547,18 +547,27 @@ void SetBattlerAiData(u32 battler, struct AiLogicData *aiData)
|
||||
aiData->speedStats[battler] = GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect);
|
||||
}
|
||||
|
||||
#define BYPASSES_ACCURACY_CALC 101 // 101 indicates for ai that the move will always hit
|
||||
static u32 Ai_SetMoveAccuracy(struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
u32 accuracy;
|
||||
u32 abilityAtk = aiData->abilities[battlerAtk];
|
||||
u32 abilityDef = aiData->abilities[battlerDef];
|
||||
if (abilityAtk == ABILITY_NO_GUARD || abilityDef == ABILITY_NO_GUARD || GetMoveAccuracy(move) == 0) // Moves with accuracy 0 or no guard ability always hit.
|
||||
accuracy = 100;
|
||||
if (CanMoveSkipAccuracyCalc(battlerAtk, battlerDef, abilityAtk, abilityDef, move, AI_CHECK))
|
||||
{
|
||||
accuracy = BYPASSES_ACCURACY_CALC;
|
||||
}
|
||||
else
|
||||
{
|
||||
accuracy = GetTotalAccuracy(battlerAtk, battlerDef, move, abilityAtk, abilityDef, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef]);
|
||||
// Cap normal accuracy at 100 for ai calcs.
|
||||
// Done for comparison with moves that bypass accuracy checks (will be seen as 101 for ai calcs))
|
||||
accuracy = (accuracy > 100) ? 100 : accuracy;
|
||||
}
|
||||
|
||||
return accuracy;
|
||||
}
|
||||
#undef BYPASSES_ACCURACY_CALC
|
||||
|
||||
static void CalcBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef, u32 weather)
|
||||
{
|
||||
@ -672,8 +681,8 @@ static u32 PpStallReduction(u32 move, u32 battlerAtk)
|
||||
u32 abilityAtk = ABILITY_NONE;
|
||||
u32 abilityDef = GetPartyMonAbility(&gPlayerParty[partyIndex]);
|
||||
u32 moveType = GetBattleMoveType(move); // Probably doesn't handle dynamic types right now
|
||||
if (CanAbilityAbsorbMove(battlerAtk, tempBattleMonIndex, abilityDef, move, moveType, ABILITY_CHECK_TRIGGER)
|
||||
|| CanAbilityBlockMove(battlerAtk, tempBattleMonIndex, abilityAtk, abilityDef, move, ABILITY_CHECK_TRIGGER)
|
||||
if (CanAbilityAbsorbMove(battlerAtk, tempBattleMonIndex, abilityDef, move, moveType, CHECK_TRIGGER)
|
||||
|| CanAbilityBlockMove(battlerAtk, tempBattleMonIndex, abilityAtk, abilityDef, move, CHECK_TRIGGER)
|
||||
|| (CalcPartyMonTypeEffectivenessMultiplier(move, species, abilityDef) == 0))
|
||||
{
|
||||
totalStallValue += currentStallValue;
|
||||
@ -1105,10 +1114,10 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
// check non-user target
|
||||
if (!(moveTarget & MOVE_TARGET_USER))
|
||||
{
|
||||
if (CanAbilityBlockMove(battlerAtk, battlerDef, abilityAtk, abilityDef, move, ABILITY_CHECK_TRIGGER_AI))
|
||||
if (CanAbilityBlockMove(battlerAtk, battlerDef, abilityAtk, abilityDef, move, AI_CHECK))
|
||||
RETURN_SCORE_MINUS(20);
|
||||
|
||||
if (CanAbilityAbsorbMove(battlerAtk, battlerDef, abilityDef, move, moveType, ABILITY_CHECK_TRIGGER_AI))
|
||||
if (CanAbilityAbsorbMove(battlerAtk, battlerDef, abilityDef, move, moveType, AI_CHECK))
|
||||
RETURN_SCORE_MINUS(20);
|
||||
|
||||
switch (abilityDef)
|
||||
|
||||
@ -1010,8 +1010,8 @@ static bool32 ShouldSwitchIfBadChoiceLock(u32 battler)
|
||||
bool32 moveAffectsTarget = TRUE;
|
||||
|
||||
if (lastUsedMove != MOVE_NONE && (AI_GetMoveEffectiveness(lastUsedMove, battler, opposingBattler) == UQ_4_12(0.0)
|
||||
|| CanAbilityAbsorbMove(battler, opposingBattler, gAiLogicData->abilities[opposingBattler], lastUsedMove, GetMoveType(lastUsedMove), ABILITY_CHECK_TRIGGER)
|
||||
|| CanAbilityBlockMove(battler, opposingBattler, gAiLogicData->abilities[battler], gAiLogicData->abilities[opposingBattler], lastUsedMove, ABILITY_CHECK_TRIGGER)))
|
||||
|| CanAbilityAbsorbMove(battler, opposingBattler, gAiLogicData->abilities[opposingBattler], lastUsedMove, GetMoveType(lastUsedMove), AI_CHECK)
|
||||
|| CanAbilityBlockMove(battler, opposingBattler, gAiLogicData->abilities[battler], gAiLogicData->abilities[opposingBattler], lastUsedMove, AI_CHECK)))
|
||||
moveAffectsTarget = FALSE;
|
||||
|
||||
if (HOLD_EFFECT_CHOICE(holdEffect) && IsBattlerItemEnabled(battler))
|
||||
|
||||
@ -514,16 +514,16 @@ bool32 IsDamageMoveUnusable(struct DamageContext *ctx)
|
||||
partnerDefAbility = aiData->abilities[BATTLE_PARTNER(ctx->battlerDef)];
|
||||
}
|
||||
|
||||
if (CanAbilityBlockMove(ctx->battlerAtk, ctx->battlerDef, ctx->abilityAtk, battlerDefAbility, ctx->move, ABILITY_CHECK_TRIGGER))
|
||||
if (CanAbilityBlockMove(ctx->battlerAtk, ctx->battlerDef, ctx->abilityAtk, battlerDefAbility, ctx->move, AI_CHECK))
|
||||
return TRUE;
|
||||
|
||||
if (CanAbilityAbsorbMove(ctx->battlerAtk, ctx->battlerDef, battlerDefAbility, ctx->move, ctx->moveType, ABILITY_CHECK_TRIGGER))
|
||||
if (CanAbilityAbsorbMove(ctx->battlerAtk, ctx->battlerDef, battlerDefAbility, ctx->move, ctx->moveType, AI_CHECK))
|
||||
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(ctx->battlerAtk, BATTLE_PARTNER(ctx->battlerDef), partnerDefAbility, ctx->move, ctx->moveType, ABILITY_CHECK_TRIGGER))
|
||||
if (CanAbilityAbsorbMove(ctx->battlerAtk, BATTLE_PARTNER(ctx->battlerDef), partnerDefAbility, ctx->move, ctx->moveType, AI_CHECK))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@ -1248,7 +1248,7 @@ static void Cmd_attackcanceler(void)
|
||||
GetBattlerAbility(gBattlerAttacker),
|
||||
abilityDef,
|
||||
gCurrentMove,
|
||||
ABILITY_RUN_SCRIPT))
|
||||
RUN_SCRIPT))
|
||||
return;
|
||||
|
||||
if (GetMoveNonVolatileStatus(gCurrentMove) == MOVE_EFFECT_PARALYSIS)
|
||||
@ -1259,7 +1259,7 @@ static void Cmd_attackcanceler(void)
|
||||
abilityDef,
|
||||
gCurrentMove,
|
||||
GetBattleMoveType(gCurrentMove),
|
||||
ABILITY_RUN_SCRIPT))
|
||||
RUN_SCRIPT))
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1432,7 +1432,7 @@ static void JumpIfMoveFailed(u32 adder, u32 move, u32 moveType, const u8 *failIn
|
||||
GetBattlerAbility(gBattlerTarget),
|
||||
move,
|
||||
moveType,
|
||||
ABILITY_RUN_SCRIPT))
|
||||
RUN_SCRIPT))
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1464,211 +1464,6 @@ static bool32 JumpIfMoveAffectedByProtect(u32 move, u32 battler, u32 shouldJump,
|
||||
return affected;
|
||||
}
|
||||
|
||||
static bool32 AccuracyCalcHelper(u32 move, u32 battler)
|
||||
{
|
||||
bool32 effect = FALSE;
|
||||
u32 ability = ABILITY_NONE;
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
u32 nonVolatileStatus = GetMoveNonVolatileStatus(move);
|
||||
|
||||
if ((gStatuses3[battler] & STATUS3_ALWAYS_HITS && gDisableStructs[battler].battlerWithSureHit == gBattlerAttacker)
|
||||
|| (B_TOXIC_NEVER_MISS >= GEN_6
|
||||
&& nonVolatileStatus == MOVE_EFFECT_TOXIC
|
||||
&& IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_POISON))
|
||||
|| gStatuses4[battler] & STATUS4_GLAIVE_RUSH)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
// If the attacker has the ability No Guard and they aren't targeting a Pokemon involved in a Sky Drop with the move Sky Drop, move hits.
|
||||
else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_NO_GUARD
|
||||
&& !(gStatuses3[battler] & STATUS3_COMMANDER)
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == SKY_DROP_NO_TARGET))
|
||||
{
|
||||
effect = TRUE;
|
||||
ability = ABILITY_NO_GUARD;
|
||||
}
|
||||
// If the target has the ability No Guard and they aren't involved in a Sky Drop or the current move isn't Sky Drop, move hits.
|
||||
else if (GetBattlerAbility(battler) == ABILITY_NO_GUARD
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == SKY_DROP_NO_TARGET))
|
||||
{
|
||||
effect = TRUE;
|
||||
ability = ABILITY_NO_GUARD;
|
||||
}
|
||||
// If the target is under the effects of Telekinesis, and the move isn't a OH-KO move, move hits.
|
||||
else if (gStatuses3[battler] & STATUS3_TELEKINESIS
|
||||
&& !(gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE)
|
||||
&& moveEffect != EFFECT_OHKO
|
||||
&& moveEffect != EFFECT_SHEER_COLD)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (gBattleStruct->battlerState[battler].pursuitTarget)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !(gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE))
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if ((gStatuses3[battler] & STATUS3_COMMANDER)
|
||||
|| (gStatuses3[battler] & STATUS3_PHANTOM_FORCE)
|
||||
|| ((gStatuses3[battler] & STATUS3_ON_AIR) && !(MoveDamagesAirborne(move) || MoveDamagesAirborneDoubleDamage(move)))
|
||||
|| ((gStatuses3[battler] & STATUS3_UNDERGROUND) && !MoveDamagesUnderground(move))
|
||||
|| ((gStatuses3[battler] & STATUS3_UNDERWATER) && !MoveDamagesUnderWater(move)))
|
||||
{
|
||||
gBattleStruct->moveResultFlags[battler] |= MOVE_RESULT_MISSED;
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (B_MINIMIZE_DMG_ACC >= GEN_6
|
||||
&& (gStatuses3[battler] & STATUS3_MINIMIZED)
|
||||
&& MoveIncreasesPowerToMinimizedTargets(move))
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (GetMoveAccuracy(move) == 0)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
|
||||
if (!effect && HasWeatherEffect())
|
||||
{
|
||||
if (MoveAlwaysHitsInRain(move) && IsBattlerWeatherAffected(battler, B_WEATHER_RAIN))
|
||||
effect = TRUE;
|
||||
else if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && MoveAlwaysHitsInHailSnow(move))
|
||||
effect = TRUE;
|
||||
|
||||
if (effect)
|
||||
return effect;
|
||||
}
|
||||
|
||||
if (ability != ABILITY_NONE)
|
||||
RecordAbilityBattle(gBattlerAttacker, ABILITY_NO_GUARD);
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect)
|
||||
{
|
||||
u32 calc, moveAcc;
|
||||
s8 buff, accStage, evasionStage;
|
||||
u32 atkParam = GetBattlerHoldEffectParam(battlerAtk);
|
||||
u32 defParam = GetBattlerHoldEffectParam(battlerDef);
|
||||
u32 atkAlly = BATTLE_PARTNER(battlerAtk);
|
||||
u32 atkAllyAbility = GetBattlerAbility(atkAlly);
|
||||
|
||||
gPotentialItemEffectBattler = battlerDef;
|
||||
accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];
|
||||
evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION];
|
||||
if (atkAbility == ABILITY_UNAWARE || atkAbility == ABILITY_KEEN_EYE || atkAbility == ABILITY_MINDS_EYE
|
||||
|| (B_ILLUMINATE_EFFECT >= GEN_9 && atkAbility == ABILITY_ILLUMINATE))
|
||||
evasionStage = DEFAULT_STAT_STAGE;
|
||||
if (MoveIgnoresDefenseEvasionStages(move))
|
||||
evasionStage = DEFAULT_STAT_STAGE;
|
||||
if (defAbility == ABILITY_UNAWARE)
|
||||
accStage = DEFAULT_STAT_STAGE;
|
||||
|
||||
if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT || gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED)
|
||||
buff = accStage;
|
||||
else
|
||||
buff = accStage + DEFAULT_STAT_STAGE - evasionStage;
|
||||
|
||||
if (buff < MIN_STAT_STAGE)
|
||||
buff = MIN_STAT_STAGE;
|
||||
if (buff > MAX_STAT_STAGE)
|
||||
buff = MAX_STAT_STAGE;
|
||||
|
||||
moveAcc = GetMoveAccuracy(move);
|
||||
// Check Thunder and Hurricane on sunny weather.
|
||||
if (IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && MoveHas50AccuracyInSun(move))
|
||||
moveAcc = 50;
|
||||
// Check Wonder Skin.
|
||||
if (defAbility == ABILITY_WONDER_SKIN && IsBattleMoveStatus(move) && moveAcc > 50)
|
||||
moveAcc = 50;
|
||||
|
||||
calc = gAccuracyStageRatios[buff].dividend * moveAcc;
|
||||
calc /= gAccuracyStageRatios[buff].divisor;
|
||||
|
||||
// Attacker's ability
|
||||
switch (atkAbility)
|
||||
{
|
||||
case ABILITY_COMPOUND_EYES:
|
||||
calc = (calc * 130) / 100; // 1.3 compound eyes boost
|
||||
break;
|
||||
case ABILITY_VICTORY_STAR:
|
||||
calc = (calc * 110) / 100; // 1.1 victory star boost
|
||||
break;
|
||||
case ABILITY_HUSTLE:
|
||||
if (IsBattleMovePhysical(move))
|
||||
calc = (calc * 80) / 100; // 1.2 hustle loss
|
||||
break;
|
||||
}
|
||||
|
||||
// Target's ability
|
||||
switch (defAbility)
|
||||
{
|
||||
case ABILITY_SAND_VEIL:
|
||||
if (HasWeatherEffect() && gBattleWeather & B_WEATHER_SANDSTORM)
|
||||
calc = (calc * 80) / 100; // 1.2 sand veil loss
|
||||
break;
|
||||
case ABILITY_SNOW_CLOAK:
|
||||
if (HasWeatherEffect() && (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)))
|
||||
calc = (calc * 80) / 100; // 1.2 snow cloak loss
|
||||
break;
|
||||
case ABILITY_TANGLED_FEET:
|
||||
if (gBattleMons[battlerDef].volatiles.confusionTurns)
|
||||
calc = (calc * 50) / 100; // 1.5 tangled feet loss
|
||||
break;
|
||||
}
|
||||
|
||||
// Attacker's ally's ability
|
||||
switch (atkAllyAbility)
|
||||
{
|
||||
case ABILITY_VICTORY_STAR:
|
||||
if (IsBattlerAlive(atkAlly))
|
||||
calc = (calc * 110) / 100; // 1.1 ally's victory star boost
|
||||
break;
|
||||
}
|
||||
|
||||
// Attacker's hold effect
|
||||
switch (atkHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_WIDE_LENS:
|
||||
calc = (calc * (100 + atkParam)) / 100;
|
||||
break;
|
||||
case HOLD_EFFECT_ZOOM_LENS:
|
||||
if (GetBattlerTurnOrderNum(battlerAtk) > GetBattlerTurnOrderNum(battlerDef))
|
||||
calc = (calc * (100 + atkParam)) / 100;
|
||||
break;
|
||||
}
|
||||
|
||||
// Target's hold effect
|
||||
switch (defHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_EVASION_UP:
|
||||
calc = (calc * (100 - defParam)) / 100;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gBattleStruct->battlerState[battlerAtk].usedMicleBerry)
|
||||
{
|
||||
if (atkAbility == ABILITY_RIPEN)
|
||||
calc = (calc * 140) / 100; // ripen gives 40% acc boost
|
||||
else
|
||||
calc = (calc * 120) / 100; // 20% acc boost
|
||||
}
|
||||
|
||||
if (gFieldStatuses & STATUS_FIELD_GRAVITY)
|
||||
calc = (calc * 5) / 3; // 1.66 Gravity acc boost
|
||||
|
||||
if (B_AFFECTION_MECHANICS == TRUE && GetBattlerAffectionHearts(battlerDef) == AFFECTION_FIVE_HEARTS)
|
||||
calc = (calc * 90) / 100;
|
||||
|
||||
if (HasWeatherEffect() && gBattleWeather & B_WEATHER_FOG)
|
||||
calc = (calc * 60) / 100; // modified by 3/5
|
||||
|
||||
return calc;
|
||||
}
|
||||
|
||||
static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move)
|
||||
{
|
||||
if (move == ACC_CURR_MOVE)
|
||||
@ -1696,7 +1491,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u
|
||||
GetBattlerAbility(gBattlerTarget),
|
||||
gCurrentMove,
|
||||
GetBattleMoveType(gCurrentMove),
|
||||
ABILITY_RUN_SCRIPT);
|
||||
RUN_SCRIPT);
|
||||
}
|
||||
}
|
||||
else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT
|
||||
@ -1726,10 +1521,11 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u
|
||||
continue;
|
||||
|
||||
numTargets++;
|
||||
if (JumpIfMoveAffectedByProtect(move, battlerDef, FALSE, failInstr) || AccuracyCalcHelper(move, battlerDef))
|
||||
u32 abilityDef = GetBattlerAbility(battlerDef);
|
||||
if (JumpIfMoveAffectedByProtect(move, battlerDef, FALSE, failInstr)
|
||||
|| CanMoveSkipAccuracyCalc(gBattlerAttacker, battlerDef, abilityAtk, abilityDef, move, RUN_SCRIPT))
|
||||
continue;
|
||||
|
||||
u32 abilityDef = GetBattlerAbility(battlerDef);
|
||||
u32 holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE);
|
||||
u32 accuracy = GetTotalAccuracy(gBattlerAttacker,
|
||||
battlerDef,
|
||||
@ -3337,7 +3133,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|
||||
GetBattlerAbility(gBattlerAttacker),
|
||||
battlerAbility,
|
||||
gBattleScripting.moveEffect,
|
||||
STATUS_CHECK_TRIGGER))
|
||||
CHECK_TRIGGER))
|
||||
SetNonVolatileStatusCondition(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_MOVE);
|
||||
break;
|
||||
case MOVE_EFFECT_CONFUSION:
|
||||
@ -12548,7 +12344,7 @@ static void Cmd_trynonvolatilestatus(void)
|
||||
GetBattlerAbility(gBattlerAttacker),
|
||||
GetBattlerAbility(gBattlerTarget),
|
||||
GetMoveNonVolatileStatus(gCurrentMove),
|
||||
STATUS_RUN_SCRIPT))
|
||||
RUN_SCRIPT))
|
||||
canInflictStatus = FALSE;
|
||||
|
||||
if (canInflictStatus && DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
|
||||
@ -13008,7 +12804,7 @@ static void Cmd_checknonvolatiletrigger(void)
|
||||
GetBattlerAbility(gBattlerAttacker),
|
||||
GetBattlerAbility(gBattlerTarget),
|
||||
cmd->nonVolatile,
|
||||
STATUS_CHECK_TRIGGER))
|
||||
CHECK_TRIGGER))
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else if (DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
|
||||
@ -65,8 +65,8 @@ static void SetRandomMultiHitCounter();
|
||||
static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item);
|
||||
static bool32 CanBeInfinitelyConfused(u32 battler);
|
||||
static bool32 IsAnyTargetAffected(u32 battlerAtk);
|
||||
static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, u32 abilityDef, u32 abilityAffected, const u8 *battleScript, enum NonVolatileStatus option);
|
||||
static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum NonVolatileStatus option);
|
||||
static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, u32 abilityDef, u32 abilityAffected, const u8 *battleScript, enum FunctionCallOption option);
|
||||
static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum FunctionCallOption option);
|
||||
|
||||
ARM_FUNC NOINLINE static uq4_12_t PercentToUQ4_12(u32 percent);
|
||||
ARM_FUNC NOINLINE static uq4_12_t PercentToUQ4_12_Floored(u32 percent);
|
||||
@ -2520,13 +2520,13 @@ static enum MoveCanceller CancellerMultiTargetMoves(void)
|
||||
gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_NO_EFFECT;
|
||||
gBattleStruct->noResultString[battlerDef] = TRUE;
|
||||
}
|
||||
else if (CanAbilityBlockMove(gBattlerAttacker, battlerDef, abilityAtk, abilityDef, gCurrentMove, ABILITY_CHECK_TRIGGER)
|
||||
else if (CanAbilityBlockMove(gBattlerAttacker, battlerDef, abilityAtk, abilityDef, gCurrentMove, CHECK_TRIGGER)
|
||||
|| (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN) && GetBattleMovePriority(gBattlerAttacker, abilityAtk, gCurrentMove) > 0))
|
||||
{
|
||||
gBattleStruct->moveResultFlags[battlerDef] = 0;
|
||||
gBattleStruct->noResultString[battlerDef] = TRUE;
|
||||
}
|
||||
else if (CanAbilityAbsorbMove(gBattlerAttacker, battlerDef, abilityDef, gCurrentMove, GetBattleMoveType(gCurrentMove), ABILITY_CHECK_TRIGGER))
|
||||
else if (CanAbilityAbsorbMove(gBattlerAttacker, battlerDef, abilityDef, gCurrentMove, GetBattleMoveType(gCurrentMove), CHECK_TRIGGER))
|
||||
{
|
||||
gBattleStruct->moveResultFlags[battlerDef] = 0;
|
||||
gBattleStruct->noResultString[battlerDef] = DO_ACCURACY_CHECK;
|
||||
@ -2962,13 +2962,13 @@ static void ChooseStatBoostAnimation(u32 battler)
|
||||
#undef ANIM_STAT_ACC
|
||||
#undef ANIM_STAT_EVASION
|
||||
|
||||
bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum AbilityEffectOptions option)
|
||||
bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option)
|
||||
{
|
||||
const u8 *battleScriptBlocksMove = NULL;
|
||||
u32 battlerAbility = battlerDef;
|
||||
s32 atkPriority = 0;
|
||||
|
||||
if (option == ABILITY_CHECK_TRIGGER_AI)
|
||||
if (option == AI_CHECK)
|
||||
atkPriority = GetBattleMovePriority(battlerAtk, abilityAtk, move);
|
||||
else
|
||||
atkPriority = GetChosenMovePriority(battlerAtk, abilityAtk);
|
||||
@ -3018,7 +3018,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a
|
||||
&& BlocksPrankster(move, battlerAtk, battlerDef, TRUE)
|
||||
&& !(IsBattleMoveStatus(move) && (abilityDef == ABILITY_MAGIC_BOUNCE || gProtectStructs[battlerDef].bounceMove)))
|
||||
{
|
||||
if (option == ABILITY_RUN_SCRIPT && !IsSpreadMove(GetBattlerMoveTargetType(battlerAtk, move)))
|
||||
if (option == RUN_SCRIPT && !IsSpreadMove(GetBattlerMoveTargetType(battlerAtk, move)))
|
||||
CancelMultiTurnMoves(battlerAtk, SKY_DROP_ATTACKCANCELLER_CHECK); // Don't cancel moves that can hit two targets bc one target might not be protected
|
||||
|
||||
battleScriptBlocksMove = BattleScript_DarkTypePreventsPrankster;
|
||||
@ -3031,7 +3031,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a
|
||||
&& IsBattlerAlive(partnerDef)
|
||||
&& !IsBattlerAlly(battlerAtk, partnerDef))
|
||||
{
|
||||
if (option == ABILITY_CHECK_TRIGGER_AI)
|
||||
if (option == AI_CHECK)
|
||||
abilityDef = gAiLogicData->abilities[partnerDef];
|
||||
else
|
||||
abilityDef = GetBattlerAbility(partnerDef);
|
||||
@ -3053,7 +3053,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a
|
||||
if (battleScriptBlocksMove == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (option == ABILITY_RUN_SCRIPT)
|
||||
if (option == RUN_SCRIPT)
|
||||
{
|
||||
gMultiHitCounter = 0; // Prevent multi-hit moves from hitting more than once after move has been absorbed.
|
||||
gLastUsedAbility = abilityDef;
|
||||
@ -3065,7 +3065,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType, enum AbilityEffectOptions option)
|
||||
bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType, enum FunctionCallOption option)
|
||||
{
|
||||
enum MoveAbsorbed effect = MOVE_ABSORBED_BY_NO_ABILITY;
|
||||
const u8 *battleScript = NULL;
|
||||
@ -3139,7 +3139,7 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32
|
||||
break;
|
||||
}
|
||||
|
||||
if (effect == MOVE_ABSORBED_BY_NO_ABILITY || option != ABILITY_RUN_SCRIPT)
|
||||
if (effect == MOVE_ABSORBED_BY_NO_ABILITY || option != RUN_SCRIPT)
|
||||
return effect;
|
||||
|
||||
switch (effect)
|
||||
@ -5122,7 +5122,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
gLastUsedAbility,
|
||||
GetBattlerAbility(gBattlerAttacker),
|
||||
gBattleStruct->synchronizeMoveEffect,
|
||||
STATUS_CHECK_TRIGGER))
|
||||
CHECK_TRIGGER))
|
||||
{
|
||||
if (B_SYNCHRONIZE_TOXIC < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
|
||||
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
|
||||
@ -5152,7 +5152,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
gLastUsedAbility,
|
||||
GetBattlerAbility(gBattlerAttacker),
|
||||
gBattleStruct->synchronizeMoveEffect,
|
||||
STATUS_CHECK_TRIGGER))
|
||||
CHECK_TRIGGER))
|
||||
{
|
||||
if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
|
||||
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
|
||||
@ -5499,24 +5499,26 @@ bool32 CanBeSlept(u32 battlerAtk, u32 battlerDef, u32 abilityDef, enum SleepClau
|
||||
if (IsSleepClauseActiveForSide(GetBattlerSide(battlerDef)) && isBlockedBySleepClause)
|
||||
return FALSE;
|
||||
|
||||
if (CanSetNonVolatileStatus(battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_SLEEP, // also covers yawn
|
||||
STATUS_CHECK_TRIGGER))
|
||||
if (CanSetNonVolatileStatus(
|
||||
battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_SLEEP, // also covers yawn
|
||||
CHECK_TRIGGER))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef)
|
||||
{
|
||||
if (CanSetNonVolatileStatus(battlerAtk,
|
||||
battlerDef,
|
||||
abilityAtk,
|
||||
abilityDef,
|
||||
MOVE_EFFECT_TOXIC, // also covers poison
|
||||
STATUS_CHECK_TRIGGER))
|
||||
if (CanSetNonVolatileStatus(
|
||||
battlerAtk,
|
||||
battlerDef,
|
||||
abilityAtk,
|
||||
abilityDef,
|
||||
MOVE_EFFECT_TOXIC, // also covers poison
|
||||
CHECK_TRIGGER))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@ -5524,36 +5526,39 @@ bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 ability
|
||||
// TODO: check order of battlerAtk and battlerDef
|
||||
bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, u32 abilityDef)
|
||||
{
|
||||
if (CanSetNonVolatileStatus(battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_BURN,
|
||||
STATUS_CHECK_TRIGGER))
|
||||
if (CanSetNonVolatileStatus(
|
||||
battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_BURN,
|
||||
CHECK_TRIGGER))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, u32 abilityDef)
|
||||
{
|
||||
if (CanSetNonVolatileStatus(battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_PARALYSIS,
|
||||
STATUS_CHECK_TRIGGER))
|
||||
if (CanSetNonVolatileStatus(
|
||||
battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_PARALYSIS,
|
||||
CHECK_TRIGGER))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, u32 abilityDef)
|
||||
{
|
||||
if (CanSetNonVolatileStatus(battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_FREEZE,
|
||||
STATUS_CHECK_TRIGGER))
|
||||
if (CanSetNonVolatileStatus(
|
||||
battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_FREEZE,
|
||||
CHECK_TRIGGER))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@ -5561,17 +5566,18 @@ bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, u32 abilityDef)
|
||||
// Unused, technically also redundant
|
||||
bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef)
|
||||
{
|
||||
if (CanSetNonVolatileStatus(battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_FREEZE_OR_FROSTBITE, // also covers frostbite
|
||||
STATUS_CHECK_TRIGGER))
|
||||
if (CanSetNonVolatileStatus(
|
||||
battlerAtk,
|
||||
battlerDef,
|
||||
ABILITY_NONE, // attacker ability does not matter
|
||||
abilityDef,
|
||||
MOVE_EFFECT_FREEZE_OR_FROSTBITE, // also covers frostbite
|
||||
CHECK_TRIGGER))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffects effect, enum NonVolatileStatus option)
|
||||
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffects effect, enum FunctionCallOption option)
|
||||
{
|
||||
const u8 *battleScript = NULL;
|
||||
u32 sideBattler = ABILITY_NONE;
|
||||
@ -5614,7 +5620,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
|
||||
else if (option == RUN_SCRIPT // Check only important during battle execution for moves
|
||||
&& CalcTypeEffectivenessMultiplierHelper(gCurrentMove, GetBattleMoveType(gCurrentMove), battlerAtk, battlerDef, abilityDef, TRUE)
|
||||
&& gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT)
|
||||
{
|
||||
@ -5741,11 +5747,11 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, u32 abilityDef, u32 abilityAffected, const u8 *battleScript, enum NonVolatileStatus option)
|
||||
static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, u32 abilityDef, u32 abilityAffected, const u8 *battleScript, enum FunctionCallOption option)
|
||||
{
|
||||
if (battleScript != NULL)
|
||||
{
|
||||
if (option == STATUS_RUN_SCRIPT)
|
||||
if (option == RUN_SCRIPT)
|
||||
{
|
||||
if (battleScript != BattleScript_NotAffected)
|
||||
gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_FAILED;
|
||||
@ -5766,17 +5772,17 @@ static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, u32 abilityDef, u32 abi
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum NonVolatileStatus option)
|
||||
static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum FunctionCallOption option)
|
||||
{
|
||||
// Can freely sleep own partner
|
||||
if (IsDoubleBattle() && IsSleepClauseEnabled() && IsBattlerAlly(battlerAtk, battlerDef))
|
||||
{
|
||||
if (option == STATUS_RUN_SCRIPT)
|
||||
if (option == RUN_SCRIPT)
|
||||
gBattleStruct->battlerState[battlerDef].sleepClauseEffectExempt = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (option == STATUS_RUN_SCRIPT)
|
||||
if (option == RUN_SCRIPT)
|
||||
gBattleStruct->battlerState[battlerDef].sleepClauseEffectExempt = FALSE;
|
||||
// Can't sleep if clause is active otherwise
|
||||
if (IsSleepClauseActiveForSide(GetBattlerSide(battlerDef)))
|
||||
@ -9767,7 +9773,7 @@ uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType)
|
||||
MulByTypeEffectiveness(&ctx, &modifier, type2);
|
||||
|
||||
if ((modifier <= UQ_4_12(1.0) && abilityDef == ABILITY_WONDER_GUARD)
|
||||
|| CanAbilityAbsorbMove(0, 0, abilityDef, MOVE_NONE, moveType, ABILITY_CHECK_TRIGGER))
|
||||
|| CanAbilityAbsorbMove(0, 0, abilityDef, MOVE_NONE, moveType, CHECK_TRIGGER))
|
||||
modifier = UQ_4_12(0.0);
|
||||
|
||||
return modifier;
|
||||
@ -11158,8 +11164,8 @@ static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerD
|
||||
{
|
||||
u32 abilityDef = GetBattlerAbility(battlerDef);
|
||||
|
||||
return CanAbilityBlockMove(battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), abilityDef, gCurrentMove, ABILITY_CHECK_TRIGGER)
|
||||
|| CanAbilityAbsorbMove(battlerAtk, battlerDef, abilityDef, gCurrentMove, moveType, ABILITY_CHECK_TRIGGER);
|
||||
return CanAbilityBlockMove(battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), abilityDef, gCurrentMove, CHECK_TRIGGER)
|
||||
|| CanAbilityAbsorbMove(battlerAtk, battlerDef, abilityDef, gCurrentMove, moveType, CHECK_TRIGGER);
|
||||
}
|
||||
|
||||
bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef)
|
||||
@ -11329,11 +11335,11 @@ void UpdateStallMons(void)
|
||||
u32 moveType = GetBattleMoveType(gCurrentMove); // Probably doesn't handle dynamic move types right now
|
||||
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
|
||||
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
|
||||
if (CanAbilityAbsorbMove(gBattlerAttacker, gBattlerTarget, abilityDef, gCurrentMove, moveType, ABILITY_CHECK_TRIGGER))
|
||||
if (CanAbilityAbsorbMove(gBattlerAttacker, gBattlerTarget, abilityDef, gCurrentMove, moveType, CHECK_TRIGGER))
|
||||
{
|
||||
gAiBattleData->playerStallMons[gBattlerPartyIndexes[gBattlerTarget]]++;
|
||||
}
|
||||
else if (CanAbilityBlockMove(gBattlerAttacker, gBattlerTarget, abilityAtk, abilityDef, gCurrentMove, ABILITY_CHECK_TRIGGER))
|
||||
else if (CanAbilityBlockMove(gBattlerAttacker, gBattlerTarget, abilityAtk, abilityDef, gCurrentMove, CHECK_TRIGGER))
|
||||
{
|
||||
gAiBattleData->playerStallMons[gBattlerPartyIndexes[gBattlerTarget]]++;
|
||||
}
|
||||
@ -11521,3 +11527,212 @@ void RemoveHazardFromField(u32 side, enum Hazards hazardType)
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option)
|
||||
{
|
||||
bool32 effect = FALSE;
|
||||
u32 ability = ABILITY_NONE;
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
u32 nonVolatileStatus = GetMoveNonVolatileStatus(move);
|
||||
|
||||
if ((gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS && gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk)
|
||||
|| (B_TOXIC_NEVER_MISS >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|
||||
|| gStatuses4[battlerDef] & STATUS4_GLAIVE_RUSH)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
// If the attacker has the ability No Guard and they aren't targeting a Pokemon involved in a Sky Drop with the move Sky Drop, move hits.
|
||||
else if (abilityAtk == ABILITY_NO_GUARD
|
||||
&& !(gStatuses3[battlerDef] & STATUS3_COMMANDER)
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battlerDef] == SKY_DROP_NO_TARGET))
|
||||
{
|
||||
effect = TRUE;
|
||||
ability = ABILITY_NO_GUARD;
|
||||
}
|
||||
// If the target has the ability No Guard and they aren't involved in a Sky Drop or the current move isn't Sky Drop, move hits.
|
||||
else if (abilityDef == ABILITY_NO_GUARD
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battlerDef] == SKY_DROP_NO_TARGET))
|
||||
{
|
||||
effect = TRUE;
|
||||
ability = ABILITY_NO_GUARD;
|
||||
}
|
||||
// If the target is under the effects of Telekinesis, and the move isn't a OH-KO move, move hits.
|
||||
else if (gStatuses3[battlerDef] & STATUS3_TELEKINESIS
|
||||
&& !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)
|
||||
&& moveEffect != EFFECT_OHKO
|
||||
&& moveEffect != EFFECT_SHEER_COLD)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (gBattleStruct->battlerState[battlerDef].pursuitTarget)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (GetActiveGimmick(battlerAtk) == GIMMICK_Z_MOVE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE))
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if ((gStatuses3[battlerDef] & STATUS3_COMMANDER)
|
||||
|| (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE)
|
||||
|| ((gStatuses3[battlerDef] & STATUS3_ON_AIR) && !(MoveDamagesAirborne(move) || MoveDamagesAirborneDoubleDamage(move)))
|
||||
|| ((gStatuses3[battlerDef] & STATUS3_UNDERGROUND) && !MoveDamagesUnderground(move))
|
||||
|| ((gStatuses3[battlerDef] & STATUS3_UNDERWATER) && !MoveDamagesUnderWater(move)))
|
||||
{
|
||||
if (option == RUN_SCRIPT)
|
||||
{
|
||||
gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_MISSED;
|
||||
effect = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
effect = FALSE;
|
||||
}
|
||||
}
|
||||
else if (B_MINIMIZE_DMG_ACC >= GEN_6
|
||||
&& (gStatuses3[battlerDef] & STATUS3_MINIMIZED)
|
||||
&& MoveIncreasesPowerToMinimizedTargets(move))
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (GetMoveAccuracy(move) == 0)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
|
||||
if (!effect && HasWeatherEffect())
|
||||
{
|
||||
if (MoveAlwaysHitsInRain(move) && IsBattlerWeatherAffected(battlerDef, B_WEATHER_RAIN))
|
||||
effect = TRUE;
|
||||
else if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && MoveAlwaysHitsInHailSnow(move))
|
||||
effect = TRUE;
|
||||
|
||||
if (effect)
|
||||
return effect;
|
||||
}
|
||||
|
||||
if (ability != ABILITY_NONE && option == RUN_SCRIPT)
|
||||
RecordAbilityBattle(battlerAtk, ABILITY_NO_GUARD);
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect)
|
||||
{
|
||||
u32 calc, moveAcc;
|
||||
s8 buff, accStage, evasionStage;
|
||||
u32 atkParam = GetBattlerHoldEffectParam(battlerAtk);
|
||||
u32 defParam = GetBattlerHoldEffectParam(battlerDef);
|
||||
|
||||
gPotentialItemEffectBattler = battlerDef;
|
||||
accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];
|
||||
evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION];
|
||||
if (atkAbility == ABILITY_UNAWARE || atkAbility == ABILITY_KEEN_EYE || atkAbility == ABILITY_MINDS_EYE
|
||||
|| (B_ILLUMINATE_EFFECT >= GEN_9 && atkAbility == ABILITY_ILLUMINATE))
|
||||
evasionStage = DEFAULT_STAT_STAGE;
|
||||
if (MoveIgnoresDefenseEvasionStages(move))
|
||||
evasionStage = DEFAULT_STAT_STAGE;
|
||||
if (defAbility == ABILITY_UNAWARE)
|
||||
accStage = DEFAULT_STAT_STAGE;
|
||||
|
||||
if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT || gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED)
|
||||
buff = accStage;
|
||||
else
|
||||
buff = accStage + DEFAULT_STAT_STAGE - evasionStage;
|
||||
|
||||
if (buff < MIN_STAT_STAGE)
|
||||
buff = MIN_STAT_STAGE;
|
||||
if (buff > MAX_STAT_STAGE)
|
||||
buff = MAX_STAT_STAGE;
|
||||
|
||||
moveAcc = GetMoveAccuracy(move);
|
||||
// Check Thunder and Hurricane on sunny weather.
|
||||
if (IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && MoveHas50AccuracyInSun(move))
|
||||
moveAcc = 50;
|
||||
// Check Wonder Skin.
|
||||
if (defAbility == ABILITY_WONDER_SKIN && IsBattleMoveStatus(move) && moveAcc > 50)
|
||||
moveAcc = 50;
|
||||
|
||||
calc = gAccuracyStageRatios[buff].dividend * moveAcc;
|
||||
calc /= gAccuracyStageRatios[buff].divisor;
|
||||
|
||||
// Attacker's ability
|
||||
switch (atkAbility)
|
||||
{
|
||||
case ABILITY_COMPOUND_EYES:
|
||||
calc = (calc * 130) / 100; // 1.3 compound eyes boost
|
||||
break;
|
||||
case ABILITY_VICTORY_STAR:
|
||||
calc = (calc * 110) / 100; // 1.1 victory star boost
|
||||
break;
|
||||
case ABILITY_HUSTLE:
|
||||
if (IsBattleMovePhysical(move))
|
||||
calc = (calc * 80) / 100; // 1.2 hustle loss
|
||||
break;
|
||||
}
|
||||
|
||||
// Target's ability
|
||||
switch (defAbility)
|
||||
{
|
||||
case ABILITY_SAND_VEIL:
|
||||
if (HasWeatherEffect() && gBattleWeather & B_WEATHER_SANDSTORM)
|
||||
calc = (calc * 80) / 100; // 1.2 sand veil loss
|
||||
break;
|
||||
case ABILITY_SNOW_CLOAK:
|
||||
if (HasWeatherEffect() && (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)))
|
||||
calc = (calc * 80) / 100; // 1.2 snow cloak loss
|
||||
break;
|
||||
case ABILITY_TANGLED_FEET:
|
||||
if (gBattleMons[battlerDef].volatiles.confusionTurns)
|
||||
calc = (calc * 50) / 100; // 1.5 tangled feet loss
|
||||
break;
|
||||
}
|
||||
|
||||
// Attacker's ally's ability
|
||||
u32 atkAlly = BATTLE_PARTNER(battlerAtk);
|
||||
switch (GetBattlerAbility(atkAlly))
|
||||
{
|
||||
case ABILITY_VICTORY_STAR:
|
||||
if (IsBattlerAlive(atkAlly))
|
||||
calc = (calc * 110) / 100; // 1.1 ally's victory star boost
|
||||
break;
|
||||
}
|
||||
|
||||
// Attacker's hold effect
|
||||
switch (atkHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_WIDE_LENS:
|
||||
calc = (calc * (100 + atkParam)) / 100;
|
||||
break;
|
||||
case HOLD_EFFECT_ZOOM_LENS:
|
||||
if (GetBattlerTurnOrderNum(battlerAtk) > GetBattlerTurnOrderNum(battlerDef))
|
||||
calc = (calc * (100 + atkParam)) / 100;
|
||||
break;
|
||||
}
|
||||
|
||||
// Target's hold effect
|
||||
switch (defHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_EVASION_UP:
|
||||
calc = (calc * (100 - defParam)) / 100;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gBattleStruct->battlerState[battlerAtk].usedMicleBerry)
|
||||
{
|
||||
if (atkAbility == ABILITY_RIPEN)
|
||||
calc = (calc * 140) / 100; // ripen gives 40% acc boost
|
||||
else
|
||||
calc = (calc * 120) / 100; // 20% acc boost
|
||||
}
|
||||
|
||||
if (gFieldStatuses & STATUS_FIELD_GRAVITY)
|
||||
calc = (calc * 5) / 3; // 1.66 Gravity acc boost
|
||||
|
||||
if (B_AFFECTION_MECHANICS == TRUE && GetBattlerAffectionHearts(battlerDef) == AFFECTION_FIVE_HEARTS)
|
||||
calc = (calc * 90) / 100;
|
||||
|
||||
if (HasWeatherEffect() && gBattleWeather & B_WEATHER_FOG)
|
||||
calc = (calc * 60) / 100; // modified by 3/5
|
||||
|
||||
return calc;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user