gfx
Snejportal  |  D2SE  |  D2SE Mods  |  World of Chaos  |  Development (Moderator: Dav92)  |  Topic: [1.10]Charm Zones?!
gfx
gfx gfx
Please login or register.

Login with username, password and session length
gfx gfx
gfx gfx

  • Welcome at our new home!!!

    This is the Snej Portal, home of several D2 Modifications and D2SE
  • On our Realmserver you can find this hosted Mods:

    Snej
    Reign of Shadows (RoS)
    Eastern Sun (ES)
  • You can also find the home of the

    Aftermath Mod here

    https://snej.org/forum/index.php?board=674.0
gfx gfx
gfx
August 24, 2019, 07:22:01 PM
*
gfx gfx
gfx* Home Help Search Login Registergfx

Author Topic: [1.10]Charm Zones?!  (Read 2145 times)

0 Members and 1 Guest are viewing this topic.

Offline Dav92Topic starter

  • Moderator
  • Bloodwitch
  • **
  • Posts: 136
  • Gender: Male
[1.10]Charm Zones?!
« on: February 19, 2017, 10:31:55 AM »
Many mods increase the inventory space with the intention of having more space for loot. But at the same time, it also increases the space you have for charms. That often leads to balancing problems and most modders want to limit the amount of charms a player can use at the same time. There are some softcoded approaches to that (setting the str/dex/vit/enr to 1 if you have more than a specific amount of charms, ...). But these are just workarounds. This posts discusses the hardcoded approach of actually limiting the area in your inventory that allows charms to work:

Let's take a look at the functions we need to modify:
D2Common.#10840 is responsible for telling the game whether a charm can be used or not (actually it's called for every item, but only charms can return TRUE).
The C prototype looks like this:
Code: [Select]
__stdcall AreCharmReqsMet(struct Unit *pItem, struct Unit *pUnit)

