summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm/code_807C4A0.s136
-rw-r--r--include/dungeon_ai_attack.h10
-rw-r--r--include/dungeon_ai_attack_1.h8
-rw-r--r--include/dungeon_ai_attack_2.h9
-rwxr-xr-xld_script.txt4
-rw-r--r--src/dungeon_ai_attack.c265
-rw-r--r--src/dungeon_ai_attack_1.c224
-rw-r--r--src/dungeon_ai_attack_2.c76
-rw-r--r--src/dungeon_ai_items.c4
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
{