diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dungeon_ai_attack_1.c | 5 | ||||
-rw-r--r-- | src/dungeon_pokemon_attributes.c | 4 | ||||
-rw-r--r-- | src/status_checker.c | 2 | ||||
-rw-r--r-- | src/type_chart.c | 27 | ||||
-rw-r--r-- | src/type_effectiveness.c | 178 |
5 files changed, 210 insertions, 6 deletions
diff --git a/src/dungeon_ai_attack_1.c b/src/dungeon_ai_attack_1.c index 6f70077..cef0aac 100644 --- a/src/dungeon_ai_attack_1.c +++ b/src/dungeon_ai_attack_1.c @@ -13,14 +13,13 @@ #include "position_util.h" #include "status_checker.h" #include "status_checks_1.h" +#include "type_effectiveness.h" extern bool8 gCanAttackInDirection[NUM_DIRECTIONS]; extern s32 gPotentialAttackTargetWeights[NUM_DIRECTIONS]; extern u8 gPotentialAttackTargetDirections[NUM_DIRECTIONS]; extern struct DungeonEntity *gPotentialTargets[NUM_DIRECTIONS]; -extern s32 WeightWeakTypePicker(struct DungeonEntity *user, struct DungeonEntity *target, u8 moveType); - s32 WeightMoveIfUsable(s32 numPotentialTargets, s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) { s32 facingDir; @@ -147,7 +146,7 @@ bool8 CanUseStatusMove(s32 targetingFlags, struct DungeonEntity *user, struct Du else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_EXPOSE) { targetData = target->entityData; - if ((targetData->type1 != TYPE_GHOST && targetData->type2 != TYPE_GHOST) || targetData->exposedStatus) + if ((targetData->types[0] != TYPE_GHOST && targetData->types[1] != TYPE_GHOST) || targetData->exposedStatus) { if (*categoryTargetingFlags2); // Flips the conditional. goto returnFalse; diff --git a/src/dungeon_pokemon_attributes.c b/src/dungeon_pokemon_attributes.c index 671162d..0550d7d 100644 --- a/src/dungeon_pokemon_attributes.c +++ b/src/dungeon_pokemon_attributes.c @@ -110,11 +110,11 @@ bool8 HasType(struct DungeonEntity *pokemon, u8 type) { return FALSE; } - if (pokemonData->type1 == type) + if (pokemonData->types[0] == type) { return TRUE; } - if (pokemonData->type2 == type) + if (pokemonData->types[1] == type) { return TRUE; } diff --git a/src/status_checker.c b/src/status_checker.c index 5dfe0f0..0aaeddf 100644 --- a/src/status_checker.c +++ b/src/status_checker.c @@ -662,7 +662,7 @@ bool8 CanUseOnTargetWithStatusChecker(struct DungeonEntity *user, struct Dungeon break; case MOVE_FORESIGHT: case MOVE_ODOR_SLEUTH: - if (targetData->type1 == TYPE_GHOST || targetData->type2 == TYPE_GHOST) + if (targetData->types[0] == TYPE_GHOST || targetData->types[1] == TYPE_GHOST) { if (!targetData->exposedStatus) { diff --git a/src/type_chart.c b/src/type_chart.c new file mode 100644 index 0000000..66a993a --- /dev/null +++ b/src/type_chart.c @@ -0,0 +1,27 @@ +#include "type_chart.h" + +#define IMMUNE EFFECTIVENESS_IMMUNE +#define RESIST EFFECTIVENESS_RESIST +#define NEUTRAL EFFECTIVENESS_NEUTRAL +#define SUPER EFFECTIVENESS_SUPER + +const s16 gTypeEffectivenessChart[NUM_TYPES][NUM_TYPES] = { + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, RESIST}, + {NEUTRAL, NEUTRAL, RESIST, RESIST, SUPER, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, NEUTRAL, RESIST, NEUTRAL, SUPER}, + {NEUTRAL, NEUTRAL, SUPER, RESIST, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, NEUTRAL, NEUTRAL}, + {NEUTRAL, NEUTRAL, RESIST, SUPER, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, SUPER, RESIST, NEUTRAL, RESIST, SUPER, NEUTRAL, RESIST, NEUTRAL, RESIST}, + {NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, IMMUNE, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, NEUTRAL}, + {NEUTRAL, NEUTRAL, RESIST, RESIST, SUPER, NEUTRAL, RESIST, NEUTRAL, NEUTRAL, SUPER, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST}, + {NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, NEUTRAL, RESIST, RESIST, RESIST, SUPER, NEUTRAL, NEUTRAL, SUPER, SUPER}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, RESIST, NEUTRAL, NEUTRAL, IMMUNE}, + {NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, SUPER, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, IMMUNE, NEUTRAL, RESIST, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, SUPER}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, RESIST}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, SUPER, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, IMMUNE, RESIST}, + {NEUTRAL, NEUTRAL, RESIST, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, RESIST, RESIST, NEUTRAL, RESIST, SUPER, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, SUPER, RESIST}, + {NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, NEUTRAL, RESIST, SUPER, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, RESIST}, + {NEUTRAL, IMMUNE, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, RESIST}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, RESIST}, + {NEUTRAL, NEUTRAL, RESIST, RESIST, NEUTRAL, RESIST, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, RESIST} +}; diff --git a/src/type_effectiveness.c b/src/type_effectiveness.c new file mode 100644 index 0000000..efc1ef9 --- /dev/null +++ b/src/type_effectiveness.c @@ -0,0 +1,178 @@ +#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 "type_chart.h" +#include "weather.h" + +#define FLASH_FIRE_STATUS_NONE 0 + +u32 gTypeEffectivenessMultipliers[] = {0, 1, 2, 4}; + +extern u8 GetFlashFireStatus(struct DungeonEntity *pokemon); + +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 can cause type effectiveness to be calculated 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; +} |