This is the fully commented function:
Code: [Select]
CPU Disasm
Address   Hex dump          Command                                  Comments
6F65FE70  /$  56            PUSH ESI                                 ; D2Common.#10840(guessed Arg1,Arg2)
6F65FE71  |.  8B7424 08     MOV ESI,DWORD PTR SS:[ARG.1]             ; pItem
6F65FE75  |.  85F6          TEST ESI,ESI
6F65FE77  |.  74 32         JZ SHORT 6F65FEAB
6F65FE79  |.  8B0E          MOV ECX,DWORD PTR DS:[ESI]               ; pItem->eType
6F65FE7B  |.  83F9 04       CMP ECX,4                                ; eType == ITEM
6F65FE7E  |.  75 31         JNE SHORT 6F65FEB1
6F65FE80  |.  8B46 14       MOV EAX,DWORD PTR DS:[ESI+14]            ; pitem->pItemData
6F65FE83  |.  85C0          TEST EAX,EAX
6F65FE85  |.  74 0C         JZ SHORT 6F65FE93
6F65FE87  |.  8B40 18       MOV EAX,DWORD PTR DS:[EAX+18]            ; pItemData->Flags
6F65FE8A  |.  25 00010000   AND EAX,00000100                         ; 0x100 == ITEMFLAG_BROKEN
6F65FE8F  |.  85C0          TEST EAX,EAX
6F65FE91  |.  75 18         JNZ SHORT 6F65FEAB
6F65FE93  |>  83F9 04       CMP ECX,4                                ; eType == ITEM
6F65FE96  |.  75 19         JNE SHORT 6F65FEB1
6F65FE98  |.  8B46 14       MOV EAX,DWORD PTR DS:[ESI+14]            ; pItem->pItemData
6F65FE9B  |.  85C0          TEST EAX,EAX
6F65FE9D  |.  74 12         JZ SHORT 6F65FEB1
6F65FE9F  |.  8B40 18       MOV EAX,DWORD PTR DS:[EAX+18]            ; pItemData->Flags
6F65FEA2  |.  25 00400000   AND EAX,00004000                         ; 0x4000 == ITEMFLAG_NOEQUIP
6F65FEA7  |.  85C0          TEST EAX,EAX
6F65FEA9  |.  74 06         JZ SHORT 6F65FEB1
6F65FEAB  |>  33C0          XOR EAX,EAX                              ; return FALSE
6F65FEAD  |.  5E            POP ESI
6F65FEAE  |.  C2 0800       RETN 8
6F65FEB1  |>  6A 0D         PUSH 0D                                  ; /Arg2 = 0D, 0xD == ITEMTYPE_CHARM
6F65FEB3  |.  56            PUSH ESI                                 ; |Arg1 => [ARG.1], pItem
6F65FEB4  |.  E8 27DEFFFF   CALL #10731                              ; \D2Common.#10731, IsItemOfItemType
6F65FEB9  |.  85C0          TEST EAX,EAX
6F65FEBB  |.  75 04         JNZ SHORT 6F65FEC1
6F65FEBD  |.  5E            POP ESI                                  ; return FALSE if item is no charm
6F65FEBE  |.  C2 0800       RETN 8
6F65FEC1  |>  833E 04       CMP DWORD PTR DS:[ESI],4                 ; pItem->eType == ITEM
6F65FEC4  |.  75 0E         JNE SHORT 6F65FED4
6F65FEC6  |.  8B46 14       MOV EAX,DWORD PTR DS:[ESI+14]            ; pItem->pItemData
6F65FEC9  |.  85C0          TEST EAX,EAX
6F65FECB  |.  74 07         JZ SHORT 6F65FED4
6F65FECD  |.  8A48 45       MOV CL,BYTE PTR DS:[EAX+45]              ; pItemData->InvPage
6F65FED0  |.  84C9          TEST CL,CL                               ; InvPage == 0 (0x0 == INVPAGE_INVENTORY)
6F65FED2  |.  74 06         JZ SHORT 6F65FEDA
6F65FED4  |>  33C0          XOR EAX,EAX                              ; return FALSE
6F65FED6  |.  5E            POP ESI
6F65FED7  |.  C2 0800       RETN 8
6F65FEDA  |>  8B4424 0C     MOV EAX,DWORD PTR SS:[ARG.2]             ; pUnit
6F65FEDE  |.  6A 00         PUSH 0                                   ; /Arg6 = 0, pbLvl
6F65FEE0  |.  6A 00         PUSH 0                                   ; |Arg5 = 0, pbDex
6F65FEE2  |.  6A 00         PUSH 0                                   ; |Arg4 = 0, pbStr
6F65FEE4  |.  6A 00         PUSH 0                                   ; |Arg3 = 0, bEquip
6F65FEE6  |.  50            PUSH EAX                                 ; |Arg2 => [ARG.2], pUnit
6F65FEE7  |.  56            PUSH ESI                                 ; |Arg1 => [ARG.1], pItem
6F65FEE8  |.  E8 5398FFFF   CALL #10756                              ; \D2Common.#10756, CheckItemRequirements
6F65FEED  |.  F7D8          NEG EAX                                  ; converts whether the reqs are met to TRUE or FALSE
6F65FEEF  |.  1BC0          SBB EAX,EAX
6F65FEF1  |.  5E            POP ESI
6F65FEF2  |.  F7D8          NEG EAX
6F65FEF4  \.  C2 0800       RETN 8
6F65FEF7      90            NOP
6F65FEF8      90            NOP
We see, that the actual requirements the charms have (level req) are only checked at the very end of the function (call to D2Common.#10576). The end is also only reached if the item is a charm. If the item in question is no charm, or if it is broken, ... this function returns FALSE.

We can use this to our advantage. For implemeting the actual charm zone we need more space. For that replace these three lines with a jump to an empty space:
Code: [Select]
6F65FEF4  \.  C2 0800       RETN 8
6F65FEF7      90            NOP
6F65FEF8      90            NOP
Like this for example:
Code: [Select]
6F65FEF4     /E9 77D60200   JMP 6F68D570

At the address we just jumped to, we are implementing the check for the charm zone. We do this by checking the position of the charm against the bounds of the charm zone:
Code: [Select]
CPU Disasm
Address   Hex dump          Command                                  Comments
6F68D570   > \85C0          TEST EAX,EAX
6F68D572   .  75 03         JNE SHORT 6F68D577
6F68D574   .  C2 0800       RETN 8                                   ; return FALSE if reqs are not met
6F68D577   >  8B44E4 04     MOV EAX,DWORD PTR SS:[ESP+4]             ; pItem
6F68D57B   .  8B40 2C       MOV EAX,DWORD PTR DS:[EAX+2C]            ; pitem->pPath
6F68D57E   .  8378 0C 05    CMP DWORD PTR DS:[EAX+0C],5              ; pPath->posX, 5 == leftBorder
6F68D582   .  72 1A         JB SHORT 6F68D59E
6F68D584   .  8378 0C 07    CMP DWORD PTR DS:[EAX+0C],7              ; pPath->posX, 7 == rightBorder
6F68D588   .  77 14         JA SHORT 6F68D59E
6F68D58A   .  8378 10 03    CMP DWORD PTR DS:[EAX+10],3              ; pPath->posY, 3 == topBorder
6F68D58E   .  72 0E         JB SHORT 6F68D59E
6F68D590   .  8378 10 04    CMP DWORD PTR DS:[EAX+10],4              ; pPath->posY, 4 == botomBorder
6F68D594   .  77 08         JA SHORT 6F68D59E
6F68D596   .  B8 01000000   MOV EAX,1                                ; return TRUE
6F68D59B   .  C2 0800       RETN 8
6F68D59E   >  31C0          XOR EAX,EAX                              ; return FALSE
6F68D5A0   .  C2 0800       RETN 8

The code above restricts the charm zone to the red box in the following screen:


This code is enough to actively restrict the use tof charms, but there's still one thing missing:
The charm doesn't have a red background when it's outside the charm area.

For that we need to modify/add some code in D2Client.dll:
Code: [Select]
CPU Disasm
Address   Hex dump          Command                                  Comments
6FAE1180  |.  6A 00         |PUSH 0                                  ; /Arg6 = 0
6FAE1182  |.  6A 00         |PUSH 0                                  ; |Arg5 = 0
6FAE1184  |.  6A 00         |PUSH 0                                  ; |Arg4 = 0
6FAE1186  |.  6A 00         |PUSH 0                                  ; |Arg3 = 0
6FAE1188  |.  50            |PUSH EAX                                ; |Arg2 => [LOCAL.5], pUnit
6FAE1189  |.  56            |PUSH ESI                                ; |Arg1, pItem
6FAE118A  |.  E8 A39D0800   |CALL <JMP.&D2Common.#10756>             ; \D2Common.#10756
6FAE118F  |.  85C0          |TEST EAX,EAX
6FAE1191  |.  0F84 EC000000 |JZ 6FAE1283
Here we also need more space to do the checks, for that change:
Code: [Select]
6FAE118F  |.  85C0          |TEST EAX,EAX
6FAE1191  |.  0F84 EC000000 |JZ 6FAE1283
to
Code: [Select]
6FAE118F     /E9 6CB30800   JMP 6FB6C500
6FAE1194     |90            NOP
6FAE1195     |90            NOP
6FAE1196     |90            NOP

At D2Client.6FB6C500 we add code to check if the item is a charm, and if it is within the charm zone:
Code: [Select]
CPU Disasm
Address   Hex dump          Command                                  Comments
6FB6C500   > \85C0          TEST EAX,EAX
6FB6C502   .^ 0F84 7B4DF7FF JE 6FAE1283                              ; item reqs not met
6FB6C508   .  6A 0D         PUSH 0D                                  ; /Arg2 = 0D, 0xD == ITEMTYPE_CHARM
6FB6C50A   .  56            PUSH ESI                                 ; |Arg1, pItem
6FB6C50B   .  E8 10E7FFFF   CALL <JMP.&D2Common.#10731>              ; \D2Common.#10731, IsItemOfItemType (CALL 6FB6AC20)
6FB6C510   .  85C0          TEST EAX,EAX
6FB6C512   .^ 0F84 7F4CF7FF JE 6FAE1197                              ; no charm, so don't continue checking the charm zone
6FB6C518   .  8B44E4 20     MOV EAX,DWORD PTR SS:[ESP+20]            ; pUnit
6FB6C51C   .  50            PUSH EAX                                 ; /Arg2, pUnit
6FB6C51D   .  56            PUSH ESI                                 ; |Arg1, pItem
6FB6C51E   .  E8 19EFFFFF   CALL <JMP.&D2Common.#10840>              ; \D2Common.#10840, AreCharmReqsMet (CALL 6FB6B43C)
6FB6C523   .  85C0          TEST EAX,EAX
6FB6C525   .^ 0F84 584DF7FF JE 6FAE1283                              ; charm reqs not met
6FB6C52B   .^ E9 674CF7FF   JMP 6FAE1197                             ; charm reqs met
This code uses the one we previously added in D2Common.dll to check for the charm zone.

With these two edits, you now have a fully working charm zone. But there are still some things to consider.
Take a look at this picture:

The red box is the charm zone we just implemented. The green and blue boxes show possible charm locations. A charm at the green position wouldn't be usable, but a charm at the blue position would be.
To make charms only work when they are in the charm zone, you need to add additional code that retreives the size of the charm and then checks if the whole item is in the zone (see this as a challenge for yourself).

Offline Seltsamuel

  • Administrator
  • Duriel
  • **
  • Posts: 1829
  • Gender: Male
    • Snej-Mod Homepage
Re: [1.10]Charm Zones?!
« Reply #1 on: February 19, 2017, 02:25:49 PM »
Hi Dav92,

nice to see you back active again :-) and even nicer that finally someone implements one of my former ideas of a charm zone. For me the only way to balance a mod but still keep a mega inventory. Nice work here.

