diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charge_move.c | 48 | ||||
-rw-r--r-- | src/code_8041AD0.c | 9 | ||||
-rw-r--r-- | src/code_8057824.c | 2 | ||||
-rw-r--r-- | src/dungeon_ai.c | 17 | ||||
-rw-r--r-- | src/dungeon_ai_1.c | 2 | ||||
-rw-r--r-- | src/dungeon_ai_attack.c | 530 | ||||
-rw-r--r-- | src/dungeon_ai_attack_1.c | 76 | ||||
-rw-r--r-- | src/dungeon_ai_item_weight.c | 6 | ||||
-rw-r--r-- | src/dungeon_ai_items.c | 12 | ||||
-rw-r--r-- | src/dungeon_ai_movement.c | 6 | ||||
-rw-r--r-- | src/dungeon_capabilities_1.c | 2 | ||||
-rw-r--r-- | src/dungeon_pokemon_attributes.c | 177 | ||||
-rw-r--r-- | src/dungeon_pokemon_attributes_1.c | 161 | ||||
-rw-r--r-- | src/dungeon_visibility.c | 2 | ||||
-rw-r--r-- | src/items.c | 2 | ||||
-rw-r--r-- | src/moves.c | 22 | ||||
-rw-r--r-- | src/moves_1.c | 8 | ||||
-rw-r--r-- | src/pokemon_3.c | 1 | ||||
-rw-r--r-- | src/status_checks.c | 4 | ||||
-rw-r--r-- | src/targeting.c | 11 | ||||
-rw-r--r-- | src/targeting_flags.c | 16 |
21 files changed, 859 insertions, 255 deletions
diff --git a/src/charge_move.c b/src/charge_move.c index 7fe358c..c0d09fc 100644 --- a/src/charge_move.c +++ b/src/charge_move.c @@ -1,9 +1,29 @@ #include "global.h" #include "charge_move.h" +#include "constants/move_id.h" #include "constants/status.h" #include "dungeon_util.h" +struct MultiTurnChargeMove +{ + u16 moveID; + u8 chargingStatus; +}; + +const struct MultiTurnChargeMove gMultiTurnChargeMoves[10] = { + {MOVE_SOLARBEAM, CHARGING_STATUS_SOLARBEAM}, + {MOVE_SKY_ATTACK, CHARGING_STATUS_SKY_ATTACK}, + {MOVE_RAZOR_WIND, CHARGING_STATUS_RAZOR_WIND}, + {MOVE_FOCUS_PUNCH, CHARGING_STATUS_FOCUS_PUNCH}, + {MOVE_SKULL_BASH, CHARGING_STATUS_SKULL_BASH}, + {MOVE_FLY, CHARGING_STATUS_FLY}, + {MOVE_BOUNCE, CHARGING_STATUS_BOUNCE}, + {MOVE_DIVE, CHARGING_STATUS_DIVE}, + {MOVE_DIG, CHARGING_STATUS_DIG}, + {MOVE_NONE, CHARGING_STATUS_NONE} +}; + const u32 gMultiTurnChargingStatuses[10] = { CHARGING_STATUS_SOLARBEAM, CHARGING_STATUS_SKY_ATTACK, @@ -19,6 +39,32 @@ const u32 gMultiTurnChargingStatuses[10] = { ALIGNED(4) const char chargingStatusFill[] = "pksdir0"; +bool8 MoveMatchesChargingStatus(struct DungeonEntity *pokemon, struct PokemonMove *move) +{ + if (!EntityExists(pokemon)) + { + return FALSE; + } + else + { + struct DungeonEntityData *pokemonData = pokemon->entityData; + s32 i; + for (i = 0; i < 100; i++) + { + if (gMultiTurnChargeMoves[i].moveID == MOVE_NONE) + { + return FALSE; + } + if (move->moveID == gMultiTurnChargeMoves[i].moveID && + pokemonData->chargingStatus == gMultiTurnChargeMoves[i].chargingStatus) + { + return TRUE; + } + } + return FALSE; + } +} + bool8 IsCharging(struct DungeonEntity *pokemon, bool8 checkCharge) { if (!EntityExists(pokemon)) @@ -53,4 +99,4 @@ bool8 IsCharging(struct DungeonEntity *pokemon, bool8 checkCharge) } return FALSE; } -} +}
\ No newline at end of file diff --git a/src/code_8041AD0.c b/src/code_8041AD0.c index 0091e9a..e1d3a1a 100644 --- a/src/code_8041AD0.c +++ b/src/code_8041AD0.c @@ -1,7 +1,9 @@ #include "global.h" +#include "constants/direction.h" +#include "constants/type.h" #include "dungeon_entity.h" #include "dungeon_global_data.h" -#include "constants/direction.h" +#include "dungeon_pokemon_attributes.h" struct unkStruct_80420E8 { @@ -16,7 +18,6 @@ extern void sub_804151C(struct DungeonEntity *r0, u32 r1, u8 r2); extern void sub_80416E0(struct DungeonEntity *r0, u32, u32); extern u8 sub_8042768(struct DungeonEntity *r0); extern void sub_806CDD4(struct DungeonEntity *r0, u8, u32); -extern u8 HasType(struct DungeonEntity *r0, u8); extern u32 sub_806F62C(u32); extern void PlaySoundEffect(u32); extern u8 sub_803F428(struct DungeonEntity *r0); @@ -343,10 +344,10 @@ void sub_8041DD8(struct DungeonEntity *r0, s16 r1) u32 temp; temp = r1; - if(HasType(r0, 0xE) != 0) + if(HasType(r0, TYPE_GHOST) != 0) sub_804151C(r0, temp, 1); else - sub_804151C(r0, 0xE, 1); + sub_804151C(r0, TYPE_GHOST, 1); } void nullsub_89(void) diff --git a/src/code_8057824.c b/src/code_8057824.c index 172f949..d763925 100644 --- a/src/code_8057824.c +++ b/src/code_8057824.c @@ -2,6 +2,7 @@ #include "dungeon_global_data.h" #include "dungeon_entity.h" #include "constants/move.h" +#include "moves.h" extern u32 gUnknown_80FCF74; extern u32 gUnknown_80FCF80; @@ -30,7 +31,6 @@ extern void sub_806F370(struct DungeonEntity *r0, struct DungeonEntity *r1, u32, extern u32 gUnknown_80FD018; extern s16 sub_8057600(void*, u32); -extern u32 GetMoveType(void*); bool32 sub_8057824(struct DungeonEntity *param_1, struct DungeonEntity *param_2) { diff --git a/src/dungeon_ai.c b/src/dungeon_ai.c index 5776bfa..b2e3b2e 100644 --- a/src/dungeon_ai.c +++ b/src/dungeon_ai.c @@ -4,16 +4,15 @@ #include "constants/ability.h" #include "constants/tactic.h" #include "dungeon_pokemon_attributes.h" -#include "dungeon_pokemon_attributes_1.h" #include "dungeon_util.h" -extern void CheckRunAwayVisualFlag(struct DungeonEntity *, u8 r1); +extern void CheckRunAwayVisualFlag(struct DungeonEntity *, bool8 showRunAwayEffect); bool8 ShouldAvoidFirstHit(struct DungeonEntity *pokemon, bool8 forceAvoid) { - if(!HasTactic(pokemon, TACTIC_AVOID_THE_FIRST_HIT)) + if (!HasTactic(pokemon, TACTIC_AVOID_THE_FIRST_HIT)) return FALSE; - if(!forceAvoid) + if (!forceAvoid) return FALSE; return TRUE; } @@ -43,8 +42,8 @@ bool8 ShouldAvoidEnemies(struct DungeonEntity *pokemon) return TRUE; } } - if (HasTactic(pokemon, TACTIC_GET_AWAY) - || (HasTactic(pokemon, TACTIC_AVOID_TROUBLE) && pokemonData->HP <= pokemonData->maxHP / 2)) + if (HasTactic(pokemon, TACTIC_GET_AWAY) || + (HasTactic(pokemon, TACTIC_AVOID_TROUBLE) && pokemonData->HP <= pokemonData->maxHP / 2)) { return TRUE; } @@ -52,11 +51,11 @@ bool8 ShouldAvoidEnemies(struct DungeonEntity *pokemon) } } -bool8 ShouldAvoidEnemies_2(struct DungeonEntity *pokemon, u8 r1) +bool8 ShouldAvoidEnemiesAndShowEffect(struct DungeonEntity *pokemon, bool8 showRunAwayEffect) { - if(ShouldAvoidEnemies(pokemon)) + if (ShouldAvoidEnemies(pokemon)) { - CheckRunAwayVisualFlag(pokemon, r1); + CheckRunAwayVisualFlag(pokemon, showRunAwayEffect); return TRUE; } return FALSE; diff --git a/src/dungeon_ai_1.c b/src/dungeon_ai_1.c index 4550c83..78c899f 100644 --- a/src/dungeon_ai_1.c +++ b/src/dungeon_ai_1.c @@ -3,7 +3,7 @@ #include "constants/status.h" #include "constants/targeting.h" -#include "dungeon_pokemon_attributes_1.h" +#include "dungeon_pokemon_attributes.h" const u8 gTargetingData[3][2][2][2] = { { diff --git a/src/dungeon_ai_attack.c b/src/dungeon_ai_attack.c index 5794038..30e5d3a 100644 --- a/src/dungeon_ai_attack.c +++ b/src/dungeon_ai_attack.c @@ -1,76 +1,526 @@ #include "global.h" #include "dungeon_ai_attack.h" +#include "constants/direction.h" +#include "constants/dungeon_action.h" #include "constants/iq_skill.h" +#include "constants/move_id.h" +#include "constants/status.h" +#include "constants/tactic.h" +#include "constants/type.h" +#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_1.h" +#include "dungeon_pokemon_attributes.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" +#include "targeting_flags.h" -bool8 IsTargetStraightAhead(struct DungeonEntity *pokemon, struct DungeonEntity *targetPokemon, s32 facingDir, s32 maxRange) +#define REGULAR_ATTACK_INDEX 4 + +const s16 gRegularAttackWeights[] = {100, 20, 30, 40, 50}; + +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 bool8 IsMoveUsable(struct DungeonEntity*, s32, bool8); +extern bool8 TargetRegularAttack(struct DungeonEntity*, u32*, 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) { - s32 posDiffX = pokemon->posWorld.x - targetPokemon->posWorld.x; - s32 effectiveMaxRange; - if (posDiffX < 0) + struct DungeonEntityData *pokemonData = pokemon->entityData; + s32 i; + s32 chargeStatus = CHARGING_STATUS_CHARGE; + struct MoveTargetResults moveTargetResults[MAX_MON_MOVES + 1]; + bool8 willNotUnlinkMove[MAX_MON_MOVES]; + s32 randomWeight; + bool8 hasPPChecker; + s32 numUsableMoves; + s32 total; + s32 weightCounter; + bool8 hasWeakTypePicker; + s32 regularAttackTargetDir; + bool8 canTargetRegularAttack; + s32 maxWeight; + if (CannotAttack(pokemon, FALSE) || + ShouldAvoidEnemiesAndShowEffect(pokemon, TRUE) || + HasTactic(pokemon, TACTIC_KEEP_YOUR_DISTANCE) || + (pokemonData->volatileStatus == VOLATILE_STATUS_CONFUSED && RollPercentChance(gConfusedAttackChance))) { - posDiffX = -posDiffX; + return; } - effectiveMaxRange = pokemon->posWorld.y - targetPokemon->posWorld.y; - if (effectiveMaxRange < 0) + if (pokemonData->chargingStatus != CHARGING_STATUS_NONE) { - effectiveMaxRange = -effectiveMaxRange; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (pokemonData->moves[i].moveFlags & MOVE_FLAG_EXISTS && + MoveMatchesChargingStatus(pokemon, &pokemonData->moves[i]) && + pokemonData->chargingStatusMoveIndex == i) + { + s32 chosenMoveIndex; + SetAction(&pokemonData->action, DUNGEON_ACTION_USE_MOVE_AI); + chosenMoveIndex = i; + if (i > 0 && pokemonData->moves[i].moveFlags & MOVE_FLAG_LINKED) + { + while (--chosenMoveIndex > 0) + { + if (!(pokemonData->moves[chosenMoveIndex].moveFlags & MOVE_FLAG_LINKED)) + { + break; + } + } + } + pokemonData->action.actionUseIndex = chosenMoveIndex; + TargetTileInFront(pokemon); + return; + } + } } - if (effectiveMaxRange < posDiffX) + total = 0; + numUsableMoves = 0; + for (i = 0; i < MAX_MON_MOVES; i++) { - effectiveMaxRange = posDiffX; + struct PokemonMove *move = &pokemonData->moves[i]; + if (pokemonData->moves[i].moveFlags & MOVE_FLAG_EXISTS) + { + if (pokemonData->moves[i].moveFlags & MOVE_FLAG_ENABLED) + { + numUsableMoves++; + } + total += move->PP; + } + } + if (total == 0) + { + struct PokemonMove struggle; + InitPokemonMove(&struggle, MOVE_STRUGGLE); + FindMoveTarget(&moveTargetResults[0], pokemon, &struggle); + if (moveTargetResults[0].moveUsable) + { + SetAction(&pokemonData->action, DUNGEON_ACTION_STRUGGLE); + pokemonData->action.facingDir = moveTargetResults[0].targetDir & DIRECTION_MASK; + TargetTileInFront(pokemon); + } + return; } - if (effectiveMaxRange > maxRange) + hasWeakTypePicker = HasIQSkill(pokemon, IQ_SKILL_WEAK_TYPE_PICKER); + hasPPChecker = HasIQSkill(pokemon, IQ_SKILL_PP_CHECKER) != FALSE; + total = 0; + for (i = 0; i < MAX_MON_MOVES; i++) { - effectiveMaxRange = maxRange; + willNotUnlinkMove[i] = TRUE; } - if (!HasIQSkill(pokemon, IQ_SKILL_COURSE_CHECKER)) + if (hasPPChecker) { - // BUG: effectiveMaxRange is already capped at maxRange, so this condition always evaluates to TRUE. - // The AI also has range checks elsewhere, so this doesn't become an issue in most cases. - // If the AI has the Long Toss or Pierce statuses and Course Checker is disabled, - // this incorrect check causes the AI to throw items at targets further than 10 tiles away. - if (effectiveMaxRange <= maxRange) + s32 minPP = 99; + s32 linkedMoveStartIndex = 0; + // Linked moves unlink if any move in the chain runs out of PP. + // With PP Checker, the AI avoids this by not using linked moves if any move in the chain has 1 PP left. + // This requires a separate check from the 0-PP check used for unlinked moves. + for (i = 0; i < MAX_MON_MOVES; i++) { - return TRUE; + struct PokemonMove *move = &pokemonData->moves[i]; + if (!(move->moveFlags & MOVE_FLAG_EXISTS)) + { + break; + } + if (i != 0 && !(move->moveFlags & MOVE_FLAG_LINKED)) + { + if (linkedMoveStartIndex + 1 < i && minPP <= 1 && linkedMoveStartIndex + 1 <= i) + { + s32 j; + for (j = linkedMoveStartIndex; j < i; j++) + { + willNotUnlinkMove[j] = FALSE; + } + } + minPP = move->PP; + linkedMoveStartIndex = i; + } + else + { + s32 newMinPP = move->PP; + if (newMinPP > minPP) + { + newMinPP = minPP; + } + minPP = newMinPP; + } + } + if (linkedMoveStartIndex + 1 < i && minPP <= 1 && linkedMoveStartIndex + 1 <= i) + { + s32 j; + for (j = linkedMoveStartIndex; j < i; j++) + { + willNotUnlinkMove[j] = FALSE; + } } } + for (i = 0; i < MAX_MON_MOVES; i++) + { + struct PokemonMove *move; + moveTargetResults[i].moveUsable = FALSE; + move = &pokemonData->moves[i]; + if (move->moveFlags & MOVE_FLAG_EXISTS && + willNotUnlinkMove[i] && + IsMoveUsable(pokemon, i, hasPPChecker) && + move->moveFlags & MOVE_FLAG_ENABLED) + { + moveTargetResults[i].moveUsable = TRUE; + if (pokemonData->chargingStatus == chargeStatus) + { + if (move->moveID == MOVE_CHARGE) + { + moveTargetResults[i].moveWeight = 0; + continue; + } + else if (GetMoveTypeForPokemon(pokemon, move) == TYPE_ELECTRIC) + { + moveTargetResults[i].moveWeight = GetMoveWeight(move); + } + else + { + moveTargetResults[i].moveWeight = 1; + } + } + else if (hasWeakTypePicker) + { + struct MoveTargetResults *results = &moveTargetResults[i]; + results->moveWeight = FindMoveTarget(results, pokemon, move); + } + else + { + moveTargetResults[i].moveWeight = GetMoveWeight(move); + } + total += moveTargetResults[i].moveWeight; + } + } + moveTargetResults[REGULAR_ATTACK_INDEX].moveWeight = 0; + if (!HasIQSkill(pokemon, IQ_SKILL_EXCLUSIVE_MOVE_USER) && pokemonData->chargingStatus != chargeStatus) + { + moveTargetResults[REGULAR_ATTACK_INDEX].moveUsable = TRUE; + if (pokemonData->chargingStatus == chargeStatus) + { + // Never reached? Charge already skips the regular attack in the outer block. + moveTargetResults[REGULAR_ATTACK_INDEX].moveWeight = 1; + } + else if (hasWeakTypePicker) + { + moveTargetResults[REGULAR_ATTACK_INDEX].moveWeight = 2; + } + else + { + moveTargetResults[REGULAR_ATTACK_INDEX].moveWeight = gRegularAttackWeights[numUsableMoves]; + } + total += moveTargetResults[REGULAR_ATTACK_INDEX].moveWeight; + } + if (hasWeakTypePicker) + { + s32 i; + maxWeight = 0; + total = 0; + for (i = 0; i < MAX_MON_MOVES + 1; i++) + { + if (!moveTargetResults[i].moveUsable) + { + moveTargetResults[i].moveWeight = 0; + } + else if (maxWeight < moveTargetResults[i].moveWeight) + { + maxWeight = moveTargetResults[i].moveWeight; + } + } + for (i = 0; i < MAX_MON_MOVES + 1; i++) + { + if (moveTargetResults[i].moveUsable) + { + if (maxWeight != moveTargetResults[i].moveWeight) + { + moveTargetResults[i].moveWeight = 0; + } + total += moveTargetResults[i].moveWeight; + } + } + } + if (total == 0) + { + return; + } + randomWeight = DungeonRandomCapped(total); + weightCounter = 0; + if (!HasIQSkill(pokemon, IQ_SKILL_EXCLUSIVE_MOVE_USER)) + { + canTargetRegularAttack = TargetRegularAttack(pokemon, ®ularAttackTargetDir, TRUE); + } else { - s32 currentPosX = pokemon->posWorld.x; - s32 currentPosY = pokemon->posWorld.y; - s32 adjacentTileOffsetX = gAdjacentTileOffsets[facingDir].x; - s32 adjacentTileOffsetY = gAdjacentTileOffsets[facingDir].y; + canTargetRegularAttack = FALSE; + regularAttackTargetDir = DIRECTION_SOUTH; + } + for (i = 0; i <= REGULAR_ATTACK_INDEX; i++) + { + if (moveTargetResults[i].moveUsable && moveTargetResults[i].moveWeight != 0) + { + weightCounter += moveTargetResults[i].moveWeight; + if (weightCounter >= randomWeight) + { + if (i == REGULAR_ATTACK_INDEX) + { + if (canTargetRegularAttack) + { + SetAction(&pokemonData->action, DUNGEON_ACTION_REGULAR_ATTACK); + pokemonData->action.facingDir = regularAttackTargetDir & DIRECTION_MASK; + TargetTileInFront(pokemon); + } + } + else + { + FindMoveTarget(&moveTargetResults[i], pokemon, &pokemonData->moves[i]); + if (moveTargetResults[i].moveUsable) + { + s32 chosenMoveIndex; + SetAction(&pokemonData->action, DUNGEON_ACTION_USE_MOVE_AI); + chosenMoveIndex = i; + if (i > 0 && pokemonData->moves[i].moveFlags & MOVE_FLAG_LINKED) + { + while (--chosenMoveIndex > 0) + { + if (!(pokemonData->moves[chosenMoveIndex].moveFlags & MOVE_FLAG_LINKED)) + { + break; + } + } + } + pokemonData->action.facingDir = moveTargetResults[i].targetDir & DIRECTION_MASK; + pokemonData->action.actionUseIndex = chosenMoveIndex; + TargetTileInFront(pokemon); + } + else + { + break; + } + } + return; + } + } + } + if (canTargetRegularAttack) + { + SetAction(&pokemonData->action, DUNGEON_ACTION_REGULAR_ATTACK); + pokemonData->action.facingDir = regularAttackTargetDir & DIRECTION_MASK; + 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 = GetMoveTargetingFlagsForPokemon(pokemon, move, TRUE); + hasStatusChecker = HasIQSkill(pokemon, IQ_SKILL_STATUS_CHECKER); + moveTargetResults->moveUsable = FALSE; + if ((pokemonData->volatileStatus == VOLATILE_STATUS_TAUNTED && !MoveDealsDirectDamage(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 <= effectiveMaxRange; i++) + for (i = 0; i < DUNGEON_MAX_POKEMON; i++) { - struct MapTile *mapTile; - currentPosX += adjacentTileOffsetX; - currentPosY += adjacentTileOffsetY; - if (currentPosX <= 0 || currentPosY <= 0 || - currentPosX >= DUNGEON_MAX_SIZE_X - 1 || currentPosY >= DUNGEON_MAX_SIZE_Y - 1) + struct DungeonEntity *target = gDungeonGlobalData->allPokemon[i]; + if (EntityExists(target) && CanSee(pokemon, target)) { - break; + numPotentialTargets = WeightMoveIfUsable(numPotentialTargets, targetingFlags, pokemon, target, move, hasStatusChecker); } - while (0); // Extra label needed to swap branch locations in ASM. - mapTile = GetMapTileAtPosition(currentPosX, currentPosY); - if (!(mapTile->tileType & (TILE_TYPE_FLOOR | TILE_TYPE_LIQUID))) + } + } + 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)) { - break; + 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); + } } - if (mapTile->pokemon == targetPokemon) + } + } + 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_TARGET_SELF) + { + 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]) { - return TRUE; + gPotentialTargetWeights_2[i] = 0; } - if (mapTile->pokemon != NULL) + } + 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 FALSE; -} + return moveWeight; +}
\ No newline at end of file diff --git a/src/dungeon_ai_attack_1.c b/src/dungeon_ai_attack_1.c new file mode 100644 index 0000000..8a186ea --- /dev/null +++ b/src/dungeon_ai_attack_1.c @@ -0,0 +1,76 @@ +#include "global.h" +#include "dungeon_ai_attack_1.h" + +#include "constants/iq_skill.h" +#include "dungeon_global_data.h" +#include "dungeon_map_access.h" +#include "dungeon_pokemon_attributes.h" +#include "dungeon_util.h" + +bool8 IsTargetStraightAhead(struct DungeonEntity *pokemon, struct DungeonEntity *targetPokemon, s32 facingDir, s32 maxRange) +{ + s32 posDiffX = pokemon->posWorld.x - targetPokemon->posWorld.x; + s32 effectiveMaxRange; + if (posDiffX < 0) + { + posDiffX = -posDiffX; + } + effectiveMaxRange = pokemon->posWorld.y - targetPokemon->posWorld.y; + if (effectiveMaxRange < 0) + { + effectiveMaxRange = -effectiveMaxRange; + } + if (effectiveMaxRange < posDiffX) + { + effectiveMaxRange = posDiffX; + } + if (effectiveMaxRange > maxRange) + { + effectiveMaxRange = maxRange; + } + if (!HasIQSkill(pokemon, IQ_SKILL_COURSE_CHECKER)) + { + // BUG: effectiveMaxRange is already capped at maxRange, so this condition always evaluates to TRUE. + // The AI also has range checks elsewhere, so this doesn't become an issue in most cases. + // If the AI has the Long Toss or Pierce statuses and Course Checker is disabled, + // this incorrect check causes the AI to throw items at targets further than 10 tiles away. + if (effectiveMaxRange <= maxRange) + { + return TRUE; + } + } + else + { + s32 currentPosX = pokemon->posWorld.x; + s32 currentPosY = pokemon->posWorld.y; + s32 adjacentTileOffsetX = gAdjacentTileOffsets[facingDir].x; + s32 adjacentTileOffsetY = gAdjacentTileOffsets[facingDir].y; + s32 i; + for (i = 0; i <= effectiveMaxRange; i++) + { + struct MapTile *mapTile; + currentPosX += adjacentTileOffsetX; + currentPosY += adjacentTileOffsetY; + if (currentPosX <= 0 || currentPosY <= 0 || + currentPosX >= DUNGEON_MAX_SIZE_X - 1 || currentPosY >= DUNGEON_MAX_SIZE_Y - 1) + { + break; + } + while (0); // Extra label needed to swap branch locations in ASM. + mapTile = GetMapTileAtPosition(currentPosX, currentPosY); + if (!(mapTile->tileType & (TILE_TYPE_FLOOR | TILE_TYPE_LIQUID))) + { + break; + } + if (mapTile->pokemon == targetPokemon) + { + return TRUE; + } + if (mapTile->pokemon != NULL) + { + break; + } + } + } + return FALSE; +} diff --git a/src/dungeon_ai_item_weight.c b/src/dungeon_ai_item_weight.c index 6c9669b..0fe019f 100644 --- a/src/dungeon_ai_item_weight.c +++ b/src/dungeon_ai_item_weight.c @@ -5,7 +5,7 @@ #include "constants/targeting.h" #include "dungeon_ai_1.h" #include "dungeon_map_access.h" -#include "dungeon_pokemon_attributes_1.h" +#include "dungeon_pokemon_attributes.h" #include "dungeon_util.h" #include "moves.h" #include "number_util.h" @@ -85,11 +85,11 @@ u32 EvaluateItem(struct DungeonEntity *targetPokemon, struct ItemSlot *item, u32 { if (move->moveFlags & MOVE_FLAG_EXISTS) { - if (move->pp == 0) + if (move->PP == 0) { itemWeight += 30; } - if (move->pp != GetMoveMaxPP(move2)) + if (move->PP != GetMoveMaxPP(move2)) { itemWeight += 6; } diff --git a/src/dungeon_ai_items.c b/src/dungeon_ai_items.c index d515ebb..183d143 100644 --- a/src/dungeon_ai_items.c +++ b/src/dungeon_ai_items.c @@ -7,7 +7,7 @@ #include "constants/targeting.h" #include "dungeon_action.h" #include "dungeon_ai_1.h" -#include "dungeon_ai_attack.h" +#include "dungeon_ai_attack_1.h" #include "dungeon_ai_item_weight.h" #include "dungeon_ai_items.h" #include "dungeon_capabilities.h" @@ -15,7 +15,7 @@ #include "dungeon_entity.h" #include "dungeon_global_data.h" #include "dungeon_map_access.h" -#include "dungeon_pokemon_attributes_1.h" +#include "dungeon_pokemon_attributes.h" #include "dungeon_random.h" #include "dungeon_random_1.h" #include "dungeon_util.h" @@ -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/dungeon_ai_movement.c b/src/dungeon_ai_movement.c index bc109eb..5fa6d87 100644 --- a/src/dungeon_ai_movement.c +++ b/src/dungeon_ai_movement.c @@ -8,10 +8,11 @@ #include "constants/targeting.h" #include "code_80521D0.h" #include "dungeon_action.h" +#include "dungeon_ai_attack.h" #include "dungeon_ai_items.h" #include "dungeon_capabilities_1.h" #include "dungeon_global_data.h" -#include "dungeon_pokemon_attributes_1.h" +#include "dungeon_pokemon_attributes.h" #include "dungeon_random.h" #include "dungeon_util.h" #include "dungeon_util_1.h" @@ -19,6 +20,7 @@ #include "map.h" #include "pokemon.h" #include "status_checks.h" +#include "targeting.h" extern char gAvailablePokemonNames[]; extern char *gPtrCouldntBeUsedMessage; @@ -27,7 +29,6 @@ extern char *gPtrItsaMonsterHouseMessage; extern void SendImmobilizeEndMessage(struct DungeonEntity*, struct DungeonEntity*); extern void SetMessageArgument(char[], struct DungeonEntity*, u32); extern void ResetAction(u16*); -extern void DecideAttack(struct DungeonEntity*); extern void MoveIfPossible(struct DungeonEntity*, bool8); extern u8 sub_8044B28(void); extern void sub_807AB38(struct DungeonEntity *, u32); @@ -35,7 +36,6 @@ extern void sub_8041888(u32); extern u8 sub_803F428(s16 *); extern void sub_803E708(u32, u32); extern struct DungeonEntity *GetLeaderEntity(); -extern void TargetTileInFront(struct DungeonEntity *); u32 sub_8075818(struct DungeonEntity *entity) { diff --git a/src/dungeon_capabilities_1.c b/src/dungeon_capabilities_1.c index bbe48bc..e6ec6fa 100644 --- a/src/dungeon_capabilities_1.c +++ b/src/dungeon_capabilities_1.c @@ -11,7 +11,7 @@ #include "dungeon_items.h" #include "dungeon_map_access.h" #include "dungeon_movement.h" -#include "dungeon_pokemon_attributes_1.h" +#include "dungeon_pokemon_attributes.h" #include "dungeon_util.h" #include "map.h" diff --git a/src/dungeon_pokemon_attributes.c b/src/dungeon_pokemon_attributes.c index c70d4ff..bd3a1f6 100644 --- a/src/dungeon_pokemon_attributes.c +++ b/src/dungeon_pokemon_attributes.c @@ -1,15 +1,27 @@ #include "global.h" #include "dungeon_pokemon_attributes.h" -#include "dungeon_util.h" #include "constants/ability.h" +#include "constants/dungeon.h" +#include "constants/iq_skill.h" +#include "constants/move_id.h" #include "constants/status.h" +#include "constants/tactic.h" +#include "constants/type.h" +#include "dungeon_global_data.h" +#include "dungeon_items.h" +#include "dungeon_util.h" +#include "dungeon_visibility.h" +#include "moves.h" +#include "pokemon.h" +#include "pokemon_3.h" + +const s16 gItemMasterMinWildLevel[] = {16}; extern u8 gAvailablePokemonNames[]; extern u32 gUnknown_80FC31C; extern u32 gUnknown_80FCEFC; extern u32 gUnknown_80FC2FC; - extern bool8 sub_805744C(struct DungeonEntity *, struct PokemonMove *, u32); extern void SetMessageArgument(char[], struct DungeonEntity*, u32); extern void sub_80522F4(struct DungeonEntity *r1, struct DungeonEntity *r2, u32); @@ -51,7 +63,7 @@ bool8 sub_80717A4(struct DungeonEntity *param_1, u16 moveID) { struct DungeonEntityData * entityData; s32 iVar3; - + entityData = param_1->entityData; if ((entityData->sleepStatus != SLEEP_STATUS_SLEEP) && (entityData->sleepStatus != SLEEP_STATUS_NAPPING) && (entityData->sleepStatus != SLEEP_STATUS_NIGHTMARE)) { return FALSE; @@ -66,10 +78,10 @@ bool8 sub_80717A4(struct DungeonEntity *param_1, u16 moveID) for(iVar3 = 0, pokeMove = entityData->moves, pokeMove2 = pokeMove; iVar3 < MAX_MON_MOVES; pokeMove++, pokeMove2++, iVar3++) { if (((pokeMove->moveFlags & MOVE_FLAG_EXISTS) != 0) && (entityData->isLeader || ((pokeMove->moveFlags & MOVE_FLAG_ENABLED) != 0))) - if((sub_805744C(param_1, pokeMove2, 1) != '\0') && (pokeMove->pp != 0)) + if((sub_805744C(param_1, pokeMove2, 1) != '\0') && (pokeMove->PP != 0)) if(pokeMove->moveID == moveID) return TRUE; - } + } return FALSE; } } @@ -90,3 +102,158 @@ bool8 HasAbility(struct DungeonEntity *pokemon, u8 ability) return FALSE; } } + +bool8 HasType(struct DungeonEntity *pokemon, u8 type) +{ + struct DungeonEntityData *pokemonData = pokemonData = pokemon->entityData; + if (type == TYPE_NONE) + { + return FALSE; + } + if (pokemonData->type1 == type) + { + return TRUE; + } + if (pokemonData->type2 == type) + { + return TRUE; + } + return FALSE; +} + +bool8 CanSeeInvisible(struct DungeonEntity *pokemon) +{ + struct DungeonEntityData *pokemonData = pokemon->entityData; + if (pokemonData->eyesightStatus != EYESIGHT_STATUS_EYEDROPS) + { + if (!HasItem(pokemon, ITEM_ID_GOGGLE_SPECS)) + return FALSE; + else + return TRUE; + } + else + return TRUE; +} + +bool8 HasTactic(struct DungeonEntity *pokemon, u8 tactic) +{ + struct DungeonEntityData *pokemonData = pokemon->entityData; + if (pokemonData->isLeader) + { + bool8 isGoTheOtherWay = tactic == TACTIC_GO_THE_OTHER_WAY; + return isGoTheOtherWay; + } + return pokemonData->tactic == tactic; +} + +bool8 HasIQSkill(struct DungeonEntity *pokemon, u8 IQSkill) +{ + return IsIQSkillSet(pokemon->entityData->IQSkillsEnabled, 1 << IQSkill); +} + +bool8 HasIQSkillPair(struct DungeonEntity *pokemon, u8 IQSkill1, u8 IQSkill2) +{ + return IsIQSkillSet(pokemon->entityData->IQSkillsEnabled, 1 << IQSkill1 | 1 << IQSkill2); +} + +void LoadIQSkills(struct DungeonEntity *pokemon) +{ + u8 *iVar2; + s32 IQSkill; + struct DungeonEntityData *pokemonData; + + pokemonData = pokemon->entityData; + if (pokemonData->isEnemy) { + iVar2 = pokemonData->IQSkillsEnabled; + SetIQSkill(iVar2, IQ_SKILL_STATUS_CHECKER); + SetIQSkill(iVar2, IQ_SKILL_PP_CHECKER); + SetIQSkill(iVar2, IQ_SKILL_ITEM_CATCHER); + if (pokemonData->isBoss) + SetIQSkill(iVar2, IQ_SKILL_SELF_CURER); + if (pokemonData->level >= *gItemMasterMinWildLevel) + SetIQSkill(iVar2, IQ_SKILL_ITEM_MASTER); + pokemonData->tactic = TACTIC_GO_AFTER_FOES; + } + else { + pokemonData->IQSkillsEnabled[0] = 0; + pokemonData->IQSkillsEnabled[1] = 0; + pokemonData->IQSkillsEnabled[2] = 0; + for(IQSkill = IQ_SKILL_TYPE_ADVANTAGE_MASTER; IQSkill < NUM_IQ_SKILLS; IQSkill++) + { + if (HasIQForSkill(pokemonData->IQ,IQSkill) && + IsIQSkillSet(pokemonData->IQSkillsSelected, 1 << IQSkill)) + { + SetIQSkill(pokemonData->IQSkillsEnabled,IQSkill); + } + } + } +} + +bool8 CanSeeTeammate(struct DungeonEntity * pokemon) +{ + struct DungeonEntity *teamMember; + s32 memberIdx; + + if (pokemon->entityData->isEnemy) { + return FALSE; + } + else + { + for(memberIdx = 0; memberIdx < MAX_TEAM_MEMBERS; memberIdx++) + { + teamMember = gDungeonGlobalData->teamPokemon[memberIdx]; + if (EntityExists(pokemon) && (pokemon != teamMember) && (CanSee(pokemon,teamMember))) + { + return TRUE; + } + } + return FALSE; + } +} + +u8 GetMoveTypeForPokemon(struct DungeonEntity *pokemon, struct PokemonMove *pokeMove) +{ + if (pokeMove->moveID == MOVE_HIDDEN_POWER) + return pokemon->entityData->hiddenPowerType; + else + return GetMoveType(pokeMove); +} + +s32 CalculateMovePower(struct DungeonEntity *pokemon, struct PokemonMove *pokeMove) +{ + if(pokeMove->moveID == MOVE_HIDDEN_POWER) + return (pokemon->entityData->hiddenPowerPower + pokeMove->powerBoost); + else + return (GetMovePower(pokeMove) + pokeMove->powerBoost); +} + +bool8 ToolboxEnabled(struct DungeonEntityData *pokemon) +{ + if(!IsToolboxEnabled(pokemon->entityID)) + return FALSE; + return TRUE; +} + +static inline bool8 sub_8071A8C_sub(struct DungeonEntityData *pokemonData) +{ + if(pokemonData->joinLocation == DUNGEON_JOIN_LOCATION_CLIENT_POKEMON || + pokemonData->joinLocation == DUNGEON_RESCUE_TEAM_BASE) + return TRUE; + else + return FALSE; +} + +bool8 sub_8071A8C(struct DungeonEntity *pokemon) +{ + struct DungeonEntityData *pokemonData; + if(EntityExists(pokemon)) + { + pokemonData = pokemon->entityData; + if(pokemonData->clientType != CLIENT_TYPE_CLIENT) + { + if(!sub_8071A8C_sub(pokemonData)) + return TRUE; + } + } + return FALSE; +} diff --git a/src/dungeon_pokemon_attributes_1.c b/src/dungeon_pokemon_attributes_1.c deleted file mode 100644 index 93d8d4a..0000000 --- a/src/dungeon_pokemon_attributes_1.c +++ /dev/null @@ -1,161 +0,0 @@ -#include "global.h" -#include "dungeon_pokemon_attributes_1.h" - -#include "constants/dungeon.h" -#include "constants/iq_skill.h" -#include "constants/move_id.h" -#include "constants/status.h" -#include "constants/tactic.h" -#include "dungeon_global_data.h" -#include "dungeon_items.h" -#include "dungeon_util.h" -#include "pokemon.h" -#include "pokemon_3.h" - -const s16 gItemMasterMinWildLevel[] = {16}; - -extern bool8 IsIQSkillSet(u8 *, u32); -extern void SetIQSkill(u8 *param_1, u32 skillIndex); -extern bool8 HasIQForSkill(s32 pokeIQ, u8 IQSkillIndex); - -extern bool8 CanSee(struct DungeonEntity *, struct DungeonEntity *); - -extern u8 GetMoveType(struct PokemonMove *move); -extern s32 GetMovePower(struct PokemonMove *move); - -bool8 CanSeeInvisible(struct DungeonEntity *pokemon) -{ - struct DungeonEntityData *pokemonData = pokemon->entityData; - if (pokemonData->eyesightStatus != EYESIGHT_STATUS_EYEDROPS) - { - if (!HasItem(pokemon, ITEM_ID_GOGGLE_SPECS)) - return FALSE; - else - return TRUE; - } - else - return TRUE; -} - -bool8 HasTactic(struct DungeonEntity *pokemon, u8 tactic) -{ - struct DungeonEntityData *pokemonData = pokemon->entityData; - if (pokemonData->isLeader) - { - bool8 isGoTheOtherWay = tactic == TACTIC_GO_THE_OTHER_WAY; - return isGoTheOtherWay; - } - return pokemonData->tactic == tactic; -} - -bool8 HasIQSkill(struct DungeonEntity *pokemon, u8 IQSkill) -{ - return IsIQSkillSet(pokemon->entityData->IQSkillsEnabled, 1 << IQSkill); -} - -bool8 HasIQSkillPair(struct DungeonEntity *pokemon, u8 IQSkill1, u8 IQSkill2) -{ - return IsIQSkillSet(pokemon->entityData->IQSkillsEnabled, 1 << IQSkill1 | 1 << IQSkill2); -} - -void LoadIQSkills(struct DungeonEntity *pokemon) -{ - u8 *iVar2; - s32 IQSkill; - struct DungeonEntityData *pokemonData; - - pokemonData = pokemon->entityData; - if (pokemonData->isEnemy) { - iVar2 = pokemonData->IQSkillsEnabled; - SetIQSkill(iVar2, IQ_SKILL_STATUS_CHECKER); - SetIQSkill(iVar2, IQ_SKILL_PP_CHECKER); - SetIQSkill(iVar2, IQ_SKILL_ITEM_CATCHER); - if (pokemonData->isBoss) - SetIQSkill(iVar2, IQ_SKILL_SELF_CURER); - if (pokemonData->level >= *gItemMasterMinWildLevel) - SetIQSkill(iVar2, IQ_SKILL_ITEM_MASTER); - pokemonData->tactic = TACTIC_GO_AFTER_FOES; - } - else { - pokemonData->IQSkillsEnabled[0] = 0; - pokemonData->IQSkillsEnabled[1] = 0; - pokemonData->IQSkillsEnabled[2] = 0; - for(IQSkill = IQ_SKILL_TYPE_ADVANTAGE_MASTER; IQSkill < NUM_IQ_SKILLS; IQSkill++) - { - if (HasIQForSkill(pokemonData->IQ,IQSkill) && - IsIQSkillSet(pokemonData->IQSkillsSelected, 1 << IQSkill)) - { - SetIQSkill(pokemonData->IQSkillsEnabled,IQSkill); - } - } - } -} - -bool8 CanSeeTeammate(struct DungeonEntity * pokemon) -{ - struct DungeonEntity *teamMember; - s32 memberIdx; - - if (pokemon->entityData->isEnemy) { - return FALSE; - } - else - { - for(memberIdx = 0; memberIdx < MAX_TEAM_MEMBERS; memberIdx++) - { - teamMember = gDungeonGlobalData->teamPokemon[memberIdx]; - if (EntityExists(pokemon) && (pokemon != teamMember) && (CanSee(pokemon,teamMember))) - { - return TRUE; - } - } - return FALSE; - } -} - -u8 GetMoveType_2(struct DungeonEntity *pokemon, struct PokemonMove *pokeMove) -{ - if(pokeMove->moveID == MOVE_HIDDEN_POWER) - return pokemon->entityData->hiddenPowerType; - else - return GetMoveType(pokeMove); -} - -s32 CalculateMovePower(struct DungeonEntity *pokemon, struct PokemonMove *pokeMove) -{ - if(pokeMove->moveID == MOVE_HIDDEN_POWER) - return (pokemon->entityData->hiddenPowerPower + pokeMove->powerBoost); - else - return (GetMovePower(pokeMove) + pokeMove->powerBoost); -} - -bool8 ToolboxEnabled(struct DungeonEntityData *pokemon) -{ - if(!IsToolboxEnabled(pokemon->entityID)) - return FALSE; - return TRUE; -} - -static inline bool8 sub_8071A8C_sub(struct DungeonEntityData *pokemonData) -{ - if(pokemonData->joinLocation == DUNGEON_JOIN_LOCATION_CLIENT_POKEMON || - pokemonData->joinLocation == DUNGEON_RESCUE_TEAM_BASE) - return TRUE; - else - return FALSE; -} - -bool8 sub_8071A8C(struct DungeonEntity *pokemon) -{ - struct DungeonEntityData *pokemonData; - if(EntityExists(pokemon)) - { - pokemonData = pokemon->entityData; - if(pokemonData->clientType != CLIENT_TYPE_CLIENT) - { - if(!sub_8071A8C_sub(pokemonData)) - return TRUE; - } - } - return FALSE; -} diff --git a/src/dungeon_visibility.c b/src/dungeon_visibility.c index 862e1a0..4a76b69 100644 --- a/src/dungeon_visibility.c +++ b/src/dungeon_visibility.c @@ -2,7 +2,7 @@ #include "dungeon_visibility.h" #include "constants/status.h" -#include "dungeon_pokemon_attributes_1.h" +#include "dungeon_pokemon_attributes.h" #include "dungeon_range.h" #include "dungeon_util.h" diff --git a/src/items.c b/src/items.c index a19b71b..4b5a710 100644 --- a/src/items.c +++ b/src/items.c @@ -39,9 +39,7 @@ extern void ExpandPlaceholdersBuffer(u8 *, const u8 *, ...); extern s32 sub_8090FEC(s32 a1, u8* a2, u8 a3); extern void sub_80073B8(u32); extern u32 sub_8097DF0(char *, struct subStruct_203B240 **); -extern void InitPokemonMove(void*, u16); // first arg is some struct extern void sub_80078A4(u32, u32, u32, u32, u32); -extern u32 GetMoveType(void*); extern u8* GetUnformattedTypeString(s16); extern void sub_80073E0(u32); extern void xxx_format_and_draw(u32, u32, u8 *, u32, u32); diff --git a/src/moves.c b/src/moves.c index f2e334c..0874f00 100644 --- a/src/moves.c +++ b/src/moves.c @@ -99,7 +99,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 ExpandPlaceholdersBuffer (buffer,gUnknown_81098EC,uVar2,move->moveFlags & MOVE_FLAG_SET ? gUnknown_8109908 : gUnknown_810990C, gMovesData[move->moveID].namePointer,localBuffer,param_3->unk4, - move->pp,maxPP); + move->PP,maxPP); break; case 2: @@ -107,7 +107,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 ExpandPlaceholdersBuffer (buffer,gUnknown_8109910,uVar2,move->moveFlags & MOVE_FLAG_SET ? gUnknown_8109908 : gUnknown_810990C, gMovesData[move->moveID].namePointer,localBuffer,param_3->unk4, - move->pp,maxPP); + move->PP,maxPP); break; case 3: @@ -115,7 +115,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 ExpandPlaceholdersBuffer (buffer,gUnknown_81098EC,uVar2,move->moveFlags & MOVE_FLAG_ENABLED ? gUnknown_8109928 : gUnknown_810990C, gMovesData[move->moveID].namePointer,localBuffer,param_3->unk4, - move->pp,maxPP); + move->PP,maxPP); break; case 4: @@ -123,7 +123,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 ExpandPlaceholdersBuffer (buffer,gUnknown_8109910,uVar2, move->moveFlags & MOVE_FLAG_ENABLED ? gUnknown_8109928 : gUnknown_810990C, gMovesData[move->moveID].namePointer,localBuffer,param_3->unk4, - move->pp,maxPP); + move->PP,maxPP); break; } } @@ -133,7 +133,7 @@ void InitPokemonMove(struct PokemonMove *move, u16 moveID) move->moveFlags = MOVE_FLAG_ENABLED | MOVE_FLAG_EXISTS; move->sealed = FALSE; move->moveID = moveID; - move->pp = GetMoveMaxPP(move); + move->PP = GetMoveMaxPP(move); move->powerBoost = 0; } @@ -146,7 +146,7 @@ void sub_8092AA8(struct PokemonMove *move, u16 moveID) move->moveFlags = MOVE_FLAG_ENABLED | MOVE_FLAG_EXISTS; move->sealed = FALSE; move->moveID = moveID; - move->pp = GetMoveMaxPP(move); + move->PP = GetMoveMaxPP(move); move->powerBoost = 0; } } @@ -155,12 +155,12 @@ void InitZeroedPPPokemonMove(struct PokemonMove *move, u16 moveID) { move->moveFlags = MOVE_FLAG_ENABLED | MOVE_FLAG_EXISTS; move->moveID = moveID; - move->pp = 0; + move->PP = 0; } -s16 GetMoveTargetingFlags(struct PokemonMove *move, u32 r1) +s16 GetMoveTargetingFlags(struct PokemonMove *move, u32 isAI) { - return gMovesData[move->moveID].targetingFlags[r1]; + return gMovesData[move->moveID].targetingFlags[isAI]; } u8 GetMoveType(struct PokemonMove *move) @@ -271,12 +271,12 @@ u8 GetMoveCriticalHitChance(struct PokemonMove *move) return gMovesData[move->moveID].criticalHitChance; } -u8 GetMoveCannotHitFrozen(struct PokemonMove *move) +bool8 MoveCannotHitFrozen(struct PokemonMove *move) { return gMovesData[move->moveID].cannotHitFrozen; } -u8 GetMoveDealsDirectDamage(struct PokemonMove *move) +bool8 MoveDealsDirectDamage(struct PokemonMove *move) { return gMovesData[move->moveID].dealsDirectDamage; } diff --git a/src/moves_1.c b/src/moves_1.c index db84d41..5a7bf6b 100644 --- a/src/moves_1.c +++ b/src/moves_1.c @@ -7,14 +7,14 @@ void SavePokemonMove(struct unkStruct_8094924 *r0, struct PokemonMove *move) { SaveIntegerBits(r0, &move->moveFlags, 4); SaveIntegerBits(r0, &move->moveID, 9); - SaveIntegerBits(r0, &move->pp, 7); + SaveIntegerBits(r0, &move->PP, 7); } void RestorePokemonMove(struct unkStruct_8094924 *r0, struct PokemonMove *move) { RestoreIntegerBits(r0, &move->moveFlags, 4); RestoreIntegerBits(r0, &move->moveID, 9); - RestoreIntegerBits(r0, &move->pp, 7); + RestoreIntegerBits(r0, &move->PP, 7); } void SavePokemonMoves(struct unkStruct_8094924 *r0, struct PokemonMove *moveSet) @@ -40,7 +40,7 @@ void sub_8094148(struct unkStruct_8094924 *r0, struct PokemonMove *move) SaveIntegerBits(r0, &move->moveFlags, 4); SaveIntegerBits(r0, &move->sealed, 1); SaveIntegerBits(r0, &move->moveID, 9); - SaveIntegerBits(r0, &move->pp, 7); + SaveIntegerBits(r0, &move->PP, 7); SaveIntegerBits(r0, &move->powerBoost, 7); } @@ -61,7 +61,7 @@ void sub_80941B0(struct unkStruct_8094924 *r0, struct PokemonMove *move) RestoreIntegerBits(r0, &move->moveFlags, 4); RestoreIntegerBits(r0, &move->sealed, 1); RestoreIntegerBits(r0, &move->moveID, 9); - RestoreIntegerBits(r0, &move->pp, 7); + RestoreIntegerBits(r0, &move->PP, 7); RestoreIntegerBits(r0, &move->powerBoost, 7); } diff --git a/src/pokemon_3.c b/src/pokemon_3.c index 9d28f98..68c894b 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -47,7 +47,6 @@ extern s16 gUnknown_810AC66; // 0x8 // 2, 4, 6, 7, 8, 9, 0xA, 0xD, 0xF, 0x11 extern s32 gUnknown_810AC90[10]; -extern void SetIQSkill(u8 *, u32); extern void AddSprite(u16 *, u32, u32, u32); extern void xxx_save_poke_sub_4_80902F4(struct unkStruct_8094924*, struct unkPokeSubStruct_4*); diff --git a/src/status_checks.c b/src/status_checks.c index b371934..12889b5 100644 --- a/src/status_checks.c +++ b/src/status_checks.c @@ -6,9 +6,12 @@ #include "constants/status.h" #include "code_80521D0.h" #include "dungeon_action.h" +#include "dungeon_ai_attack.h" #include "dungeon_capabilities_1.h" #include "dungeon_random.h" +const s16 gConfusedAttackChance = 70; + extern char *gPtrFrozenMessage; extern char *gPtrWrappedAroundMessage; extern char *gPtrWrappedByMessage; @@ -18,7 +21,6 @@ extern char *gPtrInfatuatedMessage; extern char gAvailablePokemonNames[]; extern void SetMessageArgument(char[], struct DungeonEntity*, u32); -extern void DecideAttack(struct DungeonEntity*); bool8 HasStatusAffectingActions(struct DungeonEntity *pokemon) { diff --git a/src/targeting.c b/src/targeting.c new file mode 100644 index 0000000..b77fb35 --- /dev/null +++ b/src/targeting.c @@ -0,0 +1,11 @@ +#include "global.h" +#include "targeting.h" + +#include "dungeon_util.h" + +void TargetTileInFront(struct DungeonEntity *pokemon) +{ + struct DungeonEntityData *pokemonData = pokemon->entityData; + pokemonData->targetPosition.x = pokemon->posWorld.x + gAdjacentTileOffsets[pokemonData->action.facingDir].x; + pokemonData->targetPosition.y = pokemon->posWorld.y + gAdjacentTileOffsets[pokemonData->action.facingDir].y; +} diff --git a/src/targeting_flags.c b/src/targeting_flags.c new file mode 100644 index 0000000..f315cdf --- /dev/null +++ b/src/targeting_flags.c @@ -0,0 +1,16 @@ +#include "global.h" +#include "targeting_flags.h" + +#include "constants/move_id.h" +#include "constants/type.h" +#include "dungeon_pokemon_attributes.h" +#include "moves.h" + +s16 GetMoveTargetingFlagsForPokemon(struct DungeonEntity *pokemon, struct PokemonMove *move, u32 isAI) +{ + if (move->moveID == MOVE_CURSE && !isAI && !HasType(pokemon, TYPE_GHOST)) + { + return TARGETING_FLAG_BOOST_SELF | TARGETING_FLAG_TARGET_SELF; + } + return GetMoveTargetingFlags(move, isAI); +} |