[1.10] Fixing SrvDoFunc 49

This forum is for discussions on how to edit what can not be edited through the txt files, needless to say this isn't about battle net hacking.

Moderators: Nefarius, Havvoric

Post Reply
User avatar
Ogodei
Senior Moderator
Champion of the Light
Posts: 498
Joined: Thu Mar 10, 2016 8:31 am
Italy

Hand-picked

[1.10] Fixing SrvDoFunc 49

Post by Ogodei » Sat Oct 26, 2019 11:47 am

Hello guys :)

I was tinkering around with Lady Isabelle in our mod when we stumbled upon what seemed to be a real nuisance: basically, we noticed that minions summoned through srvDoFunc #49 (for reference, the Assassin's Shadow Master \ Shadow Warrior summoning spells) didn't seem to get boni from the AuraStatCalc and PassiveCalc fields.
Therefore, I investigated a bit how the whole function was handled and found out that while the AuraStats are correctly applied, they all read the value/calc you put in AuraStatCalc2 and PassiveStatCalc2. While it is unclear if this is just a typo by the devs or it's specifically intended to be so, it is very annoying for people that are into modmaking, so here's the fix for this odd behaviour. By applying this code you will render your srvDoFunc 49 minions able to get boni from the proper calc fields.

the code we're modifying is this:

Code: Select all

6FCF990E | 8D4D 54                | lea ecx,dword ptr ss:[ebp+54]            		|
6FCF9911 | 894C24 50              | mov dword ptr ss:[esp+50],ecx          		|
6FCF9915 | C74424 18 06000000     | mov dword ptr ss:[esp+18],6        		| i = 6
6FCF991D | 8B5424 50              | mov edx,dword ptr ss:[esp+50]          		|
6FCF9921 | 66:8B02                | mov ax,word ptr ds:[edx]                 			|
6FCF9924 | 66:85C0                | test ax,ax                               				| 
6FCF9927 | 7C 34                  | jl d2game.6FCF995D                       			|
6FCF9929 | 8B0D 6070D26F          | mov ecx,dword ptr ds:[<&sgptDataTables>]  |
6FCF992F | 0FBFC0                 | movsx eax,ax 							|
6FCF9932 | 8B11                   | mov edx,dword ptr ds:[ecx]               			 |
6FCF9934 | 3B82 D40B0000          | cmp eax,dword ptr ds:[edx+BD4]           	|
6FCF993A | 7D 21                  | jge d2game.6FCF995D                      			|
6FCF993C | 8B4C24 4C              | mov ecx,dword ptr ss:[esp+4C]            		| ecx = SkillID
6FCF9940 | 8B55 6C                | mov edx,dword ptr ss:[ebp+6C]            		| edx = AuraStatCalc2
6FCF9943 | 53                     | push ebx                                 				| sLvl
6FCF9944 | 51                     | push ecx                                 				| nSkillID
6FCF9945 | 52                     | push edx                                 				| nCalcField
6FCF9946 | 56                     | push esi                                 				| ptCaster
6FCF9947 | E8 C6240200            | call <JMP.&Ordinal#11276>                		| GetCalc
What Blizzard is doing here i basically this:

Code: Select all

for (int i = 6; i > 0; i--)
{
	// count starts from 0, so aurastatcalc[1] means AuraStatCalc2
	int nValue = GetCalc(ptCaster, ptSkillTXT->aurastatcalc[1], Skill_ID, sLvl);
	AssignStat(ptStatList, ptSkillTXT->aurastat[i], nValue, Skill_ID);
}
so, each AuraStat is assigned the value from AuraStatCalc2, while we essentially want AuraStat = AuraStatCalc;

in c++, it would be like this:

Code: Select all

for (int i = 6; i > 0; i--)
{
    // count starts from 0, so aurastatcalc[1] means AuraStatCalc2 
    int nValue = GetCalc(ptCaster, ptSkillTXT->aurastatcalc[6 - i], Skill_ID, sLvl); // notice aurastatcalc[6-i] that returns the correct calc field.
    AssignStat(ptStatList, ptSkillTXT->aurastat[i], nValue , Skill_ID);
}

In order to do this, we first have to hijack the code to a custom space in our D2Game.dll

Code: Select all

6FCF993C | 8B4C24 4C             mov ecx,dword ptr ss:[esp+4C]
6FCF9940 | 8B55 6C                 mov edx,dword ptr ss:[ebp+6C]
change to:

Code: Select all

6FCF993C | E9 78D30200       jmp d2game.6FD26CB9
6FCF9941 | 90                       nop                                      
6FCF9942 | 90                       nop                  