Greetings

Seltsamuel

Offline Dav92Topic starter

  • Moderator
  • Bloodwitch
  • **
  • Posts: 136
  • Gender: Male
Re: [1.10]Charm Zones?!
« Reply #2 on: February 24, 2017, 04:46:15 PM »
Thank you. It's good to be back, let's see how much time I have for D2 in the future.

Yeah, you could either add a charm zone or a complete new inventory just for charms.

Offline Zerum

  • Global Moderator
  • Nihlathak
  • ***
  • Posts: 1293
  • Gender: Male
  • http://zerum.owns.it/
Re: [1.10]Charm Zones?!
« Reply #3 on: May 19, 2017, 11:41:55 PM »
I just saw a video of a D2 Mod, where charm zones already were implemented. Idk if the way how the modder(s) did it suit you, but here you can take a look:

https://www.youtube.com/watch?v=XyJOhJqbUmo&t=2m25s

min2:25
D2Lunatics Realm-Admin
Ex-D2Maniacs Admin

Offline AlphA

  • The Summoner
  • *****
  • Posts: 274
Re: [1.10]Charm Zones?!
« Reply #4 on: May 20, 2017, 12:35:40 AM »
Actually that was made by Dav92 himself:D

Cheers
AlphA

Offline Zerum

  • Global Moderator
  • Nihlathak
  • ***
  • Posts: 1293
  • Gender: Male
  • http://zerum.owns.it/
