Skip to content

Keep the path solve's target room check on 1.14d - #245

Open
ResurrectedTrader wants to merge 1 commit into
ThePhrozenKeep:masterfrom
ResurrectedTrader:fix/path-target-room-check-114d
Open

ResurrectedTrader wants to merge 1 commit into
ThePhrozenKeep:masterfrom
ResurrectedTrader:fix/path-target-room-check-114d

Conversation

@ResurrectedTrader

Copy link
Copy Markdown
Contributor

D2Common_10142 (the path solve) only checks tPathInfo.pTargetRoom under D2_VERSION_113C. A 1.14d build therefore goes on solving toward a target subtile that lies in no active room, where the game gives up.

1.14d

PATH_CalculatePath (Game.exe 0x649970) fails when either room is missing, before the PATH_IsTargetDestinationAllowed / bAllowInTown test:

00649A90  sub     eax, ebx
00649A92  mov     ebx, ecx
00649A94  sub     ecx, esi
00649A96  cmp     eax, 64h                          ; |dx| <= 100
00649A99  jg      loc_649C7B
00649A9F  neg     eax
00649AA1  cmp     eax, 64h
00649AA4  jg      loc_649C7B
00649AAA  cmp     ecx, 64h                          ; |dy| <= 100
00649AAD  jg      loc_649C7B
00649AB3  neg     ecx
00649AB5  cmp     ecx, 64h
00649AB8  jg      loc_649C7B
00649ABE  mov     ecx, [edi+1Ch]                    ; start room
00649AC1  push    ebx
00649AC2  mov     [ebp+var_2C], ecx
00649AC5  call    DRLGROOM_FindBetterNearbyRoom     ; target room (COLLISION_GetRoomBySubTileCoordinates)
00649ACA  cmp     [ebp+var_2C], 0                   ; start room
00649ACE  mov     [ebp+var_28], eax
00649AD1  jz      loc_649C7B                        ; -> no path
00649AD7  test    eax, eax                          ; <== target room
00649AD9  jz      loc_649C7B                        ; <== -> no path
00649ADF  mov     ecx, [ebp+arg_4]
00649AE2  lea     esi, [ebp+var_34]
00649AE5  call    PATH_CanMonsterPathInArea         ; PATH_IsTargetDestinationAllowed
00649AEA  test    eax, eax
00649AEC  jnz     short loc_649AF7
00649AEE  cmp     [ebp+arg_8], eax                  ; bAllowInTown
00649AF1  jz      loc_649C7B

1.10f

