summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dungeon_ai_attack.c219
-rw-r--r--src/dungeon_ai_items.c8
-rw-r--r--src/moves.c4
3 files changed, 218 insertions, 13 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
diff --git a/src/dungeon_ai_items.c b/src/dungeon_ai_items.c
index 2b1bb71..5e60708 100644
--- a/src/dungeon_ai_items.c
+++ b/src/dungeon_ai_items.c
@@ -40,7 +40,7 @@ extern void sub_8077274(struct DungeonEntity *, struct DungeonEntity *);
extern s32 gNumPotentialTargets;
extern u32 gPotentialTargetWeights[NUM_DIRECTIONS];
-extern u32 gPotentialTargetDirections[NUM_DIRECTIONS];
+extern u32 gPotentialItemTargetDirections[NUM_DIRECTIONS];
extern bool8 gTargetAhead[NUM_DIRECTIONS];
extern struct TeamInventory *gTeamInventory_203B460;
@@ -101,7 +101,7 @@ void DecideUseItem(struct DungeonEntity *pokemon)
pokemonData->action.actionUseIndex = selectedToolboxIndex;
pokemonData->action.lastItemThrowPosition.x = pokemon->posWorld.x;
pokemonData->action.lastItemThrowPosition.y = pokemon->posWorld.y;
- pokemonData->action.facingDir = gPotentialTargetDirections[targetIndex] & DIRECTION_MASK;
+ pokemonData->action.facingDir = gPotentialItemTargetDirections[targetIndex] & DIRECTION_MASK;
break;
}
}
@@ -261,7 +261,7 @@ void DecideUseItem(struct DungeonEntity *pokemon)
pokemonData->action.actionUseIndex = selectedToolboxIndex;
pokemonData->action.lastItemThrowPosition.x = pokemon->posWorld.x;
pokemonData->action.lastItemThrowPosition.y = pokemon->posWorld.y;
- pokemonData->action.facingDir = gPotentialTargetDirections[targetIndex] & DIRECTION_MASK;
+ pokemonData->action.facingDir = gPotentialItemTargetDirections[targetIndex] & DIRECTION_MASK;
return;
}
}
@@ -421,7 +421,7 @@ void TargetThrownItem(struct DungeonEntity *pokemon, struct DungeonEntity *targe
u32 itemWeight;
u32 *targetWeight;
gTargetAhead[targetDirection] = TRUE;
- gPotentialTargetDirections[gNumPotentialTargets] = targetDirection;
+ gPotentialItemTargetDirections[gNumPotentialTargets] = targetDirection;
targetWeight = &gPotentialTargetWeights[gNumPotentialTargets];
itemWeight = !ignoreRollChance ? EvaluateItem(targetPokemon, item, targetingFlags) : 100;
*targetWeight = itemWeight;
diff --git a/src/moves.c b/src/moves.c
index 54927d8..2a0703b 100644
--- a/src/moves.c
+++ b/src/moves.c
@@ -271,12 +271,12 @@ u8 GetMoveCriticalHitChance(struct PokemonMove *move)
return gMovesData[move->moveID].criticalHitChance;
}
-u8 GetMoveCannotHitFrozen(struct PokemonMove *move)
+bool8 GetMoveCannotHitFrozen(struct PokemonMove *move)
{
return gMovesData[move->moveID].cannotHitFrozen;
}
-u8 GetMoveDealsDirectDamage(struct PokemonMove *move)
+bool8 GetMoveDealsDirectDamage(struct PokemonMove *move)
{
return gMovesData[move->moveID].dealsDirectDamage;
}