diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dungeon_ai_attack.c | 219 | ||||
-rw-r--r-- | src/dungeon_ai_items.c | 8 | ||||
-rw-r--r-- | src/moves.c | 4 |
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; } |