Skip to content

Follow the target's monster owner chain in sub_6FCBD900 - #256

Open
ResurrectedTrader wants to merge 1 commit into
ThePhrozenKeep:masterfrom
ResurrectedTrader:fix/attack-check-monster-owner-chain
Open

ResurrectedTrader wants to merge 1 commit into
ThePhrozenKeep:masterfrom
ResurrectedTrader:fix/attack-check-monster-owner-chain

Conversation

@ResurrectedTrader

Copy link
Copy Markdown
Contributor

sub_6FCBD900 (can pUnit attack pTarget) resolves the target to its owner before comparing it with the attacker. The game follows minion owners while the unit is a monster (pets, and pets of pets). MOO tested UNIT_PLAYER, so a monster target was never resolved to its owner, and a player's pet was compared as itself rather than as its owner.

1.10f

D2Game.0x6FCBD900, Hex-Rays (sub_6FCCF320 is AIGENERAL_GetMinionOwner):

LABEL_6:
  while ( a3 != nullptr )
  {
    if ( *a3 != 1 )                        // <== UNIT_MONSTER
      break;
    v6 = sub_6FCCF320(a3);
    if ( v6 == 0 || (_DWORD *)v6 == a3 )
      break;
    a3 = (_DWORD *)v6;
  }
  if ( v3 == a3 )
    return 0;
  if ( v3 == nullptr || *v3 != 0 || a3 == nullptr || *a3 != 0 )
    return D2Common_10563(v3, a3) == 0;
  return sub_6FCBA8E0(8);
6FCBD91F  mov     esi, [esp+10h]                    ; pTarget
6FCBD923  test    esi, esi
6FCBD925  jz      6FCBD9C5
6FCBD92B  cmp     dword ptr [esi], 1                ; <== UNIT_MONSTER
6FCBD92E  jnz     6FCBD9C5
6FCBD934  mov     ecx, esi
6FCBD936  call    6FCCF320                          ; AIGENERAL_GetMinionOwner
6FCBD93B  test    eax, eax
6FCBD93D  jz      6FCBD9C5
6FCBD943  cmp     eax, esi
6FCBD945  jz      6FCBD9C5
6FCBD947  mov     esi, eax
6FCBD949  jmp     6FCBD923

1.14d

UNITS_CheckIfCanAttackTarget (Game.exe 0x00554200), Hex-Rays:

LABEL_9:
  while ( a3 != nullptr )
  {
    if ( *a3 != 1 )                        // <== UNIT_MONSTER
      break;
    v6 = (_DWORD *)GetOwnerUnit_0(a3);
    if ( v6 == nullptr || v6 == a3 )
      break;
    a3 = v6;
  }
00554250  test    esi, esi
00554252  jz      short loc_55426C
00554254  cmp     dword ptr [esi], 1                ; <== UNIT_MONSTER
00554257  jnz     short loc_55426C
00554259  mov     ecx, esi
0055425B  call    GetOwnerUnit_0
00554260  test    eax, eax
00554262  jz      short loc_55426C
00554264  cmp     eax, esi
00554266  jz      short loc_55426C
00554268  mov     esi, eax
0055426A  jmp     short loc_554250

Change

while (i && i->dwUnitType == UNIT_MONSTER). Not version-gated, since 1.10f and 1.14d agree. Also adds the 1.14d address.

🤖 Generated with Claude Code

sub_6FCBD900 resolves the target to its owner before comparing it
with the attacker. The loop must follow minion owners while the unit
is a monster (pets, and pets of pets). MOO tested UNIT_PLAYER, so a
monster target was never resolved to its owner.

1.10f (D2Game.0x6FCBD900), Hex-Rays (sub_6FCCF320 is
AIGENERAL_GetMinionOwner):

    while ( a3 != nullptr )
    {
        if ( *a3 != 1 )                    // UNIT_MONSTER
            break;
        v6 = sub_6FCCF320(a3);
        if ( v6 == 0 || (_DWORD *)v6 == a3 )
            break;
        a3 = (_DWORD *)v6;
    }

Disassembly:

    6FCBD923  test esi, esi
    6FCBD925  jz   6FCBD9C5
    6FCBD92B  cmp  dword ptr [esi], 1  ; UNIT_MONSTER
    6FCBD92E  jnz  6FCBD9C5
    6FCBD934  mov  ecx, esi
    6FCBD936  call 6FCCF320            ; AIGENERAL_GetMinionOwner
    6FCBD93B  test eax, eax
    6FCBD93D  jz   6FCBD9C5
    6FCBD943  cmp  eax, esi
    6FCBD945  jz   6FCBD9C5
    6FCBD947  mov  esi, eax
    6FCBD949  jmp  6FCBD923

1.14d (Game.exe 0x00554200) is the same: if ( *a3 != 1 ) break; at
0x00554254 cmp dword ptr [esi], 1.

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