Added nonmatching for AiConsiderMove

This commit is contained in:
AnonymousRandomPerson
2025-06-21 23:47:29 -05:00
parent c0c6961c6e
commit 64c8ffcd17
16 changed files with 368 additions and 116 deletions

View File

@@ -1,6 +1,6 @@
#pragma once
.public AbilityIsActiveVeneer
.public abs
.public CAN_ATTACK_IN_DIRECTION
.public CalcStatusDuration
.public CanAttackInDirection
.public CanSeeTarget
@@ -22,6 +22,15 @@
.public IsBlinded
.public IsTargetInRange
.public LogMessageByIdWithPopupCheckUserTarget
.public POTENTIAL_ATTACK_TARGET_DIRECTIONS
.public POTENTIAL_ATTACK_TARGET_WEIGHTS
.public POTENTIAL_TARGETS
.public StatusCheckerCheck
.public SubstitutePlaceholderStringTags
.public TryAddTargetToAiTargetList
.public UpdateStatusIconFlags
.public WeightMove
.public abs
.public ov10_022C4648
.public ov10_022C472C
.public ov10_022C4730
@@ -48,12 +57,3 @@
.public ov29_022E415C
.public ov29_022E41AC
.public ov29_022E543C
.public ov29_0231A364
.public ov29_0237CA18
.public ov29_0237CA20
.public ov29_0237CA28
.public ov29_0237CA48
.public StatusCheckerCheck
.public SubstitutePlaceholderStringTags
.public TryAddTargetToAiTargetList
.public UpdateStatusIconFlags

View File

@@ -19,7 +19,7 @@
.public ov29_0230B7D4
.public ov29_0230F8D0
.public ov29_02333FD0
.public ov29_0237CA18
.public ov29_0237CA20
.public ov29_0237CA28
.public ov29_0237CA48
.public CAN_ATTACK_IN_DIRECTION
.public POTENTIAL_ATTACK_TARGET_DIRECTIONS
.public POTENTIAL_ATTACK_TARGET_WEIGHTS
.public POTENTIAL_TARGETS

View File

