AI handling for similar utility moves (#7513)
This commit is contained in:
parent
90601792b9
commit
fda783b394
@ -168,14 +168,15 @@ bool32 HasMove(u32 battlerId, u32 move);
|
||||
bool32 HasOnlyMovesWithCategory(u32 battlerId, enum DamageCategory category, bool32 onlyOffensive);
|
||||
bool32 HasMoveWithCategory(u32 battler, enum DamageCategory category);
|
||||
bool32 HasMoveWithType(u32 battler, u32 type);
|
||||
bool32 HasMoveWithEffect(u32 battlerId, enum BattleMoveEffects moveEffect);
|
||||
bool32 HasMoveWithEffect(u32 battler, enum BattleMoveEffects moveEffect);
|
||||
bool32 HasMoveWithAIEffect(u32 battler, u32 aiEffect);
|
||||
bool32 HasBattlerSideMoveWithEffect(u32 battler, u32 effect);
|
||||
bool32 HasBattlerSideMoveWithAIEffect(u32 battler, u32 effect);
|
||||
bool32 HasBattlerSideUsedMoveWithEffect(u32 battler, u32 effect);
|
||||
bool32 HasNonVolatileMoveEffect(u32 battlerId, u32 effect);
|
||||
bool32 IsPowerBasedOnStatus(u32 battlerId, enum BattleMoveEffects effect, u32 argument);
|
||||
bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect);
|
||||
bool32 HasBattlerSideMoveWithAdditionalEffect(u32 battler, u32 moveEffect);
|
||||
bool32 HasBattlerSideUsedMoveWithAdditionalEffect(u32 battler, u32 moveEffect);
|
||||
bool32 HasMoveWithCriticalHitChance(u32 battlerId);
|
||||
bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, enum BattleMoveEffects exception);
|
||||
bool32 HasMoveThatLowersOwnStats(u32 battlerId);
|
||||
@ -252,11 +253,9 @@ bool32 HasTwoOpponents(u32 battler);
|
||||
bool32 HasPartner(u32 battler);
|
||||
bool32 HasPartnerIgnoreFlags(u32 battler);
|
||||
// HasPartner respects the Attacks Partner AI flag; HasPartnerIgnoreFlags checks only if a live pokemon is adjacent.
|
||||
bool32 AreMovesEquivalent(u32 battlerAtk, u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
|
||||
bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove);
|
||||
bool32 IsMoveEffectWeather(u32 move);
|
||||
bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove);
|
||||
bool32 PartnerMoveEffectIs(u32 battlerAtkPartner, u32 partnerMove, enum BattleMoveEffects effectCheck);
|
||||
bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck);
|
||||
bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
|
||||
@ -301,4 +300,22 @@ bool32 HasBattlerSideAbility(u32 battlerDef, u32 ability, struct AiLogicData *ai
|
||||
u32 GetThinkingBattler(u32 battler);
|
||||
bool32 IsNaturalEnemy(u32 speciesAttacker, u32 speciesTarget);
|
||||
|
||||
// These are for the purpose of not doubling up on moves during double battles.
|
||||
// Used in GetAIEffectGroup for move effects and GetAIEffectGroupFromMove for additional effects
|
||||
#define AI_EFFECT_NONE 0
|
||||
#define AI_EFFECT_WEATHER (1 << 0)
|
||||
#define AI_EFFECT_TERRAIN (1 << 1)
|
||||
#define AI_EFFECT_CLEAR_HAZARDS (1 << 2)
|
||||
#define AI_EFFECT_BREAK_SCREENS (1 << 3)
|
||||
#define AI_EFFECT_RESET_STATS (1 << 4)
|
||||
#define AI_EFFECT_FORCE_SWITCH (1 << 5)
|
||||
#define AI_EFFECT_TORMENT (1 << 6)
|
||||
#define AI_EFFECT_LIGHT_SCREEN (1 << 7)
|
||||
#define AI_EFFECT_REFLECT (1 << 8)
|
||||
#define AI_EFFECT_GRAVITY (1 << 9)
|
||||
#define AI_EFFECT_CHANGE_ABILITY (1 << 10)
|
||||
|
||||
// As Aurora Veil should almost never be used alongside the other screens, we save the bit.
|
||||
#define AI_EFFECT_AURORA_VEIL (AI_EFFECT_LIGHT_SCREEN | AI_EFFECT_REFLECT)
|
||||
|
||||
#endif //GUARD_BATTLE_AI_UTIL_H
|
||||
|
||||
@ -375,14 +375,15 @@ static enum FieldEffectOutcome BenefitsFromMistyTerrain(u32 battler)
|
||||
|
||||
// harass dragons
|
||||
if ((grounded || allyGrounded)
|
||||
&& (HasDamagingMoveOfType(FOE(battler), TYPE_DRAGON) || HasDamagingMoveOfType(BATTLE_PARTNER(FOE(battler)), TYPE_DRAGON)))
|
||||
&& (HasDamagingMoveOfType(FOE(battler), TYPE_DRAGON) || HasDamagingMoveOfType(BATTLE_PARTNER(FOE(battler)), TYPE_DRAGON)))
|
||||
return FIELD_EFFECT_POSITIVE;
|
||||
|
||||
if ((grounded || allyGrounded) && HasBattlerSideUsedMoveWithAdditionalEffect(FOE(battler), MOVE_EFFECT_SLEEP))
|
||||
if ((grounded || allyGrounded)
|
||||
&& (HasNonVolatileMoveEffect(FOE(battler), MOVE_EFFECT_SLEEP) || HasNonVolatileMoveEffect(BATTLE_PARTNER(FOE(battler)), MOVE_EFFECT_SLEEP)))
|
||||
return FIELD_EFFECT_POSITIVE;
|
||||
|
||||
if (grounded && ((gBattleMons[battler].status1 & STATUS1_SLEEP)
|
||||
|| (gStatuses3[battler] & STATUS3_YAWN)))
|
||||
|| (gStatuses3[battler] & STATUS3_YAWN)))
|
||||
return FIELD_EFFECT_POSITIVE;
|
||||
|
||||
return FIELD_EFFECT_NEUTRAL;
|
||||
|
||||
@ -1648,7 +1648,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
// other
|
||||
case EFFECT_HAZE:
|
||||
if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
{
|
||||
ADJUST_SCORE(-10); // partner already using haze
|
||||
}
|
||||
@ -1707,19 +1707,19 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-1); // may still want to just poison
|
||||
//fallthrough
|
||||
case EFFECT_LIGHT_SCREEN:
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_LIGHTSCREEN
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL)
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_REFLECT:
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_REFLECT
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_REFLECT | SIDE_STATUS_AURORA_VEIL)
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_AURORA_VEIL:
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)
|
||||
|| !(weather & (B_WEATHER_ICY_ANY)))
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
|| !(weather & (B_WEATHER_ICY_ANY)))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_SHEER_COLD:
|
||||
@ -1734,7 +1734,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_MIST:
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_FOCUS_ENERGY:
|
||||
@ -1742,19 +1742,14 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_NON_VOLATILE_STATUS:
|
||||
if (GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_FOES_AND_ALLY
|
||||
&& PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_CONFUSE:
|
||||
if (GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_FOES_AND_ALLY
|
||||
&& PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
case EFFECT_SWAGGER:
|
||||
case EFFECT_FLATTER:
|
||||
if (!AI_CanConfuse(battlerAtk, battlerDef, aiData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)
|
||||
|| !AI_CanConfuse(battlerAtk, battlerDef, aiData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_SUBSTITUTE:
|
||||
@ -1788,7 +1783,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
else if (gDisableStructs[battlerDef].disableTimer == 0
|
||||
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
|
||||
&& !PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
&& !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
{
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMove, CONSIDER_PRIORITY)) // Attacker should go first
|
||||
{
|
||||
@ -1884,7 +1879,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_STICKY_WEB:
|
||||
if (IsHazardOnSide(GetBattlerSide(battlerDef), HAZARDS_STICKY_WEB))
|
||||
ADJUST_SCORE(-10);
|
||||
if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10); // only one mon needs to set up Sticky Web
|
||||
break;
|
||||
case EFFECT_FORESIGHT:
|
||||
@ -1912,7 +1907,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
ADJUST_SCORE(-10); //Both enemies are perish songed
|
||||
}
|
||||
else if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
else if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
{
|
||||
ADJUST_SCORE(-10);
|
||||
}
|
||||
@ -1929,23 +1924,23 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_SANDSTORM:
|
||||
if (weather & (B_WEATHER_SANDSTORM | B_WEATHER_PRIMAL_ANY)
|
||||
|| (HasPartner(battlerAtk) && IsMoveEffectWeather(aiData->partnerMove)))
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-8);
|
||||
break;
|
||||
case EFFECT_SUNNY_DAY:
|
||||
if (weather & (B_WEATHER_SUN | B_WEATHER_PRIMAL_ANY)
|
||||
|| (HasPartner(battlerAtk) && IsMoveEffectWeather(aiData->partnerMove)))
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-8);
|
||||
break;
|
||||
case EFFECT_RAIN_DANCE:
|
||||
if (weather & (B_WEATHER_RAIN | B_WEATHER_PRIMAL_ANY)
|
||||
|| (HasPartner(battlerAtk) && IsMoveEffectWeather(aiData->partnerMove)))
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-8);
|
||||
break;
|
||||
case EFFECT_HAIL:
|
||||
case EFFECT_SNOWSCAPE:
|
||||
if (weather & (B_WEATHER_ICY_ANY | B_WEATHER_PRIMAL_ANY)
|
||||
|| (HasPartner(battlerAtk) && IsMoveEffectWeather(aiData->partnerMove)))
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-8);
|
||||
break;
|
||||
case EFFECT_ATTRACT:
|
||||
@ -1954,7 +1949,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_SAFEGUARD:
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_MAGNITUDE:
|
||||
@ -1980,7 +1975,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_CHILLY_RECEPTION:
|
||||
if (CountUsablePartyMons(battlerAtk) == 0)
|
||||
ADJUST_SCORE(-10);
|
||||
else if (weather & (B_WEATHER_ICY_ANY | B_WEATHER_PRIMAL_ANY) || IsMoveEffectWeather(aiData->partnerMove))
|
||||
else if (weather & (B_WEATHER_ICY_ANY | B_WEATHER_PRIMAL_ANY)
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-8);
|
||||
break;
|
||||
case EFFECT_BELLY_DRUM:
|
||||
@ -2046,7 +2042,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_FOLLOW_ME:
|
||||
case EFFECT_HELPING_HAND:
|
||||
if (!hasPartner
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)
|
||||
|| (aiData->partnerMove != MOVE_NONE && IsBattleMoveStatus(aiData->partnerMove))
|
||||
|| gBattleStruct->monToSwitchIntoId[BATTLE_PARTNER(battlerAtk)] != PARTY_SIZE) //Partner is switching out.
|
||||
ADJUST_SCORE(-10);
|
||||
@ -2096,13 +2092,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_MUD_SPORT:
|
||||
if (gFieldStatuses & STATUS_FIELD_MUDSPORT
|
||||
|| gBattleMons[battlerAtk].volatiles.mudSport
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_WATER_SPORT:
|
||||
if (gFieldStatuses & STATUS_FIELD_WATERSPORT
|
||||
|| gBattleMons[battlerAtk].volatiles.waterSport
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_ABSORB:
|
||||
@ -2239,7 +2235,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_HEAL_BELL:
|
||||
if (!AnyPartyMemberStatused(battlerAtk, IsSoundMove(move)) || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (!AnyPartyMemberStatused(battlerAtk, IsSoundMove(move)) || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_ENDURE:
|
||||
@ -2336,7 +2332,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)
|
||||
|| AreAnyHazardsOnSide(GetBattlerSide(battlerAtk)))
|
||||
{
|
||||
if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
{
|
||||
ADJUST_SCORE(-10); //Only need one hazards removal
|
||||
break;
|
||||
@ -2440,12 +2436,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_SIMPLE_BEAM:
|
||||
case EFFECT_SKILL_SWAP:
|
||||
case EFFECT_WORRY_SEED:
|
||||
if (!CanEffectChangeAbility(battlerAtk, battlerDef, moveEffect, aiData))
|
||||
if (!CanEffectChangeAbility(battlerAtk, battlerDef, moveEffect, aiData)
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_AND_RETURN_SCORE(NO_DAMAGE_OR_FAILS);
|
||||
break;
|
||||
case EFFECT_SNATCH:
|
||||
if (!HasMoveWithFlag(battlerDef, MoveCanBeSnatched)
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_POWER_TRICK:
|
||||
@ -2542,23 +2539,28 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_GRASSY_TERRAIN:
|
||||
if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) || gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN)
|
||||
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_ELECTRIC_TERRAIN:
|
||||
if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) || gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
|
||||
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_PSYCHIC_TERRAIN:
|
||||
if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) || gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN)
|
||||
if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_MISTY_TERRAIN:
|
||||
if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), aiData->partnerMove) || gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)
|
||||
if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_STEEL_ROLLER:
|
||||
if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY))
|
||||
if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)
|
||||
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_PLEDGE:
|
||||
@ -2888,7 +2890,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_COURT_CHANGE:
|
||||
case EFFECT_TEATIME:
|
||||
if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_PLACEHOLDER:
|
||||
@ -3009,6 +3011,10 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
// check what effect partner is using
|
||||
if (aiData->partnerMove != 0 && hasPartner)
|
||||
{
|
||||
// This catches weather, terrain, screens, etc
|
||||
if (AreMovesEquivalent(battlerAtk, battlerAtkPartner, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
|
||||
switch (partnerEffect)
|
||||
{
|
||||
case EFFECT_HELPING_HAND:
|
||||
@ -3022,16 +3028,6 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(WEAK_EFFECT);
|
||||
}
|
||||
break;
|
||||
// Don't change weather if ally already decided to do so.
|
||||
case EFFECT_SUNNY_DAY:
|
||||
case EFFECT_HAIL:
|
||||
case EFFECT_SNOWSCAPE:
|
||||
case EFFECT_RAIN_DANCE:
|
||||
case EFFECT_SANDSTORM:
|
||||
case EFFECT_CHILLY_RECEPTION:
|
||||
if (IsMoveEffectWeather(move))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_AFTER_YOU:
|
||||
if (effect == EFFECT_TRICK_ROOM && !(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
@ -4110,7 +4106,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
break;
|
||||
case EFFECT_HAZE:
|
||||
if (AnyStatIsRaised(BATTLE_PARTNER(battlerAtk))
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
break;
|
||||
score += AI_TryToClearStats(battlerAtk, battlerDef, moveTargetsBothOpponents);
|
||||
break;
|
||||
@ -5243,6 +5239,7 @@ case EFFECT_GUARD_SPLIT:
|
||||
if ((AreAnyHazardsOnSide(GetBattlerSide(battlerAtk)) && CountUsablePartyMons(battlerAtk) != 0)
|
||||
|| (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].volatiles.wrapped))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_SPECTRAL_THIEF:
|
||||
ADJUST_SCORE(AI_ShouldCopyStatChanges(battlerAtk, battlerDef));
|
||||
break;
|
||||
|
||||
@ -24,6 +24,9 @@
|
||||
#include "constants/moves.h"
|
||||
#include "constants/items.h"
|
||||
|
||||
static u32 GetAIEffectGroup(enum BattleMoveEffects effect);
|
||||
static u32 GetAIEffectGroupFromMove(u32 battler, u32 move);
|
||||
|
||||
// Functions
|
||||
static bool32 AI_IsDoubleSpreadMove(u32 battlerAtk, u32 move)
|
||||
{
|
||||
@ -2222,21 +2225,37 @@ bool32 HasMoveWithType(u32 battler, u32 type)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasMoveWithEffect(u32 battlerId, enum BattleMoveEffects effect)
|
||||
bool32 HasMoveWithEffect(u32 battler, enum BattleMoveEffects effect)
|
||||
{
|
||||
s32 i;
|
||||
u16 *moves = GetMovesArray(battlerId);
|
||||
u16 *moves = GetMovesArray(battler);
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE
|
||||
&& GetMoveEffect(moves[i]) == effect)
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetMoveEffect(moves[i]) == effect)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasMoveWithAIEffect(u32 battler, u32 aiEffect)
|
||||
{
|
||||
s32 i;
|
||||
u16 *moves = GetMovesArray(battler);
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE)
|
||||
{
|
||||
if (GetAIEffectGroupFromMove(battler, moves[i]) & aiEffect)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasBattlerSideMoveWithEffect(u32 battler, u32 effect)
|
||||
{
|
||||
if (HasMoveWithEffect(battler, effect))
|
||||
@ -2246,18 +2265,44 @@ bool32 HasBattlerSideMoveWithEffect(u32 battler, u32 effect)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasBattlerSideMoveWithAIEffect(u32 battler, u32 aiEffect)
|
||||
{
|
||||
if (HasMoveWithAIEffect(battler, aiEffect))
|
||||
return TRUE;
|
||||
if (HasPartnerIgnoreFlags(battler) && HasMoveWithAIEffect(BATTLE_PARTNER(battler), aiEffect))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// HasBattlerSideMoveWithEffect checks if the AI knows a side has a move effect,
|
||||
// while HasBattlerSideUsedMoveWithEffect checks if the side has ever used a move effect.
|
||||
// The former acts the same way as the latter if AI_FLAG_OMNISCIENT isn't used.
|
||||
// while HasBattlerSideUsedMoveWithEffect checks if the side has actively USED the move effect.
|
||||
// It matches both on move effect and on AI move effect; eg, EFFECT_HAZE will also bring up Freezy Frost or Clear Smog, anything with AI_EFFECT_RESET_STATS.
|
||||
bool32 HasBattlerSideUsedMoveWithEffect(u32 battler, u32 effect)
|
||||
{
|
||||
u32 aiEffect = GetAIEffectGroup(effect);
|
||||
u32 i;
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (GetMoveEffect(gBattleHistory->usedMoves[battler][i]) == effect)
|
||||
return TRUE;
|
||||
if (HasPartnerIgnoreFlags(battler) && GetMoveEffect(gBattleHistory->usedMoves[BATTLE_PARTNER(battler)][i]) == effect)
|
||||
return TRUE;
|
||||
|
||||
if (aiEffect != AI_EFFECT_NONE)
|
||||
{
|
||||
if (GetAIEffectGroupFromMove(battler, gBattleHistory->usedMoves[battler][i]) & aiEffect)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (HasPartnerIgnoreFlags(battler))
|
||||
{
|
||||
if (GetMoveEffect(gBattleHistory->usedMoves[BATTLE_PARTNER(battler)][i]) == effect)
|
||||
return TRUE;
|
||||
|
||||
if (aiEffect != AI_EFFECT_NONE)
|
||||
{
|
||||
if (GetAIEffectGroupFromMove(battler, gBattleHistory->usedMoves[BATTLE_PARTNER(battler)][i]) & aiEffect)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@ -2316,22 +2361,6 @@ bool32 HasBattlerSideMoveWithAdditionalEffect(u32 battler, u32 moveEffect)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// HasBattlerSideMoveWithAdditionalEffect checks if the AI knows a side has a move effect,
|
||||
// while HasBattlerSideUsedMoveWithAdditionalEffect checks if the side has ever used a move effect.
|
||||
// The former acts the same way as the latter if AI_FLAG_OMNISCIENT isn't used.
|
||||
bool32 HasBattlerSideUsedMoveWithAdditionalEffect(u32 battler, u32 moveEffect)
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (MoveHasAdditionalEffect(gBattleHistory->usedMoves[battler][i], moveEffect))
|
||||
return TRUE;
|
||||
if (HasPartnerIgnoreFlags(battler) && MoveHasAdditionalEffect(gBattleHistory->usedMoves[BATTLE_PARTNER(battler)][i], moveEffect))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasMoveWithCriticalHitChance(u32 battlerId)
|
||||
{
|
||||
s32 i;
|
||||
@ -3732,8 +3761,7 @@ bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects mo
|
||||
u32 atkSide = GetBattlerSide(battlerAtk);
|
||||
|
||||
// Don't waste a turn if screens will be broken
|
||||
if (HasMoveWithEffect(battlerDef, EFFECT_BRICK_BREAK)
|
||||
|| HasMoveWithEffect(battlerDef, EFFECT_RAGING_BULL))
|
||||
if (HasMoveWithAIEffect(battlerDef, AI_EFFECT_BREAK_SCREENS))
|
||||
return FALSE;
|
||||
|
||||
switch (moveEffect)
|
||||
@ -3747,13 +3775,13 @@ bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects mo
|
||||
case EFFECT_REFLECT:
|
||||
// Use only if the player has a physical move and AI doesn't already have Reflect itself active.
|
||||
if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)
|
||||
&& !(gSideStatuses[atkSide] & SIDE_STATUS_REFLECT))
|
||||
&& !(gSideStatuses[atkSide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_AURORA_VEIL)))
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_LIGHT_SCREEN:
|
||||
// Use only if the player has a special move and AI doesn't already have Light Screen itself active.
|
||||
if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)
|
||||
&& !(gSideStatuses[atkSide] & SIDE_STATUS_LIGHTSCREEN))
|
||||
&& !(gSideStatuses[atkSide] & (SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL)))
|
||||
return TRUE;
|
||||
break;
|
||||
default:
|
||||
@ -3821,33 +3849,178 @@ u32 GetAllyChosenMove(u32 battlerId)
|
||||
return gBattleMons[partnerBattler].moves[gBattleStruct->chosenMovePositions[partnerBattler]];
|
||||
}
|
||||
|
||||
//PARTNER_MOVE_EFFECT_IS_SAME
|
||||
bool32 AreMovesEquivalent(u32 battlerAtk, u32 battlerAtkPartner, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!IsBattlerAlive(battlerAtkPartner) || partnerMove == MOVE_NONE)
|
||||
return FALSE;
|
||||
|
||||
u32 battlerDef = gBattleStruct->moveTarget[battlerAtk];
|
||||
|
||||
// We don't care the effect is basically the same; we would use this move anyway.
|
||||
if (GetBestDmgMoveFromBattler(battlerAtk, battlerDef, AI_ATTACKING) == move)
|
||||
return FALSE;
|
||||
|
||||
u32 atkEffect = GetAIEffectGroupFromMove(battlerAtk, move);
|
||||
u32 partnerEffect = GetAIEffectGroupFromMove(battlerAtkPartner, partnerMove);
|
||||
|
||||
// shared bits indicate they're meaningfully the same in some way
|
||||
if (atkEffect & partnerEffect)
|
||||
{
|
||||
if (gMovesInfo[move].target == MOVE_TARGET_SELECTED && gMovesInfo[partnerMove].target == MOVE_TARGET_SELECTED)
|
||||
{
|
||||
if (battlerDef == gBattleStruct->moveTarget[battlerAtkPartner])
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static u32 GetAIEffectGroup(enum BattleMoveEffects effect)
|
||||
{
|
||||
u32 aiEffect = AI_EFFECT_NONE;
|
||||
|
||||
switch (effect)
|
||||
{
|
||||
case EFFECT_SUNNY_DAY:
|
||||
case EFFECT_RAIN_DANCE:
|
||||
case EFFECT_SANDSTORM:
|
||||
case EFFECT_HAIL:
|
||||
case EFFECT_SNOWSCAPE:
|
||||
case EFFECT_CHILLY_RECEPTION:
|
||||
aiEffect |= AI_EFFECT_WEATHER;
|
||||
break;
|
||||
case EFFECT_ELECTRIC_TERRAIN:
|
||||
case EFFECT_GRASSY_TERRAIN:
|
||||
case EFFECT_MISTY_TERRAIN:
|
||||
case EFFECT_PSYCHIC_TERRAIN:
|
||||
case EFFECT_STEEL_ROLLER:
|
||||
case EFFECT_ICE_SPINNER:
|
||||
aiEffect |= AI_EFFECT_TERRAIN;
|
||||
break;
|
||||
case EFFECT_COURT_CHANGE:
|
||||
aiEffect |= AI_EFFECT_CLEAR_HAZARDS | AI_EFFECT_AURORA_VEIL | AI_EFFECT_BREAK_SCREENS;
|
||||
break;
|
||||
case EFFECT_DEFOG:
|
||||
aiEffect |= AI_EFFECT_CLEAR_HAZARDS | AI_EFFECT_BREAK_SCREENS;
|
||||
break;
|
||||
case EFFECT_RAPID_SPIN:
|
||||
case EFFECT_TIDY_UP:
|
||||
aiEffect |= AI_EFFECT_CLEAR_HAZARDS;
|
||||
break;
|
||||
case EFFECT_BRICK_BREAK:
|
||||
case EFFECT_RAGING_BULL:
|
||||
aiEffect |= AI_EFFECT_BREAK_SCREENS;
|
||||
break;
|
||||
case EFFECT_HAZE:
|
||||
aiEffect |= AI_EFFECT_RESET_STATS;
|
||||
break;
|
||||
case EFFECT_HIT_SWITCH_TARGET:
|
||||
case EFFECT_ROAR:
|
||||
aiEffect |= AI_EFFECT_FORCE_SWITCH;
|
||||
break;
|
||||
case EFFECT_TORMENT:
|
||||
aiEffect |= AI_EFFECT_TORMENT;
|
||||
break;
|
||||
case EFFECT_AURORA_VEIL:
|
||||
aiEffect |= AI_EFFECT_AURORA_VEIL;
|
||||
break;
|
||||
case EFFECT_LIGHT_SCREEN:
|
||||
aiEffect |= AI_EFFECT_LIGHT_SCREEN;
|
||||
break;
|
||||
case EFFECT_REFLECT:
|
||||
aiEffect |= AI_EFFECT_REFLECT;
|
||||
break;
|
||||
case EFFECT_GRAVITY:
|
||||
aiEffect |= AI_EFFECT_GRAVITY;
|
||||
break;
|
||||
case EFFECT_DOODLE:
|
||||
case EFFECT_ENTRAINMENT:
|
||||
case EFFECT_GASTRO_ACID:
|
||||
case EFFECT_ROLE_PLAY:
|
||||
case EFFECT_SIMPLE_BEAM:
|
||||
case EFFECT_SKILL_SWAP:
|
||||
case EFFECT_WORRY_SEED:
|
||||
aiEffect |= AI_EFFECT_CHANGE_ABILITY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return aiEffect;
|
||||
}
|
||||
|
||||
static u32 GetAIEffectGroupFromMove(u32 battler, u32 move)
|
||||
{
|
||||
u32 aiEffect = GetAIEffectGroup(GetMoveEffect(move));
|
||||
|
||||
u32 i;
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
|
||||
for (i = 0; i < additionalEffectCount; i++)
|
||||
{
|
||||
switch (GetMoveAdditionalEffectById(move, i)->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_SUN:
|
||||
case MOVE_EFFECT_RAIN:
|
||||
case MOVE_EFFECT_SANDSTORM:
|
||||
case MOVE_EFFECT_HAIL:
|
||||
aiEffect |= AI_EFFECT_WEATHER;
|
||||
break;
|
||||
case MOVE_EFFECT_ELECTRIC_TERRAIN:
|
||||
case MOVE_EFFECT_GRASSY_TERRAIN:
|
||||
case MOVE_EFFECT_MISTY_TERRAIN:
|
||||
case MOVE_EFFECT_PSYCHIC_TERRAIN:
|
||||
aiEffect |= AI_EFFECT_TERRAIN;
|
||||
break;
|
||||
case MOVE_EFFECT_DEFOG:
|
||||
aiEffect |= AI_EFFECT_CLEAR_HAZARDS | AI_EFFECT_BREAK_SCREENS;
|
||||
break;
|
||||
case MOVE_EFFECT_CLEAR_SMOG:
|
||||
case MOVE_EFFECT_HAZE:
|
||||
aiEffect |= AI_EFFECT_RESET_STATS;
|
||||
break;
|
||||
case MOVE_EFFECT_TORMENT_SIDE:
|
||||
aiEffect |= AI_EFFECT_TORMENT;
|
||||
break;
|
||||
case MOVE_EFFECT_LIGHT_SCREEN:
|
||||
aiEffect |= AI_EFFECT_LIGHT_SCREEN;
|
||||
break;
|
||||
case MOVE_EFFECT_REFLECT:
|
||||
aiEffect |= AI_EFFECT_REFLECT;
|
||||
break;
|
||||
case MOVE_EFFECT_AURORA_VEIL:
|
||||
aiEffect |= AI_EFFECT_AURORA_VEIL;
|
||||
break;
|
||||
case MOVE_EFFECT_GRAVITY:
|
||||
aiEffect |= AI_EFFECT_GRAVITY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return aiEffect;
|
||||
}
|
||||
|
||||
// It matches both on move effect and on AI move effect; eg, EFFECT_HAZE will also bring up Freezy Frost or Clear Smog, anything with AI_EFFECT_RESET_STATS.
|
||||
bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!HasPartner(battlerAtkPartner))
|
||||
return FALSE;
|
||||
|
||||
if (GetMoveEffect(move) == GetMoveEffect(partnerMove)
|
||||
&& partnerMove != MOVE_NONE
|
||||
&& gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef)
|
||||
&& partnerMove != MOVE_NONE)
|
||||
{
|
||||
if (gMovesInfo[move].target == MOVE_TARGET_SELECTED && gMovesInfo[partnerMove].target == MOVE_TARGET_SELECTED)
|
||||
{
|
||||
return gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//PARTNER_MOVE_EFFECT_IS_SAME_NO_TARGET
|
||||
bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!HasPartner(battlerAtkPartner))
|
||||
return FALSE;
|
||||
|
||||
if (GetMoveEffect(move) == GetMoveEffect(partnerMove)
|
||||
&& partnerMove != MOVE_NONE)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//PARTNER_MOVE_EFFECT_IS_STATUS_SAME_TARGET
|
||||
bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove)
|
||||
{
|
||||
@ -3868,37 +4041,6 @@ bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsMoveEffectWeather(u32 move)
|
||||
{
|
||||
enum BattleMoveEffects effect = GetMoveEffect(move);
|
||||
if (move != MOVE_NONE
|
||||
&& (effect == EFFECT_SUNNY_DAY
|
||||
|| effect == EFFECT_RAIN_DANCE
|
||||
|| effect == EFFECT_SANDSTORM
|
||||
|| effect == EFFECT_HAIL
|
||||
|| effect == EFFECT_SNOWSCAPE
|
||||
|| effect == EFFECT_CHILLY_RECEPTION))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//PARTNER_MOVE_EFFECT_IS_TERRAIN
|
||||
bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove)
|
||||
{
|
||||
if (!HasPartner(battlerAtkPartner))
|
||||
return FALSE;
|
||||
|
||||
enum BattleMoveEffects partnerEffect = GetMoveEffect(partnerMove);
|
||||
if (partnerMove != MOVE_NONE
|
||||
&& (partnerEffect == EFFECT_GRASSY_TERRAIN
|
||||
|| partnerEffect == EFFECT_MISTY_TERRAIN
|
||||
|| partnerEffect == EFFECT_ELECTRIC_TERRAIN
|
||||
|| partnerEffect == EFFECT_PSYCHIC_TERRAIN))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//PARTNER_MOVE_EFFECT_IS
|
||||
bool32 PartnerMoveEffectIs(u32 battlerAtkPartner, u32 partnerMove, enum BattleMoveEffects effectCheck)
|
||||
{
|
||||
@ -4363,17 +4505,14 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef,
|
||||
if (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE))
|
||||
return NO_INCREASE;
|
||||
|
||||
// Don't increase stats if opposing battler has used Haze effect
|
||||
if (!RandomPercentage(RNG_AI_BOOST_INTO_HAZE, BOOST_INTO_HAZE_CHANCE) &&
|
||||
(HasBattlerSideUsedMoveWithEffect(battlerDef, EFFECT_HAZE)
|
||||
|| HasBattlerSideUsedMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_CLEAR_SMOG)
|
||||
|| HasBattlerSideUsedMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_HAZE)))
|
||||
// Don't increase stats if opposing battler has used Haze effect or AI effect
|
||||
if (!RandomPercentage(RNG_AI_BOOST_INTO_HAZE, BOOST_INTO_HAZE_CHANCE)
|
||||
&& HasBattlerSideUsedMoveWithEffect(battlerDef, EFFECT_HAZE))
|
||||
return NO_INCREASE;
|
||||
|
||||
// Don't increase if AI is at +1 and opponent has Haze effect
|
||||
if (gBattleMons[battlerAtk].statStages[statId] >= MAX_STAT_STAGE - 5 && (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_HAZE)
|
||||
|| HasBattlerSideMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_CLEAR_SMOG)
|
||||
|| HasBattlerSideMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_HAZE)))
|
||||
if (gBattleMons[battlerAtk].statStages[statId] >= MAX_STAT_STAGE - 5
|
||||
&& HasBattlerSideMoveWithAIEffect(battlerDef, AI_EFFECT_RESET_STATS))
|
||||
return NO_INCREASE;
|
||||
|
||||
// Don't increase stats if AI could KO target through Sturdy effect, as otherwise it always 2HKOs
|
||||
@ -4976,11 +5115,7 @@ bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef)
|
||||
bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData)
|
||||
{
|
||||
if (CountUsablePartyMons(battlerDef) == 0
|
||||
|| HasBattlerSideMoveWithEffect(battlerDef, EFFECT_COURT_CHANGE)
|
||||
|| HasBattlerSideMoveWithEffect(battlerDef, EFFECT_DEFOG)
|
||||
|| HasBattlerSideMoveWithEffect(battlerDef, EFFECT_RAPID_SPIN)
|
||||
|| HasBattlerSideMoveWithEffect(battlerDef, EFFECT_TIDY_UP)
|
||||
|| HasBattlerSideMoveWithEffect(battlerDef, MOVE_EFFECT_DEFOG))
|
||||
|| HasBattlerSideMoveWithAIEffect(battlerDef, AI_EFFECT_CLEAR_HAZARDS))
|
||||
return FALSE;
|
||||
|
||||
if (IsBattleMoveStatus(move))
|
||||
@ -5023,27 +5158,17 @@ void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, struct AiLogicData *aiData)
|
||||
{
|
||||
u32 preventsStatLoss;
|
||||
u32 partnerAbility;
|
||||
u32 partnerHoldEffect = aiData->holdEffects[battlerAtkPartner];
|
||||
u32 partnerAbility = aiData->abilities[battlerAtkPartner];
|
||||
u32 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battlerAtk));
|
||||
u32 opposingBattler = GetBattlerAtPosition(opposingPosition);
|
||||
|
||||
if (DoesBattlerIgnoreAbilityChecks(battlerAtk, aiData->abilities[battlerAtk], move))
|
||||
partnerAbility = ABILITY_NONE;
|
||||
else
|
||||
partnerAbility = aiData->abilities[battlerAtkPartner];
|
||||
|
||||
if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] == MAX_STAT_STAGE
|
||||
|| partnerAbility == ABILITY_CONTRARY
|
||||
|| partnerAbility == ABILITY_GOOD_AS_GOLD
|
||||
|| HasMoveWithEffect(BATTLE_OPPOSITE(battlerAtk), EFFECT_FOUL_PLAY)
|
||||
|| HasMoveWithEffect(BATTLE_OPPOSITE(battlerAtkPartner), EFFECT_FOUL_PLAY))
|
||||
|| HasBattlerSideMoveWithEffect(FOE(battlerAtk), EFFECT_FOUL_PLAY))
|
||||
return FALSE;
|
||||
|
||||
preventsStatLoss = (partnerAbility == ABILITY_CLEAR_BODY
|
||||
|| partnerAbility == ABILITY_FULL_METAL_BODY
|
||||
|| partnerAbility == ABILITY_WHITE_SMOKE
|
||||
|| partnerHoldEffect == HOLD_EFFECT_CLEAR_AMULET);
|
||||
preventsStatLoss = !CanLowerStat(battlerAtk, battlerAtkPartner, aiData, STAT_DEF);
|
||||
|
||||
switch (GetMoveEffect(aiData->partnerMove))
|
||||
{
|
||||
|
||||
@ -90,7 +90,7 @@ TO_DO_BATTLE_TEST("AI understands Instruct")
|
||||
TO_DO_BATTLE_TEST("AI understands Quick Guard")
|
||||
TO_DO_BATTLE_TEST("AI understands Wide Guard")
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI will not use the same nondamaging move as its partner for no reason")
|
||||
AI_DOUBLE_BATTLE_TEST("AI won't use the same nondamaging move as its partner for no reason")
|
||||
{
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_AROMATHERAPY; }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user