From 64c8ffcd1783f3347cbfbf00c3ef1ca2323bd5f4 Mon Sep 17 00:00:00 2001 From: AnonymousRandomPerson Date: Sat, 21 Jun 2025 23:47:29 -0500 Subject: [PATCH] Added nonmatching for AiConsiderMove --- asm/include/overlay_29_02318E70.inc | 20 +-- asm/include/overlay_29_02319FB0.inc | 8 +- asm/overlay_29_02318E70.s | 45 ++--- asm/overlay_29_02319FB0.s | 26 +-- asm/overlay_29_bss_0237CA18.s | 16 +- include/dungeon_ai_attack.h | 21 +++ include/dungeon_ai_attack_1.h | 2 +- include/dungeon_ai_itcm.h | 8 +- include/move_data.h | 53 +++--- include/overlay_29_02319F8C.h | 9 - include/util.h | 2 + main.lsf | 2 +- src/dungeon_ai_attack.c | 259 ++++++++++++++++++++++++++++ src/dungeon_ai_attack_1.c | 2 +- src/dungeon_ai_itcm.c | 2 +- src/overlay_29_02319F8C.c | 9 - 16 files changed, 368 insertions(+), 116 deletions(-) delete mode 100644 include/overlay_29_02319F8C.h create mode 100644 src/dungeon_ai_attack.c delete mode 100644 src/overlay_29_02319F8C.c diff --git a/asm/include/overlay_29_02318E70.inc b/asm/include/overlay_29_02318E70.inc index 871bd8cd..30006360 100644 --- a/asm/include/overlay_29_02318E70.inc +++ b/asm/include/overlay_29_02318E70.inc @@ -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 diff --git a/asm/include/overlay_29_02319FB0.inc b/asm/include/overlay_29_02319FB0.inc index 8b0f98d4..cb2a4340 100644 --- a/asm/include/overlay_29_02319FB0.inc +++ b/asm/include/overlay_29_02319FB0.inc @@ -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 diff --git a/asm/overlay_29_02318E70.s b/asm/overlay_29_02318E70.s index 15847139..6d5e9746 100644 --- a/asm/overlay_29_02318E70.s +++ b/asm/overlay_29_02318E70.s @@ -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 diff --git a/asm/overlay_29_02319FB0.s b/asm/overlay_29_02319FB0.s index 158796ee..1e554738 100644 --- a/asm/overlay_29_02319FB0.s +++ b/asm/overlay_29_02319FB0.s @@ -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] diff --git a/asm/overlay_29_bss_0237CA18.s b/asm/overlay_29_bss_0237CA18.s index ec23a8e2..4a753ed0 100644 --- a/asm/overlay_29_bss_0237CA18.s +++ b/asm/overlay_29_bss_0237CA18.s @@ -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: diff --git a/include/dungeon_ai_attack.h b/include/dungeon_ai_attack.h index 6d277b25..55ee52d0 100644 --- a/include/dungeon_ai_attack.h +++ b/include/dungeon_ai_attack.h @@ -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 diff --git a/include/dungeon_ai_attack_1.h b/include/dungeon_ai_attack_1.h index e53a29ef..a6731b91 100644 --- a/include/dungeon_ai_attack_1.h +++ b/include/dungeon_ai_attack_1.h @@ -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 diff --git a/include/dungeon_ai_itcm.h b/include/dungeon_ai_itcm.h index 0b50ffd3..3e863c9c 100644 --- a/include/dungeon_ai_itcm.h +++ b/include/dungeon_ai_itcm.h @@ -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); diff --git a/include/move_data.h b/include/move_data.h index 236217f5..cfed47fa 100644 --- a/include/move_data.h +++ b/include/move_data.h @@ -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. diff --git a/include/overlay_29_02319F8C.h b/include/overlay_29_02319F8C.h deleted file mode 100644 index e173ecda..00000000 --- a/include/overlay_29_02319F8C.h +++ /dev/null @@ -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 diff --git a/include/util.h b/include/util.h index ee83887f..750849c4 100644 --- a/include/util.h +++ b/include/util.h @@ -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; diff --git a/main.lsf b/main.lsf index 5dcf5be8..81a81e9a 100644 --- a/main.lsf +++ b/main.lsf @@ -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 diff --git a/src/dungeon_ai_attack.c b/src/dungeon_ai_attack.c new file mode 100644 index 00000000..a162754c --- /dev/null +++ b/src/dungeon_ai_attack.c @@ -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; +} diff --git a/src/dungeon_ai_attack_1.c b/src/dungeon_ai_attack_1.c index c625f512..7b7a57c1 100644 --- a/src/dungeon_ai_attack_1.c +++ b/src/dungeon_ai_attack_1.c @@ -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)); diff --git a/src/dungeon_ai_itcm.c b/src/dungeon_ai_itcm.c index 622f1cf1..2da8cb14 100644 --- a/src/dungeon_ai_itcm.c +++ b/src/dungeon_ai_itcm.c @@ -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); diff --git a/src/overlay_29_02319F8C.c b/src/overlay_29_02319F8C.c deleted file mode 100644 index 3b97457b..00000000 --- a/src/overlay_29_02319F8C.c +++ /dev/null @@ -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; -}