diff --git a/asm/include/overlay_29_02301234.inc b/asm/include/overlay_29_023012F8.inc similarity index 89% rename from asm/include/overlay_29_02301234.inc rename to asm/include/overlay_29_023012F8.inc index 38869820..f7c9317a 100644 --- a/asm/include/overlay_29_02301234.inc +++ b/asm/include/overlay_29_023012F8.inc @@ -1,4 +1,5 @@ #pragma once +.public DIRECTIONAL_BIT_MASKS__02352770 .public DIRECTIONS_XY .public DUNGEON_PTR .public DungeonRandInt @@ -10,5 +11,3 @@ .public IsTacticSet .public ItemIsActive__022FF898 .public SECONDARY_TERRAIN_TYPES -.public DIRECTIONAL_BIT_MASKS__02352770 -.public DIRECTIONAL_BIT_MASKS__02352778 diff --git a/asm/overlay_29_02301234.s b/asm/overlay_29_023012F8.s similarity index 74% rename from asm/overlay_29_02301234.s rename to asm/overlay_29_023012F8.s index 3c7786fd..c9ce09d2 100644 --- a/asm/overlay_29_02301234.s +++ b/asm/overlay_29_023012F8.s @@ -1,100 +1,8 @@ .include "asm/macros.inc" - .include "overlay_29_02301234.inc" + .include "overlay_29_023012F8.inc" .text - arm_func_start CanAttackInDirection -CanAttackInDirection: ; 0x02301234 - stmdb sp!, {r4, r5, r6, lr} - mov r6, r0 - ldr r2, [r6, #0xb4] - mov r5, r1 - ldrsh r1, [r2, #2] - bl GetMobilityTypeCheckSlipAndFloating - mov r4, r0 - ldr r1, _023012EC ; =DIRECTIONS_XY - mov ip, r5, lsl #2 - cmp r4, #1 - ldr r0, _023012F0 ; =DIRECTIONS_XY + 2 - ldrsh r3, [r1, ip] - ldrsh lr, [r6, #4] - ldrsh r1, [r0, ip] - ldrsh r2, [r6, #6] - add r0, lr, r3 - movls r4, #2 - add r1, r2, r1 - bl GetTile - ldrh r1, [r0] - tst r1, #0x10 - movne r0, #0 - ldmneia sp!, {r4, r5, r6, pc} - ldr r0, [r0, #0xc] - cmp r0, #0 - ldrne r0, [r0] - cmpne r0, #1 - movne r0, #0 - ldmneia sp!, {r4, r5, r6, pc} -#ifdef JAPAN - bl IsCurrentTilesetBackground - cmp r0, #0 - bne _02302778 - ldr r0, [r6, #0xb4] - ldrb r0, [r0, #0xef] - cmp r0, #3 - moveq r4, #3 - beq _02302778 - mov r0, r6 - mov r1, #0x10 - bl ItemIsActive__022FF898 - cmp r0, #0 - movne r4, #3 - bne _02302778 - mov r0, r6 - mov r1, #0xc - bl IqSkillIsEnabled - cmp r0, #0 - movne r4, #2 - bne _02302778 - mov r0, r6 - mov r1, #0xd - bl IqSkillIsEnabled - cmp r0, #0 - beq _02302778 - tst r5, #1 - movne r4, #2 - moveq r4, #3 -_02302778: -#else - mov r0, r6 - mov r1, r4 - and r2, r5, #0xff - bl GetDirectionalMobilityType - mov r4, r0 -#endif - ldrsh r0, [r6, #4] - ldrsh r1, [r6, #6] - bl GetTile - add r0, r0, r4 - ldr r1, _023012F4 ; =DIRECTIONAL_BIT_MASKS__02352778 - and r2, r5, #7 - ldrb r1, [r1, r2] - ldrb r0, [r0, #8] - tst r1, r0 -#ifdef JAPAN - movne r0, #1 - moveq r0, #0 - and r0, r0, #0xff -#else - moveq r0, #0 - movne r0, #1 -#endif - ldmia sp!, {r4, r5, r6, pc} - .align 2, 0 -_023012EC: .word DIRECTIONS_XY -_023012F0: .word DIRECTIONS_XY + 2 -_023012F4: .word DIRECTIONAL_BIT_MASKS__02352778 - arm_func_end CanAttackInDirection - arm_func_start CanAiMonsterMoveInDirection CanAiMonsterMoveInDirection: ; 0x023012F8 stmdb sp!, {r4, r5, r6, r7, r8, lr} diff --git a/include/dungeon_capabilities_4.h b/include/dungeon_capabilities_4.h index 8b51a057..8ebdd512 100644 --- a/include/dungeon_capabilities_4.h +++ b/include/dungeon_capabilities_4.h @@ -8,5 +8,8 @@ bool8 IsMonsterCornered(struct entity *monster); // Checks if the given monster can move in the specified direction. Includes if an allied or neutral monster is standing on an adjacent tile, as the monsters can swap places. // Returns false if an enemy monster is standing on the target tile bool8 CanMonsterMoveOrSwapWithAllyInDirection(struct entity *monster, s32 direction); +// Returns whether a monster can attack in a given direction. +// The check fails if the destination tile is impassable, contains a monster that isn't of type entity_type::ENTITY_MONSTER or if the monster can't directly move from the current tile into the destination tile. +bool8 CanAttackInDirection(struct entity *monster, s32 direction); #endif //PMDSKY_DUNGEON_CAPABILITIES_4_H diff --git a/main.lsf b/main.lsf index 8dec0ada..f999caf4 100644 --- a/main.lsf +++ b/main.lsf @@ -378,7 +378,7 @@ Overlay OVY_29 Object src/dungeon_capabilities_3.o Object asm/overlay_29_02300FCC.o Object src/dungeon_capabilities_4.o - Object asm/overlay_29_02301234.o + Object asm/overlay_29_023012F8.o Object src/dungeon_ai_targeting.o Object asm/overlay_29_023016D8.o Object src/dungeon_ai_targeting_1.o diff --git a/src/dungeon_capabilities_4.c b/src/dungeon_capabilities_4.c index 1e457160..5c19525a 100644 --- a/src/dungeon_capabilities_4.c +++ b/src/dungeon_capabilities_4.c @@ -68,3 +68,47 @@ bool8 CanMonsterMoveOrSwapWithAllyInDirection(struct entity *monster, s32 direct return FALSE; } + +bool8 CanAttackInDirection(struct entity *monster, s32 direction) +{ + struct monster *monster_info = GetEntInfo(monster); + enum mobility_type mobility = GetMobilityTypeCheckSlipAndFloating(monster, monster_info->id); + if (mobility <= MOBILITY_SECONDARY) + mobility = MOBILITY_HOVERING; + const struct tile *current_map_tile = GetTile(monster->pos.x + DIRECTIONS_XY[direction].x, + monster->pos.y + DIRECTIONS_XY[direction].y); + + if (current_map_tile->terrain_flags & TERRAIN_TYPE_IMPASSABLE_WALL) + return FALSE; + + if (current_map_tile->monster != NULL && current_map_tile->monster->type != ENTITY_MONSTER) + return FALSE; + + #ifdef JAPAN + if (!IsCurrentTilesetBackground()) + { + if (GetEntInfo(monster)->invisible_class_status.status == STATUS_INVISIBLE_MOBILE) + mobility = MOBILITY_INTANGIBLE; + else if (ItemIsActive__022FF898(monster, ITEM_MOBILE_SCARF)) + mobility = MOBILITY_INTANGIBLE; + else if (IqSkillIsEnabled(monster, IQ_ALL_TERRAIN_HIKER)) + // BUG: If a Pokémon can normally attack through walls, All-Terrain Hiker will block them from attacking through walls. + // This bug is fixed in the NA/EU versions. + mobility = MOBILITY_HOVERING; + else if (IqSkillIsEnabled(monster, IQ_ABSOLUTE_MOVER)) { + if (direction & 1) + mobility = MOBILITY_HOVERING; + else + mobility = MOBILITY_INTANGIBLE; + } + } + #else + mobility = GetDirectionalMobilityType(monster, mobility, direction); + #endif + + current_map_tile = GetTile(monster->pos.x, monster->pos.y); + if (!(current_map_tile->walkable_neighbor_flags[mobility] & DIRECTIONAL_BIT_MASKS__02352778[direction & DIRECTION_MASK])) + return FALSE; + + return TRUE; +} diff --git a/src/move_checks.c b/src/move_checks.c index ba4f2490..d8f2da90 100644 --- a/src/move_checks.c +++ b/src/move_checks.c @@ -35,6 +35,7 @@ bool8 StatusCheckerCheck(struct entity *attacker, struct move *move) return FALSE; break; case MOVE_MIRROR_MOVE: + // This check is inconsistent for the Chatot Scarf because it includes RNG. if (MirrorMoveIsActive(attacker)) return FALSE; break;