summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dungeon_ai_attack_1.c5
-rw-r--r--src/dungeon_pokemon_attributes.c4
-rw-r--r--src/status_checker.c2
-rw-r--r--src/type_chart.c27
-rw-r--r--src/type_effectiveness.c178
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;
+}