mirror of
https://github.com/pret/pokefirered.git
synced 2026-05-11 22:45:18 -05:00
updated Cmd_accuracycheck
This commit is contained in:
parent
a1b3e83aac
commit
bb55f18b33
|
|
@ -1441,7 +1441,7 @@ BattleScript_EffectMeanLook::
|
|||
attackcanceler
|
||||
attackstring
|
||||
ppreduce
|
||||
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC
|
||||
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
|
||||
jumpifstatus2 BS_TARGET, STATUS2_ESCAPE_PREVENTION, BattleScript_ButItFailed
|
||||
jumpifstatus2 BS_TARGET, STATUS2_SUBSTITUTE, BattleScript_ButItFailed
|
||||
attackanimation
|
||||
|
|
|
|||
|
|
@ -585,6 +585,8 @@ struct BattleStruct
|
|||
u8 supremeOverlordCounter[MAX_BATTLERS_COUNT];
|
||||
struct Illusion illusion[MAX_BATTLERS_COUNT];
|
||||
u8 trainerSlideFirstSTABMoveMsgState:2;
|
||||
u8 blunderPolicy:1; // should blunder policy activate
|
||||
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
||||
}; // size == 0x200 bytes
|
||||
|
||||
extern struct BattleStruct *gBattleStruct;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@
|
|||
#define WINDOW_CLEAR (1 << 0)
|
||||
#define WINDOW_BG1 (1 << 7)
|
||||
|
||||
struct StatFractions
|
||||
{
|
||||
u8 dividend;
|
||||
u8 divisor;
|
||||
};
|
||||
|
||||
void AI_CalcDmg(u8 attacker, u8 defender);
|
||||
u8 TypeCalc(u16 move, u8 attacker, u8 defender);
|
||||
u8 AI_TypeCalc(u16 move, u16 targetSpecies, u16 targetAbility);
|
||||
|
|
@ -21,7 +27,9 @@ bool8 UproarWakeUpCheck(u8 battlerId);
|
|||
u8 GetCatchingBattler(void);
|
||||
bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler);
|
||||
u32 GetHighestStatId(u32 battlerId);
|
||||
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
|
||||
|
||||
extern void (* const gBattleScriptingCommandsTable[])(void);
|
||||
extern const struct StatFractions gAccuracyStageRatios[];
|
||||
|
||||
#endif // GUARD_BATTLE_SCRIPT_COMMANDS_H
|
||||
|
|
|
|||
|
|
@ -133,13 +133,15 @@ void HandleAction_RunBattleScript(void);
|
|||
u8 GetMoveTarget(u16 move, u8 setTarget);
|
||||
u8 IsMonDisobedient(void);
|
||||
// new
|
||||
bool32 IsNeutralizingGasOnField(void);
|
||||
bool32 IsMyceliumMightOnField(void);
|
||||
bool32 IsMoldBreakerTypeAbility(u32 ability);
|
||||
u32 GetBattlerAbility(u32 battler);
|
||||
u32 IsAbilityOnSide(u32 battler, u32 ability);
|
||||
u32 IsAbilityOnOpposingSide(u32 battler, u32 ability);
|
||||
u32 IsAbilityOnField(u32 ability);
|
||||
u32 IsAbilityOnFieldExcept(u32 battler, u32 ability);
|
||||
u32 IsAbilityPreventingEscape(u32 battler);
|
||||
u32 GetBattlerHoldEffect(u32 battler, bool32 checkNegating);
|
||||
bool32 IsBattlerAlive(u32 battler);
|
||||
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind);
|
||||
u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect);
|
||||
|
|
@ -175,6 +177,10 @@ u32 GetIllusionMonSpecies(u32 battler);
|
|||
struct Pokemon *GetIllusionMonPtr(u32 battler);
|
||||
void ClearIllusionMon(u32 battler);
|
||||
bool32 SetIllusionMon(struct Pokemon *mon, u32 battler);
|
||||
u32 GetBattlerAffectionHearts(u32 battler);
|
||||
u32 GetBattlerHoldEffect(u32 battler, bool32 checkNegating);
|
||||
u32 GetBattlerHoldEffectIgnoreAbility(u32 battler, bool32 checkNegating);
|
||||
u32 GetBattlerHoldEffectInternal(u32 battler, bool32 checkNegating, bool32 checkAbility);
|
||||
|
||||
// battle_ai_util.h
|
||||
bool32 IsHealingMove(u32 move);
|
||||
|
|
|
|||
|
|
@ -136,11 +136,16 @@
|
|||
#define FRIENDSHIP_EVENT_FAINT_OUTSIDE_BATTLE 8
|
||||
#define FRIENDSHIP_EVENT_FAINT_LARGE 9
|
||||
|
||||
#if P_UPDATED_FRIENDSHIP >= GEN_8
|
||||
#define STANDARD_FRIENDSHIP 50
|
||||
#else
|
||||
#define STANDARD_FRIENDSHIP 70
|
||||
#endif
|
||||
// Constants for GetBattlerAffectionHearts (based on friendship value)
|
||||
#define AFFECTION_NO_HEARTS 0 // 0-79 friendship
|
||||
#define AFFECTION_ONE_HEART 1 // 80-129 friendship
|
||||
#define AFFECTION_TWO_HEARTS 2 // 130-179 friendship
|
||||
#define AFFECTION_THREE_HEARTS 3 // 180-219 friendship
|
||||
#define AFFECTION_FOUR_HEARTS 4 // 220-254 friendship
|
||||
#define AFFECTION_FIVE_HEARTS 5 // Max friendship
|
||||
|
||||
// Friendship value that the majority of species use.
|
||||
#define STANDARD_FRIENDSHIP ((P_UPDATED_FRIENDSHIP >= GEN_8) ? 50 : 70)
|
||||
|
||||
#define MAX_FRIENDSHIP 255
|
||||
#define MAX_SHEEN 255
|
||||
|
|
|
|||
|
|
@ -657,7 +657,7 @@ void SetBattleMonMoveSlot(struct BattlePokemon *mon, u16 move, u8 slot);
|
|||
u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove);
|
||||
void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move);
|
||||
s32 CalculateBaseDamageOld(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u32 sideStatus, u16 powerOverride, u8 typeOverride, u8 battlerIdAtk, u8 battlerIdDef);
|
||||
|
||||
u32 GetMonAffectionHearts(struct Pokemon *pokemon);
|
||||
u8 CountAliveMonsInBattle(u8 caseId, u32 battler);
|
||||
|
||||
u8 GetDefaultMoveTarget(u8 battlerId);
|
||||
|
|
|
|||
|
|
@ -604,13 +604,7 @@ void (* const gBattleScriptingCommandsTable[])(void) =
|
|||
Cmd_callnative, //0xFF
|
||||
};
|
||||
|
||||
struct StatFractions
|
||||
{
|
||||
u8 dividend;
|
||||
u8 divisor;
|
||||
};
|
||||
|
||||
static const struct StatFractions sAccuracyStageRatios[] =
|
||||
const struct StatFractions gAccuracyStageRatios[] =
|
||||
{
|
||||
{ 33, 100}, // -6
|
||||
{ 36, 100}, // -5
|
||||
|
|
@ -1156,22 +1150,23 @@ static void Cmd_attackcanceler(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void JumpIfMoveFailed(u8 adder, u16 move)
|
||||
static bool32 JumpIfMoveFailed(u8 adder, u16 move)
|
||||
{
|
||||
const u8 *BS_ptr = gBattlescriptCurrInstr + adder;
|
||||
if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
||||
{
|
||||
gLastLandedMoves[gBattlerTarget] = 0;
|
||||
gLastHitByType[gBattlerTarget] = 0;
|
||||
BS_ptr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
||||
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
TrySetDestinyBondToHappen();
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBattlerTarget, 0, 0, move))
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
gBattlescriptCurrInstr = BS_ptr;
|
||||
gBattlescriptCurrInstr += adder;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void Cmd_jumpifaffectedbyprotect(void)
|
||||
|
|
@ -1191,7 +1186,7 @@ static void Cmd_jumpifaffectedbyprotect(void)
|
|||
static bool8 JumpIfMoveAffectedByProtect(u16 move)
|
||||
{
|
||||
bool8 affected = FALSE;
|
||||
if (DEFENDER_IS_PROTECTED)
|
||||
if (IsBattlerProtected(gBattlerTarget, move))
|
||||
{
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
JumpIfMoveFailed(7, move);
|
||||
|
|
@ -1201,43 +1196,81 @@ static bool8 JumpIfMoveAffectedByProtect(u16 move)
|
|||
return affected;
|
||||
}
|
||||
|
||||
static bool8 AccuracyCalcHelper(u16 move)
|
||||
static bool32 AccuracyCalcHelper(u16 move)
|
||||
{
|
||||
if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
|
||||
if ((gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
|
||||
|| (B_TOXIC_NEVER_MISS >= GEN_6 && gMovesInfo[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_POISON))
|
||||
|| gStatuses4[gBattlerTarget] & STATUS4_GLAIVE_RUSH)
|
||||
{
|
||||
JumpIfMoveFailed(7, move);
|
||||
return 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 && (move != MOVE_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF))
|
||||
{
|
||||
if (!JumpIfMoveFailed(7, move))
|
||||
RecordAbilityBattle(gBattlerAttacker, ABILITY_NO_GUARD);
|
||||
return TRUE;
|
||||
}
|
||||
// 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(gBattlerTarget) == ABILITY_NO_GUARD && (move != MOVE_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF))
|
||||
{
|
||||
if (!JumpIfMoveFailed(7, move))
|
||||
RecordAbilityBattle(gBattlerTarget, ABILITY_NO_GUARD);
|
||||
return TRUE;
|
||||
}
|
||||
// If the target is under the effects of Telekinesis, and the move isn't a OH-KO move, move hits.
|
||||
else if (gStatuses3[gBattlerTarget] & STATUS3_TELEKINESIS
|
||||
&& !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE)
|
||||
&& gMovesInfo[move].effect != EFFECT_OHKO)
|
||||
{
|
||||
JumpIfMoveFailed(7, move);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!(gHitMarker & HITMARKER_IGNORE_ON_AIR) && gStatuses3[gBattlerTarget] & STATUS3_ON_AIR)
|
||||
// TODO: Z-Moves
|
||||
// if (gBattleStruct->zmove.active && !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE))
|
||||
// {
|
||||
// JumpIfMoveFailed(7, move);
|
||||
// return TRUE;
|
||||
// }
|
||||
|
||||
if ((gStatuses3[gBattlerTarget] & STATUS3_PHANTOM_FORCE)
|
||||
|| ((gStatuses3[gBattlerTarget] & STATUS3_ON_AIR) && !(gMovesInfo[move].damagesAirborne || gMovesInfo[move].damagesAirborneDoubleDamage))
|
||||
|| ((gStatuses3[gBattlerTarget] & STATUS3_UNDERGROUND) && !gMovesInfo[move].damagesUnderground)
|
||||
|| ((gStatuses3[gBattlerTarget] & STATUS3_UNDERWATER) && !gMovesInfo[move].damagesUnderwater))
|
||||
{
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
JumpIfMoveFailed(7, move);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gHitMarker &= ~HITMARKER_IGNORE_ON_AIR;
|
||||
|
||||
if (!(gHitMarker & HITMARKER_IGNORE_UNDERGROUND) && gStatuses3[gBattlerTarget] & STATUS3_UNDERGROUND)
|
||||
if (WEATHER_HAS_EFFECT)
|
||||
{
|
||||
if ((gMovesInfo[move].effect == EFFECT_THUNDER || gMovesInfo[move].effect == EFFECT_RAIN_ALWAYS_HIT)
|
||||
&& IsBattlerWeatherAffected(gBattlerTarget, B_WEATHER_RAIN))
|
||||
{
|
||||
// thunder/hurricane/genie moves ignore acc checks in rain unless target is holding utility umbrella
|
||||
JumpIfMoveFailed(7, move);
|
||||
return TRUE;
|
||||
}
|
||||
else if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && gMovesInfo[move].effect == EFFECT_BLIZZARD)
|
||||
{
|
||||
// Blizzard ignores acc checks in Hail in Gen4+
|
||||
JumpIfMoveFailed(7, move);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (B_MINIMIZE_DMG_ACC >= GEN_6
|
||||
&& (gStatuses3[gBattlerTarget] & STATUS3_MINIMIZED)
|
||||
&& gMovesInfo[move].minimizeDoubleDamage)
|
||||
{
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
JumpIfMoveFailed(7, move);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gHitMarker &= ~HITMARKER_IGNORE_UNDERGROUND;
|
||||
|
||||
if (!(gHitMarker & HITMARKER_IGNORE_UNDERWATER) && gStatuses3[gBattlerTarget] & STATUS3_UNDERWATER)
|
||||
{
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
JumpIfMoveFailed(7, move);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gHitMarker &= ~HITMARKER_IGNORE_UNDERWATER;
|
||||
|
||||
if ((WEATHER_HAS_EFFECT && (gBattleWeather & B_WEATHER_RAIN) && gMovesInfo[move].effect == EFFECT_THUNDER)
|
||||
|| (gMovesInfo[move].effect == EFFECT_ALWAYS_HIT || gMovesInfo[move].effect == EFFECT_VITAL_THROW))
|
||||
if (gMovesInfo[move].accuracy == 0)
|
||||
{
|
||||
JumpIfMoveFailed(7, move);
|
||||
return TRUE;
|
||||
|
|
@ -1246,10 +1279,137 @@ static bool8 AccuracyCalcHelper(u16 move)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
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 (gMovesInfo[move].ignoresTargetDefenseEvasionStages)
|
||||
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 = gMovesInfo[move].accuracy;
|
||||
// Check Thunder and Hurricane on sunny weather.
|
||||
if (IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && gMovesInfo[move].effect == EFFECT_THUNDER)
|
||||
moveAcc = 50;
|
||||
// Check Wonder Skin.
|
||||
if (defAbility == ABILITY_WONDER_SKIN && IS_MOVE_STATUS(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 (IS_MOVE_PHYSICAL(move))
|
||||
calc = (calc * 80) / 100; // 1.2 hustle loss
|
||||
break;
|
||||
}
|
||||
|
||||
// Target's ability
|
||||
switch (defAbility)
|
||||
{
|
||||
case ABILITY_SAND_VEIL:
|
||||
if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM)
|
||||
calc = (calc * 80) / 100; // 1.2 sand veil loss
|
||||
break;
|
||||
case ABILITY_SNOW_CLOAK:
|
||||
if (WEATHER_HAS_EFFECT && (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)))
|
||||
calc = (calc * 80) / 100; // 1.2 snow cloak loss
|
||||
break;
|
||||
case ABILITY_TANGLED_FEET:
|
||||
if (gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
|
||||
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 (gProtectStructs[battlerAtk].usedMicleBerry)
|
||||
{
|
||||
gProtectStructs[battlerAtk].usedMicleBerry = FALSE;
|
||||
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;
|
||||
|
||||
return calc;
|
||||
}
|
||||
|
||||
static void Cmd_accuracycheck(void)
|
||||
{
|
||||
u16 move = T2_READ_16(gBattlescriptCurrInstr + 5);
|
||||
CMD_ARGS(const u8 *failInstr, u16 move);
|
||||
|
||||
u32 type, move = cmd->move;
|
||||
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move);
|
||||
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
|
||||
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
|
||||
u32 holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
|
||||
|
||||
// pokefirered specific
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE
|
||||
&& !BtlCtrl_OakOldMan_TestState2Flag(1)
|
||||
&& gMovesInfo[move].power != 0
|
||||
|
|
@ -1263,89 +1423,61 @@ static void Cmd_accuracycheck(void)
|
|||
JumpIfMoveFailed(7, move);
|
||||
return;
|
||||
}
|
||||
if (move == NO_ACC_CALC || move == NO_ACC_CALC_CHECK_LOCK_ON)
|
||||
|
||||
if (move == ACC_CURR_MOVE)
|
||||
move = gCurrentMove;
|
||||
|
||||
if (move == NO_ACC_CALC_CHECK_LOCK_ON)
|
||||
{
|
||||
if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && move == NO_ACC_CALC_CHECK_LOCK_ON && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
|
||||
gBattlescriptCurrInstr += 7;
|
||||
else if (gStatuses3[gBattlerTarget] & (STATUS3_ON_AIR | STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
|
||||
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
||||
else if (!JumpIfMoveAffectedByProtect(0))
|
||||
gBattlescriptCurrInstr += 7;
|
||||
if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
else if (gStatuses3[gBattlerTarget] & (STATUS3_SEMI_INVULNERABLE))
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else if (!JumpIfMoveAffectedByProtect(gCurrentMove))
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT
|
||||
|| (gSpecialStatuses[gBattlerAttacker].multiHitOn
|
||||
&& (abilityAtk == ABILITY_SKILL_LINK || holdEffectAtk == HOLD_EFFECT_LOADED_DICE
|
||||
|| !(gMovesInfo[move].effect == EFFECT_TRIPLE_KICK || gMovesInfo[move].effect == EFFECT_POPULATION_BOMB))))
|
||||
{
|
||||
// No acc checks for second hit of Parental Bond or multi hit moves, except Triple Kick/Triple Axel/Population Bomb
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 type, moveAcc, holdEffect, param;
|
||||
s8 buff;
|
||||
u16 calc;
|
||||
|
||||
if (move == ACC_CURR_MOVE)
|
||||
move = gCurrentMove;
|
||||
u32 accuracy;
|
||||
|
||||
GET_MOVE_TYPE(move, type);
|
||||
|
||||
if (JumpIfMoveAffectedByProtect(move))
|
||||
return;
|
||||
if (AccuracyCalcHelper(move))
|
||||
return;
|
||||
|
||||
if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT)
|
||||
{
|
||||
u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_ACC];
|
||||
buff = acc;
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_ACC];
|
||||
buff = acc + DEFAULT_STAT_STAGE - gBattleMons[gBattlerTarget].statStages[STAT_EVASION];
|
||||
}
|
||||
accuracy = GetTotalAccuracy(
|
||||
gBattlerAttacker,
|
||||
gBattlerTarget,
|
||||
move,
|
||||
abilityAtk,
|
||||
abilityDef,
|
||||
holdEffectAtk,
|
||||
GetBattlerHoldEffect(gBattlerTarget, TRUE)
|
||||
);
|
||||
|
||||
if (buff < MIN_STAT_STAGE)
|
||||
buff = MIN_STAT_STAGE;
|
||||
if (buff > MAX_STAT_STAGE)
|
||||
buff = MAX_STAT_STAGE;
|
||||
|
||||
moveAcc = gMovesInfo[move].accuracy;
|
||||
// check Thunder on sunny weather
|
||||
if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SUN && gMovesInfo[move].effect == EFFECT_THUNDER)
|
||||
moveAcc = 50;
|
||||
|
||||
calc = sAccuracyStageRatios[buff].dividend * moveAcc;
|
||||
calc /= sAccuracyStageRatios[buff].divisor;
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].ability == ABILITY_COMPOUND_EYES)
|
||||
calc = (calc * 130) / 100; // 1.3 compound eyes boost
|
||||
if (WEATHER_HAS_EFFECT && gBattleMons[gBattlerTarget].ability == ABILITY_SAND_VEIL && gBattleWeather & B_WEATHER_SANDSTORM)
|
||||
calc = (calc * 80) / 100; // 1.2 sand veil loss
|
||||
if (gBattleMons[gBattlerAttacker].ability == ABILITY_HUSTLE && IS_TYPE_PHYSICAL(type))
|
||||
calc = (calc * 80) / 100; // 1.2 hustle loss
|
||||
|
||||
if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY)
|
||||
{
|
||||
holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect;
|
||||
param = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
||||
}
|
||||
else
|
||||
{
|
||||
holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item);
|
||||
param = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item);
|
||||
}
|
||||
|
||||
gPotentialItemEffectBattler = gBattlerTarget;
|
||||
|
||||
if (holdEffect == HOLD_EFFECT_EVASION_UP)
|
||||
calc = (calc * (100 - param)) / 100;
|
||||
|
||||
// final calculation
|
||||
if ((Random() % 100 + 1) > calc)
|
||||
if (!RandomPercentage(RNG_ACCURACY, accuracy))
|
||||
{
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
||||
&& (gMovesInfo[move].target == MOVE_TARGET_BOTH || gMovesInfo[move].target == MOVE_TARGET_FOES_AND_ALLY))
|
||||
if (holdEffectAtk == HOLD_EFFECT_BLUNDER_POLICY)
|
||||
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
|
||||
(moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY))
|
||||
gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_ATK;
|
||||
else
|
||||
gBattleCommunication[MISS_TYPE] = B_MSG_MISSED;
|
||||
|
||||
CheckWonderGuardAndLevitate();
|
||||
if (gMovesInfo[move].power)
|
||||
CalcTypeEffectivenessMultiplier(move, type, gBattlerAttacker, gBattlerTarget, abilityDef, TRUE);
|
||||
}
|
||||
JumpIfMoveFailed(7, move);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3566,44 +3566,90 @@ static bool32 IsBattlerModernFatefulEncounter(u8 battlerId)
|
|||
return GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_MODERN_FATEFUL_ENCOUNTER, NULL);
|
||||
}
|
||||
|
||||
bool32 IsNeutralizingGasOnField(void)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (IsBattlerAlive(i) && gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gStatuses3[i] & STATUS3_GASTRO_ACID))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsMyceliumMightOnField(void)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (IsBattlerAlive(i) && gBattleMons[i].ability == ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gCurrentMove))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsMoldBreakerTypeAbility(u32 ability)
|
||||
{
|
||||
return (ability == ABILITY_MOLD_BREAKER || ability == ABILITY_TERAVOLT || ability == ABILITY_TURBOBLAZE);
|
||||
}
|
||||
|
||||
u32 GetBattlerAbility(u32 battler)
|
||||
{
|
||||
// if (gStatuses3[battler] & STATUS3_GASTRO_ACID)
|
||||
// return ABILITY_NONE;
|
||||
if (gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed)
|
||||
return gBattleMons[battler].ability;
|
||||
|
||||
// if (IsNeutralizingGasOnField() && !IsNeutralizingGasBannedAbility(gBattleMons[battler].ability))
|
||||
// return ABILITY_NONE;
|
||||
if (gStatuses3[battler] & STATUS3_GASTRO_ACID)
|
||||
return ABILITY_NONE;
|
||||
|
||||
// if (IsMyceliumMightOnField())
|
||||
// return ABILITY_NONE;
|
||||
if (IsNeutralizingGasOnField()
|
||||
&& gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS
|
||||
&& GetBattlerHoldEffectIgnoreAbility(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD)
|
||||
return ABILITY_NONE;
|
||||
|
||||
// if (((IsMoldBreakerTypeAbility(gBattleMons[gBattlerAttacker].ability)
|
||||
// && !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID))
|
||||
// || gBattleMoves[gCurrentMove].ignoresTargetAbility)
|
||||
// && sAbilitiesAffectedByMoldBreaker[gBattleMons[battler].ability]
|
||||
// && gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker
|
||||
// && gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE
|
||||
// && gCurrentTurnActionNumber < gBattlersCount)
|
||||
// return ABILITY_NONE;
|
||||
if (IsMyceliumMightOnField())
|
||||
return ABILITY_NONE;
|
||||
|
||||
if (((IsMoldBreakerTypeAbility(gBattleMons[gBattlerAttacker].ability)
|
||||
&& !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID))
|
||||
|| gMovesInfo[gCurrentMove].ignoresTargetAbility)
|
||||
&& gAbilitiesInfo[gBattleMons[battler].ability].breakable
|
||||
&& gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker
|
||||
&& gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE
|
||||
&& gCurrentTurnActionNumber < gBattlersCount)
|
||||
return ABILITY_NONE;
|
||||
|
||||
return gBattleMons[battler].ability;
|
||||
}
|
||||
|
||||
u32 GetBattlerHoldEffect(u32 battler, bool32 checkNegating)
|
||||
{
|
||||
return GetBattlerHoldEffectInternal(battler, checkNegating, TRUE);
|
||||
}
|
||||
|
||||
u32 GetBattlerHoldEffectIgnoreAbility(u32 battler, bool32 checkNegating)
|
||||
{
|
||||
return GetBattlerHoldEffectInternal(battler, checkNegating, FALSE);
|
||||
}
|
||||
|
||||
u32 GetBattlerHoldEffectInternal(u32 battler, bool32 checkNegating, bool32 checkAbility)
|
||||
{
|
||||
if (checkNegating)
|
||||
{
|
||||
// if (gStatuses3[battler] & STATUS3_EMBARGO)
|
||||
// return HOLD_EFFECT_NONE;
|
||||
// if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM)
|
||||
// return HOLD_EFFECT_NONE;
|
||||
if (GetBattlerAbility(battler) == ABILITY_KLUTZ)
|
||||
if (gStatuses3[battler] & STATUS3_EMBARGO)
|
||||
return HOLD_EFFECT_NONE;
|
||||
if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM)
|
||||
return HOLD_EFFECT_NONE;
|
||||
if (checkAbility && GetBattlerAbility(battler) == ABILITY_KLUTZ)
|
||||
return HOLD_EFFECT_NONE;
|
||||
}
|
||||
|
||||
gPotentialItemEffectBattler = battler;
|
||||
|
||||
if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY)
|
||||
if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER)
|
||||
return gEnigmaBerries[battler].holdEffect;
|
||||
else
|
||||
return ItemId_GetHoldEffect(gBattleMons[battler].item);
|
||||
|
|
@ -6116,6 +6162,23 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battler)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
u32 GetBattlerAffectionHearts(u32 battler)
|
||||
{
|
||||
u8 side = GetBattlerSide(battler);
|
||||
struct Pokemon *party = GetSideParty(side);
|
||||
u16 species = GetMonData(&party[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES);
|
||||
|
||||
if (side != B_SIDE_PLAYER)
|
||||
return AFFECTION_NO_HEARTS;
|
||||
else if (gSpeciesInfo[species].isMegaEvolution
|
||||
|| (gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_BATTLE_TOWER
|
||||
| BATTLE_TYPE_LINK)))
|
||||
return AFFECTION_NO_HEARTS;
|
||||
|
||||
return GetMonAffectionHearts(&party[gBattlerPartyIndexes[battler]]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// battle_ai_util.c
|
||||
|
|
|
|||
|
|
@ -6166,3 +6166,21 @@ u16 GetFormSpeciesId(u16 speciesId, u8 formId)
|
|||
else
|
||||
return speciesId;
|
||||
}
|
||||
|
||||
u32 GetMonAffectionHearts(struct Pokemon *pokemon)
|
||||
{
|
||||
u32 friendship = GetMonData(pokemon, MON_DATA_FRIENDSHIP, NULL);
|
||||
|
||||
if (friendship == MAX_FRIENDSHIP)
|
||||
return AFFECTION_FIVE_HEARTS;
|
||||
if (friendship >= 220)
|
||||
return AFFECTION_FOUR_HEARTS;
|
||||
if (friendship >= 180)
|
||||
return AFFECTION_THREE_HEARTS;
|
||||
if (friendship >= 130)
|
||||
return AFFECTION_TWO_HEARTS;
|
||||
if (friendship >= 80)
|
||||
return AFFECTION_ONE_HEART;
|
||||
|
||||
return AFFECTION_NO_HEARTS;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user