summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSeth Barberee <seth.barberee@gmail.com>2022-02-17 21:45:57 -0800
committerGitHub <noreply@github.com>2022-02-17 21:45:57 -0800
commit3555fb7c945ef5152910a84390ecbd1a38ea585d (patch)
tree4237c0ab086005ea05539b8de7c10b867eec43db /src
parent1d64db5214b455bbd6f50ad6369ec04420e03984 (diff)
parentece475a4804a64790cfa86dfa0ba577a732adee8 (diff)
Merge pull request #96 from AnonymousRandomPerson/master
Attack AI decomp
Diffstat (limited to 'src')
-rw-r--r--src/charge_move.c48
-rw-r--r--src/code_8041AD0.c9
-rw-r--r--src/code_8057824.c2
-rw-r--r--src/dungeon_ai.c17
-rw-r--r--src/dungeon_ai_1.c2
-rw-r--r--src/dungeon_ai_attack.c530
-rw-r--r--src/dungeon_ai_attack_1.c76
-rw-r--r--src/dungeon_ai_item_weight.c6
-rw-r--r--src/dungeon_ai_items.c12
-rw-r--r--src/dungeon_ai_movement.c6
-rw-r--r--src/dungeon_capabilities_1.c2
-rw-r--r--src/dungeon_pokemon_attributes.c177
-rw-r--r--src/dungeon_pokemon_attributes_1.c161
-rw-r--r--src/dungeon_visibility.c2
-rw-r--r--src/items.c2
-rw-r--r--src/moves.c22
-rw-r--r--src/moves_1.c8
-rw-r--r--src/pokemon_3.c1
-rw-r--r--src/status_checks.c4
-rw-r--r--src/targeting.c11
-rw-r--r--src/targeting_flags.c16
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, &regularAttackTargetDir, 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);
+}