1.10f does not have the check, which is why it stays version-gated. D2Common.0x6FDA8600 (#10142) only asserts the start room (tPathInfo.hRoomStart). It accepts a NULL target room and, for the in-town test, falls back to the room halfway between start and target:

6FDA88E7  mov     eax, [esi+1Ch]                    ; start room
6FDA88EA  cmp     eax, ebp
6FDA88EC  mov     [esp+78h+var_2C], eax
6FDA88F0  jz      short loc_6FDA8969
6FDA88F2  mov     ecx, [eax]
6FDA88F4  cmp     edi, ecx
6FDA88F6  jl      short loc_6FDA8911
6FDA88F8  mov     edx, [eax+8]
6FDA88FB  add     edx, ecx
6FDA88FD  cmp     edi, edx
6FDA88FF  jge     short loc_6FDA8911
6FDA8901  mov     ecx, [eax+4]
6FDA8904  cmp     ebx, ecx
6FDA8906  jl      short loc_6FDA8911
6FDA8908  mov     edx, [eax+0Ch]
6FDA890B  add     edx, ecx
6FDA890D  cmp     ebx, edx
6FDA890F  jl      short loc_6FDA896B
6FDA8911  lea     ecx, [esp+78h+arg_0]
6FDA8915  lea     edx, [esp+78h+var_68]
6FDA8919  push    ecx
6FDA891A  push    edx
6FDA891B  push    eax
6FDA891C  mov     [esp+84h+var_68], ebp
6FDA8920  mov     [esp+84h+arg_0], ebp
6FDA8927  call    DUNGEON_GetAdjacentRoomsListFromRoom ; target room: search the adjacent rooms
6FDA892C  xor     edx, edx
6FDA892E  cmp     [esp+78h+arg_0], ebp
6FDA8932  jbe     short loc_6FDA8969
6FDA8934  mov     eax, [esp+78h+var_68]
6FDA8938  mov     eax, [eax+edx*4]
6FDA893B  cmp     eax, ebp
6FDA893D  jz      short loc_6FDA895E
6FDA893F  mov     ecx, [eax]
6FDA8941  cmp     edi, ecx
6FDA8943  jl      short loc_6FDA895E
6FDA8945  mov     ebp, [eax+8]
6FDA8948  add     ebp, ecx
6FDA894A  cmp     edi, ebp
6FDA894C  jge     short loc_6FDA895E
6FDA894E  mov     ecx, [eax+4]
6FDA8951  cmp     ebx, ecx
6FDA8953  jl      short loc_6FDA895E
6FDA8955  mov     eax, [eax+0Ch]
6FDA8958  add     eax, ecx
6FDA895A  cmp     ebx, eax
6FDA895C  jl      short loc_6FDA8997
6FDA895E  mov     eax, [esp+78h+arg_0]
6FDA8962  inc     edx
6FDA8963  xor     ebp, ebp
6FDA8965  cmp     edx, eax
6FDA8967  jb      short loc_6FDA8934
6FDA8969  xor     eax, eax                          ; not found: target room = NULL, no bail-out
6FDA896B  mov     [esp+78h+var_28], eax             ; target room
6FDA896F  mov     eax, [esp+78h+var_2C]
6FDA8973  xor     ebp, ebp
6FDA8975  cmp     eax, ebp
6FDA8977  jnz     short loc_6FDA89A0                ; start room: assert only
6FDA8979  push    327h
6FDA897E  push    6FDE51B4h
6FDA8983  push    6FDE5170h
6FDA8988  call    6FDC4352h
6FDA898D  add     esp, 0Ch
6FDA8990  push    0FFFFFFFFh
6FDA8992  call    6FDC446Fh
6FDA8997  mov     ecx, [esp+78h+var_68]
6FDA899B  mov     eax, [ecx+edx*4]
6FDA899E  jmp     short loc_6FDA896B
6FDA89A0  mov     ebx, [esp+78h+arg_4]
6FDA89A7  cmp     ebx, ebp
6FDA89A9  jz      loc_6FDA8A3F
6FDA89AF  cmp     dword ptr [ebx], 1
6FDA89B2  jnz     loc_6FDA8A3F
6FDA89B8  mov     ecx, ebx
6FDA89BA  call    sub_6FDA56C0
6FDA89BF  test    eax, eax
6FDA89C1  jnz     short loc_6FDA8A3F
6FDA89C3  mov     eax, [esp+78h+var_28]             ; target room NULL?
6FDA89C7  cmp     eax, ebp
6FDA89C9  jnz     short loc_6FDA8A1F                ; -> use the midpoint's room instead
6FDA89CB  mov     edi, [esp+78h+var_30+2]
6FDA89CF  mov     ecx, [esp+78h+var_34+2]
6FDA89D3  and     edi, 0FFFFh
6FDA89D9  and     ecx, 0FFFFh
6FDA89DF  mov     eax, edi
6FDA89E1  mov     ebx, [esp+78h+var_30]
6FDA89E5  sub     eax, ecx
6FDA89E7  mov     ebp, [esp+78h+var_34]
6FDA89EB  cdq
6FDA89EC  sub     eax, edx
6FDA89EE  and     ebx, 0FFFFh
6FDA89F4  sar     eax, 1
6FDA89F6  add     eax, ecx
6FDA89F8  and     ebp, 0FFFFh
6FDA89FE  push    eax
6FDA89FF  mov     eax, ebx
6FDA8A01  sub     eax, ebp
6FDA8A03  mov     ecx, [esp+7Ch+var_2C]
6FDA8A07  cdq
6FDA8A08  sub     eax, edx
6FDA8A0A  mov     edx, eax
6FDA8A0C  sar     edx, 1
6FDA8A0E  add     edx, ebp
6FDA8A10  call    sub_6FD46620
6FDA8A15  push    edi
6FDA8A16  mov     edx, ebx
6FDA8A18  mov     ecx, eax
6FDA8A1A  call    sub_6FD46620
6FDA8A1F  push    eax
6FDA8A20  call    DUNGEON_IsRoomInTown              ; in-town test
6FDA8A25  xor     ebp, ebp
6FDA8A27  test    eax, eax
6FDA8A29  jz      short loc_6FDA8A38
6FDA8A2B  cmp     [esp+78h+arg_8], ebp              ; bAllowInTown
6FDA8A32  jz      loc_6FDA8DFE
6FDA8A38  mov     ebx, [esp+78h+arg_4]
6FDA8A3F  mov     edx, [esi+3Ch]
6FDA8A42  mov     edi, [esi+58h]

Change

Keep the check for D2_VERSION_113C and for 1.14 or later:

#if defined(D2_VERSION_113C) || (D2_VERSION_MAJOR >= 1 && D2_VERSION_MINOR >= 14)

This uses the same D2_VERSION_MAJOR / D2_VERSION_MINOR test as MOO's other version gates. I have not checked 1.11 / 1.12 / 1.13d, so they keep the current behaviour.

🤖 Generated with Claude Code

D2Common_10142 only checks tPathInfo.pTargetRoom under D2_VERSION_113C,
so a 1.14d build solves toward a target subtile that is in no active
room, where the game gives up.

1.14d PATH_CalculatePath (Game.exe.0x649970) fails when either room is
missing, before the in-area / bAllowInTown test: start room at
0x649ACA/0x649AD1, target room at 0x649AD7/0x649AD9.

1.10f does not have the check (D2Common.0x6FDA8600 only asserts the
start room and tolerates a NULL target room), so it stays gated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant