split status_checker into status_actions and move_checks

This commit is contained in:
Seth Barberee 2022-12-15 21:18:01 -08:00
parent ad30396f48
commit 29b6e36457
6 changed files with 972 additions and 941 deletions

10
include/move_checks.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef GUARD_MOVE_CHECKS_H
#define GUARD_MOVE_CHECKS_H
bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct PokemonMove *move);
bool8 CanUseOnTargetWithStatusChecker(struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move);
bool8 HasDisabledMove(struct PokemonMove *moves);
bool8 LastUsedMoveOutOfPP(struct PokemonMove *moves);
bool8 HasLastUsedMove(struct PokemonMove *moves);
#endif

View File

@ -1,5 +1,5 @@
#ifndef GUARD_STATUS_CHECKER_H
#define GUARD_STATUS_CHECKER_H
#ifndef GUARD_STATUS_ACTIONS_H
#define GUARD_STATUS_ACTIONS_H
#include "constants/move.h"
#include "dungeon_entity.h"
@ -52,10 +52,5 @@ bool8 sub_805C468(struct DungeonEntity *pokemon, struct DungeonEntity *target);
bool8 StairsOrbAction(struct DungeonEntity *pokemon, struct DungeonEntity *target);
bool8 LongtossOrbAction(struct DungeonEntity *pokemon, struct DungeonEntity *target);
bool8 PierceOrbAction(struct DungeonEntity *pokemon, struct DungeonEntity *target);
bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct PokemonMove *move);
bool8 CanUseOnTargetWithStatusChecker(struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move);
bool8 HasDisabledMove(struct PokemonMove *moves);
bool8 LastUsedMoveOutOfPP(struct PokemonMove *moves);
bool8 HasLastUsedMove(struct PokemonMove *moves);
#endif

View File

