498 lines
18 KiB
C
498 lines
18 KiB
C
#include "global.h"
|
|
#include "battle_z_move.h"
|
|
#include "malloc.h"
|
|
#include "battle.h"
|
|
#include "battle_anim.h"
|
|
#include "battle_ai_field_statuses.h"
|
|
#include "battle_ai_util.h"
|
|
#include "battle_ai_main.h"
|
|
#include "battle_ai_switch_items.h"
|
|
#include "battle_factory.h"
|
|
#include "battle_setup.h"
|
|
#include "event_data.h"
|
|
#include "data.h"
|
|
#include "item.h"
|
|
#include "move.h"
|
|
#include "pokemon.h"
|
|
#include "random.h"
|
|
#include "recorded_battle.h"
|
|
#include "util.h"
|
|
#include "constants/abilities.h"
|
|
#include "constants/battle_ai.h"
|
|
#include "constants/battle_move_effects.h"
|
|
#include "constants/moves.h"
|
|
#include "constants/items.h"
|
|
|
|
static bool32 DoesAbilityBenefitFromWeather(enum Ability ability, u32 weather);
|
|
static bool32 DoesAbilityBenefitFromFieldStatus(enum Ability ability, u32 fieldStatus);
|
|
// A move is light sensitive if it is boosted by Sunny Day and weakened by low light weathers.
|
|
static bool32 IsLightSensitiveMove(u32 move);
|
|
static bool32 HasLightSensitiveMove(u32 battler);
|
|
// The following functions all feed into WeatherChecker, which is then called by ShouldSetWeather and ShouldClearWeather.
|
|
// BenefitsFrom functions all return FIELD_EFFECT_POSITIVE if the weather or field effect is good to have in place from the perspective of the battler, FIELD_EFFECT_NEUTRAL if it is neither good nor bad, and FIELD_EFFECT_NEGATIVE if it is bad.
|
|
// The purpose of WeatherChecker and FieldStatusChecker is to cleanly homogenize the logic that's the same with all of them, and to more easily apply single battle logic to double battles.
|
|
// ShouldSetWeather and ShouldClearWeather are looking for a positive or negative result respectively, and check the entire side.
|
|
// If one pokemon has a positive result and the other has a negative result, it defaults to the opinion of the battler that may change the weather or field status.
|
|
static enum FieldEffectOutcome BenefitsFromSun(u32 battler);
|
|
static enum FieldEffectOutcome BenefitsFromSandstorm(u32 battler);
|
|
static enum FieldEffectOutcome BenefitsFromHailOrSnow(u32 battler, u32 weather);
|
|
static enum FieldEffectOutcome BenefitsFromRain(u32 battler);
|
|
// The following functions all feed into FieldStatusChecker, which is then called by ShouldSetFieldStatus and ShouldClearFieldStatus.
|
|
// They work approximately the same as the weather functions.
|
|
static enum FieldEffectOutcome BenefitsFromElectricTerrain(u32 battler);
|
|
static enum FieldEffectOutcome BenefitsFromGrassyTerrain(u32 battler);
|
|
static enum FieldEffectOutcome BenefitsFromMistyTerrain(u32 battler);
|
|
static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler);
|
|
static enum FieldEffectOutcome BenefitsFromGravity(u32 battler);
|
|
static enum FieldEffectOutcome BenefitsFromTrickRoom(u32 battler);
|
|
|
|
bool32 WeatherChecker(u32 battler, u32 weather, enum FieldEffectOutcome desiredResult)
|
|
{
|
|
if (IsWeatherActive(B_WEATHER_PRIMAL_ANY) != WEATHER_INACTIVE)
|
|
return (FIELD_EFFECT_BLOCKED == desiredResult);
|
|
|
|
enum FieldEffectOutcome result = FIELD_EFFECT_NEUTRAL;
|
|
enum FieldEffectOutcome firstResult = FIELD_EFFECT_NEUTRAL;
|
|
|
|
u32 i;
|
|
u32 battlersOnSide = 1;
|
|
|
|
if (HasPartner(battler))
|
|
battlersOnSide = 2;
|
|
|
|
for (i = 0; i < battlersOnSide; i++)
|
|
{
|
|
if (weather & B_WEATHER_RAIN)
|
|
result = BenefitsFromRain(battler);
|
|
else if (weather & B_WEATHER_SUN)
|
|
result = BenefitsFromSun(battler);
|
|
else if (weather & B_WEATHER_SANDSTORM)
|
|
result = BenefitsFromSandstorm(battler);
|
|
else if (weather & B_WEATHER_ICY_ANY)
|
|
result = BenefitsFromHailOrSnow(battler, weather);
|
|
|
|
battler = BATTLE_PARTNER(battler);
|
|
|
|
if (result != FIELD_EFFECT_NEUTRAL)
|
|
{
|
|
if (weather & B_WEATHER_DAMAGING_ANY && i == 0 && battlersOnSide == 2)
|
|
firstResult = result;
|
|
}
|
|
}
|
|
if (firstResult != FIELD_EFFECT_NEUTRAL)
|
|
return (firstResult == result) && (result == desiredResult);
|
|
return (result == desiredResult);
|
|
}
|
|
|
|
bool32 FieldStatusChecker(u32 battler, u32 fieldStatus, enum FieldEffectOutcome desiredResult)
|
|
{
|
|
enum FieldEffectOutcome result = FIELD_EFFECT_NEUTRAL;
|
|
enum FieldEffectOutcome firstResult = FIELD_EFFECT_NEUTRAL;
|
|
u32 i;
|
|
|
|
u32 battlersOnSide = 1;
|
|
|
|
if (HasPartner(battler))
|
|
battlersOnSide = 2;
|
|
|
|
for (i = 0; i < battlersOnSide; i++)
|
|
{
|
|
// terrains
|
|
if (fieldStatus & STATUS_FIELD_ELECTRIC_TERRAIN)
|
|
result = BenefitsFromElectricTerrain(battler);
|
|
if (fieldStatus & STATUS_FIELD_GRASSY_TERRAIN)
|
|
result = BenefitsFromGrassyTerrain(battler);
|
|
if (fieldStatus & STATUS_FIELD_MISTY_TERRAIN)
|
|
result = BenefitsFromMistyTerrain(battler);
|
|
if (fieldStatus & STATUS_FIELD_PSYCHIC_TERRAIN)
|
|
result = BenefitsFromPsychicTerrain(battler);
|
|
|
|
// other field statuses
|
|
if (fieldStatus & STATUS_FIELD_GRAVITY)
|
|
result = BenefitsFromGravity(battler);
|
|
if (fieldStatus & STATUS_FIELD_TRICK_ROOM)
|
|
result = BenefitsFromTrickRoom(battler);
|
|
|
|
battler = BATTLE_PARTNER(battler);
|
|
|
|
if (result != FIELD_EFFECT_NEUTRAL)
|
|
{
|
|
// Trick room wants both pokemon to agree, not just one
|
|
if (fieldStatus & STATUS_FIELD_TRICK_ROOM && i == 0 && battlersOnSide == 2)
|
|
firstResult = result;
|
|
}
|
|
}
|
|
if (firstResult != FIELD_EFFECT_NEUTRAL)
|
|
return (firstResult == result) && (result == desiredResult);
|
|
return (result == desiredResult);
|
|
}
|
|
|
|
static bool32 DoesAbilityBenefitFromWeather(enum Ability ability, u32 weather)
|
|
{
|
|
switch (ability)
|
|
{
|
|
case ABILITY_FORECAST:
|
|
return (weather & (B_WEATHER_RAIN | B_WEATHER_SUN | B_WEATHER_ICY_ANY));
|
|
case ABILITY_MAGIC_GUARD:
|
|
case ABILITY_OVERCOAT:
|
|
return (weather & B_WEATHER_DAMAGING_ANY);
|
|
case ABILITY_SAND_FORCE:
|
|
case ABILITY_SAND_RUSH:
|
|
case ABILITY_SAND_VEIL:
|
|
return (weather & B_WEATHER_SANDSTORM);
|
|
case ABILITY_ICE_BODY:
|
|
case ABILITY_ICE_FACE:
|
|
case ABILITY_SNOW_CLOAK:
|
|
return (weather & B_WEATHER_ICY_ANY);
|
|
case ABILITY_SLUSH_RUSH:
|
|
return (weather & B_WEATHER_SNOW);
|
|
case ABILITY_DRY_SKIN:
|
|
case ABILITY_HYDRATION:
|
|
case ABILITY_RAIN_DISH:
|
|
case ABILITY_SWIFT_SWIM:
|
|
return (weather & B_WEATHER_RAIN);
|
|
case ABILITY_CHLOROPHYLL:
|
|
case ABILITY_FLOWER_GIFT:
|
|
case ABILITY_HARVEST:
|
|
case ABILITY_LEAF_GUARD:
|
|
case ABILITY_ORICHALCUM_PULSE:
|
|
case ABILITY_PROTOSYNTHESIS:
|
|
case ABILITY_SOLAR_POWER:
|
|
return (weather & B_WEATHER_SUN);
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static bool32 DoesAbilityBenefitFromFieldStatus(enum Ability ability, u32 fieldStatus)
|
|
{
|
|
switch (ability)
|
|
{
|
|
case ABILITY_MIMICRY:
|
|
return (fieldStatus & STATUS_FIELD_TERRAIN_ANY);
|
|
case ABILITY_HADRON_ENGINE:
|
|
case ABILITY_QUARK_DRIVE:
|
|
case ABILITY_SURGE_SURFER:
|
|
return (fieldStatus & STATUS_FIELD_ELECTRIC_TERRAIN);
|
|
case ABILITY_GRASS_PELT:
|
|
return (fieldStatus & STATUS_FIELD_GRASSY_TERRAIN);
|
|
// no abilities inherently benefit from Misty or Psychic Terrains
|
|
// return (fieldStatus & STATUS_FIELD_MISTY_TERRAIN);
|
|
// return (fieldStatus & STATUS_FIELD_PSYCHIC_TERRAIN);
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static bool32 IsLightSensitiveMove(u32 move)
|
|
{
|
|
switch (GetMoveEffect(move))
|
|
{
|
|
case EFFECT_SOLAR_BEAM:
|
|
case EFFECT_MORNING_SUN:
|
|
case EFFECT_SYNTHESIS:
|
|
case EFFECT_MOONLIGHT:
|
|
case EFFECT_GROWTH:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static bool32 HasLightSensitiveMove(u32 battler)
|
|
{
|
|
s32 i;
|
|
u16 *moves = GetMovesArray(battler);
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && IsLightSensitiveMove(moves[i]))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Sun
|
|
// Utility Umbrella does NOT block Ancient Pokemon from their stat boosts.
|
|
static enum FieldEffectOutcome BenefitsFromSun(u32 battler)
|
|
{
|
|
enum Ability ability = gAiLogicData->abilities[battler];
|
|
|
|
if (gAiLogicData->holdEffects[battler] == HOLD_EFFECT_UTILITY_UMBRELLA)
|
|
{
|
|
if (ability == ABILITY_ORICHALCUM_PULSE || ability == ABILITY_PROTOSYNTHESIS)
|
|
return FIELD_EFFECT_POSITIVE;
|
|
else
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
if (DoesAbilityBenefitFromWeather(ability, B_WEATHER_SUN)
|
|
|| HasLightSensitiveMove(battler)
|
|
|| HasDamagingMoveOfType(battler, TYPE_FIRE)
|
|
|| HasMoveWithEffect(battler, EFFECT_HYDRO_STEAM))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasMoveWithFlag(battler, MoveHas50AccuracyInSun) || HasDamagingMoveOfType(battler, TYPE_WATER) || gAiLogicData->abilities[battler] == ABILITY_DRY_SKIN)
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
// Sandstorm
|
|
static enum FieldEffectOutcome BenefitsFromSandstorm(u32 battler)
|
|
{
|
|
if (DoesAbilityBenefitFromWeather(gAiLogicData->abilities[battler], B_WEATHER_SANDSTORM)
|
|
|| IS_BATTLER_OF_TYPE(battler, TYPE_ROCK))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (gAiLogicData->holdEffects[battler] == HOLD_EFFECT_SAFETY_GOGGLES || IS_BATTLER_ANY_TYPE(battler, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL))
|
|
{
|
|
if (!(IS_BATTLER_ANY_TYPE(LEFT_FOE(battler), TYPE_ROCK, TYPE_GROUND, TYPE_STEEL))
|
|
|| gAiLogicData->holdEffects[LEFT_FOE(battler)] == HOLD_EFFECT_SAFETY_GOGGLES
|
|
|| DoesAbilityBenefitFromWeather(gAiLogicData->abilities[LEFT_FOE(battler)], B_WEATHER_SANDSTORM))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
else
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
}
|
|
|
|
// Hail or Snow
|
|
static enum FieldEffectOutcome BenefitsFromHailOrSnow(u32 battler, u32 weather)
|
|
{
|
|
if (DoesAbilityBenefitFromWeather(gAiLogicData->abilities[battler], weather)
|
|
|| IS_BATTLER_OF_TYPE(battler, TYPE_ICE)
|
|
|| HasMoveWithFlag(battler, MoveAlwaysHitsInHailSnow)
|
|
|| HasBattlerSideMoveWithEffect(battler, EFFECT_AURORA_VEIL))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if ((weather & B_WEATHER_DAMAGING_ANY) && gAiLogicData->holdEffects[battler] != HOLD_EFFECT_SAFETY_GOGGLES)
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
if (HasLightSensitiveMove(battler))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
if (HasMoveWithFlag(LEFT_FOE(battler), MoveAlwaysHitsInHailSnow))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
// Rain
|
|
static enum FieldEffectOutcome BenefitsFromRain(u32 battler)
|
|
{
|
|
if (gAiLogicData->holdEffects[battler] == HOLD_EFFECT_UTILITY_UMBRELLA)
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
|
|
if (DoesAbilityBenefitFromWeather(gAiLogicData->abilities[battler], B_WEATHER_RAIN)
|
|
|| HasMoveWithFlag(battler, MoveAlwaysHitsInRain)
|
|
|| HasDamagingMoveOfType(battler, TYPE_WATER))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasLightSensitiveMove(battler) || HasDamagingMoveOfType(battler, TYPE_FIRE))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
if (HasMoveWithFlag(LEFT_FOE(battler), MoveAlwaysHitsInRain))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
//TODO: when is electric terrain bad?
|
|
static enum FieldEffectOutcome BenefitsFromElectricTerrain(u32 battler)
|
|
{
|
|
if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_ELECTRIC_TERRAIN))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasMoveWithEffect(battler, EFFECT_RISING_VOLTAGE))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if ((HasMoveWithEffect(LEFT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(LEFT_FOE(battler)))
|
|
|| (HasMoveWithEffect(RIGHT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(RIGHT_FOE(battler))))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
bool32 grounded = AI_IsBattlerGrounded(battler);
|
|
if (grounded && HasBattlerSideMoveWithAdditionalEffect(LEFT_FOE(battler), MOVE_EFFECT_SLEEP))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (grounded && ((gBattleMons[battler].status1 & STATUS1_SLEEP)
|
|
|| gBattleMons[battler].volatiles.yawn
|
|
|| HasDamagingMoveOfType(battler, TYPE_ELECTRIC)))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_RISING_VOLTAGE))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
//TODO: when is grassy terrain bad?
|
|
static enum FieldEffectOutcome BenefitsFromGrassyTerrain(u32 battler)
|
|
{
|
|
if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_GRASSY_TERRAIN))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasBattlerSideMoveWithEffect(battler, EFFECT_GRASSY_GLIDE))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
if (HasMoveWithAdditionalEffect(battler, MOVE_EFFECT_FLORAL_HEALING))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
bool32 grounded = AI_IsBattlerGrounded(battler);
|
|
|
|
// Weaken spamming Earthquake, Magnitude, and Bulldoze.
|
|
if (grounded && (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_EARTHQUAKE)
|
|
|| HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_MAGNITUDE)))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (grounded && HasDamagingMoveOfType(battler, TYPE_GRASS))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_GRASSY_GLIDE))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
//TODO: when is misty terrain bad?
|
|
static enum FieldEffectOutcome BenefitsFromMistyTerrain(u32 battler)
|
|
{
|
|
if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_MISTY_TERRAIN))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasBattlerSideMoveWithEffect(battler, EFFECT_MISTY_EXPLOSION))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
bool32 grounded = AI_IsBattlerGrounded(battler);
|
|
bool32 allyGrounded = FALSE;
|
|
if (HasPartner(battler))
|
|
allyGrounded = AI_IsBattlerGrounded(BATTLE_PARTNER(battler));
|
|
|
|
if ((HasMoveWithEffect(LEFT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(LEFT_FOE(battler)))
|
|
|| (HasMoveWithEffect(RIGHT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(RIGHT_FOE(battler))))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
// harass dragons
|
|
if ((grounded || allyGrounded)
|
|
&& (HasDamagingMoveOfType(LEFT_FOE(battler), TYPE_DRAGON) || HasDamagingMoveOfType(RIGHT_FOE(battler), TYPE_DRAGON)))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if ((grounded || allyGrounded)
|
|
&& (HasNonVolatileMoveEffect(LEFT_FOE(battler), MOVE_EFFECT_SLEEP) || HasNonVolatileMoveEffect(RIGHT_FOE(battler), MOVE_EFFECT_SLEEP)))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (grounded && (gBattleMons[battler].status1 & STATUS1_SLEEP || gBattleMons[battler].volatiles.yawn))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
//TODO: when is Psychic Terrain negative?
|
|
static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler)
|
|
{
|
|
if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_PSYCHIC_TERRAIN))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasBattlerSideMoveWithEffect(battler, EFFECT_EXPANDING_FORCE))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
bool32 grounded = AI_IsBattlerGrounded(battler);
|
|
bool32 allyGrounded = FALSE;
|
|
if (HasPartner(battler))
|
|
allyGrounded = AI_IsBattlerGrounded(BATTLE_PARTNER(battler));
|
|
|
|
// don't bother if we're not grounded
|
|
if (grounded || allyGrounded)
|
|
{
|
|
// harass priority
|
|
if (AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_GALE_WINGS)
|
|
|| AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_TRIAGE)
|
|
|| AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_PRANKSTER))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
}
|
|
|
|
if (grounded && HasDamagingMoveOfType(battler, TYPE_PSYCHIC))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_EXPANDING_FORCE))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
if (AI_IsAbilityOnSide(battler, ABILITY_GALE_WINGS)
|
|
|| AI_IsAbilityOnSide(battler, ABILITY_TRIAGE)
|
|
|| AI_IsAbilityOnSide(battler, ABILITY_PRANKSTER))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
static enum FieldEffectOutcome BenefitsFromGravity(u32 battler)
|
|
{
|
|
if (!AI_IsBattlerGrounded(battler))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
if (AI_IsAbilityOnSide(battler, ABILITY_HUSTLE))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
|
|
if (HasMoveWithFlag(battler, IsMoveGravityBanned))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
if (IsBattlerAlive(LEFT_FOE(battler)))
|
|
{
|
|
if (HasMoveWithLowAccuracy(battler, LEFT_FOE(battler), LOW_ACCURACY_THRESHOLD, FALSE)
|
|
|| (!AI_IsBattlerGrounded(LEFT_FOE(battler)) && HasDamagingMoveOfType(battler, TYPE_GROUND)))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
}
|
|
|
|
if (IsBattlerAlive(RIGHT_FOE(battler)))
|
|
{
|
|
if (HasMoveWithLowAccuracy(battler, RIGHT_FOE(battler), LOW_ACCURACY_THRESHOLD, FALSE)
|
|
|| (!AI_IsBattlerGrounded(RIGHT_FOE(battler)) && HasDamagingMoveOfType(battler, TYPE_GROUND)))
|
|
return FIELD_EFFECT_POSITIVE;
|
|
}
|
|
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
}
|
|
|
|
|
|
static enum FieldEffectOutcome BenefitsFromTrickRoom(u32 battler)
|
|
{
|
|
// If we're in singles, we literally only care about speed.
|
|
if (IsBattle1v1())
|
|
{
|
|
if (gAiLogicData->speedStats[battler] < gAiLogicData->speedStats[LEFT_FOE(battler)])
|
|
return FIELD_EFFECT_POSITIVE;
|
|
// If we tie, we shouldn't change trick room state.
|
|
else if (gAiLogicData->speedStats[battler] == gAiLogicData->speedStats[LEFT_FOE(battler)])
|
|
return FIELD_EFFECT_NEUTRAL;
|
|
else
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
}
|
|
|
|
// First checking if we have enough priority for one pokemon to disregard Trick Room entirely.
|
|
if (!(gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN))
|
|
{
|
|
u16* aiMoves = GetMovesArray(battler);
|
|
for (int i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
u16 move = aiMoves[i];
|
|
if (GetBattleMovePriority(battler, gAiLogicData->abilities[battler], move) > 0 && !(GetMovePriority(move) > 0 && IsBattleMoveStatus(move)))
|
|
{
|
|
return FIELD_EFFECT_POSITIVE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we are faster or tie, we don't want trick room.
|
|
if ((gAiLogicData->speedStats[battler] >= gAiLogicData->speedStats[LEFT_FOE(battler)]) || (gAiLogicData->speedStats[battler] >= gAiLogicData->speedStats[RIGHT_FOE(battler)]))
|
|
return FIELD_EFFECT_NEGATIVE;
|
|
|
|
return FIELD_EFFECT_POSITIVE;
|
|
}
|
|
|
|
|