Re: [1.10]Charm Zones?!
« Reply #5 on: May 20, 2017, 10:44:08 AM »
Oh :O
lol  ::)
« Last Edit: June 03, 2017, 12:08:08 AM by Zerum »
D2Lunatics Realm-Admin
Ex-D2Maniacs Admin

Offline Black Eternity

  • Little Pickpocket
  • *
  • Posts: 1
Re: [1.10]Charm Zones?!
« Reply #6 on: May 25, 2017, 05:47:16 AM »
How is the border calculated?


obviously your values are:
posX 5 , 7
posY 3 , 4


But I fail to see how this makes any sense compared to the picture you have provided.
Trying to get this working for my own mod.


Edit: I was able to get it working how I wanted by just experimenting with different values but I still don't really understand the logic.
« Last Edit: May 25, 2017, 06:59:23 AM by Black Eternity »

Offline Dav92Topic starter

  • Moderator
  • Bloodwitch
  • **
  • Posts: 136
  • Gender: Male
Re: [1.10]Charm Zones?!
« Reply #7 on: May 25, 2017, 10:00:45 AM »
How is the border calculated?


obviously your values are:
posX 5 , 7
posY 3 , 4


But I fail to see how this makes any sense compared to the picture you have provided.

Top left of the inventory is (x=0,y=0). Counting from there you get to (x=5, y=3) for the top left inventory slot for the charm inventory.

Snejportal  |  D2SE  |  D2SE Mods  |  World of Chaos  |  Development (Moderator: Dav92)  |  Topic: [1.10]Charm Zones?!
 

gfxgfx
gfx
SMF 2.0.10 | SMF © 2015, Simple Machines  Snejtheme V2 by Seltsamuel/Faust (based on Helios Multi by Bloc)
gfx