then, in our custom space, we'll write:

Code: Select all

6FD26CAF | 8B4424 18              | mov eax,dword ptr ss:[esp+18]                | // [ESP+18] = i
6FD26CB3 | B9 06000000            | mov ecx,6                                             | /* 
6FD26CB8 | 29C1                   | sub ecx,eax                                               | i = (i - 6) *4
6FD26CBA | B8 04000000            | mov eax,4                                             |
6FD26CBF | F7E1                   | mul ecx                                                     | */
6FD26CC1 | 8B5405 68              | mov edx,dword ptr ss:[ebp+eax+68]        | EDX becomes SkillCalc Field = AuraStatCalc[0 + i]
6FD26CC5 | 8B4C24 4C              | mov ecx,dword ptr ss:[esp+4C]               | ECX becomes nSkillID again
6FD26CC9 | E9 752CFDFF            | jmp d2game.6FCF9943                          | jump back to the vanilla code
the same goes for passivestats, but since I already explained what the code does and what we are to change I will go faster here:

As for the passivestats: we will do the same

Code: Select all

6FCF99A4 | 8B4C24 4C             mov ecx,dword ptr ss:[esp+4C]
6FCF99A8 | 8B95 A8000000       mov edx,dword ptr ss:[ebp+A8]
change to:

Code: Select all

6FCF99A4 | E9 25D30200      | jmp d2game.6FD26CCE 
6FCF99A9 | 90                     | nop 
6FCF99AA | 90                     | nop
6FCF99AB | 90                     | nop  
6FCF99AC | 90                     | nop
6FCF99AD | 90                     | nop 
and then:

Code: Select all

6FD26CCE | 8B4424 18              | mov eax,dword ptr ss:[esp+18]             | // [ESP+18] = i
6FD26CD2 | B9 05000000            | mov ecx,5                                          | /*
6FD26CD7 | 29C1                   | sub ecx,eax                                            | i = (i - 5) *4
6FD26CD9 | B8 04000000            | mov eax,4                                          |
6FD26CDE | F7E1                   | mul ecx                                                  | */
6FD26CE0 | 8B9405 A4000000        | mov edx,dword ptr ss:[ebp+eax+A4]| EDX becomes SkillCalc Field = PassiveStatCalc[0 + i]
6FD26CE7 | 8B4C24 4C              | mov ecx,dword ptr ss:[esp+4C]            | ECX becomes nSkillID again
6FD26CEB | E9 BE2CFDFF            | jmp d2game.6FCF99AE                      | jump back to the vanilla code
So, now each bonus from an aurastat or passivestat field will get boni from the respective calc field.

One last one: the boni you assign via aurastat or passivestat are not displayed on the client (think of resists, for example) but even if you don't literally see them, they are there, so don't worry about that.

Also, srvDoFunc 49 skips assigning boni to the minions if your skill level is lesser or equal to 1. In order to fix this you need to change the following code

Code: Select all

6FCF988C | 83FB 01                    | cmp ebx,1                                 |
6FCF988F | 0F8E 70010000          | jle d2game.6FCF9A05                |   if sLvl is lesser or equal to 1 , skip boni
to :

Code: Select all

6FCF988C | 83FB 00                    | cmp ebx,0                                 |
6FCF988F | 0F8E 70010000          | jle d2game.6FCF9A05                |   if sLvl is lesser or equal to 0 , skip boni
Happy modding!

User avatar
Tomkomaster
Posts: 89
Joined: Thu Feb 07, 2008 1:15 am
Slovakia

Re: [1.10] Fixing SrvDoFunc 49

Post by Tomkomaster » Sun Oct 27, 2019 9:47 am

Very nice find, thank you. Anyone can do the same for 1.13c ?

User avatar
devurandom
Forum Regular
Angel
Posts: 895
Joined: Sat Mar 07, 2015 9:07 pm
United States of America

Re: [1.10] Fixing SrvDoFunc 49

Post by devurandom » Wed Oct 30, 2019 2:43 am

In 1.13c you can make the first jump to slackspace here. Be aware pure ASM probably won't work, unless you edit the .reloc table to add those long jumps, or you use a rebased dll. The latter method might
still give relocation headaches in newer windows versions.

Code: Select all

6FCB17C1  ║·  8B5424 1C     ║MOV EDX,DWORD PTR SS:[ARG.3]
6FCB17C5  ║·  8B46 6C       ║MOV EAX,DWORD PTR DS:[ESI+6C]
Assembly Reference | 1.13d Code Edits | UVLoD | BaseMod Plugin

