summaryrefslogtreecommitdiff
path: root/src/type_effectiveness.c
diff options
context:
space:
mode:
authorSeth Barberee <seth.barberee@gmail.com>2022-03-11 10:10:49 -0800
committerGitHub <noreply@github.com>2022-03-11 10:10:49 -0800
commit30fea2d6f303e0e57b62032f56da86c8223ef1f7 (patch)
tree9636ef46bb5f555874dc8ba16c82dc79bc563a12 /src/type_effectiveness.c
parentea1aa9c0c5c3a4167912d1078fffdd5e69cbbe98 (diff)
parentcf492fd141b33c21f369dfa7aabebf3c52cb8ec1 (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.c174
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;
+}