Skip to content

Handle a unit with no used skill in UNITS_CanAnimModeUseAttackRate - #244

Open
ResurrectedTrader wants to merge 1 commit into
ThePhrozenKeep:masterfrom
ResurrectedTrader:fix/units-attack-rate-null-used-skill
Open

ResurrectedTrader wants to merge 1 commit into
ThePhrozenKeep:masterfrom
ResurrectedTrader:fix/units-attack-rate-null-used-skill

Conversation

@ResurrectedTrader

@ResurrectedTrader ResurrectedTrader commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

For a mode with bCanUseSkillAttackRate, UNITS_CanAnimModeUseAttackRate dereferences UNITS_GetUsedSkill(pUnit) without checking it. The game checks for NULL and treats a missing skill as "no attack rate", which falls back to the default rate.

Players can already reach it, and monsters can too once the missing break in the same function is fixed (#243).

1.10f

Inlined in UNITS_UpdateAnimRateAndVelocity (D2Common.0x6FDBF050, #10376):

6FDBF647  mov     esi, [edx+0Ch]                    ; bCanUseAttackRate
6FDBF64A  test    esi, esi
6FDBF64C  jnz     short loc_6FDBF69B
6FDBF64E  mov     esi, [edx+8]                      ; bCanUseSkillAttackRate
6FDBF651  test    esi, esi
6FDBF653  jz      loc_6FDBF81E
6FDBF659  mov     ecx, [ebp+0A8h]                   ; pUnit->pSkills
6FDBF65F  call    sub_6FDAFF30                      ; used skill
6FDBF664  test    eax, eax                          ; <== NULL check
6FDBF666  jz      loc_6FDBF816                      ; <== no skill -> default rate
6FDBF66C  push    0BF4h
6FDBF671  push    6FDE5CF4h
6FDBF676  push    eax
6FDBF677  call    D2Common_10963                    ; skill id
6FDBF67C  mov     ecx, eax
6FDBF67E  call    sub_6FD9E040                      ; Skills.txt record
6FDBF683  mov     edx, ds:gdwBitMasks
6FDBF689  xor     ecx, ecx
6FDBF68B  mov     cl, [eax+6]
6FDBF68E  and     ecx, [edx+0Ch]                    ; SKILLSFLAG_USEATTACKRATE
6FDBF691  mov     [esp+20h+arg_8], ecx
6FDBF695  jz      loc_6FDBF816
6FDBF69B  push    1
6FDBF69D  push    ebp
6FDBF69E  call    D2Common_10440                    ; attack rate

1.14d

Game.exe 0x621580:

006215E5  cmp     dword ptr [eax+0Ch], 0            ; bCanUseAttackRate
006215E9  jz      short loc_6215F4
006215EB  mov     eax, 1
006215F0  pop     ebp
006215F1  retn    8
006215F4  cmp     dword ptr [eax+8], 0              ; bCanUseSkillAttackRate
006215F8  jz      short loc_6215B7                  ; -> return 0
006215FA  mov     eax, [ebp+arg_0]
006215FD  push    eax
006215FE  call    GetCurrentSkill                   ; used skill
00621603  test    eax, eax                          ; <== NULL check
00621605  jz      short loc_6215B7                  ; <== no skill -> return 0
00621607  push    0BFAh
0062160C  push    offset aUnitsUnitsCpp
00621611  push    eax
00621612  call    GetSkillId_1
00621617  mov     ecx, eax
00621619  call    TXT_Skills_GetLine
0062161E  movzx   eax, byte ptr [eax+6]             ; Skills.txt flags
00621622  and     eax, ds:dword_6CE274              ; SKILLSFLAG_USEATTACKRATE
00621628  pop     ebp
00621629  retn    8

Change

Return FALSE when UNITS_GetUsedSkill returns NULL.

🤖 Generated with Claude Code

For a mode with bCanUseSkillAttackRate, UNITS_GetUsedSkill() was
dereferenced without a NULL check. The game checks it and treats a
missing skill as "no attack rate".

1.10f, inlined in UNITS_UpdateAnimRateAndVelocity (D2Common.0x6FDBF050):
sub_6FDAFF30 (used skill) at 0x6FDBF65F, then "test eax, eax / jz" at
0x6FDBF664 skips to the default-rate path. 1.14d: Game.exe.0x621603.

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