diff options
Diffstat (limited to 'src/status_checker.c')
-rw-r--r-- | src/status_checker.c | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/src/status_checker.c b/src/status_checker.c new file mode 100644 index 0000000..07d6c7f --- /dev/null +++ b/src/status_checker.c @@ -0,0 +1,537 @@ +#include "global.h" +#include "status_checker.h" + +#include "constants/move_id.h" +#include "constants/status.h" +#include "constants/type.h" +#include "constants/weather.h" +#include "dungeon_engine.h" +#include "dungeon_global_data.h" +#include "dungeon_pokemon_attributes.h" +#include "dungeon_util.h" +#include "dungeon_visibility.h" +#include "map.h" +#include "number_util.h" +#include "status_checks_1.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->attackStage >= MAX_STAT_STAGE) + { + return FALSE; + } + break; + case MOVE_BELLY_DRUM: + if (pokemonData->attackStage >= 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->defenseStage >= 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->defenseStage >= MAX_STAT_STAGE && pokemonData->specialDefenseStage >= 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->evasionStage >= 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->attackStage >= MAX_STAT_STAGE && pokemonData->defenseStage >= MAX_STAT_STAGE) + { + return FALSE; + } + break; + case MOVE_CAMOUFLAGE: + if (HasType(pokemon, gDungeonCamouflageTypes[gDungeonGlobalData->tileset])) + { + return FALSE; + } + break; + case MOVE_TAIL_GLOW: + if (pokemonData->specialAttackStage >= 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->attackStage >= 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->evasionStage >= MAX_STAT_STAGE) + { + return FALSE; + } + break; + case MOVE_GROWTH: + if (pokemonData->specialAttackStage >= MAX_STAT_STAGE) + { + return FALSE; + } + break; + case MOVE_SWORDS_DANCE: + if (pokemonData->attackStage >= 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->specialAttackStage < MAX_STAT_STAGE) + { + break; + } + case MOVE_AMNESIA: + if (pokemonData->specialDefenseStage >= 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->attackStage >= MAX_STAT_STAGE) + { + continue; + } + if (target->entityData->specialAttackStage < 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->attackStage >= MAX_STAT_STAGE) + { + continue; + } + if (target->entityData->specialAttackStage < MAX_STAT_STAGE) + { + break; + } + } + } + if (i == MAX_TEAM_MEMBERS) + { + return FALSE; + } + break; + } + } + return TRUE; +} |