diff options
author | AnonymousRandomPerson <chenghanngan.us@gmail.com> | 2022-03-05 00:07:15 -0500 |
---|---|---|
committer | AnonymousRandomPerson <chenghanngan.us@gmail.com> | 2022-03-10 22:33:12 -0500 |
commit | 7e0046a2c9a056f3c3694a8c7b7bb9ac37a8e220 (patch) | |
tree | b7ae8a4f1c8b8f353f9b80ec51e83f417998e50a | |
parent | f7a73281cfdfe36af057d1700cc046b80da98f70 (diff) |
Decomped IsTargetInLineRange()
.
-rw-r--r-- | asm/code_807C4A0.s | 136 | ||||
-rw-r--r-- | include/dungeon_ai_attack.h | 10 | ||||
-rw-r--r-- | include/dungeon_ai_attack_1.h | 8 | ||||
-rw-r--r-- | include/dungeon_ai_attack_2.h | 9 | ||||
-rwxr-xr-x | ld_script.txt | 4 | ||||
-rw-r--r-- | src/dungeon_ai_attack.c | 265 | ||||
-rw-r--r-- | src/dungeon_ai_attack_1.c | 224 | ||||
-rw-r--r-- | src/dungeon_ai_attack_2.c | 76 | ||||
-rw-r--r-- | src/dungeon_ai_items.c | 4 |
9 files changed, 320 insertions, 416 deletions
diff --git a/asm/code_807C4A0.s b/asm/code_807C4A0.s deleted file mode 100644 index 9cbdbb5..0000000 --- a/asm/code_807C4A0.s +++ /dev/null @@ -1,136 +0,0 @@ - #include "asm/constants/gba_constants.inc" - #include "asm/macros.inc" - - .syntax unified - - .text - - thumb_func_start IsTargetInLineRange -IsTargetInLineRange: - push {r4-r7,lr} - adds r4, r0, 0 - adds r5, r1, 0 - movs r0, 0x4 - ldrsh r1, [r4, r0] - movs r3, 0x4 - ldrsh r0, [r5, r3] - subs r3, r1, r0 - cmp r3, 0 - bge _0807C4B6 - negs r3, r3 -_0807C4B6: - movs r6, 0x6 - ldrsh r1, [r4, r6] - movs r7, 0x6 - ldrsh r0, [r5, r7] - subs r1, r0 - cmp r1, 0 - bge _0807C4C6 - negs r1, r1 -_0807C4C6: - adds r0, r1, 0 - cmp r1, r3 - bge _0807C4CE - adds r0, r3, 0 -_0807C4CE: - cmp r0, 0xA - bgt _0807C578 - cmp r0, r2 - bgt _0807C578 - movs r6, 0x1 - negs r6, r6 - cmp r3, r1 - bne _0807C516 - movs r0, 0x4 - ldrsh r1, [r4, r0] - movs r2, 0x4 - ldrsh r0, [r5, r2] - ldrh r2, [r4, 0x4] - ldrh r3, [r5, 0x4] - cmp r1, r0 - bge _0807C4FE - movs r6, 0x6 - ldrsh r1, [r4, r6] - movs r7, 0x6 - ldrsh r0, [r5, r7] - cmp r1, r0 - blt _0807C574 - cmp r1, r0 - bgt _0807C574 -_0807C4FE: - lsls r1, r2, 16 - lsls r0, r3, 16 - movs r6, 0x7 - cmp r1, r0 - ble _0807C570 - movs r0, 0x6 - ldrsh r1, [r4, r0] - movs r2, 0x6 - ldrsh r0, [r5, r2] - cmp r1, r0 - ble _0807C570 - b _0807C574 -_0807C516: - movs r3, 0x4 - ldrsh r1, [r4, r3] - movs r7, 0x4 - ldrsh r0, [r5, r7] - ldrh r2, [r4, 0x4] - ldrh r3, [r5, 0x4] - cmp r1, r0 - bne _0807C532 - movs r0, 0x6 - ldrsh r1, [r4, r0] - movs r7, 0x6 - ldrsh r0, [r5, r7] - cmp r1, r0 - blt _0807C574 -_0807C532: - lsls r1, r2, 16 - lsls r0, r3, 16 - cmp r1, r0 - bge _0807C546 - movs r0, 0x6 - ldrsh r1, [r4, r0] - movs r7, 0x6 - ldrsh r0, [r5, r7] - cmp r1, r0 - beq _0807C574 -_0807C546: - lsls r1, r2, 16 - lsls r0, r3, 16 - cmp r1, r0 - bne _0807C55A - movs r0, 0x6 - ldrsh r1, [r4, r0] - movs r7, 0x6 - ldrsh r0, [r5, r7] - cmp r1, r0 - bgt _0807C574 -_0807C55A: - lsls r1, r2, 16 - lsls r0, r3, 16 - cmp r1, r0 - ble _0807C570 - movs r0, 0x6 - ldrsh r1, [r4, r0] - movs r2, 0x6 - ldrsh r0, [r5, r2] - cmp r1, r0 - bne _0807C570 - movs r6, 0x6 -_0807C570: - cmp r6, 0 - blt _0807C578 -_0807C574: - movs r0, 0x1 - b _0807C57A -_0807C578: - movs r0, 0 -_0807C57A: - pop {r4-r7} - pop {r1} - bx r1 - thumb_func_end IsTargetInLineRange - - .align 2, 0
\ No newline at end of file diff --git a/include/dungeon_ai_attack.h b/include/dungeon_ai_attack.h index 1878889..bd874a4 100644 --- a/include/dungeon_ai_attack.h +++ b/include/dungeon_ai_attack.h @@ -3,6 +3,8 @@ #include "dungeon_entity.h" +#define RANGED_ATTACK_RANGE 10 + struct MoveTargetResults { bool8 moveUsable; @@ -14,5 +16,13 @@ struct MoveTargetResults void DecideAttack(struct DungeonEntity *pokemon); // 0x7C04C s32 FindMoveTarget(struct MoveTargetResults *moveTargetResults, struct DungeonEntity *pokemon, struct PokemonMove *move); +// 0x7C4A0 +bool8 IsTargetInLineRange(struct DungeonEntity *user, struct DungeonEntity *target, s32 range); +// 0x7C580 +s32 WeightMoveIfUsable(s32 numPotentialTargets, s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, u32 hasStatusChecker); +// 0x7C648 +bool8 CanUseStatusMove(s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker); +// 0x7C7AC +s32 WeightMove(struct DungeonEntity *user, s32 targetingFlags, struct DungeonEntity *target, u32 moveType); #endif diff --git a/include/dungeon_ai_attack_1.h b/include/dungeon_ai_attack_1.h index 160c32e..89a1f0d 100644 --- a/include/dungeon_ai_attack_1.h +++ b/include/dungeon_ai_attack_1.h @@ -3,11 +3,7 @@ #include "dungeon_entity.h" -// 0x7C580 -s32 WeightMoveIfUsable(s32 numPotentialTargets, s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, u32 hasStatusChecker); -// 0x7C648 -bool8 CanUseStatusMove(s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker); -// 0x7C7AC -s32 WeightMove(struct DungeonEntity *user, s32 targetingFlags, struct DungeonEntity *target, u32 moveType); +// 0x7C9F8 +bool8 IsTargetStraightAhead(struct DungeonEntity *pokemon, struct DungeonEntity *targetPokemon, s32 facingDir, s32 maxRange); #endif diff --git a/include/dungeon_ai_attack_2.h b/include/dungeon_ai_attack_2.h deleted file mode 100644 index 00711b6..0000000 --- a/include/dungeon_ai_attack_2.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef GUARD_DUNGEON_AI_ATTACK_2_H -#define GUARD_DUNGEON_AI_ATTACK_2_H - -#include "dungeon_entity.h" - -// 0x7C9F8 -bool8 IsTargetStraightAhead(struct DungeonEntity *pokemon, struct DungeonEntity *targetPokemon, s32 facingDir, s32 maxRange); - -#endif diff --git a/ld_script.txt b/ld_script.txt index 7f20c1c..9230a24 100755 --- a/ld_script.txt +++ b/ld_script.txt @@ -243,10 +243,8 @@ SECTIONS { src/status.o(.text); asm/code_8077274.o(.text); src/dungeon_ai_attack.o(.text); - asm/code_807C4A0.o(.text); - src/dungeon_ai_attack_1.o(.text); asm/code_807C854.o(.text); - src/dungeon_ai_attack_2.o(.text); + src/dungeon_ai_attack_1.o(.text); asm/code_807CABC.o(.text); src/targeting_flags.o(.text); asm/code_807CD9C.o(.text); diff --git a/src/dungeon_ai_attack.c b/src/dungeon_ai_attack.c index 35d15c8..3e2a9f3 100644 --- a/src/dungeon_ai_attack.c +++ b/src/dungeon_ai_attack.c @@ -7,13 +7,14 @@ #include "constants/move_id.h" #include "constants/status.h" #include "constants/tactic.h" +#include "constants/targeting.h" #include "constants/type.h" #include "charge_move.h" #include "dungeon_action.h" #include "dungeon_ai_targeting.h" #include "dungeon_ai_targeting_1.h" +#include "dungeon_ai_targeting_2.h" #include "dungeon_ai_attack_1.h" -#include "dungeon_ai_attack_2.h" #include "dungeon_capabilities_1.h" #include "dungeon_global_data.h" #include "dungeon_map_access.h" @@ -26,8 +27,10 @@ #include "position_util.h" #include "status_checker.h" #include "status_checks.h" +#include "status_checks_1.h" #include "targeting.h" #include "targeting_flags.h" +#include "type_effectiveness.h" #define REGULAR_ATTACK_INDEX 4 @@ -41,7 +44,6 @@ extern struct DungeonEntity *gPotentialTargets[NUM_DIRECTIONS]; extern bool8 IsMoveUsable_1(struct DungeonEntity*, s32, bool8); extern bool8 TargetRegularAttack(struct DungeonEntity*, u32*, bool8); -extern bool8 IsTargetInLineRange(struct DungeonEntity*, struct DungeonEntity*, s32); void DecideAttack(struct DungeonEntity *pokemon) { @@ -521,4 +523,261 @@ s32 FindMoveTarget(struct MoveTargetResults *moveTargetResults, struct DungeonEn moveTargetResults->moveWeight = 8; } return moveWeight; -}
\ No newline at end of file +} + +bool8 IsTargetInLineRange(struct DungeonEntity *user, struct DungeonEntity *target, s32 range) +{ + s32 posDiffX = user->posWorld.x - target->posWorld.x; + s32 posDiffY, maxPosDiff; + s32 direction; + if (posDiffX < 0) + { + posDiffX = -posDiffX; + } + posDiffY = user->posWorld.y - target->posWorld.y; + if (posDiffY < 0) + { + posDiffY = -posDiffY; + } + maxPosDiff = posDiffY; + if (posDiffY < posDiffX) + { + maxPosDiff = posDiffX; + } + if (maxPosDiff > RANGED_ATTACK_RANGE || maxPosDiff > range) + { + return FALSE; + } + direction = -1; + if (posDiffX == posDiffY) + { + if (user->posWorld.x < target->posWorld.x && + (user->posWorld.y < target->posWorld.y || user->posWorld.y > target->posWorld.y)) + { + returnTrue: + return TRUE; + } + if (user->posWorld.x > target->posWorld.x); // Fixes register loading order. + direction = DIRECTION_SOUTHWEST; + if (user->posWorld.x <= target->posWorld.x || user->posWorld.y <= target->posWorld.y) + { + goto checkDirectionSet; + } + goto returnTrue; + } + else if (user->posWorld.x == target->posWorld.x && user->posWorld.y < target->posWorld.y) + { + return TRUE; + } + else if (user->posWorld.x < target->posWorld.x && user->posWorld.y == target->posWorld.y) + { + return TRUE; + } + else if (user->posWorld.x == target->posWorld.x && user->posWorld.y > target->posWorld.y) + { + return TRUE; + } + else if (user->posWorld.x > target->posWorld.x && user->posWorld.y == target->posWorld.y) + { + direction = DIRECTION_WEST; + } + checkDirectionSet: + if (direction < 0) + { + return FALSE; + } + return TRUE; +} + +s32 WeightMoveIfUsable(s32 numPotentialTargets, s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) +{ + s32 facingDir; + s32 targetingFlags2 = (s16) targetingFlags; + bool8 hasStatusChecker2 = hasStatusChecker; + struct DungeonEntityData *userData = user->entityData; + if ((user->posWorld.x == target->posWorld.x && user->posWorld.y == target->posWorld.y) || + (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_ROOM || + (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_FLOOR || + (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_SELF) + { + facingDir = userData->action.facingDir; + } + else + { + facingDir = CalculateFacingDir(&user->posWorld, &target->posWorld); + } + if (!gCanAttackInDirection[facingDir] && + CanUseStatusMove(targetingFlags2, user, target, move, hasStatusChecker2)) + { + gCanAttackInDirection[facingDir] = TRUE; + do { gPotentialAttackTargetDirections[numPotentialTargets] = facingDir; } while (0); + gPotentialAttackTargetWeights[numPotentialTargets] = WeightMove(user, targetingFlags2, target, GetMoveTypeForPokemon(user, move)); + gPotentialTargets[numPotentialTargets] = target; + numPotentialTargets++; + } + return numPotentialTargets; +} + +bool8 CanUseStatusMove(s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) +{ + struct DungeonEntityData *targetData; + s32 targetingFlags2 = (s16) targetingFlags; + bool8 hasStatusChecker2 = hasStatusChecker; + bool8 hasTarget = FALSE; + u32 categoryTargetingFlags = targetingFlags2 & 0xF; + u32 *categoryTargetingFlags2 = &categoryTargetingFlags; // Fixes a regswap. + if (*categoryTargetingFlags2 == TARGETING_FLAG_TARGET_OTHER) + { + if (CanTarget(user, target, FALSE, TRUE) == TARGET_CAPABILITY_CAN_TARGET) + { + hasTarget = TRUE; + } + } + else if (categoryTargetingFlags == TARGETING_FLAG_HEAL_TEAM) + { + goto checkCanTarget; + } + else if (categoryTargetingFlags == TARGETING_FLAG_LONG_RANGE) + { + targetData = target->entityData; + goto checkThirdParty; + } + else if (categoryTargetingFlags == TARGETING_FLAG_ATTACK_ALL) + { + targetData = target->entityData; + if (user == target) + { + goto returnFalse; + } + checkThirdParty: + hasTarget = TRUE; + if (targetData->shopkeeperMode == SHOPKEEPER_FRIENDLY || + targetData->clientType == CLIENT_TYPE_DONT_MOVE || + targetData->clientType == CLIENT_TYPE_CLIENT) + { + returnFalse: + return FALSE; + } + } + else if (categoryTargetingFlags == TARGETING_FLAG_BOOST_TEAM) + { + if (user == target) + { + goto returnFalse; + } + checkCanTarget: + if (CanTarget(user, target, FALSE, TRUE) == TARGET_CAPABILITY_CANNOT_ATTACK) + { + hasTarget = TRUE; + } + } + else if ((u16) (categoryTargetingFlags - 3) <= 1) // categoryTargetingFlags == TARGETING_FLAG_ITEM + { + hasTarget = TRUE; + } + + if (hasTarget) + { + if (hasStatusChecker2) + { + if (!CanUseOnTargetWithStatusChecker(user, target, move)) + { + goto returnFalse; + } + if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_SET_TRAP) + { + goto rollMoveUseChance; + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_HP) + { + if (!HasQuarterHPOrLess(target)) + { + if (*categoryTargetingFlags2); + goto returnFalse; + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_STATUS) + { + if (!HasNegativeStatus(target)) + { + if (*categoryTargetingFlags2); // Flips the conditional. + goto returnFalse; + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_DREAM_EATER) + { + if (!IsSleeping(target)) + { + if (*categoryTargetingFlags2); // Flips the conditional. + goto returnFalse; + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_EXPOSE) + { + targetData = target->entityData; + if ((targetData->types[0] != TYPE_GHOST && targetData->types[1] != TYPE_GHOST) || targetData->exposedStatus) + { + if (*categoryTargetingFlags2); // Flips the conditional. + goto returnFalse; + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_ALL) + { + if (!HasNegativeStatus(target) && !HasQuarterHPOrLess(target)) + { + if (*categoryTargetingFlags2); // Flips the conditional. + goto returnFalse; + } + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_SET_TRAP) + { + s32 useChance; + rollMoveUseChance: + useChance = GetMoveAccuracy(move, ACCURACY_TYPE_USE_CHANCE); + if (DungeonRandomCapped(100) >= useChance) + { + goto returnFalse; + } + } + } + return hasTarget; +} + +s32 WeightMove(struct DungeonEntity *user, s32 targetingFlags, struct DungeonEntity *target, u32 moveType) +{ +#ifndef NONMATCHING + register struct DungeonEntityData *targetData asm("r4"); +#else + struct DungeonEntityData *targetData; +#endif + s32 targetingFlags2 = (s16) targetingFlags; + u8 moveType2 = moveType; + u8 weight = 1; + struct DungeonEntityData *targetData2; + targetData2 = targetData = target->entityData; + if (!targetData->isEnemy || (targetingFlags2 & 0xF) != TARGETING_FLAG_TARGET_OTHER) + { + return 1; + } + else if (HasIQSkill(user, IQ_SKILL_EXP_GO_GETTER)) + { + // BUG: expYieldRankings has lower values as the Pokémon's experience yield increases. + // This causes Exp. Go-Getter to prioritizes Pokémon worth less experience + // instead of Pokémon worth more experience. + weight = gDungeonGlobalData->expYieldRankings[targetData->entityID]; + } + else if (HasIQSkill(user, IQ_SKILL_EFFICIENCY_EXPERT)) + { + weight = -12 - targetData2->HP; + if (weight == 0) + { + weight = 1; + } + } + else if (HasIQSkill(user, IQ_SKILL_WEAK_TYPE_PICKER)) + { + weight = WeightWeakTypePicker(user, target, moveType2) + 1; + } + return weight; +} diff --git a/src/dungeon_ai_attack_1.c b/src/dungeon_ai_attack_1.c index cef0aac..641bc8c 100644 --- a/src/dungeon_ai_attack_1.c +++ b/src/dungeon_ai_attack_1.c @@ -1,214 +1,76 @@ #include "global.h" #include "dungeon_ai_attack_1.h" -#include "constants/direction.h" #include "constants/iq_skill.h" -#include "constants/targeting.h" -#include "constants/type.h" -#include "dungeon_ai_targeting_2.h" #include "dungeon_global_data.h" +#include "dungeon_map_access.h" #include "dungeon_pokemon_attributes.h" -#include "dungeon_random.h" -#include "moves.h" -#include "position_util.h" -#include "status_checker.h" -#include "status_checks_1.h" -#include "type_effectiveness.h" +#include "dungeon_util.h" -extern bool8 gCanAttackInDirection[NUM_DIRECTIONS]; -extern s32 gPotentialAttackTargetWeights[NUM_DIRECTIONS]; -extern u8 gPotentialAttackTargetDirections[NUM_DIRECTIONS]; -extern struct DungeonEntity *gPotentialTargets[NUM_DIRECTIONS]; - -s32 WeightMoveIfUsable(s32 numPotentialTargets, s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) +bool8 IsTargetStraightAhead(struct DungeonEntity *pokemon, struct DungeonEntity *targetPokemon, s32 facingDir, s32 maxRange) { - s32 facingDir; - s32 targetingFlags2 = (s16) targetingFlags; - bool8 hasStatusChecker2 = hasStatusChecker; - struct DungeonEntityData *userData = user->entityData; - if ((user->posWorld.x == target->posWorld.x && user->posWorld.y == target->posWorld.y) || - (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_ROOM || - (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_FLOOR || - (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_SELF) - { - facingDir = userData->action.facingDir; - } - else - { - facingDir = CalculateFacingDir(&user->posWorld, &target->posWorld); - } - if (!gCanAttackInDirection[facingDir] && - CanUseStatusMove(targetingFlags2, user, target, move, hasStatusChecker2)) + s32 posDiffX = pokemon->posWorld.x - targetPokemon->posWorld.x; + s32 effectiveMaxRange; + if (posDiffX < 0) { - gCanAttackInDirection[facingDir] = TRUE; - do { gPotentialAttackTargetDirections[numPotentialTargets] = facingDir; } while (0); - gPotentialAttackTargetWeights[numPotentialTargets] = WeightMove(user, targetingFlags2, target, GetMoveTypeForPokemon(user, move)); - gPotentialTargets[numPotentialTargets] = target; - numPotentialTargets++; + posDiffX = -posDiffX; } - return numPotentialTargets; -} - -bool8 CanUseStatusMove(s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) -{ - struct DungeonEntityData *targetData; - s32 targetingFlags2 = (s16) targetingFlags; - bool8 hasStatusChecker2 = hasStatusChecker; - bool8 hasTarget = FALSE; - u32 categoryTargetingFlags = targetingFlags2 & 0xF; - u32 *categoryTargetingFlags2 = &categoryTargetingFlags; // Fixes a regswap. - if (*categoryTargetingFlags2 == TARGETING_FLAG_TARGET_OTHER) + effectiveMaxRange = pokemon->posWorld.y - targetPokemon->posWorld.y; + if (effectiveMaxRange < 0) { - if (CanTarget(user, target, FALSE, TRUE) == TARGET_CAPABILITY_CAN_TARGET) - { - hasTarget = TRUE; - } + effectiveMaxRange = -effectiveMaxRange; } - else if (categoryTargetingFlags == TARGETING_FLAG_HEAL_TEAM) + if (effectiveMaxRange < posDiffX) { - goto checkCanTarget; + effectiveMaxRange = posDiffX; } - else if (categoryTargetingFlags == TARGETING_FLAG_LONG_RANGE) + if (effectiveMaxRange > maxRange) { - targetData = target->entityData; - goto checkThirdParty; + effectiveMaxRange = maxRange; } - else if (categoryTargetingFlags == TARGETING_FLAG_ATTACK_ALL) + if (!HasIQSkill(pokemon, IQ_SKILL_COURSE_CHECKER)) { - targetData = target->entityData; - if (user == target) + // 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) { - goto returnFalse; - } - checkThirdParty: - hasTarget = TRUE; - if (targetData->shopkeeperMode == SHOPKEEPER_FRIENDLY || - targetData->clientType == CLIENT_TYPE_DONT_MOVE || - targetData->clientType == CLIENT_TYPE_CLIENT) - { - returnFalse: - return FALSE; + return TRUE; } } - else if (categoryTargetingFlags == TARGETING_FLAG_BOOST_TEAM) - { - if (user == target) - { - goto returnFalse; - } - checkCanTarget: - if (CanTarget(user, target, FALSE, TRUE) == TARGET_CAPABILITY_CANNOT_ATTACK) - { - hasTarget = TRUE; - } - } - else if ((u16) (categoryTargetingFlags - 3) <= 1) // categoryTargetingFlags == TARGETING_FLAG_ITEM - { - hasTarget = TRUE; - } - - if (hasTarget) + else { - if (hasStatusChecker2) + 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++) { - if (!CanUseOnTargetWithStatusChecker(user, target, move)) + struct MapTile *mapTile; + currentPosX += adjacentTileOffsetX; + currentPosY += adjacentTileOffsetY; + if (currentPosX <= 0 || currentPosY <= 0 || + currentPosX >= DUNGEON_MAX_SIZE_X - 1 || currentPosY >= DUNGEON_MAX_SIZE_Y - 1) { - goto returnFalse; + break; } - if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_SET_TRAP) + while (0); // Extra label needed to swap branch locations in ASM. + mapTile = GetMapTile_1(currentPosX, currentPosY); + if (!(mapTile->tileType & (TILE_TYPE_FLOOR | TILE_TYPE_LIQUID))) { - goto rollMoveUseChance; + break; } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_HP) + if (mapTile->pokemon == targetPokemon) { - if (!HasQuarterHPOrLess(target)) - { - if (*categoryTargetingFlags2); - goto returnFalse; - } + return TRUE; } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_STATUS) + if (mapTile->pokemon != NULL) { - if (!HasNegativeStatus(target)) - { - if (*categoryTargetingFlags2); // Flips the conditional. - goto returnFalse; - } - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_DREAM_EATER) - { - if (!IsSleeping(target)) - { - if (*categoryTargetingFlags2); // Flips the conditional. - goto returnFalse; - } - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_EXPOSE) - { - targetData = target->entityData; - if ((targetData->types[0] != TYPE_GHOST && targetData->types[1] != TYPE_GHOST) || targetData->exposedStatus) - { - if (*categoryTargetingFlags2); // Flips the conditional. - goto returnFalse; - } - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_ALL) - { - if (!HasNegativeStatus(target) && !HasQuarterHPOrLess(target)) - { - if (*categoryTargetingFlags2); // Flips the conditional. - goto returnFalse; - } + break; } } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_SET_TRAP) - { - s32 useChance; - rollMoveUseChance: - useChance = GetMoveAccuracy(move, ACCURACY_TYPE_USE_CHANCE); - if (DungeonRandomCapped(100) >= useChance) - { - goto returnFalse; - } - } - } - return hasTarget; -} - -s32 WeightMove(struct DungeonEntity *user, s32 targetingFlags, struct DungeonEntity *target, u32 moveType) -{ -#ifndef NONMATCHING - register struct DungeonEntityData *targetData asm("r4"); -#else - struct DungeonEntityData *targetData; -#endif - s32 targetingFlags2 = (s16) targetingFlags; - u8 moveType2 = moveType; - u8 weight = 1; - struct DungeonEntityData *targetData2; - targetData2 = targetData = target->entityData; - if (!targetData->isEnemy || (targetingFlags2 & 0xF) != TARGETING_FLAG_TARGET_OTHER) - { - return 1; - } - else if (HasIQSkill(user, IQ_SKILL_EXP_GO_GETTER)) - { - // BUG: expYieldRankings has lower values as the Pokémon's experience yield increases. - // This causes Exp. Go-Getter to prioritizes Pokémon worth less experience - // instead of Pokémon worth more experience. - weight = gDungeonGlobalData->expYieldRankings[targetData->entityID]; - } - else if (HasIQSkill(user, IQ_SKILL_EFFICIENCY_EXPERT)) - { - weight = -12 - targetData2->HP; - if (weight == 0) - { - weight = 1; - } - } - else if (HasIQSkill(user, IQ_SKILL_WEAK_TYPE_PICKER)) - { - weight = WeightWeakTypePicker(user, target, moveType2) + 1; } - return weight; + return FALSE; } diff --git a/src/dungeon_ai_attack_2.c b/src/dungeon_ai_attack_2.c deleted file mode 100644 index 41e924a..0000000 --- a/src/dungeon_ai_attack_2.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "global.h" -#include "dungeon_ai_attack_2.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 = GetMapTile_1(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_items.c b/src/dungeon_ai_items.c index 31d57ff..7b85cf7 100644 --- a/src/dungeon_ai_items.c +++ b/src/dungeon_ai_items.c @@ -6,7 +6,8 @@ #include "constants/status.h" #include "constants/targeting.h" #include "dungeon_action.h" -#include "dungeon_ai_attack_2.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_ai_targeting_2.h" @@ -28,7 +29,6 @@ #define NUM_POTENTIAL_ROCK_TARGETS 20 #define GROUND_ITEM_TOOLBOX_INDEX 0x80 #define HELD_ITEM_TOOLBOX_INDEX 0x81 -#define RANGED_ATTACK_RANGE 10 enum ItemTargetFlag { |