@ -220,7 +220,8 @@ SECTIONS {
asm/code_805744C.o(.text);
src/code_8057824.o(.text);
asm/code_8057824.o(.text);
src/status_checker.o(.text);
src/status_actions.o(.text);
src/move_checks.o(.text);
asm/code_805D8C8.o(.text);
src/targeting.o(.text);
src/code_8069E0C.o(.text);
@ -459,7 +460,7 @@ SECTIONS {
data/data_80F4E2C.o(.rodata);
src/type_chart.o(.rodata);
data/data_80F54B4.o(.rodata);
src/status_checker.o(.rodata);
src/move_checks.o(.rodata);
data/data_80F5668.o(.rodata);
src/dungeon_pokemon_attributes.o(.rodata);
data/data_80F59C8.o(.rodata);

View File

@ -22,8 +22,8 @@
#include "dungeon_visibility.h"
#include "move_util.h"
#include "moves.h"
#include "move_checks.h"
#include "position_util.h"
#include "status_checker.h"
#include "status_checks.h"
#include "status_checks_1.h"
#include "targeting.h"

954
src/move_checks.c Normal file
View File

@ -0,0 +1,954 @@
#include "global.h"
#include "constants/status.h"
#include "constants/type.h"
#include "constants/weather.h"
#include "dungeon_engine.h"
#include "dungeon_global_data.h"
#include "dungeon_items.h"
#include "dungeon_map_access.h"
#include "dungeon_pokemon_attributes.h"
#include "dungeon_util.h"
#include "dungeon_visibility.h"
#include "move_checks.h"
#include "moves.h"
#include "number_util.h"
#include "status.h"
#include "status_actions.h"
#include "status_checks_1.h"
#include "team_inventory.h"
#include "text_util.h"
#include "tile_types.h"
#include "trap.h"
#include "weather.h"
// Array indices correspond to the current dungeon tileset.
const u8 gDungeonCamouflageTypes[76] = {
TYPE_WATER,
TYPE_GRASS,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_GRASS,
TYPE_GROUND,
TYPE_NORMAL,
TYPE_NORMAL,
TYPE_GRASS,
TYPE_ICE,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_ICE,
TYPE_ICE,
TYPE_GRASS,
TYPE_GROUND,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_ICE,
TYPE_GRASS,
TYPE_GRASS,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_GRASS,
TYPE_ROCK,
TYPE_ROCK,
TYPE_GRASS,
TYPE_GRASS,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_ICE,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_GRASS,
TYPE_ROCK,
TYPE_ROCK,
TYPE_GROUND,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_ICE,
TYPE_ROCK,
TYPE_WATER,
TYPE_GRASS,
TYPE_GRASS,
TYPE_GROUND,
TYPE_WATER,
TYPE_ROCK,
TYPE_ROCK,
TYPE_GRASS,
TYPE_NORMAL,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_GRASS,
TYPE_ROCK,
TYPE_GRASS,
TYPE_GRASS,
TYPE_ROCK,
TYPE_GRASS,
TYPE_ROCK,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_ICE,
TYPE_WATER,
TYPE_WATER,
TYPE_ROCK
};
bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct PokemonMove *move)
{
struct DungeonEntityData *pokemonData = pokemon->entityData;
switch (move->moveID)
{
case MOVE_HAIL:
if (GetWeather(pokemon) == WEATHER_HAIL)
{
return FALSE;
}
break;
case MOVE_RAGE:
if (pokemonData->chargingStatus == CHARGING_STATUS_RAGE)
{
return FALSE;
}
break;
case MOVE_COUNTER:
case MOVE_PURSUIT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_COUNTER)
{
return FALSE;
}
break;
case MOVE_MIRROR_MOVE:
if (pokemonData->protectionStatus == PROTECTION_STATUS_MIRROR_MOVE)
{
return FALSE;
}
break;
case MOVE_HOWL:
case MOVE_MEDITATE:
case MOVE_SHARPEN:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_BELLY_DRUM:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE || RoundUpFixedPoint(pokemonData->belly) <= 0)
{
return FALSE;
}
break;
case MOVE_ACID_ARMOR:
case MOVE_BARRIER:
case MOVE_DEFENSE_CURL:
case MOVE_HARDEN:
case MOVE_IRON_DEFENSE:
case MOVE_WITHDRAW:
if (pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_BIDE:
case MOVE_REVENGE:
if (pokemonData->chargingStatus == CHARGING_STATUS_BIDE)
{
return FALSE;
}
break;
case MOVE_AGILITY:
{
u32 r1;
#ifndef NONMATCHING
asm("":"=r"(r1));
#else
r1 = 0;
#endif
if (pokemon->entityData->movementSpeed >= MAX_MOVEMENT_SPEED)
{
r1 = !r1;
return FALSE;
}
break;
}
case MOVE_LOCK_ON:
case MOVE_MIND_READER:
if (pokemonData->moveStatus == MOVE_STATUS_SURE_SHOT)
{
return FALSE;
}
break;
case MOVE_COSMIC_POWER:
if (pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE && pokemonData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_ENDURE:
if (pokemonData->protectionStatus == PROTECTION_STATUS_ENDURE)
{
return FALSE;
}
break;
case MOVE_CHARGE:
if (pokemonData->chargingStatus == CHARGING_STATUS_CHARGE)
{
return FALSE;
}
break;
case MOVE_MIST:
if (pokemonData->protectionStatus == PROTECTION_STATUS_MIST)
{
return FALSE;
}
break;
case MOVE_LIGHT_SCREEN:
if (pokemonData->protectionStatus == PROTECTION_STATUS_LIGHT_SCREEN)
{
return FALSE;
}
break;
case MOVE_MINIMIZE:
if (pokemonData->accuracyStages[STAT_STAGE_EVASION] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_INGRAIN:
if (pokemonData->immobilizeStatus == IMMOBILIZE_STATUS_INGRAIN || pokemonData->maxHP / 2 < pokemonData->HP)
{
return FALSE;
}
break;
case MOVE_SWALLOW:
if (pokemonData->maxHP <= pokemonData->HP || pokemonData->stockpileCount == 0)
{
return FALSE;
}
break;
case MOVE_SPIT_UP:
if (pokemonData->stockpileCount == 0)
{
return FALSE;
}
break;
case MOVE_DOOM_DESIRE:
case MOVE_FUTURE_SIGHT:
if (pokemonData->moveStatus == MOVE_STATUS_SET_DAMAGE)
{
return FALSE;
}
break;
case MOVE_BULK_UP:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE && pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_CAMOUFLAGE:
if (HasType(pokemon, gDungeonCamouflageTypes[gDungeonGlobalData->tileset]))
{
return FALSE;
}
break;
case MOVE_TAIL_GLOW:
if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_DESTINY_BOND:
if (pokemonData->linkedStatus == LINKED_STATUS_DESTINY_BOND)
{
return FALSE;
}
break;
case MOVE_MIRROR_COAT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_MIRROR_COAT)
{
return FALSE;
}
break;
case MOVE_REFLECT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_REFLECT)
{
return FALSE;
}
break;
case MOVE_DRAGON_DANCE:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE && pokemon->entityData->movementSpeed >= MAX_MOVEMENT_SPEED)
{
return FALSE;
}
break;
case MOVE_MAGIC_COAT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_MAGIC_COAT)
{
return FALSE;
}
break;
case MOVE_DETECT:
case MOVE_PROTECT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_PROTECT)
{
return FALSE;
}
break;
case MOVE_RAIN_DANCE:
if (GetWeather(pokemon) == WEATHER_RAIN)
{
return FALSE;
}
break;
case MOVE_SANDSTORM:
if (GetWeather(pokemon) == WEATHER_SANDSTORM)
{
return FALSE;
}
break;
case MOVE_SUNNY_DAY:
if (GetWeather(pokemon) == WEATHER_SUNNY)
{
return FALSE;
}
break;
case MOVE_SAFEGUARD:
if (pokemonData->protectionStatus == PROTECTION_STATUS_SAFEGUARD)
{
return FALSE;
}
break;
case MOVE_INVISIFY:
if (pokemonData->transformStatus == TRANSFORM_STATUS_INVISIBLE)
{
return FALSE;
}
break;
case MOVE_FOCUS_ENERGY:
if (pokemonData->moveStatus == MOVE_STATUS_FOCUS_ENERGY)
{
return FALSE;
}
break;
case MOVE_TAKEAWAY:
if (pokemonData->heldItem.itemFlags & ITEM_FLAG_EXISTS)
{
return FALSE;
}
break;
case MOVE_REST:
if (!HasQuarterHPOrLess(pokemon) && !HasNegativeStatus(pokemon))
{
return FALSE;
}
break;
case MOVE_DIVE:
if (IsTileGround(GetMapTileForDungeonEntity_2(pokemon)))
{
return FALSE;
}
break;
case MOVE_DIG:
{
struct MapTile *tile = GetMapTileForDungeonEntity_2(pokemon);
if (!IsTileGround(tile) || (tile->tileType & (TILE_TYPE_FLOOR | TILE_TYPE_LIQUID)) != TILE_TYPE_FLOOR)
{
return FALSE;
}
break;
}
case MOVE_TRAP_BUSTER:
{
struct DungeonEntity *mapObject = GetMapTileForDungeonEntity_2(pokemon)->mapObject;
if (mapObject == NULL || GetEntityType(mapObject) != ENTITY_TRAP)
{
return FALSE;
}
break;
}
case MOVE_MUD_SPORT:
if (gDungeonGlobalData->mudSportTurnsLeft > 0)
{
return FALSE;
}
break;
case MOVE_WATER_SPORT:
if (gDungeonGlobalData->waterSportTurnsLeft > 0)
{
return FALSE;
}
break;
case MOVE_GRUDGE:
if (pokemonData->grudgeStatus)
{
return FALSE;
}
break;
case MOVE_DECOY_MAKER:
case MOVE_FOLLOW_ME:
case MOVE_SUBSTITUTE:
if (gDungeonGlobalData->decoyActive)
{
return FALSE;
}
break;
case MOVE_STOCKPILE:
if (pokemonData->stockpileCount >= MAX_STOCKPILE_COUNT)
{
return FALSE;
}
break;
case MOVE_CLEANSE:
if (pokemonData->heldItem.itemFlags & ITEM_FLAG_EXISTS &&
!(pokemonData->heldItem.itemFlags & ITEM_FLAG_STICKY))
{
return FALSE;
}
break;
case MOVE_DOUBLE_TEAM:
if (pokemonData->accuracyStages[STAT_STAGE_EVASION] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_GROWTH:
if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_SWORDS_DANCE:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_WISH:
if (pokemonData->isEnemy || pokemonData->protectionStatus == PROTECTION_STATUS_WISH)
{
return FALSE;
}
break;
case MOVE_TRANSFORM:
if (pokemonData->transformStatus == TRANSFORM_STATUS_TRANSFORMED)
{
return FALSE;
}
break;
case MOVE_SPIKES:
if (!CanLayTrap(&pokemon->posWorld))
{
return FALSE;
}
break;
case MOVE_CALM_MIND:
if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE)
{
break;
}
case MOVE_AMNESIA:
if (pokemonData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_SNATCH:
if (pokemonData->waitingStatus == WAITING_STATUS_SNATCH)
{
return FALSE;
}
break;
case MOVE_BEAT_UP:
case MOVE_BLOWBACK:
case MOVE_HURL:
case MOVE_MEMENTO:
case MOVE_ROAR:
case MOVE_STAY_AWAY:
case MOVE_SWITCHER:
case MOVE_TELEPORT:
case MOVE_VITAL_THROW:
case MOVE_WARP:
case MOVE_WHIRLWIND:
if (IsBossBattle())
{
return FALSE;
}
break;
case MOVE_CONVERSION_2:
if (pokemonData->protectionStatus == PROTECTION_STATUS_CONVERSION_2)
{
return FALSE;
}
break;
case MOVE_HELPING_HAND:
if (pokemonData->isEnemy)
{
s32 i;
for (i = 0; i < DUNGEON_MAX_WILD_POKEMON; i++)
{
struct DungeonEntity *target = gDungeonGlobalData->wildPokemon[i];
if (EntityExists(target) && target != pokemon && CanSee(pokemon, target))
{
if (target->entityData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE)
{
continue;
}
if (target->entityData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE)
{
break;
}
}
}
if (i == DUNGEON_MAX_WILD_POKEMON)
{
return FALSE;
}
break;
}
else
{
s32 i;
for (i = 0; i < MAX_TEAM_MEMBERS; i++)
{
struct DungeonEntity *target = gDungeonGlobalData->teamPokemon[i];
if (EntityExists(target) && target != pokemon && CanSee(pokemon, target))
{
if (target->entityData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE)
{
continue;
}
if (target->entityData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE)
{
break;
}
}
}
if (i == MAX_TEAM_MEMBERS)
{
return FALSE;
}
break;
}
}
return TRUE;
}
bool8 CanUseOnTargetWithStatusChecker(struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move)
{
struct DungeonEntityData *userData = user->entityData;
struct DungeonEntityData *targetData = target->entityData;
s32 i;
if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_FROZEN && MoveCannotHitFrozen(move))
{
return FALSE;
}
switch (move->moveID)
{
case MOVE_GRASSWHISTLE:
case MOVE_HYPNOSIS:
case MOVE_LOVELY_KISS:
case MOVE_SING:
case MOVE_SLEEP_POWDER:
case MOVE_SPORE:
if (IsSleeping(target))
{
return FALSE;
}
break;
case MOVE_YAWN:
if (targetData->sleepStatus == SLEEP_STATUS_YAWNING)
{
return FALSE;
}
if (IsSleeping(target))
{
return FALSE;
}
break;
case MOVE_NIGHTMARE:
if (targetData->sleepStatus == SLEEP_STATUS_NIGHTMARE)
{
return FALSE;
}
break;
case MOVE_SWEET_SCENT:
if (targetData->accuracyStages[STAT_STAGE_EVASION] <= 0)
{
return FALSE;
}
break;
case MOVE_CHARM:
if (targetData->attackMultipliers[STAT_STAGE_ATTACK] < STAT_MULTIPLIER_THRESHOLD)
{
return FALSE;
}
break;
case MOVE_ENCORE:
if (targetData->volatileStatus == VOLATILE_STATUS_ENCORE)
{
return FALSE;
}
if (!HasLastUsedMove(targetData->moves))
{
return FALSE;
}
break;
case MOVE_SUPER_FANG:
if (targetData->HP <= 1)
{
return FALSE;
}
break;
case MOVE_PAIN_SPLIT:
if (targetData->HP <= userData->HP)
{
return FALSE;
}
break;
case MOVE_TORMENT:
if (HasDisabledMove(targetData->moves) || !HasLastUsedMove(targetData->moves))
{
return FALSE;
}
break;
case MOVE_COTTON_SPORE:
case MOVE_SCARY_FACE:
case MOVE_STRING_SHOT:
if (target->entityData->movementSpeed <= 0)
{
return FALSE;
}
break;
case MOVE_SCREECH:
if (targetData->defenseMultipliers[STAT_STAGE_DEFENSE] < STAT_MULTIPLIER_THRESHOLD)
{
return FALSE;
}
break;
case MOVE_FAKE_TEARS:
if (targetData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] <= 0)
{
return FALSE;
}
break;
case MOVE_SPITE:
if (LastUsedMoveOutOfPP(targetData->moves))
{
return FALSE;
}
break;
case MOVE_SMOKESCREEN:
if (targetData->moveStatus == MOVE_STATUS_WHIFFER)
{
return FALSE;
}
break;
case MOVE_MEMENTO:
if (targetData->attackMultipliers[STAT_STAGE_ATTACK] < STAT_MULTIPLIER_THRESHOLD &&
targetData->attackMultipliers[STAT_STAGE_SPECIAL_ATTACK] < STAT_MULTIPLIER_THRESHOLD)
{
return FALSE;
}
break;
case MOVE_WILL_O_WISP:
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BURNED)
{
return FALSE;
}
break;
case MOVE_FORESIGHT:
case MOVE_ODOR_SLEUTH:
if (targetData->types[0] == TYPE_GHOST || targetData->types[1] == TYPE_GHOST)
{
if (!targetData->exposedStatus)
{
break;
}
}
if (targetData->accuracyStages[STAT_STAGE_EVASION] <= DEFAULT_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_DISABLE:
case MOVE_GLARE:
case MOVE_STUN_SPORE:
case MOVE_THUNDER_WAVE:
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_PARALYZED)
{
return FALSE;
}
break;
case MOVE_ENDEAVOR:
if (targetData->HP - userData->HP <= 0)
{
return FALSE;
}
break;
case MOVE_LEER:
case MOVE_TAIL_WHIP:
if (targetData->defenseStages[STAT_STAGE_DEFENSE] <= 0)
{
return FALSE;
}
break;
case MOVE_METAL_SOUND:
if (targetData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] <= 0)
{
return FALSE;
}
break;
case MOVE_TICKLE:
if (targetData->attackStages[STAT_STAGE_ATTACK] <= 0 &&
targetData->defenseStages[STAT_STAGE_DEFENSE] <= 0)
{
return FALSE;
}
break;
case MOVE_BLOCK:
case MOVE_MEAN_LOOK:
case MOVE_SPIDER_WEB:
if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_IMMOBILIZED)
{
return FALSE;
}
break;
case MOVE_HAZE:
{
for (i = 0; i < 2; i++)
{
if (targetData->attackStages[i] < DEFAULT_STAT_STAGE) break;
if (targetData->defenseStages[i] < DEFAULT_STAT_STAGE) break;
if (targetData->accuracyStages[i] < DEFAULT_STAT_STAGE ||
targetData->attackMultipliers[i] < DEFAULT_STAT_MULTIPLIER ||
targetData->defenseMultipliers[i] < DEFAULT_STAT_MULTIPLIER)
{
break;
}
}
if (i == 2)
{
return FALSE;
}
break;
}
case MOVE_UPROAR:
if (targetData->sleepStatus == SLEEP_STATUS_SLEEPLESS)
{
return FALSE;
}
break;
case MOVE_PSYCH_UP:
{
for (i = 0; i < 2; i++)
{
if (userData->attackStages[i] < targetData->attackStages[i]) break;
if (userData->defenseStages[i] < targetData->defenseStages[i] ||
userData->accuracyStages[i] < targetData->accuracyStages[i] ||
userData->attackMultipliers[i] < targetData->attackMultipliers[i] ||
userData->defenseMultipliers[i] < targetData->defenseMultipliers[i])
{
break;
}
}
if (i == 2)
{
return FALSE;
}
break;
}
case MOVE_FLASH:
case MOVE_KINESIS:
case MOVE_SAND_ATTACK:
if (targetData->accuracyStages[STAT_STAGE_ACCURACY] <= 0)
{
return FALSE;
}
break;
case MOVE_TAUNT:
if (targetData->volatileStatus == VOLATILE_STATUS_TAUNTED)
{
return FALSE;
}
break;
case MOVE_TRICK:
if (!(userData->heldItem.itemFlags & ITEM_FLAG_EXISTS) ||
!(targetData->heldItem.itemFlags & ITEM_FLAG_EXISTS))
{
return FALSE;
}
break;
case MOVE_KNOCK_OFF:
if (!(targetData->heldItem.itemFlags & ITEM_FLAG_EXISTS))
{
return FALSE;
}
break;
case MOVE_FEATHERDANCE:
case MOVE_GROWL:
if (targetData->attackStages[STAT_STAGE_ATTACK] <= 0)
{
return FALSE;
}
break;
case MOVE_ROLE_PLAY:
if (userData->abilities[0] == targetData->abilities[0] &&
userData->abilities[1] == targetData->abilities[1])
{
return FALSE;
}
break;
case MOVE_CURSE:
if (HasType(user, TYPE_GHOST))
{
if (targetData->waitingStatus == WAITING_STATUS_CURSED)
{
return FALSE;
}
}
else
{
if (userData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE &&
userData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
}
break;
case MOVE_IMPRISON:
case MOVE_OBSERVER:
if (targetData->volatileStatus == VOLATILE_STATUS_PAUSED)
{
return FALSE;
}
break;
case MOVE_FALSE_SWIPE:
if (targetData->HP <= 1)
{
return FALSE;
}
break;
case MOVE_LEECH_SEED:
if (targetData->linkedStatus == LINKED_STATUS_LEECH_SEED)
{
return FALSE;
}
break;
case MOVE_PERISH_SONG:
if (targetData->perishSongTimer != 0)
{
return FALSE;
}
break;
case MOVE_MIMIC:
case MOVE_SKETCH:
if (!HasLastUsedMove(targetData->moves))
{
return FALSE;
}
break;
case MOVE_ATTRACT:
if (targetData->volatileStatus == VOLATILE_STATUS_INFATUATED)
{
return FALSE;
}
break;
case MOVE_WRAP:
if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_WRAPPED_AROUND_FOE)
{
return FALSE;
}
if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_WRAPPED_BY_FOE)
{
return FALSE;
}
break;
case MOVE_TOXIC:
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BADLY_POISONED)
{
return FALSE;
}
break;
case MOVE_POISON_GAS:
case MOVE_POISONPOWDER:
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_POISONED)
{
return FALSE;
}
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BADLY_POISONED)
{
return FALSE;
}
break;
case MOVE_CONFUSE_RAY:
case MOVE_FLATTER:
case MOVE_SUPERSONIC:
case MOVE_SWAGGER:
case MOVE_SWEET_KISS:
case MOVE_TEETER_DANCE:
case MOVE_TOTTER:
if (targetData->volatileStatus == VOLATILE_STATUS_CONFUSED)
{
return FALSE;
}
break;
}
return TRUE;
}
bool8 HasDisabledMove(struct PokemonMove *moves)
{
s32 i;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i].moveFlags & MOVE_FLAG_EXISTS && moves[i].moveFlags & MOVE_FLAG_DISABLED)
{
return TRUE;
}
}
if (moves[STRUGGLE_MOVE_INDEX].moveFlags & MOVE_FLAG_DISABLED)
{
return TRUE;
}
return FALSE;
}
bool8 LastUsedMoveOutOfPP(struct PokemonMove *moves)
{
s32 i;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i].moveFlags & MOVE_FLAG_EXISTS &&
moves[i].moveFlags & MOVE_FLAG_LAST_USED &&
moves[i].PP == 0)
{
return TRUE;
}
}
return FALSE;
}
bool8 HasLastUsedMove(struct PokemonMove *moves)
{
s32 i;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i].moveFlags & MOVE_FLAG_EXISTS && moves[i].moveFlags & MOVE_FLAG_LAST_USED)
{
return TRUE;
}
}
if (moves[STRUGGLE_MOVE_INDEX].moveFlags & MOVE_FLAG_LAST_USED)
{
return TRUE;
}
return FALSE;
}

