SetStreamMissile's missile id is an int: callers push it as a whole or sign-extended dword
Ghidra v1846 · 4ca0e98
The parameter is int16_t, but no caller narrows the argument: 004f284a MOVSX EDX,word ptr [ESI+0xec] / 004f2851 PUSH EDX (the skill row's cltmissile, sign-extended to 32 bits), and 004e2790 MOV ECX,[EBP-0xc] / 004e2793 PUSH ECX and 004f3647 MOV EDX,[EBP-0x10] / 004f364a PUSH EDX (int locals pushed whole). With an int16_t parameter VC8 narrows each argument (MOVZX from the word), so the declared type was int; the body storing only the low word (0064a4f6 MOV CX,word ptr [EBP+0xc]; 0064a4fa MOV word ptr [EAX+0x4],CX) is what VC8 makes of an int stored into a 16-bit field. Recompiled with VC8 SP1 (oracle, tree 3dba660): SetStreamMissile still matches, and its three callers get closer - Skills_CltDoFunc_Mon_CurseCenter_StreamRange 0.627 -> 0.840, Skills_CltDoFunc_Nec_CurseCenter_StreamMissile 0.714 -> 0.817, Skills_CltDoFunc_Ass_AuraLevel_StreamMissile 0.778 -> 0.790; no function lost.
Changes 1, applied together
Set prototype
win 0x0064a4e0signaturevoid SetStreamMissile(D2UnitStrc * pUnit, int16_t nStreamMissile)→void SetStreamMissile(D2UnitStrc * pUnit, int nStreamMissile)convention__stdcall