summaryrefslogtreecommitdiff
path: root/src/dungeon_ai_attack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dungeon_ai_attack.c')
-rw-r--r--src/dungeon_ai_attack.c219
1 files changed, 212 insertions, 7 deletions
diff --git a/src/dungeon_ai_attack.c b/src/dungeon_ai_attack.c
index 416d4da..5667d75 100644
--- a/src/dungeon_ai_attack.c
+++ b/src/dungeon_ai_attack.c
@@ -11,12 +11,18 @@
#include "charge_move.h"
#include "dungeon_action.h"
#include "dungeon_ai.h"
+#include "dungeon_ai_attack_1.h"
#include "dungeon_capabilities_1.h"
+#include "dungeon_global_data.h"
+#include "dungeon_map_access.h"
#include "dungeon_pokemon_attributes.h"
#include "dungeon_pokemon_attributes_1.h"
#include "dungeon_random.h"
#include "dungeon_random_1.h"
+#include "dungeon_util.h"
+#include "dungeon_visibility.h"
#include "moves.h"
+#include "position_util.h"
#include "status_checks.h"
#include "targeting.h"
@@ -24,16 +30,21 @@
const s16 gRegularAttackWeights[] = {100, 20, 30, 40, 50};
-struct MoveTargetResults
-{
- bool8 moveUsable;
- u8 targetDir;
- s32 moveWeight;
-};
+extern bool8 gCanAttackInDirection[NUM_DIRECTIONS];
+extern s32 gNumPotentialTargets;
+extern s32 gPotentialTargetWeights_2[NUM_DIRECTIONS];
+extern u8 gPotentialAttackTargetDirections[NUM_DIRECTIONS];
+extern struct DungeonEntity *gPotentialTargets[NUM_DIRECTIONS];
-extern s32 FindMoveTarget(struct MoveTargetResults*, struct DungeonEntity*, struct PokemonMove*);
extern bool8 IsMoveUsable(struct DungeonEntity*, s32, bool8);
extern bool8 TargetRegularAttack(struct DungeonEntity*, u32*, bool8);
+extern s16 GetTargetingFlags(struct DungeonEntity*, struct PokemonMove*, bool8);
+extern bool8 CanUseWithStatusChecker(struct DungeonEntity*, struct PokemonMove*);
+extern bool8 CanAttackInFront(struct DungeonEntity*, s32);
+extern s32 WeightMoveIfUsable(s32, s32, struct DungeonEntity*, struct DungeonEntity*, struct PokemonMove*, bool8);
+extern bool8 IsTargetInLineRange(struct DungeonEntity*, struct DungeonEntity*, s32);
+extern bool8 CanUseStatusMove(s32, struct DungeonEntity*, struct DungeonEntity*, struct PokemonMove*, bool8);
+extern s32 WeightMove(struct DungeonEntity*, s32, struct DungeonEntity*, u8);
void DecideAttack(struct DungeonEntity *pokemon)
{
@@ -320,3 +331,197 @@ void DecideAttack(struct DungeonEntity *pokemon)
TargetTileInFront(pokemon);
}
}
+
+s32 FindMoveTarget(struct MoveTargetResults *moveTargetResults, struct DungeonEntity *pokemon, struct PokemonMove *move)
+{
+ s32 targetingFlags;
+ s32 moveWeight = 1;
+ struct DungeonEntityData *pokemonData = pokemon->entityData;
+ s32 numPotentialTargets = 0;
+ s32 i;
+ bool8 hasStatusChecker;
+ s32 rangeTargetingFlags;
+ s32 rangeTargetingFlags2;
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ gCanAttackInDirection[i] = FALSE;
+ }
+ targetingFlags = GetTargetingFlags(pokemon, move, TRUE);
+ hasStatusChecker = HasIQSkill(pokemon, IQ_SKILL_STATUS_CHECKER);
+ moveTargetResults->moveUsable = FALSE;
+ if ((pokemonData->volatileStatus == VOLATILE_STATUS_TAUNTED && !GetMoveDealsDirectDamage(move)) ||
+ (hasStatusChecker && !CanUseWithStatusChecker(pokemon, move)))
+ {
+ return 1;
+ }
+ rangeTargetingFlags = targetingFlags & 0xF0;
+ if (rangeTargetingFlags == TARGETING_FLAG_TARGET_OTHER ||
+ rangeTargetingFlags == TARGETING_FLAG_TARGET_FRONTAL_CONE ||
+ rangeTargetingFlags == TARGETING_FLAG_TARGET_AROUND)
+ {
+ if (pokemonData->eyesightStatus == EYESIGHT_STATUS_BLINKER)
+ {
+ u8 facingDir = pokemonData->action.facingDir;
+ i = facingDir; // Fixes a regswap.
+ if (!gCanAttackInDirection[i])
+ {
+ gCanAttackInDirection[i] = TRUE;
+ gPotentialAttackTargetDirections[numPotentialTargets] = i;
+ gPotentialTargetWeights_2[numPotentialTargets] = 99;
+ gPotentialTargets[numPotentialTargets] = NULL;
+ numPotentialTargets++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ // Double assignment to fix a regswap.
+ s16 rangeTargetingFlags = rangeTargetingFlags2 = targetingFlags & 0xF0;
+ struct MapTile *adjacentTile = GetMapTileAtPosition(pokemon->posWorld.x + gAdjacentTileOffsets[i].x,
+ pokemon->posWorld.y + gAdjacentTileOffsets[i].y);
+ struct DungeonEntity *adjacentPokemon = adjacentTile->pokemon;
+ if (adjacentPokemon != NULL && GetEntityType(adjacentPokemon) == ENTITY_POKEMON)
+ {
+ if (rangeTargetingFlags != TARGETING_FLAG_TARGET_FRONTAL_CONE &&
+ rangeTargetingFlags != TARGETING_FLAG_TARGET_AROUND)
+ {
+ if (!CanAttackInFront(pokemon, i))
+ {
+ continue;
+ }
+ }
+ numPotentialTargets = WeightMoveIfUsable(numPotentialTargets, targetingFlags, pokemon, adjacentPokemon, move, hasStatusChecker);
+ }
+ }
+ }
+ }
+ else if (rangeTargetingFlags == TARGETING_FLAG_TARGET_ROOM)
+ {
+ s32 i;
+ for (i = 0; i < DUNGEON_MAX_POKEMON; i++)
+ {
+ struct DungeonEntity *target = gDungeonGlobalData->allPokemon[i];
+ if (EntityExists(target) && CanSee(pokemon, target))
+ {
+ numPotentialTargets = WeightMoveIfUsable(numPotentialTargets, targetingFlags, pokemon, target, move, hasStatusChecker);
+ }
+ }
+ }
+ else if (rangeTargetingFlags == TARGETING_FLAG_TARGET_2_TILES_AHEAD)
+ {
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ struct MapTile *targetTile = GetMapTileAtPosition(pokemon->posWorld.x + gAdjacentTileOffsets[i].x,
+ pokemon->posWorld.y + gAdjacentTileOffsets[i].y);
+ if (CanAttackInFront(pokemon, i))
+ {
+ struct DungeonEntity *targetPokemon = targetTile->pokemon;
+ if (targetPokemon != NULL && GetEntityType(targetPokemon) == ENTITY_POKEMON)
+ {
+ s32 prevNumPotentialTargets = numPotentialTargets;
+ numPotentialTargets = WeightMoveIfUsable(numPotentialTargets, targetingFlags, pokemon, targetPokemon, move, hasStatusChecker);
+ if (prevNumPotentialTargets != numPotentialTargets)
+ {
+ continue;
+ }
+ }
+ targetTile = GetMapTileAtPosition(pokemon->posWorld.x + gAdjacentTileOffsets[i].x * 2,
+ pokemon->posWorld.y + gAdjacentTileOffsets[i].y * 2);
+ targetPokemon = targetTile->pokemon;
+ if (targetPokemon != NULL && GetEntityType(targetPokemon) == ENTITY_POKEMON)
+ {
+ numPotentialTargets = WeightMoveIfUsable(numPotentialTargets, targetingFlags, pokemon, targetPokemon, move, hasStatusChecker);
+ }
+ }
+ }
+ }
+ else if (rangeTargetingFlags == TARGETING_FLAG_TARGET_LINE || rangeTargetingFlags == TARGETING_FLAG_CUT_CORNERS)
+ {
+ s32 maxRange = 1;
+ s32 i;
+ if (rangeTargetingFlags == TARGETING_FLAG_TARGET_LINE)
+ {
+ maxRange = 10;
+ }
+ for (i = 0; i < DUNGEON_MAX_POKEMON; i++)
+ {
+ struct DungeonEntity *target = gDungeonGlobalData->allPokemon[i];
+ if (EntityExists(target) && pokemon != target)
+ {
+ s32 facingDir = CalculateFacingDir(&pokemon->posWorld, &target->posWorld);
+ if (!gCanAttackInDirection[facingDir] &&
+ CanSee(pokemon, target) &&
+ IsTargetInLineRange(pokemon, target, maxRange) &&
+ CanUseStatusMove(targetingFlags, pokemon, target, move, hasStatusChecker) &&
+ IsTargetStraightAhead(pokemon, target, facingDir, maxRange))
+ {
+ gCanAttackInDirection[facingDir] = TRUE;
+ gPotentialAttackTargetDirections[numPotentialTargets] = facingDir;
+ gPotentialTargetWeights_2[numPotentialTargets] = WeightMove(pokemon, targetingFlags, target, GetMoveTypeForPokemon(pokemon, move));
+ gPotentialTargets[numPotentialTargets] = target;
+ numPotentialTargets++;
+ }
+ }
+ }
+ }
+ else if (rangeTargetingFlags == TARGETING_FLAG_TARGET_FLOOR)
+ {
+ s32 i;
+ for (i = 0; i < DUNGEON_MAX_POKEMON; i++)
+ {
+ struct DungeonEntity *target = gDungeonGlobalData->allPokemon[i];
+ if (EntityExists(target))
+ {
+ numPotentialTargets = WeightMoveIfUsable(numPotentialTargets, targetingFlags, pokemon, target, move, hasStatusChecker);
+ }
+ }
+ }
+ else if (rangeTargetingFlags == TARGETING_FLAG_SELF_HEAL)
+ {
+ numPotentialTargets = WeightMoveIfUsable(numPotentialTargets, targetingFlags, pokemon, pokemon, move, hasStatusChecker);
+ }
+ if (numPotentialTargets == 0)
+ {
+ moveTargetResults->moveUsable = FALSE;
+ }
+ else
+ {
+ s32 totalWeight = 0;
+ s32 maxWeight = 0;
+ s32 weightCounter;
+ s32 i;
+ for (i = 0; i < numPotentialTargets; i++)
+ {
+ if (maxWeight < gPotentialTargetWeights_2[i])
+ {
+ maxWeight = gPotentialTargetWeights_2[i];
+ }
+ }
+ for (i = 0; i < numPotentialTargets; i++)
+ {
+ if (maxWeight != gPotentialTargetWeights_2[i])
+ {
+ gPotentialTargetWeights_2[i] = 0;
+ }
+ }
+ moveWeight = maxWeight;
+ for (i = 0; i < numPotentialTargets; i++)
+ {
+ totalWeight += gPotentialTargetWeights_2[i];
+ }
+ weightCounter = DungeonRandomCapped(totalWeight);
+ for (i = 0; i < numPotentialTargets; i++)
+ {
+ weightCounter -= gPotentialTargetWeights_2[i];
+ if (weightCounter < 0)
+ {
+ break;
+ }
+ }
+ moveTargetResults->moveUsable = TRUE;
+ moveTargetResults->targetDir = gPotentialAttackTargetDirections[i];
+ moveTargetResults->moveWeight = 8;
+ }
+ return moveWeight;
+} \ No newline at end of file