@@ -834,7 +834,7 @@ _02319854:
arm_func_start ov29_0231985C
ov29_0231985C: ; 0x0231985C
mov r2, #0
ldr r0, _0231987C ; =ov29_0237CA18
ldr r0, _0231987C ; =CAN_ATTACK_IN_DIRECTION
mov r1, r2
_02319868:
strb r1, [r0, r2]
@@ -843,9 +843,11 @@ _02319868:
blt _02319868
bx lr
.align 2, 0
_0231987C: .word ov29_0237CA18
_0231987C: .word CAN_ATTACK_IN_DIRECTION
arm_func_end ov29_0231985C
; https://decomp.me/scratch/jVfou
#ifndef NONMATCHING
arm_func_start AiConsiderMove
AiConsiderMove: ; 0x02319880
#ifdef JAPAN
@@ -921,13 +923,13 @@ _02319958:
cmp r0, #0
beq _023199C0
ldrb r6, [r6, #0x4c]
ldr r4, _02319F70 ; =ov29_0237CA18
ldr r4, _02319F70 ; =CAN_ATTACK_IN_DIRECTION
ldrb r0, [r4, r6]
cmp r0, #0
bne _02319E88
ldr r1, _02319F74 ; =ov29_0237CA20
ldr r1, _02319F74 ; =POTENTIAL_ATTACK_TARGET_DIRECTIONS
mov r3, #1
ldr r0, _02319F78 ; =ov29_0237CA28
ldr r0, _02319F78 ; =POTENTIAL_ATTACK_TARGET_WEIGHTS
mov r2, #0x63
strb r3, [r4, r6]
strb r6, [r1]
@@ -1105,7 +1107,7 @@ _02319BF0:
add r0, sl, #4
add r1, r1, #4
bl GetDirectionTowardsPosition
ldr r1, _02319F70 ; =ov29_0237CA18
ldr r1, _02319F70 ; =CAN_ATTACK_IN_DIRECTION
str r0, [sp, #0x1c]
ldrb r0, [r1, r0]
cmp r0, #0
@@ -1201,12 +1203,12 @@ _02319D50:
bl IsTargetInRange
cmp r0, #0
beq _02319DE8
ldr r1, _02319F70 ; =ov29_0237CA18
ldr r1, _02319F70 ; =CAN_ATTACK_IN_DIRECTION
ldr r0, [sp, #0x1c]
mov r2, #1
strb r2, [r1, r0]
mov r1, r0
ldr r0, _02319F74 ; =ov29_0237CA20
ldr r0, _02319F74 ; =POTENTIAL_ATTACK_TARGET_DIRECTIONS
strb r1, [r0, r5]
mov r0, sl
mov r1, sb
@@ -1215,11 +1217,11 @@ _02319D50:
ldr r1, [sp, #0x24]
ldr r2, [sp, #0x18]
mov r0, sl
bl ov29_0231A364
ldr r1, _02319F84 ; =ov29_0237CA28
bl WeightMove
ldr r1, _02319F84 ; =POTENTIAL_ATTACK_TARGET_WEIGHTS
str r0, [r1, r5, lsl #2]
ldr r1, [sp, #0x18]
ldr r0, _02319F88 ; =ov29_0237CA48
ldr r0, _02319F88 ; =POTENTIAL_TARGETS
str r1, [r0, r5, lsl #2]
add r5, r5, #1
_02319DE8:
@@ -1276,7 +1278,7 @@ _02319E88:
mov r0, #0
str r0, [sp, #0x14]
mov r4, r0
ldr r3, _02319F84 ; =ov29_0237CA28
ldr r3, _02319F84 ; =POTENTIAL_ATTACK_TARGET_WEIGHTS
b _02319EC4
_02319EB0:
ldr r2, [r3, r4, lsl #2]
@@ -1289,7 +1291,7 @@ _02319EC4:
blt _02319EB0
mov r6, #0
mov r2, r6
ldr r4, _02319F84 ; =ov29_0237CA28
ldr r4, _02319F84 ; =POTENTIAL_ATTACK_TARGET_WEIGHTS
b _02319EF0
_02319EDC:
ldr r3, [r4, r6, lsl #2]
@@ -1301,7 +1303,7 @@ _02319EF0:
cmp r6, r5
blt _02319EDC
mov r3, #0
ldr r2, _02319F84 ; =ov29_0237CA28
ldr r2, _02319F84 ; =POTENTIAL_ATTACK_TARGET_WEIGHTS
b _02319F10
_02319F04:
ldr r1, [r2, r3, lsl #2]
@@ -1312,7 +1314,7 @@ _02319F10:
blt _02319F04
bl DungeonRandInt
mov r3, #0
ldr r2, _02319F84 ; =ov29_0237CA28
ldr r2, _02319F84 ; =POTENTIAL_ATTACK_TARGET_WEIGHTS
b _02319F38
_02319F28:
ldr r1, [r2, r3, lsl #2]
@@ -1323,7 +1325,7 @@ _02319F38:
cmp r3, r5
blt _02319F28
_02319F40:
ldr r1, _02319F74 ; =ov29_0237CA20
ldr r1, _02319F74 ; =POTENTIAL_ATTACK_TARGET_DIRECTIONS
ldr r0, [sp, #8]
mov r2, #1
strb r2, [r0]
@@ -1338,11 +1340,12 @@ _02319F64:
ldmia sp!, {r4, r5, r6, r7, r8, sb, sl, fp, pc}
.align 2, 0
_02319F6C: .word 0x00000273
_02319F70: .word ov29_0237CA18
_02319F74: .word ov29_0237CA20
_02319F78: .word ov29_0237CA28
_02319F70: .word CAN_ATTACK_IN_DIRECTION
_02319F74: .word POTENTIAL_ATTACK_TARGET_DIRECTIONS
_02319F78: .word POTENTIAL_ATTACK_TARGET_WEIGHTS
_02319F7C: .word DIRECTIONS_XY
_02319F80: .word DUNGEON_PTR
_02319F84: .word ov29_0237CA28
_02319F88: .word ov29_0237CA48
_02319F84: .word POTENTIAL_ATTACK_TARGET_WEIGHTS
_02319F88: .word POTENTIAL_TARGETS
arm_func_end AiConsiderMove
#endif

View File

@@ -30,7 +30,7 @@ TryAddTargetToAiTargetList: ; 0x02319FB0
bl GetDirectionTowardsPosition
mov r5, r0
_0231A010:
ldr r4, _0231A094 ; =ov29_0237CA18
ldr r4, _0231A094 ; =CAN_ATTACK_IN_DIRECTION
ldrb r0, [r4, r5]
cmp r0, #0
movne r0, sb
@@ -44,7 +44,7 @@ _0231A010:
bl IsAiTargetEligible
cmp r0, #0
beq _0231A08C
ldr r2, _0231A098 ; =ov29_0237CA20
ldr r2, _0231A098 ; =POTENTIAL_ATTACK_TARGET_DIRECTIONS
mov r3, #1
ldr r1, [sp, #0x20]
mov r0, r7
@@ -55,9 +55,9 @@ _0231A010:
mov r0, r7
mov r1, r8
mov r2, r6
bl ov29_0231A364
ldr r2, _0231A09C ; =ov29_0237CA28
ldr r1, _0231A0A0 ; =ov29_0237CA48
bl WeightMove
ldr r2, _0231A09C ; =POTENTIAL_ATTACK_TARGET_WEIGHTS
ldr r1, _0231A0A0 ; =POTENTIAL_TARGETS
str r0, [r2, sb, lsl #2]
str r6, [r1, sb, lsl #2]
add sb, sb, #1
@@ -65,10 +65,10 @@ _0231A08C:
mov r0, sb
ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, pc}
.align 2, 0
_0231A094: .word ov29_0237CA18
_0231A098: .word ov29_0237CA20
_0231A09C: .word ov29_0237CA28
_0231A0A0: .word ov29_0237CA48
_0231A094: .word CAN_ATTACK_IN_DIRECTION
_0231A098: .word POTENTIAL_ATTACK_TARGET_DIRECTIONS
_0231A09C: .word POTENTIAL_ATTACK_TARGET_WEIGHTS
_0231A0A0: .word POTENTIAL_TARGETS
arm_func_end TryAddTargetToAiTargetList
arm_func_start IsAiTargetEligible
@@ -266,8 +266,8 @@ _0231A358:
_0231A360: .word 0x000001B7
arm_func_end IsAiTargetEligible
arm_func_start ov29_0231A364
ov29_0231A364: ; 0x0231A364
arm_func_start WeightMove
WeightMove: ; 0x0231A364
stmdb sp!, {r3, r4, r5, r6, r7, r8, sb, lr}
mov r7, r2
mov sb, r0
@@ -340,7 +340,7 @@ _0231A454:
ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, pc}
.align 2, 0
_0231A45C: .word DUNGEON_PTR
arm_func_end ov29_0231A364
arm_func_end WeightMove
arm_func_start TargetRegularAttack
TargetRegularAttack: ; 0x0231A460
@@ -431,7 +431,7 @@ _0231A58C:
mov r2, r8
mov r0, sl
mov r3, r1
bl ov29_0231A364
bl WeightMove
add r1, sp, #8
cmp fp, #0
str r0, [r1, r4, lsl #2]

View File

@@ -2,17 +2,17 @@
.include "overlay_29_bss_0237CA18.inc"
.bss
.global ov29_0237CA18
ov29_0237CA18:
.global CAN_ATTACK_IN_DIRECTION
CAN_ATTACK_IN_DIRECTION:
.space 0x8
.global ov29_0237CA20
ov29_0237CA20:
.global POTENTIAL_ATTACK_TARGET_DIRECTIONS
POTENTIAL_ATTACK_TARGET_DIRECTIONS:
.space 0x8
.global ov29_0237CA28
ov29_0237CA28:
.global POTENTIAL_ATTACK_TARGET_WEIGHTS
POTENTIAL_ATTACK_TARGET_WEIGHTS:
.space 0x20
.global ov29_0237CA48
ov29_0237CA48:
.global POTENTIAL_TARGETS
POTENTIAL_TARGETS:
.space 0x20
.global ov29_0237CA68
ov29_0237CA68:

View File

@@ -1,6 +1,27 @@
#ifndef PMDSKY_DUNGEON_AI_ATTACK_H
#define PMDSKY_DUNGEON_AI_ATTACK_H
#include "dungeon_mode.h"
#define RANGED_ATTACK_RANGE 10
struct ai_possible_move
{
bool8 can_be_used;
u8 direction;
s32 weight;
};
// The AI uses this function to check if a move has any potential targets, to calculate the list of potential targets and to calculate the move's special weight. The weight is calculated using WeightMove.
// This function also sets the flag can_be_used on the ai_possible_move struct if it makes sense to use it.
// The weight returned by this function is not the same as GetMoveAiWeight. If the AI does not have Weak-Type Picker, AiConsiderMove is called after the AI has selected which move it will use (using GetMoveAiWeight). It determines whether it makes sense for the AI to actually use the chosen move (i.e., whether targets are in range), and which direction the AI will use the move in if so. The return value of this function is not used anywhere in this case.
// If the AI has Weak-Type Picker, the AI calls this function earlier in the AI logic to determine which move to use, using the returned special weight to find which move has the most advantageous type matchups.
// ai_possible_move: ai_possible_move struct for this move
// monster: Entity pointer
// move: Move pointer
// return: Move's calculated special weight
u32 AiConsiderMove(struct ai_possible_move *ai_possible_move, struct entity *monster, struct move *move);
// Checks if an entity pointer points to a valid entity (not entity type 0, which represents no entity).
bool8 EntityIsValid__02319F8C(struct entity *entity);
#endif //PMDSKY_DUNGEON_AI_ATTACK_H

View File

@@ -10,6 +10,6 @@
// target: target pointer
// direction: direction ID
// n_tiles: move range (in number of tiles)
bool8 IsTargetInRange(struct entity *user, struct entity *target, enum direction_id direction, s32 n_tiles);
bool8 IsTargetInRange(struct entity *user, struct entity *target, s32 direction, s32 n_tiles);
#endif //PMDSKY_DUNGEON_AI_ATTACK_1_H

View File

@@ -1,15 +1,9 @@
#ifndef PMDSKY_DUNGEON_AI_ITCM_H
#define PMDSKY_DUNGEON_AI_ITCM_H
#include "dungeon_ai_attack.h"
#include "dungeon_mode.h"
struct ai_possible_move
{
bool8 can_be_used;
u8 direction;
s32 weight;
};
// Determines if an AI-controlled monster will use a move and which one it will use.
void ChooseAiMove(struct entity *monster);

View File

@@ -21,21 +21,21 @@ enum move_target
// In the move data, this is the upper 4 bits of the joint Range + Target bitfield
enum move_range
{
RANGE_FRONT = 0, // 1 tile in front
RANGE_FRONT_AND_SIDES = 1, // also cuts corners
RANGE_NEARBY = 2, // the 8 surrounding tiles
RANGE_ROOM = 3, // the whole room
RANGE_FRONT_2 = 4, // 2 tiles in front, also cuts corners but the AI doesn't account for that
RANGE_FRONT_10 = 5, // 10 tiles in front
RANGE_FLOOR = 6, // the whole floor
RANGE_FRONT = 0, // 1 tile in front
RANGE_FRONT_AND_SIDES = 0x10, // also cuts corners
RANGE_NEARBY = 0x20, // the 8 surrounding tiles
RANGE_ROOM = 0x30, // the whole room
RANGE_FRONT_2 = 0x40, // 2 tiles in front, also cuts corners but the AI doesn't account for that
RANGE_FRONT_10 = 0x50, // 10 tiles in front
RANGE_FLOOR = 0x60, // the whole floor
// Depends on the move:
// - if the target is the user, then the range is also just the user
// - if the target is enemies after charging, the range is front or front with corner cutting,
// depending on the move
RANGE_USER = 7,
RANGE_FRONT_WITH_CORNER_CUTTING = 8, // same as RANGE_FRONT but cuts corners
RANGE_USER = 0x70,
RANGE_FRONT_WITH_CORNER_CUTTING = 0x80, // same as RANGE_FRONT but cuts corners
// same as RANGE_FRONT_2 but the AI accounts for corner-cutting
RANGE_FRONT_2_WITH_CORNER_CUTTING = 9,
RANGE_FRONT_2_WITH_CORNER_CUTTING = 0x90,
RANGE_SPECIAL = 15, // for weird moves
};
@@ -46,32 +46,23 @@ enum move_ai_condition
AI_CONDITION_NONE = 0,
// The AI will consider a target elegible wirh a chance equal to the
// move's "ai_condition_random_chance" value
AI_CONDITION_RANDOM = 1,
AI_CONDITION_HP_25 = 2, // Target has HP <= 25%
AI_CONDITION_STATUS = 3, // Target has a negative status condition
AI_CONDITION_ASLEEP = 4, // Target is asleep, napping or in a nightmare
AI_CONDITION_GHOST = 5, // Target is ghost-type and not exposed
AI_CONDITION_HP_25_OR_STATUS = 6, // Target has HP <= 25% or a negative status condition
};
// In the move data, the target and range are encoded together in the first byte of a single
// two-byte field. The target is the lower half, and the range is the upper half.
struct move_target_and_range
{
enum move_target target : 4;
enum move_range range : 4;
enum move_ai_condition ai_condition : 4;
AI_CONDITION_RANDOM = 0x100,
AI_CONDITION_HP_25 = 0x200, // Target has HP <= 25%
AI_CONDITION_STATUS = 0x300, // Target has a negative status condition
AI_CONDITION_ASLEEP = 0x400, // Target is asleep, napping or in a nightmare
AI_CONDITION_GHOST = 0x500, // Target is ghost-type and not exposed
AI_CONDITION_HP_25_OR_STATUS = 0x600, // Target has HP <= 25% or a negative status condition
};
// Data for a single move
struct move_data
{
u16 base_power; // 0x0
u8 type; // 0x2
u8 category; // 0x3
struct move_target_and_range target_range; // 0x4
struct move_target_and_range ai_target_range; // 0x6: Target/range as seen by the AI
u8 pp; // 0x8
u16 base_power; // 0x0
u8 type; // 0x2
u8 category; // 0x3
u16 target_range; // 0x4
u16 ai_target_range; // 0x6: Target/range as seen by the AI
u8 pp; // 0x8
u8 ai_weight; // 0x9: Possibly. Weight for AI's random move selection
// 0xA: Both accuracy values are used to calculate the move's actual accuracy.
// See the PMD Info Spreadsheet.

View File

@@ -1,9 +0,0 @@
#ifndef PMDSKY_OVERLAY_29_02319F8C_H
#define PMDSKY_OVERLAY_29_02319F8C_H
#include "dungeon_mode.h"
// Checks if an entity pointer points to a valid entity (not entity type 0, which represents no entity).
bool8 EntityIsValid__02319F8C(struct entity *entity);
#endif //PMDSKY_OVERLAY_29_02319F8C_H

View File

@@ -40,6 +40,8 @@ static inline s32 Min(s32 a, s32 b)
return a < b ? a : b;
}
#define MAX(A, B) ((A > B) ? A : B)
static inline s32 Max(s32 a, s32 b)
{
return a > b ? a : b;

View File

@@ -419,7 +419,7 @@ Overlay OVY_29
Object asm/overlay_29_02318D58.o
Object src/overlay_29_02318E4C.o
Object asm/overlay_29_02318E70.o
Object src/overlay_29_02319F8C.o
Object src/dungeon_ai_attack.o
Object asm/overlay_29_02319FB0.o
Object src/dungeon_ai_attack_1.o
Object asm/overlay_29_0231A7A0.o

259
src/dungeon_ai_attack.c Normal file
View File

@@ -0,0 +1,259 @@
#include "dungeon_ai_attack.h"
#include "dg_random.h"
#include "dungeon_ai_attack_1.h"
#include "dungeon_map_access.h"
#include "dungeon_pokemon_attributes_1.h"
#include "dungeon_statuses.h"
#include "dungeon_util.h"
#include "dungeon_util_static.h"
#include "dungeon_visibility.h"
#include "main_0208655C.h"
#include "move_data.h"
#include "position_util.h"
extern struct dungeon *DUNGEON_PTR[];
extern bool8 CAN_ATTACK_IN_DIRECTION[NUM_DIRECTIONS];
extern u8 POTENTIAL_ATTACK_TARGET_DIRECTIONS[NUM_DIRECTIONS];
extern s32 POTENTIAL_ATTACK_TARGET_WEIGHTS[NUM_DIRECTIONS];
extern struct entity *POTENTIAL_TARGETS[NUM_DIRECTIONS];
extern void ov29_0231985C();
extern u16 GetEntityMoveTargetAndRange(struct entity *entity, struct move *move, bool8 is_ai);
extern bool8 IsAffectedByTaunt(struct move *move);
extern bool8 StatusCheckerCheck(struct entity *attacker, struct move *move);
extern u16 GetMoveTargetAndRange(struct move *move, bool8 is_ai);
extern bool8 CanAttackInDirection(struct entity *monster, s32 direction);
extern s32 TryAddTargetToAiTargetList(s32 current_num_targets, s32 move_ai_range, struct entity *user, struct entity *target, struct move *move, bool8 check_all_conditions);
extern bool8 IsAiTargetEligible(s32 move_ai_range, struct entity *user, struct entity *target, struct move *move, bool8 check_all_conditions);
extern enum type_id GetMoveTypeForMonster(struct entity *entity, struct move *move);
extern s32 WeightMove(struct entity *user, s32 targeting_flags, struct entity *target, enum type_id move_type);
// https://decomp.me/scratch/jVfou
#ifdef NONMATCHING
u32 AiConsiderMove(struct ai_possible_move *ai_possible_move, struct entity *monster, struct move *move)
{
struct monster *pokemon_info = GetEntInfo(monster);
s32 move_weight = 1;
bool8 has_status_checker;
s32 num_potential_targets = 0;
ov29_0231985C();
s32 targeting_flags = GetEntityMoveTargetAndRange(monster, move, TRUE);
has_status_checker = IqSkillIsEnabled(monster, IQ_STATUS_CHECKER);
ai_possible_move->can_be_used = FALSE;
if (pokemon_info->cringe_class_status.cringe == STATUS_CRINGE_TAUNTED && !IsAffectedByTaunt(move))
return move_weight;
if (has_status_checker && !StatusCheckerCheck(monster, move))
return move_weight;
if (GetMoveTargetAndRange(move, FALSE) == TARGET_USER + RANGE_USER + AI_CONDITION_HP_25)
{
s32 max_hp = MIN(pokemon_info->max_hp_stat + pokemon_info->max_hp_boost, 999);
if (pokemon_info->hp == max_hp)
return move_weight;
}
s32 i;
s32 range_targeting_flags = targeting_flags & 0xF0;
if (range_targeting_flags == RANGE_FRONT ||
range_targeting_flags == RANGE_FRONT_AND_SIDES ||
range_targeting_flags == RANGE_NEARBY)
{
if (IsBlinded(monster, TRUE))
{
u8 direction = pokemon_info->action.direction;
if (!CAN_ATTACK_IN_DIRECTION[direction])
{
CAN_ATTACK_IN_DIRECTION[direction] = TRUE;
POTENTIAL_ATTACK_TARGET_DIRECTIONS[num_potential_targets] = direction;
POTENTIAL_ATTACK_TARGET_WEIGHTS[num_potential_targets] = 99;
POTENTIAL_ATTACK_TARGET_WEIGHTS[NUM_DIRECTIONS] = 0;
num_potential_targets++;
}
}
else
{
for (i = 0; i < NUM_DIRECTIONS; i++)
{
struct entity *adjacent_monster = GetTile(monster->pos.x + DIRECTIONS_XY[i].x, monster->pos.y + DIRECTIONS_XY[i].y)->monster;
if (adjacent_monster != NULL &&
adjacent_monster->type == ENTITY_MONSTER &&
(range_targeting_flags == RANGE_FRONT_AND_SIDES ||
range_targeting_flags == RANGE_NEARBY ||
CanAttackInDirection(monster, i)))
{
num_potential_targets = TryAddTargetToAiTargetList(num_potential_targets, targeting_flags, monster, adjacent_monster, move, has_status_checker);
}
}
}
}
else if (range_targeting_flags == RANGE_ROOM)
{
for (i = 0; i < DUNGEON_MAX_POKEMON; i++)
{
struct entity *target = DUNGEON_PTR[0]->active_monster_ptrs[i];
if (EntityIsValid__02319F8C(target) && CanSeeTarget(monster, target))
num_potential_targets = TryAddTargetToAiTargetList(num_potential_targets, targeting_flags, monster, target, move, has_status_checker);
}
}
else if (range_targeting_flags == RANGE_FRONT_2)
{
for (i = 0; i < NUM_DIRECTIONS; i++)
{
const struct tile *target_tile = GetTile(monster->pos.x + DIRECTIONS_XY[i].x, monster->pos.y + DIRECTIONS_XY[i].y);
if (CanAttackInDirection(monster, i))
{
if (target_tile->monster != NULL && target_tile->monster->type == ENTITY_MONSTER)
{
s32 prev_num_potential_targets = num_potential_targets;
num_potential_targets = TryAddTargetToAiTargetList(num_potential_targets, targeting_flags, monster, target_tile->monster, move, has_status_checker);
if (prev_num_potential_targets != num_potential_targets)
continue;
}
target_tile = GetTile(monster->pos.x + DIRECTIONS_XY[i].x * 2, monster->pos.y + DIRECTIONS_XY[i].y * 2);
if (target_tile->monster != NULL && target_tile->monster->type == ENTITY_MONSTER)
num_potential_targets = TryAddTargetToAiTargetList(num_potential_targets, targeting_flags, monster, target_tile->monster, move, has_status_checker);
}
}
}
else if (range_targeting_flags == RANGE_FRONT_10 ||
range_targeting_flags == RANGE_FRONT_WITH_CORNER_CUTTING ||
range_targeting_flags == RANGE_FRONT_2_WITH_CORNER_CUTTING)
{
s32 max_range;
if (range_targeting_flags == RANGE_FRONT_10)
max_range = RANGED_ATTACK_RANGE;
else
max_range = 1;
if (range_targeting_flags == RANGE_FRONT_2_WITH_CORNER_CUTTING)
max_range = 2;
for (s32 i = 0; i < DUNGEON_MAX_POKEMON; i++)
{
s32 direction;
struct entity *target = DUNGEON_PTR[0]->active_monster_ptrs[i];
if (EntityIsValid__02319F8C(target) && monster != target)
{
direction = GetDirectionTowardsPosition(&monster->pos, &target->pos);
if (!CAN_ATTACK_IN_DIRECTION[direction] && CanSeeTarget(monster, target))
{
s32 target_pos_x = target->pos.x;
s32 monster_pos_x = monster->pos.x;
s32 distance_x = abs(monster_pos_x - target_pos_x);
s32 target_pos_y = target->pos.y;
s32 monster_pos_y = monster->pos.y;
s32 distance_y = abs(monster_pos_y - target_pos_y);
s32 distance = MAX(distance_x, distance_y);
bool8 is_target_in_line_range;
if (distance > RANGED_ATTACK_RANGE)
is_target_in_line_range = FALSE;
else if (distance > max_range)
is_target_in_line_range = FALSE;
else
{
s32 target_direction = DIR_NONE;
if (distance_x == distance_y)
{
if (monster_pos_x < target_pos_x && monster_pos_y < target_pos_y)
target_direction = DIR_DOWN_RIGHT;
else if (monster_pos_x < target_pos_x && monster_pos_y > target_pos_y)
target_direction = DIR_UP_RIGHT;
else if (monster_pos_x > target_pos_x && monster_pos_y > target_pos_y)
target_direction = DIR_UP_LEFT;
else
target_direction = DIR_DOWN_LEFT;
}
else if (monster_pos_x == target_pos_x && monster_pos_y < target_pos_y)
target_direction = DIR_DOWN;
else if (monster_pos_x < target_pos_x && monster_pos_y == target_pos_y)
target_direction = DIR_RIGHT;
else if (monster_pos_x == target_pos_x && monster_pos_y > target_pos_y)
target_direction = DIR_UP;
else if (monster_pos_x > target_pos_x && monster_pos_y == target_pos_y)
target_direction = DIR_LEFT;
if (target_direction >= DIR_DOWN)
is_target_in_line_range = TRUE;
else
is_target_in_line_range = FALSE;
}
if (is_target_in_line_range)
{
if (IsAiTargetEligible(targeting_flags, monster, target, move, has_status_checker) &&
IsTargetInRange(monster, target, direction, max_range))
{
CAN_ATTACK_IN_DIRECTION[direction] = TRUE;
POTENTIAL_ATTACK_TARGET_DIRECTIONS[num_potential_targets] = direction;
POTENTIAL_ATTACK_TARGET_WEIGHTS[num_potential_targets] = WeightMove(monster, targeting_flags, target, GetMoveTypeForMonster(monster, move));
POTENTIAL_TARGETS[num_potential_targets] = target;
num_potential_targets++;
}
}
}
}
}
}
else if (range_targeting_flags == RANGE_FLOOR)
{
for (i = 0; i < DUNGEON_MAX_POKEMON; i++)
{
struct entity *target = DUNGEON_PTR[0]->active_monster_ptrs[i];
if (EntityIsValid__02319F8C(target))
num_potential_targets = TryAddTargetToAiTargetList(num_potential_targets, targeting_flags, monster, target, move, has_status_checker);
}
}
else if (range_targeting_flags == RANGE_USER)
num_potential_targets = TryAddTargetToAiTargetList(num_potential_targets, targeting_flags, monster, monster, move, has_status_checker);
if (num_potential_targets == 0)
ai_possible_move->can_be_used = FALSE;
else
{
s32 total_weight = 0;
s32 max_weight = 0;
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;
}
move_weight = max_weight;
for (i = 0; i < num_potential_targets; i++)
{
total_weight += POTENTIAL_ATTACK_TARGET_WEIGHTS[i];
}
s32 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;
}
ai_possible_move->can_be_used = TRUE;
ai_possible_move->direction = POTENTIAL_ATTACK_TARGET_DIRECTIONS[i];
ai_possible_move->weight = 8;
}
return move_weight;
}
#endif
bool8 EntityIsValid__02319F8C(struct entity *entity)
{
if (entity == NULL)
return FALSE;
return entity->type != ENTITY_NOTHING;
}

View File

@@ -7,7 +7,7 @@
#include "main_0208655C.h"
#include "util.h"
bool8 IsTargetInRange(struct entity *user, struct entity *target, enum direction_id direction, s32 n_tiles)
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));

View File

@@ -3,6 +3,7 @@
#include "direction.h"
#include "dungeon_action.h"
#include "dungeon_action_helper.h"
#include "dungeon_ai_attack.h"
#include "dungeon_ai_targeting.h"
#include "dungeon_capabilities_3.h"
#include "dungeon_capabilities_4.h"
@@ -23,7 +24,6 @@ const s16 AI_REGULAR_ATTACK_WEIGHTS[5] = { 100, 20, 30, 40, 50 };
extern struct dungeon *DUNGEON_PTR[];
extern u32 AiConsiderMove(struct ai_possible_move *ai_possible_move, struct entity *monster, struct move *move);
extern bool8 ov29_02338350(struct entity *monster);
extern bool8 TargetRegularAttack(struct entity *pokemon, u32 *target_dir, bool8 skip_petrified);
extern void SetActionRegularAttack(struct action_data *monster_action, u8 direction);

View File

@@ -1,9 +0,0 @@
#include "overlay_29_02319F8C.h"
bool8 EntityIsValid__02319F8C(struct entity *entity)
{
if (entity == NULL)
return FALSE;
return entity->type != ENTITY_NOTHING;
}