View File

@ -1,5 +1,5 @@
#include "global.h"
#include "status_checker.h"
#include "status_actions.h"
#include "code_80521D0.h"
#include "code_8077274_1.h"
@ -146,6 +146,7 @@ extern u8 *gPtrForecastPreventsTypeSwitchMessage[];
extern u8 *gUnknown_80FEB08[];
extern u8 gUnknown_202DE58[];
extern s16 gUnknown_80F4E08;
extern u8 gDungeonCamouflageTypes[76];
struct Position_Alt
{
@ -156,85 +157,6 @@ struct Position_Alt
} temp;
};
// Array indices correspond to the current dungeon tileset.
const u8 gDungeonCamouflageTypes[76] = {
TYPE_WATER,
TYPE_GRASS,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_GRASS,
TYPE_GROUND,
TYPE_NORMAL,
TYPE_NORMAL,
TYPE_GRASS,
TYPE_ICE,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_ICE,
TYPE_ICE,
TYPE_GRASS,
TYPE_GROUND,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_ICE,
TYPE_GRASS,
TYPE_GRASS,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_GRASS,
TYPE_ROCK,
TYPE_ROCK,
TYPE_GRASS,
TYPE_GRASS,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_ICE,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_ROCK,
TYPE_GRASS,
TYPE_ROCK,
TYPE_ROCK,
TYPE_GROUND,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_ICE,
TYPE_ROCK,
TYPE_WATER,
TYPE_GRASS,
TYPE_GRASS,
TYPE_GROUND,
TYPE_WATER,
TYPE_ROCK,
TYPE_ROCK,
TYPE_GRASS,
TYPE_NORMAL,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_GRASS,
TYPE_ROCK,
TYPE_GRASS,
TYPE_GRASS,
TYPE_ROCK,
TYPE_GRASS,
TYPE_ROCK,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_NORMAL,
TYPE_ROCK,
TYPE_NORMAL,
TYPE_ICE,
TYPE_WATER,
TYPE_WATER,
TYPE_ROCK
};
extern s16 gUnknown_80F4DC6;
extern u8 *gUnknown_80FEFF4[];
@ -1382,854 +1304,3 @@ bool8 PierceOrbAction(struct DungeonEntity *pokemon, struct DungeonEntity *targe
PierceStatusTarget(pokemon, target);
return TRUE;
}
bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct PokemonMove *move)
{
struct DungeonEntityData *pokemonData = pokemon->entityData;
switch (move->moveID)
{
case MOVE_HAIL:
if (GetWeather(pokemon) == WEATHER_HAIL)
{
return FALSE;
}
break;
case MOVE_RAGE:
if (pokemonData->chargingStatus == CHARGING_STATUS_RAGE)
{
return FALSE;
}
break;
case MOVE_COUNTER:
case MOVE_PURSUIT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_COUNTER)
{
return FALSE;
}
break;
case MOVE_MIRROR_MOVE:
if (pokemonData->protectionStatus == PROTECTION_STATUS_MIRROR_MOVE)
{
return FALSE;
}
break;
case MOVE_HOWL:
case MOVE_MEDITATE:
case MOVE_SHARPEN:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_BELLY_DRUM:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE || RoundUpFixedPoint(pokemonData->belly) <= 0)
{
return FALSE;
}
break;
case MOVE_ACID_ARMOR:
case MOVE_BARRIER:
case MOVE_DEFENSE_CURL:
case MOVE_HARDEN:
case MOVE_IRON_DEFENSE:
case MOVE_WITHDRAW:
if (pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_BIDE:
case MOVE_REVENGE:
if (pokemonData->chargingStatus == CHARGING_STATUS_BIDE)
{
return FALSE;
}
break;
case MOVE_AGILITY:
{
u32 r1;
#ifndef NONMATCHING
asm("":"=r"(r1));
#else
r1 = 0;
#endif
if (pokemon->entityData->movementSpeed >= MAX_MOVEMENT_SPEED)
{
r1 = !r1;
return FALSE;
}
break;
}
case MOVE_LOCK_ON:
case MOVE_MIND_READER:
if (pokemonData->moveStatus == MOVE_STATUS_SURE_SHOT)
{
return FALSE;
}
break;
case MOVE_COSMIC_POWER:
if (pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE && pokemonData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_ENDURE:
if (pokemonData->protectionStatus == PROTECTION_STATUS_ENDURE)
{
return FALSE;
}
break;
case MOVE_CHARGE:
if (pokemonData->chargingStatus == CHARGING_STATUS_CHARGE)
{
return FALSE;
}
break;
case MOVE_MIST:
if (pokemonData->protectionStatus == PROTECTION_STATUS_MIST)
{
return FALSE;
}
break;
case MOVE_LIGHT_SCREEN:
if (pokemonData->protectionStatus == PROTECTION_STATUS_LIGHT_SCREEN)
{
return FALSE;
}
break;
case MOVE_MINIMIZE:
if (pokemonData->accuracyStages[STAT_STAGE_EVASION] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_INGRAIN:
if (pokemonData->immobilizeStatus == IMMOBILIZE_STATUS_INGRAIN || pokemonData->maxHP / 2 < pokemonData->HP)
{
return FALSE;
}
break;
case MOVE_SWALLOW:
if (pokemonData->maxHP <= pokemonData->HP || pokemonData->stockpileCount == 0)
{
return FALSE;
}
break;
case MOVE_SPIT_UP:
if (pokemonData->stockpileCount == 0)
{
return FALSE;
}
break;
case MOVE_DOOM_DESIRE:
case MOVE_FUTURE_SIGHT:
if (pokemonData->moveStatus == MOVE_STATUS_SET_DAMAGE)
{
return FALSE;
}
break;
case MOVE_BULK_UP:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE && pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_CAMOUFLAGE:
if (HasType(pokemon, gDungeonCamouflageTypes[gDungeonGlobalData->tileset]))
{
return FALSE;
}
break;
case MOVE_TAIL_GLOW:
if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_DESTINY_BOND:
if (pokemonData->linkedStatus == LINKED_STATUS_DESTINY_BOND)
{
return FALSE;
}
break;
case MOVE_MIRROR_COAT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_MIRROR_COAT)
{
return FALSE;
}
break;
case MOVE_REFLECT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_REFLECT)
{
return FALSE;
}
break;
case MOVE_DRAGON_DANCE:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE && pokemon->entityData->movementSpeed >= MAX_MOVEMENT_SPEED)
{
return FALSE;
}
break;
case MOVE_MAGIC_COAT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_MAGIC_COAT)
{
return FALSE;
}
break;
case MOVE_DETECT:
case MOVE_PROTECT:
if (pokemonData->protectionStatus == PROTECTION_STATUS_PROTECT)
{
return FALSE;
}
break;
case MOVE_RAIN_DANCE:
if (GetWeather(pokemon) == WEATHER_RAIN)
{
return FALSE;
}
break;
case MOVE_SANDSTORM:
if (GetWeather(pokemon) == WEATHER_SANDSTORM)
{
return FALSE;
}
break;
case MOVE_SUNNY_DAY:
if (GetWeather(pokemon) == WEATHER_SUNNY)
{
return FALSE;
}
break;
case MOVE_SAFEGUARD:
if (pokemonData->protectionStatus == PROTECTION_STATUS_SAFEGUARD)
{
return FALSE;
}
break;
case MOVE_INVISIFY:
if (pokemonData->transformStatus == TRANSFORM_STATUS_INVISIBLE)
{
return FALSE;
}
break;
case MOVE_FOCUS_ENERGY:
if (pokemonData->moveStatus == MOVE_STATUS_FOCUS_ENERGY)
{
return FALSE;
}
break;
case MOVE_TAKEAWAY:
if (pokemonData->heldItem.itemFlags & ITEM_FLAG_EXISTS)
{
return FALSE;
}
break;
case MOVE_REST:
if (!HasQuarterHPOrLess(pokemon) && !HasNegativeStatus(pokemon))
{
return FALSE;
}
break;
case MOVE_DIVE:
if (IsTileGround(GetMapTileForDungeonEntity_2(pokemon)))
{
return FALSE;
}
break;
case MOVE_DIG:
{
struct MapTile *tile = GetMapTileForDungeonEntity_2(pokemon);
if (!IsTileGround(tile) || (tile->tileType & (TILE_TYPE_FLOOR | TILE_TYPE_LIQUID)) != TILE_TYPE_FLOOR)
{
return FALSE;
}
break;
}
case MOVE_TRAP_BUSTER:
{
struct DungeonEntity *mapObject = GetMapTileForDungeonEntity_2(pokemon)->mapObject;
if (mapObject == NULL || GetEntityType(mapObject) != ENTITY_TRAP)
{
return FALSE;
}
break;
}
case MOVE_MUD_SPORT:
if (gDungeonGlobalData->mudSportTurnsLeft > 0)
{
return FALSE;
}
break;
case MOVE_WATER_SPORT:
if (gDungeonGlobalData->waterSportTurnsLeft > 0)
{
return FALSE;
}
break;
case MOVE_GRUDGE:
if (pokemonData->grudgeStatus)
{
return FALSE;
}
break;
case MOVE_DECOY_MAKER:
case MOVE_FOLLOW_ME:
case MOVE_SUBSTITUTE:
if (gDungeonGlobalData->decoyActive)
{
return FALSE;
}
break;
case MOVE_STOCKPILE:
if (pokemonData->stockpileCount >= MAX_STOCKPILE_COUNT)
{
return FALSE;
}
break;
case MOVE_CLEANSE:
if (pokemonData->heldItem.itemFlags & ITEM_FLAG_EXISTS &&
!(pokemonData->heldItem.itemFlags & ITEM_FLAG_STICKY))
{
return FALSE;
}
break;
case MOVE_DOUBLE_TEAM:
if (pokemonData->accuracyStages[STAT_STAGE_EVASION] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_GROWTH:
if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_SWORDS_DANCE:
if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_WISH:
if (pokemonData->isEnemy || pokemonData->protectionStatus == PROTECTION_STATUS_WISH)
{
return FALSE;
}
break;
case MOVE_TRANSFORM:
if (pokemonData->transformStatus == TRANSFORM_STATUS_TRANSFORMED)
{
return FALSE;
}
break;
case MOVE_SPIKES:
if (!CanLayTrap(&pokemon->posWorld))
{
return FALSE;
}
break;
case MOVE_CALM_MIND:
if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE)
{
break;
}
case MOVE_AMNESIA:
if (pokemonData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_SNATCH:
if (pokemonData->waitingStatus == WAITING_STATUS_SNATCH)
{
return FALSE;
}
break;
case MOVE_BEAT_UP:
case MOVE_BLOWBACK:
case MOVE_HURL:
case MOVE_MEMENTO:
case MOVE_ROAR:
case MOVE_STAY_AWAY:
case MOVE_SWITCHER:
case MOVE_TELEPORT:
case MOVE_VITAL_THROW:
case MOVE_WARP:
case MOVE_WHIRLWIND:
if (IsBossBattle())
{
return FALSE;
}
break;
case MOVE_CONVERSION_2:
if (pokemonData->protectionStatus == PROTECTION_STATUS_CONVERSION_2)
{
return FALSE;
}
break;
case MOVE_HELPING_HAND:
if (pokemonData->isEnemy)
{
s32 i;
for (i = 0; i < DUNGEON_MAX_WILD_POKEMON; i++)
{
struct DungeonEntity *target = gDungeonGlobalData->wildPokemon[i];
if (EntityExists(target) && target != pokemon && CanSee(pokemon, target))
{
if (target->entityData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE)
{
continue;
}
if (target->entityData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE)
{
break;
}
}
}
if (i == DUNGEON_MAX_WILD_POKEMON)
{
return FALSE;
}
break;
}
else
{
s32 i;
for (i = 0; i < MAX_TEAM_MEMBERS; i++)
{
struct DungeonEntity *target = gDungeonGlobalData->teamPokemon[i];
if (EntityExists(target) && target != pokemon && CanSee(pokemon, target))
{
if (target->entityData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE)
{
continue;
}
if (target->entityData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE)
{
break;
}
}
}
if (i == MAX_TEAM_MEMBERS)
{
return FALSE;
}
break;
}
}
return TRUE;
}
bool8 CanUseOnTargetWithStatusChecker(struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move)
{
struct DungeonEntityData *userData = user->entityData;
struct DungeonEntityData *targetData = target->entityData;
s32 i;
if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_FROZEN && MoveCannotHitFrozen(move))
{
return FALSE;
}
switch (move->moveID)
{
case MOVE_GRASSWHISTLE:
case MOVE_HYPNOSIS:
case MOVE_LOVELY_KISS:
case MOVE_SING:
case MOVE_SLEEP_POWDER:
case MOVE_SPORE:
if (IsSleeping(target))
{
return FALSE;
}
break;
case MOVE_YAWN:
if (targetData->sleepStatus == SLEEP_STATUS_YAWNING)
{
return FALSE;
}
if (IsSleeping(target))
{
return FALSE;
}
break;
case MOVE_NIGHTMARE:
if (targetData->sleepStatus == SLEEP_STATUS_NIGHTMARE)
{
return FALSE;
}
break;
case MOVE_SWEET_SCENT:
if (targetData->accuracyStages[STAT_STAGE_EVASION] <= 0)
{
return FALSE;
}
break;
case MOVE_CHARM:
if (targetData->attackMultipliers[STAT_STAGE_ATTACK] < STAT_MULTIPLIER_THRESHOLD)
{
return FALSE;
}
break;
case MOVE_ENCORE:
if (targetData->volatileStatus == VOLATILE_STATUS_ENCORE)
{
return FALSE;
}
if (!HasLastUsedMove(targetData->moves))
{
return FALSE;
}
break;
case MOVE_SUPER_FANG:
if (targetData->HP <= 1)
{
return FALSE;
}
break;
case MOVE_PAIN_SPLIT:
if (targetData->HP <= userData->HP)
{
return FALSE;
}
break;
case MOVE_TORMENT:
if (HasDisabledMove(targetData->moves) || !HasLastUsedMove(targetData->moves))
{
return FALSE;
}
break;
case MOVE_COTTON_SPORE:
case MOVE_SCARY_FACE:
case MOVE_STRING_SHOT:
if (target->entityData->movementSpeed <= 0)
{
return FALSE;
}
break;
case MOVE_SCREECH:
if (targetData->defenseMultipliers[STAT_STAGE_DEFENSE] < STAT_MULTIPLIER_THRESHOLD)
{
return FALSE;
}
break;
case MOVE_FAKE_TEARS:
if (targetData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] <= 0)
{
return FALSE;
}
break;
case MOVE_SPITE:
if (LastUsedMoveOutOfPP(targetData->moves))
{
return FALSE;
}
break;
case MOVE_SMOKESCREEN:
if (targetData->moveStatus == MOVE_STATUS_WHIFFER)
{
return FALSE;
}
break;
case MOVE_MEMENTO:
if (targetData->attackMultipliers[STAT_STAGE_ATTACK] < STAT_MULTIPLIER_THRESHOLD &&
targetData->attackMultipliers[STAT_STAGE_SPECIAL_ATTACK] < STAT_MULTIPLIER_THRESHOLD)
{
return FALSE;
}
break;
case MOVE_WILL_O_WISP:
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BURNED)
{
return FALSE;
}
break;
case MOVE_FORESIGHT:
case MOVE_ODOR_SLEUTH:
if (targetData->types[0] == TYPE_GHOST || targetData->types[1] == TYPE_GHOST)
{
if (!targetData->exposedStatus)
{
break;
}
}
if (targetData->accuracyStages[STAT_STAGE_EVASION] <= DEFAULT_STAT_STAGE)
{
return FALSE;
}
break;
case MOVE_DISABLE:
case MOVE_GLARE:
case MOVE_STUN_SPORE:
case MOVE_THUNDER_WAVE:
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_PARALYZED)
{
return FALSE;
}
break;
case MOVE_ENDEAVOR:
if (targetData->HP - userData->HP <= 0)
{
return FALSE;
}
break;
case MOVE_LEER:
case MOVE_TAIL_WHIP:
if (targetData->defenseStages[STAT_STAGE_DEFENSE] <= 0)
{
return FALSE;
}
break;
case MOVE_METAL_SOUND:
if (targetData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] <= 0)
{
return FALSE;
}
break;
case MOVE_TICKLE:
if (targetData->attackStages[STAT_STAGE_ATTACK] <= 0 &&
targetData->defenseStages[STAT_STAGE_DEFENSE] <= 0)
{
return FALSE;
}
break;
case MOVE_BLOCK:
case MOVE_MEAN_LOOK:
case MOVE_SPIDER_WEB:
if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_IMMOBILIZED)
{
return FALSE;
}
break;
case MOVE_HAZE:
{
for (i = 0; i < 2; i++)
{
if (targetData->attackStages[i] < DEFAULT_STAT_STAGE) break;
if (targetData->defenseStages[i] < DEFAULT_STAT_STAGE) break;
if (targetData->accuracyStages[i] < DEFAULT_STAT_STAGE ||
targetData->attackMultipliers[i] < DEFAULT_STAT_MULTIPLIER ||
targetData->defenseMultipliers[i] < DEFAULT_STAT_MULTIPLIER)
{
break;
}
}
if (i == 2)
{
return FALSE;
}
break;
}
case MOVE_UPROAR:
if (targetData->sleepStatus == SLEEP_STATUS_SLEEPLESS)
{
return FALSE;
}
break;
case MOVE_PSYCH_UP:
{
for (i = 0; i < 2; i++)
{
if (userData->attackStages[i] < targetData->attackStages[i]) break;
if (userData->defenseStages[i] < targetData->defenseStages[i] ||
userData->accuracyStages[i] < targetData->accuracyStages[i] ||
userData->attackMultipliers[i] < targetData->attackMultipliers[i] ||
userData->defenseMultipliers[i] < targetData->defenseMultipliers[i])
{
break;
}
}
if (i == 2)
{
return FALSE;
}
break;
}
case MOVE_FLASH:
case MOVE_KINESIS:
case MOVE_SAND_ATTACK:
if (targetData->accuracyStages[STAT_STAGE_ACCURACY] <= 0)
{
return FALSE;
}
break;
case MOVE_TAUNT:
if (targetData->volatileStatus == VOLATILE_STATUS_TAUNTED)
{
return FALSE;
}
break;
case MOVE_TRICK:
if (!(userData->heldItem.itemFlags & ITEM_FLAG_EXISTS) ||
!(targetData->heldItem.itemFlags & ITEM_FLAG_EXISTS))
{
return FALSE;
}
break;
case MOVE_KNOCK_OFF:
if (!(targetData->heldItem.itemFlags & ITEM_FLAG_EXISTS))
{
return FALSE;
}
break;
case MOVE_FEATHERDANCE:
case MOVE_GROWL:
if (targetData->attackStages[STAT_STAGE_ATTACK] <= 0)
{
return FALSE;
}
break;
case MOVE_ROLE_PLAY:
if (userData->abilities[0] == targetData->abilities[0] &&
userData->abilities[1] == targetData->abilities[1])
{
return FALSE;
}
break;
case MOVE_CURSE:
if (HasType(user, TYPE_GHOST))
{
if (targetData->waitingStatus == WAITING_STATUS_CURSED)
{
return FALSE;
}
}
else
{
if (userData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE &&
userData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE)
{
return FALSE;
}
}
break;
case MOVE_IMPRISON:
case MOVE_OBSERVER:
if (targetData->volatileStatus == VOLATILE_STATUS_PAUSED)
{
return FALSE;
}
break;
case MOVE_FALSE_SWIPE:
if (targetData->HP <= 1)
{
return FALSE;
}
break;
case MOVE_LEECH_SEED:
if (targetData->linkedStatus == LINKED_STATUS_LEECH_SEED)
{
return FALSE;
}
break;
case MOVE_PERISH_SONG:
if (targetData->perishSongTimer != 0)
{
return FALSE;
}
break;
case MOVE_MIMIC:
case MOVE_SKETCH:
if (!HasLastUsedMove(targetData->moves))
{
return FALSE;
}
break;
case MOVE_ATTRACT:
if (targetData->volatileStatus == VOLATILE_STATUS_INFATUATED)
{
return FALSE;
}
break;
case MOVE_WRAP:
if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_WRAPPED_AROUND_FOE)
{
return FALSE;
}
if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_WRAPPED_BY_FOE)
{
return FALSE;
}
break;
case MOVE_TOXIC:
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BADLY_POISONED)
{
return FALSE;
}
break;
case MOVE_POISON_GAS:
case MOVE_POISONPOWDER:
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_POISONED)
{
return FALSE;
}
if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BADLY_POISONED)
{
return FALSE;
}
break;
case MOVE_CONFUSE_RAY:
case MOVE_FLATTER:
case MOVE_SUPERSONIC:
case MOVE_SWAGGER:
case MOVE_SWEET_KISS:
case MOVE_TEETER_DANCE:
case MOVE_TOTTER:
if (targetData->volatileStatus == VOLATILE_STATUS_CONFUSED)
{
return FALSE;
}
break;
}
return TRUE;
}
bool8 HasDisabledMove(struct PokemonMove *moves)
{
s32 i;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i].moveFlags & MOVE_FLAG_EXISTS && moves[i].moveFlags & MOVE_FLAG_DISABLED)
{
return TRUE;
}
}
if (moves[STRUGGLE_MOVE_INDEX].moveFlags & MOVE_FLAG_DISABLED)
{
return TRUE;
}
return FALSE;
}
bool8 LastUsedMoveOutOfPP(struct PokemonMove *moves)
{
s32 i;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i].moveFlags & MOVE_FLAG_EXISTS &&
moves[i].moveFlags & MOVE_FLAG_LAST_USED &&
moves[i].PP == 0)
{
return TRUE;
}
}
return FALSE;
}
bool8 HasLastUsedMove(struct PokemonMove *moves)
{
s32 i;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i].moveFlags & MOVE_FLAG_EXISTS && moves[i].moveFlags & MOVE_FLAG_LAST_USED)
{
return TRUE;
}
}
if (moves[STRUGGLE_MOVE_INDEX].moveFlags & MOVE_FLAG_LAST_USED)
{
return TRUE;
}
return FALSE;
}