Decomped TargetRegularAttack

This commit is contained in:
AnonymousRandomPerson
2025-09-22 20:43:49 -04:00
parent c9b9b65fdf
commit 48780aa1ab
9 changed files with 134 additions and 247 deletions

View File

@@ -1,10 +0,0 @@
#pragma once
.public CanAttackInDirection
.public DIRECTIONS_XY
.public DungeonRandInt
.public GetTile
.public GetTreatmentBetweenMonsters
.public IqSkillIsEnabled
.public IsBlinded
.public ov29_0230F8D0
.public WeightMoveWithIqSkills

View File

@@ -1,168 +0,0 @@
.include "asm/macros.inc"
.include "overlay_29_0231A460.inc"
.text
arm_func_start TargetRegularAttack
TargetRegularAttack: ; 0x0231A460
stmdb sp!, {r3, r4, r5, r6, r7, r8, sb, sl, fp, lr}
sub sp, sp, #0x48
mov sl, r0
ldr r3, [sl, #0xb4]
mov sb, r1
str r2, [sp]
mov r1, #1
ldrb r6, [r3, #0x4c]
mov r4, #0
bl IsBlinded
cmp r0, #0
movne r7, #1
bne _0231A4AC
mov r0, sl
mov r1, #0xf
bl ov29_0230F8D0
cmp r0, #0xff
mov r7, #8
movne r6, r0
_0231A4AC:
mov r0, sl
mov r1, #9
bl IqSkillIsEnabled
cmp r0, #0
bne _0231A4D4
mov r0, sl
mov r1, #0xa
bl IqSkillIsEnabled
cmp r0, #0
beq _0231A4DC
_0231A4D4:
mov r2, #1
b _0231A4E0
_0231A4DC:
mov r2, #0
_0231A4E0:
mov r0, sl
mov r1, #8
and fp, r2, #0xff
bl IqSkillIsEnabled
str r0, [sp, #4]
mov r5, #0
b _0231A5CC
_0231A4FC:
and r6, r6, #7
ldr r1, _0231A690 ; =DIRECTIONS_XY
mov r2, r6, lsl #2
ldrsh r3, [r1, r2]
add r1, r1, r6, lsl #2
ldrsh r0, [sl, #4]
ldrsh r2, [sl, #6]
ldrsh r1, [r1, #2]
add r0, r0, r3
add r1, r2, r1
bl GetTile
ldr r8, [r0, #0xc]
cmp r8, #0
beq _0231A5C4
ldr r0, [r8]
cmp r0, #1
bne _0231A5C4
mov r0, sl
mov r1, r6
bl CanAttackInDirection
cmp r0, #0
beq _0231A5C4
ldr r3, [sp]
mov r0, sl
mov r1, r8
mov r2, #0
bl GetTreatmentBetweenMonsters
cmp r0, #1
bne _0231A5C4
ldr r0, [sp, #4]
cmp r0, #0
beq _0231A58C
ldr r0, [r8, #0xb4]
ldrb r0, [r0, #0xc4]
cmp r0, #1
beq _0231A5C4
_0231A58C:
add r0, sp, #0x28
mov r1, #0
str r6, [r0, r4, lsl #2]
mov r2, r8
mov r0, sl
mov r3, r1
bl WeightMoveWithIqSkills
add r1, sp, #8
cmp fp, #0
str r0, [r1, r4, lsl #2]
streq r6, [sb]
moveq r0, #1
beq _0231A688
add r4, r4, #1
_0231A5C4:
add r5, r5, #1
add r6, r6, #1
_0231A5CC:
cmp r5, r7
blt _0231A4FC
cmp r4, #0
mov r0, #0
beq _0231A688
mov r5, r0
mov r3, r0
add r2, sp, #8
b _0231A600
_0231A5F0:
ldr r1, [r2, r3, lsl #2]
add r3, r3, #1
cmp r5, r1
movlt r5, r1
_0231A600:
cmp r3, r4
blt _0231A5F0
mov r6, #0
mov r1, r6
add r3, sp, #8
b _0231A628
_0231A618:
ldr r2, [r3, r6, lsl #2]
cmp r5, r2
strne r1, [r3, r6, lsl #2]
add r6, r6, #1
_0231A628:
cmp r6, r4
blt _0231A618
mov r3, #0
add r2, sp, #8
b _0231A648
_0231A63C:
ldr r1, [r2, r3, lsl #2]
add r3, r3, #1
add r0, r0, r1
_0231A648:
cmp r3, r4
blt _0231A63C
bl DungeonRandInt
mov r3, #0
add r2, sp, #8
b _0231A670
_0231A660:
ldr r1, [r2, r3, lsl #2]
subs r0, r0, r1
bmi _0231A678
add r3, r3, #1
_0231A670:
cmp r3, r4
blt _0231A660
_0231A678:
add r1, sp, #0x28
ldr r1, [r1, r3, lsl #2]
mov r0, #1
str r1, [sb]
_0231A688:
add sp, sp, #0x48
ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, sl, fp, pc}
.align 2, 0
_0231A690: .word DIRECTIONS_XY
arm_func_end TargetRegularAttack

View File

@@ -53,5 +53,19 @@ s32 TryAddTargetToAiTargetList(s32 current_num_targets, s32 move_ai_range, struc
bool8 IsAiTargetEligible(s32 move_ai_range, struct entity *user, struct entity *target, struct move *move, bool8 check_all_conditions);
// Calculates a move weight used for deciding which target the move should be used on. If the user is an ally, the target is an enemy Pokémon, and the user has Exp. Go-Getter, Efficiency Expert, or Weak-Type Picker enabled, this function calculates a move weight based on that IQ skill's functionality. Otherwise, this function returns a weight of 1.
s32 WeightMoveWithIqSkills(struct entity *user, s32 move_ai_range, struct entity *target, enum type_id move_type);
// Decides which direction the AI will use its regular attack in.
// pokemon: User entity pointer
// target_dir: [output] direction that the regular attack should be targeted at.
// skip_petrified: If true, the AI will ignore enemies that are petrified. If false, the AI will include petrified enemies when targeting.
// return: True if there is a target for the regular attack, false if there is no target.
bool8 TargetRegularAttack(struct entity *pokemon, u32 *target_dir, bool8 skip_petrified);
// Returns true if the target is within range of the user's move, false otherwise.
// If the user does not have Course Checker, it simply checks if the distance between user and target is less or equal than the move range.
// Otherwise, it will iterate through all tiles in the direction specified, checking for walls or other monsters in the way, and return false if they are found.
// user: user pointer
// target: target pointer
// direction: direction ID
// n_tiles: move range (in number of tiles)
bool8 IsTargetInRange(struct entity *user, struct entity *target, s32 direction, s32 n_tiles);
#endif //PMDSKY_DUNGEON_AI_ATTACK_H

View File

@@ -1,15 +0,0 @@
#ifndef PMDSKY_DUNGEON_AI_ATTACK_1_H
#define PMDSKY_DUNGEON_AI_ATTACK_1_H
#include "dungeon_mode.h"
// Returns true if the target is within range of the user's move, false otherwise.
// If the user does not have Course Checker, it simply checks if the distance between user and target is less or equal than the move range.
// Otherwise, it will iterate through all tiles in the direction specified, checking for walls or other monsters in the way, and return false if they are found.
// user: user pointer
// target: target pointer
// direction: direction ID
// n_tiles: move range (in number of tiles)
bool8 IsTargetInRange(struct entity *user, struct entity *target, s32 direction, s32 n_tiles);
#endif //PMDSKY_DUNGEON_AI_ATTACK_1_H

View File

@@ -524,8 +524,6 @@ Overlay OVY_29
Object src/inflict_status.o
Object src/dungeon_ai_attack.o
Object asm/overlay_29_bss_0237CA18.o
Object asm/overlay_29_0231A460.o
Object src/dungeon_ai_attack_1.o
Object asm/overlay_29_0231A7A0.o
Object src/overlay_29_0231A87C.o
Object asm/overlay_29_0231A8A0.o

View File

@@ -1,6 +1,5 @@
#include "dungeon_ai_attack.h"
#include "dg_random.h"
#include "dungeon_ai_attack_1.h"
#include "dungeon_ai_targeting_1.h"
#include "dungeon_capabilities.h"
#include "dungeon_capabilities_4.h"
@@ -34,6 +33,8 @@ s32 AI_POTENTIAL_ATTACK_TARGET_WEIGHTS[NUM_DIRECTIONS] = {0};
struct entity *AI_POTENTIAL_ATTACK_TARGETS[NUM_DIRECTIONS] = {0};
#endif
extern enum direction_id ov29_0230F8D0(struct entity *pokemon, s32);
void ResetAiCanAttackInDirection()
{
for (s32 i = 0; i < NUM_DIRECTIONS; i++)
@@ -932,3 +933,121 @@ s32 WeightMoveWithIqSkills(struct entity *user, s32 move_ai_range, struct entity
return weight;
}
bool8 TargetRegularAttack(struct entity *pokemon, u32 *target_dir, bool8 skip_petrified)
{
s32 num_potential_targets = 0;
s32 i;
struct monster *pokemon_info = GetEntInfo(pokemon);
s32 direction = pokemon_info->action.direction;
s32 face_turn_limit;
if (IsBlinded(pokemon, TRUE))
face_turn_limit = 1;
else
{
enum direction_id ov29_0230F8D0_result = ov29_0230F8D0(pokemon, 15);
face_turn_limit = 8;
if (ov29_0230F8D0_result != 0xFF)
direction = ov29_0230F8D0_result;
}
s32 potential_attack_target_directions[NUM_DIRECTIONS];
s32 potential_attack_target_weights[NUM_DIRECTIONS];
bool8 has_targeting_iq = IqSkillIsEnabled(pokemon, IQ_EXP_GO_GETTER) || IqSkillIsEnabled(pokemon, IQ_EFFICIENCY_EXPERT);
bool8 has_status_checker = IqSkillIsEnabled(pokemon, IQ_STATUS_CHECKER);
for (i = 0; i < face_turn_limit; i++, direction++)
{
struct entity *target;
direction &= DIRECTION_MASK;
target = GetTile(pokemon->pos.x + DIRECTIONS_XY[direction].x, pokemon->pos.y + DIRECTIONS_XY[direction].y)->monster;
if (target != NULL &&
GetEntityType(target) == ENTITY_MONSTER &&
CanAttackInDirection(pokemon, direction) &&
GetTreatmentBetweenMonsters(pokemon, target, FALSE, skip_petrified) == TREATMENT_TREAT_AS_ENEMY &&
(!has_status_checker || GetEntInfo(target)->frozen_class_status.freeze != STATUS_FROZEN_FROZEN))
{
potential_attack_target_directions[num_potential_targets] = direction;
potential_attack_target_weights[num_potential_targets] = WeightMoveWithIqSkills(pokemon, TARGET_ENEMIES, target, TYPE_NONE);
if (!has_targeting_iq)
{
*target_dir = direction;
return TRUE;
}
num_potential_targets++;
}
}
if (num_potential_targets == 0)
return FALSE;
s32 total_weight = 0;
s32 max_weight = 0;
s32 weight_counter;
for (i = 0; i < num_potential_targets; i++)
{
if (max_weight < potential_attack_target_weights[i])
max_weight = potential_attack_target_weights[i];
}
for (i = 0; i < num_potential_targets; i++)
{
if (max_weight != potential_attack_target_weights[i])
potential_attack_target_weights[i] = 0;
}
for (i = 0; i < num_potential_targets; i++)
{
total_weight += potential_attack_target_weights[i];
}
weight_counter = DungeonRandInt(total_weight);
for (i = 0; i < num_potential_targets; i++)
{
weight_counter -= potential_attack_target_weights[i];
if (weight_counter < 0)
break;
}
*target_dir = potential_attack_target_directions[i];
return TRUE;
}
bool8 IsTargetInRange(struct entity *user, struct entity *target, s32 direction, s32 n_tiles)
{
s32 effective_max_range = Max(abs(user->pos.x - target->pos.x), abs(user->pos.y - target->pos.y));
if (effective_max_range > n_tiles)
effective_max_range = n_tiles;
if (!IqSkillIsEnabled(user, IQ_COURSE_CHECKER))
// BUG: effective_max_range is already capped at max_range, 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.
return effective_max_range <= n_tiles;
s32 i;
s32 current_pos_x = user->pos.x;
s32 current_pos_y = user->pos.y;
s32 adjacent_tile_offset_x = DIRECTIONS_XY[direction].x;
s32 adjacent_tile_offset_y = DIRECTIONS_XY[direction].y;
for (i = 0; i <= effective_max_range; i++)
{
current_pos_x += adjacent_tile_offset_x;
current_pos_y += adjacent_tile_offset_y;
if (current_pos_x < 1 || current_pos_y < 1 ||
current_pos_x >= DUNGEON_MAX_SIZE_X - 1 || current_pos_y >= DUNGEON_MAX_SIZE_Y - 1)
break;
const struct tile *map_tile = GetTile(current_pos_x, current_pos_y);
if (GetTerrainType(map_tile) == TERRAIN_TYPE_WALL)
return FALSE;
if (map_tile->monster == target)
return TRUE;
if (map_tile->monster != NULL)
return FALSE;
}
return FALSE;
}

View File

@@ -1,49 +0,0 @@
#include "dungeon_ai_attack_1.h"
#include "dungeon.h"
#include "dungeon_map_access.h"
#include "dungeon_pokemon_attributes.h"
#include "dungeon_pokemon_attributes_1.h"
#include "dungeon_util.h"
#include "dungeon_util_static.h"
#include "main_0208655C.h"
#include "util.h"
bool8 IsTargetInRange(struct entity *user, struct entity *target, s32 direction, s32 n_tiles)
{
s32 effective_max_range = Max(abs(user->pos.x - target->pos.x), abs(user->pos.y - target->pos.y));
if (effective_max_range > n_tiles)
effective_max_range = n_tiles;
if (!IqSkillIsEnabled(user, IQ_COURSE_CHECKER))
// BUG: effective_max_range is already capped at max_range, 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.
return effective_max_range <= n_tiles;
s32 i;
s32 current_pos_x = user->pos.x;
s32 current_pos_y = user->pos.y;
s32 adjacent_tile_offset_x = DIRECTIONS_XY[direction].x;
s32 adjacent_tile_offset_y = DIRECTIONS_XY[direction].y;
for (i = 0; i <= effective_max_range; i++)
{
current_pos_x += adjacent_tile_offset_x;
current_pos_y += adjacent_tile_offset_y;
if (current_pos_x < 1 || current_pos_y < 1 ||
current_pos_x >= DUNGEON_MAX_SIZE_X - 1 || current_pos_y >= DUNGEON_MAX_SIZE_Y - 1)
break;
const struct tile *map_tile = GetTile(current_pos_x, current_pos_y);
if (GetTerrainType(map_tile) == TERRAIN_TYPE_WALL)
return FALSE;
if (map_tile->monster == target)
return TRUE;
if (map_tile->monster != NULL)
return FALSE;
}
return FALSE;
}

View File

@@ -22,7 +22,6 @@
#define REGULAR_ATTACK_INDEX 4
extern bool8 TargetRegularAttack(struct entity *pokemon, u32 *target_dir, bool8 skip_petrified);
extern void SetActionRegularAttack(struct action_data *monster_action, u8 direction);
extern void SetActionStruggle(struct action_data *monster_action, u8 direction);
extern bool8 CanAiUseMove(struct entity *monster, u32 move_index, bool8 extra_checks);

View File

@@ -2,7 +2,6 @@
#include "dg_random.h"
#include "dungeon.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_1.h"