diff options
author | Seth Barberee <seth.barberee@gmail.com> | 2022-03-11 10:10:49 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-11 10:10:49 -0800 |
commit | 30fea2d6f303e0e57b62032f56da86c8223ef1f7 (patch) | |
tree | 9636ef46bb5f555874dc8ba16c82dc79bc563a12 /src/type_effectiveness.c | |
parent | ea1aa9c0c5c3a4167912d1078fffdd5e69cbbe98 (diff) | |
parent | cf492fd141b33c21f369dfa7aabebf3c52cb8ec1 (diff) |
Merge pull request #98 from AnonymousRandomPerson/master
Finished attack AI decomp
Diffstat (limited to 'src/type_effectiveness.c')
-rw-r--r-- | src/type_effectiveness.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/type_effectiveness.c b/src/type_effectiveness.c new file mode 100644 index 0000000..8a9ee04 --- /dev/null +++ b/src/type_effectiveness.c @@ -0,0 +1,174 @@ +#include "global.h" +#include "type_effectiveness.h" + +#include "constants/ability.h" +#include "constants/status.h" +#include "constants/weather.h" +#include "dungeon_global_data.h" +#include "dungeon_pokemon_attributes.h" +#include "dungeon_util.h" +#include "status.h" +#include "type_chart.h" +#include "weather.h" + +u32 gTypeEffectivenessMultipliers[] = {0, 1, 2, 4}; + +s32 WeightWeakTypePicker(struct DungeonEntity *user, struct DungeonEntity *target, u8 moveType) +{ + s32 weight = 1; + bool8 checkExposed = FALSE; + struct DungeonEntityData *userData; + struct DungeonEntityData *targetData; + u8 *targetTypes; + u8 *targetType; + u32 moveTypeOffset; + if (!EntityExists(target)) + { + return 1; + } + if (moveType == TYPE_NORMAL || moveType == TYPE_FIGHTING) + { + checkExposed = TRUE; + } + userData = user->entityData; + targetData = target->entityData; + if (moveType == TYPE_FIRE && GetFlashFireStatus(target) != FLASH_FIRE_STATUS_NONE) + { + return 0; + } + if (moveType == TYPE_ELECTRIC && HasAbility(target, ABILITY_VOLT_ABSORB)) + { + return 0; + } + if (moveType == TYPE_WATER && HasAbility(target, ABILITY_WATER_ABSORB)) + { + return 0; + } + if (moveType == TYPE_GROUND && HasAbility(target, ABILITY_LEVITATE)) + { + return 1; + } + targetTypes = targetData->types; + moveTypeOffset = moveType * NUM_TYPES * sizeof(s16); + targetType = targetData->types; + do + { + s32 effectiveness; + u32 typeEffectivenessMultipliers[NUM_EFFECTIVENESS]; + memcpy(typeEffectivenessMultipliers, gTypeEffectivenessMultipliers, NUM_EFFECTIVENESS * sizeof(u32)); + if (checkExposed && *targetType == TYPE_GHOST && !targetData->exposedStatus) + { + effectiveness = 0; + gDungeonGlobalData->pokemonExposed = TRUE; + } + else + { + effectiveness = gTypeEffectivenessChart[moveType][*targetType]; + // Used to swap variable initialization order at the loop start. + effectiveness = *(s16*)(((s8*) gTypeEffectivenessChart) + moveTypeOffset + *targetType * 2); + } + if (weight == 0) + { + goto breakLoop; + } + weight *= typeEffectivenessMultipliers[effectiveness]; + weight /= 2; + if (weight == 0) + { + // BUG: If the Pokémon's first type resists the move, the second type is ignored. + // This calculates type effectiveness incorrectly if the first type resists the move and the second type is weak to the move. + // For example, a Fire-type move is considered not very effective against a Rock/Bug-type like Anorith. + return 2; + } + } while ((s32)(++targetType) <= (s32)(targetTypes + 1)); + breakLoop: + if ((moveType == TYPE_FIRE || moveType == TYPE_ICE) && HasAbility(target, ABILITY_THICK_FAT)) + { + return 2; + } + if (moveType == TYPE_WATER && HasAbility(user, ABILITY_TORRENT)) + { + s32 maxHP = userData->maxHP; + if (maxHP < 0) + { + maxHP += 3; + } + if (maxHP >> 2 >= userData->HP) + { + weight *= 2; + } + } + if (moveType == TYPE_GRASS && HasAbility(user, ABILITY_OVERGROW)) + { + s32 maxHP = userData->maxHP; + if (maxHP < 0) + { + maxHP += 3; + } + if (maxHP >> 2 >= userData->HP) + { + weight *= 2; + } + } + if (moveType == TYPE_BUG && HasAbility(user, ABILITY_SWARM)) + { + s32 maxHP = userData->maxHP; + if (maxHP < 0) + { + maxHP += 3; + } + if (maxHP >> 2 >= userData->HP) + { + weight *= 2; + } + } + if (moveType == TYPE_FIRE && HasAbility(user, ABILITY_BLAZE)) + { + s32 maxHP = userData->maxHP; + if (maxHP < 0) + { + maxHP += 3; + } + if (maxHP >> 2 >= userData->HP) + { + weight *= 2; + } + } + if (weight == 0) + { + return 2; + } + if (HasType(user, moveType)) + { + weight *= 2; + } + targetTypes = targetData->types; + if (GetWeather(user) == WEATHER_SUNNY) + { + if (moveType == TYPE_FIRE) + { + weight *= 2; + } + else if (moveType == TYPE_WATER) + { + return 2; + } + } + if (gDungeonGlobalData->mudSportTurnsLeft != 0 && moveType == TYPE_ELECTRIC) + { + return 2; + } + if (gDungeonGlobalData->waterSportTurnsLeft != 0 && moveType == TYPE_FIRE) + { + return 2; + } + if (moveType == TYPE_ELECTRIC && userData->chargingStatus == CHARGING_STATUS_CHARGE) + { + weight *= 2; + } + if (weight > 2) + { + weight = 3; + } + return weight + 2; +} |