Fiat paper money is the most elaborate and well devised form of slavery the world has ever seen..

User avatar
thaison
Junior Member
Paladin
Posts: 105
Joined: Fri Apr 03, 2015 11:59 am
Location: Viet Nam
Vietnam

Re: [1.10] Fixing SrvDoFunc 49

Post by thaison » Fri Jul 17, 2020 9:32 am

[1.13c]
Patch - D2Game.0x91660
Version C++ has been corrected:
Attachments
Fixing SrvDoFunc 49.rar
(782 Bytes) Downloaded 70 times

mengxuecen
Posts: 31
Joined: Mon Mar 11, 2019 5:34 am

Re: [1.10] Fixing SrvDoFunc 49

Post by mengxuecen » Mon Apr 05, 2021 4:03 am

MonUMod::AssignMod

Help me....

User avatar
thaison
Junior Member
Paladin
Posts: 105
Joined: Fri Apr 03, 2015 11:59 am
Location: Viet Nam
Vietnam

Re: [1.10] Fixing SrvDoFunc 49

Post by thaison » Tue Apr 06, 2021 7:19 am

mengxuecen wrote:
Mon Apr 05, 2021 4:03 am
MonUMod::AssignMod

Help me....

Code: Select all

D2PTR(D2GAME, MonUModAssignMod_I, 0x232B0)
void __fastcall MonUMod::AssignMod(Game* pGame, UnitAny* pMonster, int nMonUMod, BOOL bNewBoss)
{
    __asm
    {
	push bNewBoss
	push pMonster
	mov esi, pGame
	mov ebx, nMonUMod
	call MonUModAssignMod_I
    }
}

mengxuecen
Posts: 31
Joined: Mon Mar 11, 2019 5:34 am

Re: [1.10] Fixing SrvDoFunc 49

Post by mengxuecen » Tue Apr 06, 2021 10:17 am

Thx thaison!

D2COMMON_SetStatInListExp

Is that it?

D2FUNC(D2COMMON, SetUnitState, void, __stdcall, (StatList* pStatList, int nStat, int nValue, WORD nLayer), -10188) // 1.13c

User avatar
thaison
Junior Member
Paladin
Posts: 105
Joined: Fri Apr 03, 2015 11:59 am
Location: Viet Nam
Vietnam

Re: [1.10] Fixing SrvDoFunc 49

Post by thaison » Tue Apr 06, 2021 2:27 pm

mengxuecen wrote:
Tue Apr 06, 2021 10:17 am
Thx thaison!

D2COMMON_SetStatInListExp

Is that it?

D2FUNC(D2COMMON, SetUnitState, void, __stdcall, (StatList* pStatList, int nStat, int nValue, WORD nLayer), -10188) // 1.13c

Code: Select all

D2FUNC(D2COMMON, SetStatInListExp, void, __stdcall, (StatList* pStatList, int nStat, int nValue, WORD nLayer), -10188)

mengxuecen
Posts: 31
Joined: Mon Mar 11, 2019 5:34 am

Re: [1.10] Fixing SrvDoFunc 49

Post by mengxuecen » Fri Apr 09, 2021 3:43 pm

// SrvDoFunc49Fix
{ D2DLL_D2GAME, { 0x91660 }, PATCH_NOPBLOCK, FALSE, 5 },
{ D2DLL_D2GAME, { 0x91660 }, PATCH_JMP, FALSE, 0 },
{ D2DLL_D2GAME, { 0x91660 + 1 }, (DWORD)Patch_sub_91660, TRUE, 0 },
@Thaison Help......Error C0000005

PATCH_NOPBLOCK =5 ? :cry:

User avatar
thaison
Junior Member
Paladin
Posts: 105
Joined: Fri Apr 03, 2015 11:59 am
Location: Viet Nam
Vietnam

Re: [1.10] Fixing SrvDoFunc 49

Post by thaison » Sat Apr 10, 2021 2:07 am

mengxuecen wrote:
Fri Apr 09, 2021 3:43 pm
// SrvDoFunc49Fix
{ D2DLL_D2GAME, { 0x91660 }, PATCH_NOPBLOCK, FALSE, 5 },
{ D2DLL_D2GAME, { 0x91660 }, PATCH_JMP, FALSE, 0 },
{ D2DLL_D2GAME, { 0x91660 + 1 }, (DWORD)Patch_sub_91660, TRUE, 0 },
@Thaison Help......Error C0000005

PATCH_NOPBLOCK =5 ? :cry:
Not NOP.

Post Reply

Return to “Code Editing”