Node Pages and other d2common functions

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

0
No votes
 
Total votes: 0

User avatar
weapon-x
Forum Legend
Arch-Angel
Posts: 1047
Joined: Wed Mar 18, 2009 4:52 am
Location: Mindanao, Philippines
Contact:
Philippines

Node Pages and other d2common functions

Post by weapon-x » Wed Jun 15, 2016 2:56 am

Code: Select all

D2Common.10307
Function:   Get the Node Page
Offset:     00052100 (6FD92100) in v1.10 
Parameters: Arg1 - ptItem
Returns:    Page Number

Node Pages
{
   00: Inventory (Contains pages) 
   01: BodyLoc 
   02: Belt 
   03: Ground 
   04: Cursor            //4 is definitely the cursor
}
i am kinda confused with page 0, how do we know which page the item is in if its in inventory?

and is there any known function which sets the node page of an item?
" It's not the size of the dog in the fight, it's the size of the fight in the dog. "

~Mark Twain

User avatar
Nefarius
Retired Admin
Cherub
Posts: 11607
Joined: Sat Jun 15, 2002 8:13 pm
Location: Where the blood forever rains
Contact:

Hand-picked

Re: Node Pages and other d2common functions

Post by Nefarius » Wed Jun 15, 2016 6:59 am

That returns the grid type (+69), not the page (+45). The grid ID itself is at +68 corresponding with the page. Here's a full documentation of the related structures/values.
Also, the values you give there are item modes and not grid types which are not what that function returns (although they're used to instruct the game where to look for more specific information).

Caution: I copy/pasted this from my source files and this is slightly different from vanilla.

Code: Select all

struct D2ItemData
{
    int eQuality;                                       // +00
    D2Seed tModSeed;                                    // +04
    DWORD dwPlayerID;                                   // +0C
    DWORD dwModSeed;                                    // +10
    DWORD dwCMDFlags;                                   // +14
    DWORD dwItemFlags;                                  // +18
    DWORD dwReserved[2];                                // +1C
    int nPruneFrame;                                    // +24
    int nIndex;                                         // +28
    int nLevel;                                         // +2C
    WORD wItemVersion;                                  // +30
    WORD wRarePrefix;                                   // +32
    WORD wRareSuffix;                                   // +34
    WORD wAutoMagic;                                    // +36
    WORD wPrefix[MAXIMUM_MAGIC_PREFIXES_AND_SUFFIXES];  // +38
    WORD wSuffix[MAXIMUM_MAGIC_PREFIXES_AND_SUFFIXES];  // +3E
    BYTE eBodyLoc;                                      // +44
    BYTE ePage;                                         // +45
    BYTE eExchangePage;                                 // +46
    BYTE ePreviousPage;                                 // +47
    BYTE bGrade;                                        // +48 - New
    BYTE bVariant;                                      // +49
    char szPlayerName[MAXIMUM_CHARACTER_NAME_LENGTH];   // +4A
    WORD wRuneWordIndex;                                // +5A - New
    D2Inventory* hInventory;                            // +5C +00
    D2Unit* pPrevItem;                                  // +60 +04
    D2Unit* pNextItem;                                  // +64 +08
    BYTE eInventoryGrid;                                // +68 +0C (Equals eInventoryPage + 1, ePage + 3)
    BYTE eInventoryGridType;                            // +69 +0D
    D2Unit* pPrevItemInPage;                            // +6C +10
    D2Unit* pNextItemInPage;                            // +70 +14
};

enum ITEMFLAG
{
    ITEMFLAG_RELOAD         = 0x00000001,       // NOTE: Updates client side stats.
    ITEMFLAG_BOUGHT         = 0x00000002,
    ITEMFLAG_CURSOR         = 0x00000004,
    ITEMFLAG_IGNORE         = 0x00000008,       // NOTE: Tells the client not to reset the cursor when the update packet is received.
    ITEMFLAG_IDENTIFIED     = 0x00000010,
    ITEMFLAG_REMOVED        = 0x00000020,
    ITEMFLAG_ADDED          = 0x00000040,
    ITEMFLAG_TAKEN          = 0x00000080,
    ITEMFLAG_BROKEN         = 0x00000100,
    ITEMFLAG_RESTORED       = 0x00000200,
    ITEMFLAG_SORTED         = 0x00000400,
    ITEMFLAG_SOCKETED       = 0x00000800,
    ITEMFLAG_MONSTER        = 0x00001000,
    ITEMFLAG_NEW            = 0x00002000,
    ITEMFLAG_DISABLED       = 0x00004000,
    ITEMFLAG_HARDCORE       = 0x00008000,
    ITEMFLAG_BODYPART       = 0x00010000,
    ITEMFLAG_BEGINNER       = 0x00020000,
    ITEMFLAG_RESTRICT       = 0x00040000,       // NOTE: When this is set, ITEMFLAG_RELOAD updates are not sent.
    ITEMFLAG_SERVER         = 0x00080000,
    ITEMFLAG_100000         = 0x00100000,
    ITEMFLAG_COMPACT        = 0x00200000,
    ITEMFLAG_ETHEREAL       = 0x00400000,
    ITEMFLAG_SAVED          = 0x00800000,
    ITEMFLAG_PLAYERNAME     = 0x01000000,
    ITEMFLAG_CRUDE          = 0x02000000,
    ITEMFLAG_RUNEWORD       = 0x04000000,
    ITEMFLAG_MAGICAL        = 0x08000000,       // NOTE: ITEMFLAG_COPIED in the original game, but nothing ever tests it.
    ITEMFLAG_STAFFMODS      = 0x10000000,       // NOTE: New
    ITEMFLAG_CURSED         = 0x20000000,       // NOTE: New
    ITEMFLAG_DROW           = 0x40000000,       // NOTE: New
    ITEMFLAG_TAGGED         = 0x80000000        // NOTE: New, purpose depends on the item type we're using it with.
};

enum ITEMCMD
{
    ITEMCMD_DELETE                                  = 0x00000001, // Deletes the item after all updates have been dispatched.
    ITEMCMD_INVENTORY_PUT_ITEM                      = 0x00000002, // Sends message # 04 (D2GAME.6FCC46D0).
    ITEMCMD_INVENTORY_TAKE_ITEM                     = 0x00000004, // Sends message # 05 (D2GAME.6FCC1BC0).
    ITEMCMD_BODYLOC_PUT_ITEM                        = 0x00000008, // Sends message # 06 (D2GAME.6FCC1BC0).
    ITEMCMD_BODYLOC_TAKE_ITEM                       = 0x00000010, // Sends message # 08 (D2GAME.6FCC1BC0).
    ITEMCMD_BODYLOC_EXCHANGE_ITEM                   = 0x00000020, // Sends message # 09 (D2GAME.6FCC1BC0).
    ITEMCMD_CURSOR_PICKUP_ITEM                      = 0x00000040, // Sends message # 01 (D2GAME.6FCC46D0).
    ITEMCMD_INVENTORY_ADD_ITEM                      = 0x00000080, // Sends message # 04 (D2GAME.6FCC46D0).
    ITEMCMD_CURSOR_STACK_ITEM                       = 0x00000100, // Sends message # 10 (D2GAME.6FCC46D0).
    ITEMCMD_BODYLOC_ADD_ITEM                        = 0x00000200, // Sends message # 06 (D2GAME.6FCC1BC0).
    ITEMCMD_BELT_PUT_ITEM                           = 0x00000400, // Sends message # 13 (D2GAME.6FCC46D0).
    ITEMCMD_BELT_TAKE_ITEM                          = 0x00000800, // Sends message # 15 (D2GAME.6FCC46D0).
    ITEMCMD_BELT_EXCHANGE_ITEM                      = 0x00001000, // Sends message # 16 (D2GAME.6FCC46D0).
    ITEMCMD_BELT_ADD_ITEM                           = 0x00002000, // Sends message # 13 (D2GAME.6FCC46D0).
    ITEMCMD_INVENTORY_SET_ITEM                      = 0x00004000, // Sends message # 17 (D2GAME.6FCC1BC0).
    ITEMCMD_INVENTORY_MOVE_ITEM_TO_BODYLOC          = 0x00008000, // Sends message # 20 (D2GAME.6FCC1BC0).
    ITEMCMD_BODYLOC_EXCHANGE_OPPOSITE_ITEM          = 0x00010000, // Sends message # 07 (D2GAME.6FCC1BC0).
    ITEMCMD_20000                                   = 0x00020000, // Nothing in D2GAME.DLL checks or sets this.
    ITEMCMD_INVENTORY_EXCHANGE_ITEM                 = 0x00040000, // Sends message # 14 (D2GAME.6FCC46D0).
    ITEMCMD_80000                                   = 0x00080000, // Sends message # 22 (D2GAME.6FCC1BC0), nothing in D2GAME.DLL sets this.
    ITEMCMD_CURSOR_SET_ITEM                         = 0x00100000, // Sends message # 18 (D2GAME.6FCC46D0), Blizzard calls this ITEM_CMDFLAG_SETHANDITEM.
    ITEMCMD_BODYLOC_SWAP_ITEMS                      = 0x00200000  // Sends message # 23 (D2GAME.6FCC1BC0).
};
The various values for eBodyLoc, ePage, eExchangePage, ePreviousPage, eInventoryGrid and eInventoryGridType

Code: Select all

enum BODYLOC
{
    BODYLOC_NONE,                       // 0
    BODYLOC_HEAD,                       // 1
    BODYLOC_NECK,                       // 2
    BODYLOC_TORSO,                      // 3
    BODYLOC_R_ARM,                      // 4
    BODYLOC_L_ARM,                      // 5
    BODYLOC_R_RING,                     // 6
    BODYLOC_L_RING,                     // 7
    BODYLOC_BELT,                       // 8
    BODYLOC_FEET,                       // 9
    BODYLOC_GLOVES,                     // 10
    BODYLOC_SWAPPED_R_ARM,              // 11
    BODYLOC_SWAPPED_L_ARM,              // 12
    NUM_BODYLOCS
};

enum INVENTORY_PAGE_PLAYER
{
    INVENTORY_PAGE_PLAYER_INVENTORY,        // 0
    INVENTORY_PAGE_PLAYER_TRADE_RECEIVE,    // 1
    INVENTORY_PAGE_PLAYER_TRADE_GIVE,       // 2
    INVENTORY_PAGE_PLAYER_HORADRIC_CUBE,    // 3
    INVENTORY_PAGE_PLAYER_STASH,            // 4
    NUM_PLAYER_INVENTORY_PAGES
};

enum INVENTORY_PAGE_NPC
{
    INVENTORY_PAGE_NPC_ARMOR,               // 0
    INVENTORY_PAGE_NPC_WEAPON_1,            // 1
    INVENTORY_PAGE_NPC_WEAPON_2,            // 2 - INVENTORY_PAGE_NPC_MAGIC
    INVENTORY_PAGE_NPC_MISC,                // 3
    NUM_NPC_INVENTORY_PAGES
};

#define INVENTORY_PAGE_NONE                 ((BYTE)-1)

enum INVENTORY_GRID
{
    INVENTORY_GRID_BODYLOC,             // 0
    INVENTORY_GRID_BELT,                // 1
    INVENTORY_GRID_INVENTORY,           // 2
    NUM_INVENTORY_GRIDS
};

enum INVENTORY_GRID_TYPE
{
    INVENTORY_GRID_TYPE_NONE,           // 0
    INVENTORY_GRID_TYPE_INVENTORY,      // 1
    INVENTORY_GRID_TYPE_BELT,           // 2
    INVENTORY_GRID_TYPE_BODYLOC,        // 3
    INVENTORY_GRID_TYPE_SWAPPED,        // 4
    NUM_INVENTORY_GRID_TYPES
};

Inventory stuff itself to which these related:

Code: Select all

struct D2InventoryGrid
{
    D2Unit* pItem;                      // +00
    D2Unit* pLastItem;                  // +04
    BYTE bW;                            // +08
    BYTE bH;                            // +09
    WORD wUnused;                       // +0A
    D2Unit** hpItems;                   // +0C
};

struct D2Inventory
{
    DWORD dwMagic;                          // +00
    D2MemoryManager* hMemoryManager;        // +04
    D2Unit* pUnit;                          // +08
    D2Unit* pItem;                          // +0C
    D2Unit* pLastItem;                      // +10
    D2InventoryGrid* pGrids;                // +14
    int nGridCount;                         // +18
    DWORD dwPrimaryWeaponID;                // +1C
    D2Unit* pCursor;                        // +20
    DWORD dwID;                             // +24
    DWORD dwGemCount;                       // +28
    D2InventoryUpdateList* hUpdates;        // +2C
    D2InventoryUpdateList* hUpdatesLast;    // +30
    D2Corpse* pCorpse;                      // +34
    D2Corpse* pCorpseLast;                  // +38
    int nCorpseCount;                       // +3C
};

And some utility stuff to convert between grids and pages.

Code: Select all

__forceinline int _GetGridFromPage(BYTE ePage)
{
    // WRITTEN 2014.FEB.25 (by Nefarius)
    return (int)ePage + INVENTORY_GRID_INVENTORY;
}

__forceinline BYTE _GetPageFromGrid(int nGrid)
{
    // WRITTEN 2014.FEB.25 (by Nefarius)

    if (nGrid < INVENTORY_GRID_INVENTORY)
        return INVENTORY_PAGE_NONE;

    nGrid -= INVENTORY_GRID_INVENTORY;
    if (nGrid >= ((BYTE)-1))
        return INVENTORY_PAGE_NONE;
    else
        return (BYTE)nGrid;
}

#define GET_PAGE_FROM_GRID(n)                           _GetPageFromGrid((n))
#define GET_GRID_FROM_PAGE(n)                           _GetGridFromPage((n))

#define INVENTORY_GRID_DEFAULT                          (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_INVENTORY)
#define INVENTORY_GRID_TRADE_RECEIVE                    (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_TRADE_RECEIVE)
#define INVENTORY_GRID_TRADE_GIVE                       (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_TRADE_GIVE)
#define INVENTORY_GRID_HORADRIC_CUBE                    (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_HORADRIC_CUBE)
#define INVENTORY_GRID_STASH                            (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_STASH)

Here's an example of how one would go about using these values:

Code: Select all

BOOL __fastcall ITEMS_IsRemoveable(D2Unit* pItem)
{
    // WRITTEN 2014.MAY.31 (by Nefarius)
    // CHANGED 2015.MAR.16 (by Nefarius) - Raise error if pItemData is NULL.

    const DWORD dwMask = ITEMFLAG_IDENTIFIED|ITEMFLAG_CURSED;

    if (!UNIT_IS_ITEM(pItem))
        return FALSE;

    D2ItemData* pItemData;
    ASSERT(pItemData = pItem->pItemData);

    if (pItemData->dwPlayerID != -1)
    {
        // NOTE: We only want cursed items to become unremoveable when they're
        // also giving the player their stats. This means that we have to test
        // whenever they're identified, we also have to check whenever they're
        // equipped inside a bodyloc or, if the item is a charm, the inventory.

        if (dwMask == (pItemData->ItemFlags & dwMask))
        {
            BYTE eGridType;
            if ((eGridType = pItemData->eInventoryGridType) == INVENTORY_GRID_TYPE_BODYLOC)
                return FALSE;

            if (eGridType == INVENTORY_GRID_TYPE_INVENTORY)
            {
                if (ITEMS_IsA(pItem, ITEMTYPE_CHARM))
                {
                    if (pItemData->ePage == INVENTORY_PAGE_PLAYER_INVENTORY)
                        return FALSE;
                }
            }
        }
    }

    return TRUE;
}
And for completeness the item modes.

Code: Select all

enum ITEMMODE
{
    ITEMMODE_INVENTORY,                 // 0
    ITEMMODE_BODYLOC,                   // 1
    ITEMMODE_BELT,                      // 2
    ITEMMODE_ROOM,                      // 3
    ITEMMODE_CURSOR,                    // 4
    ITEMMODE_DROP,                      // 5
    ITEMMODE_SOCKET,                    // 6
    NUM_ITEMMODES
};
''(...) The game can basically be considered unhackable. '' - Blizzard Entertainment (30th May 2000)
Black Omen Productions | MetalStorm: Progress Report | Screenshots

User avatar
weapon-x
Forum Legend
Arch-Angel
Posts: 1047
Joined: Wed Mar 18, 2009 4:52 am
Location: Mindanao, Philippines
Contact:
Philippines

Re: Node Pages and other d2common functions

Post by weapon-x » Wed Jun 15, 2016 7:07 am

Nefarius" wrote:That returns the grid type (+69), not the page (+45). The grid ID itself is at +68 corresponding with the page. Here's a full documentation of the related structures/values.
Also, the values you give there are item modes and not grid types which are not what that function returns (although they're used to instruct the game where to look for more specific information).

Caution: I copy/pasted this from my source files and this is slightly different from vanilla.

Code: Select all

struct D2ItemData
{
    int eQuality;                                       // +00
    D2Seed tModSeed;                                    // +04
    DWORD dwPlayerID;                                   // +0C
    DWORD dwModSeed;                                    // +10
    DWORD dwCMDFlags;                                   // +14
    DWORD dwItemFlags;                                  // +18
    DWORD dwReserved[2];                                // +1C
    int nPruneFrame;                                    // +24
    int nIndex;                                         // +28
    int nLevel;                                         // +2C
    WORD wItemVersion;                                  // +30
    WORD wRarePrefix;                                   // +32
    WORD wRareSuffix;                                   // +34
    WORD wAutoMagic;                                    // +36
    WORD wPrefix[MAXIMUM_MAGIC_PREFIXES_AND_SUFFIXES];  // +38
    WORD wSuffix[MAXIMUM_MAGIC_PREFIXES_AND_SUFFIXES];  // +3E
    BYTE eBodyLoc;                                      // +44
    BYTE ePage;                                         // +45
    BYTE eExchangePage;                                 // +46
    BYTE ePreviousPage;                                 // +47
    BYTE bGrade;                                        // +48 - New
    BYTE bVariant;                                      // +49
    char szPlayerName[MAXIMUM_CHARACTER_NAME_LENGTH];   // +4A
    WORD wRuneWordIndex;                                // +5A - New
    D2Inventory* hInventory;                            // +5C +00
    D2Unit* pPrevItem;                                  // +60 +04
    D2Unit* pNextItem;                                  // +64 +08
    BYTE eInventoryGrid;                                // +68 +0C (Equals eInventoryPage + 1, ePage + 3)
    BYTE eInventoryGridType;                            // +69 +0D
    D2Unit* pPrevItemInPage;                            // +6C +10
    D2Unit* pNextItemInPage;                            // +70 +14
};

enum ITEMFLAG
{
    ITEMFLAG_RELOAD         = 0x00000001,       // NOTE: Updates client side stats.
    ITEMFLAG_BOUGHT         = 0x00000002,
    ITEMFLAG_CURSOR         = 0x00000004,
    ITEMFLAG_IGNORE         = 0x00000008,       // NOTE: Tells the client not to reset the cursor when the update packet is received.
    ITEMFLAG_IDENTIFIED     = 0x00000010,
    ITEMFLAG_REMOVED        = 0x00000020,
    ITEMFLAG_ADDED          = 0x00000040,
    ITEMFLAG_TAKEN          = 0x00000080,
    ITEMFLAG_BROKEN         = 0x00000100,
    ITEMFLAG_RESTORED       = 0x00000200,
    ITEMFLAG_SORTED         = 0x00000400,
    ITEMFLAG_SOCKETED       = 0x00000800,
    ITEMFLAG_MONSTER        = 0x00001000,
    ITEMFLAG_NEW            = 0x00002000,
    ITEMFLAG_DISABLED       = 0x00004000,
    ITEMFLAG_HARDCORE       = 0x00008000,
    ITEMFLAG_BODYPART       = 0x00010000,
    ITEMFLAG_BEGINNER       = 0x00020000,
    ITEMFLAG_RESTRICT       = 0x00040000,       // NOTE: When this is set, ITEMFLAG_RELOAD updates are not sent.
    ITEMFLAG_SERVER         = 0x00080000,
    ITEMFLAG_100000         = 0x00100000,
    ITEMFLAG_COMPACT        = 0x00200000,
    ITEMFLAG_ETHEREAL       = 0x00400000,
    ITEMFLAG_SAVED          = 0x00800000,
    ITEMFLAG_PLAYERNAME     = 0x01000000,
    ITEMFLAG_CRUDE          = 0x02000000,
    ITEMFLAG_RUNEWORD       = 0x04000000,
    ITEMFLAG_MAGICAL        = 0x08000000,       // NOTE: ITEMFLAG_COPIED in the original game, but nothing ever tests it.
    ITEMFLAG_STAFFMODS      = 0x10000000,       // NOTE: New
    ITEMFLAG_CURSED         = 0x20000000,       // NOTE: New
    ITEMFLAG_DROW           = 0x40000000,       // NOTE: New
    ITEMFLAG_TAGGED         = 0x80000000        // NOTE: New, purpose depends on the item type we're using it with.
};

enum ITEMCMD
{
    ITEMCMD_DELETE                                  = 0x00000001, // Deletes the item after all updates have been dispatched.
    ITEMCMD_INVENTORY_PUT_ITEM                      = 0x00000002, // Sends message # 04 (D2GAME.6FCC46D0).
    ITEMCMD_INVENTORY_TAKE_ITEM                     = 0x00000004, // Sends message # 05 (D2GAME.6FCC1BC0).
    ITEMCMD_BODYLOC_PUT_ITEM                        = 0x00000008, // Sends message # 06 (D2GAME.6FCC1BC0).
    ITEMCMD_BODYLOC_TAKE_ITEM                       = 0x00000010, // Sends message # 08 (D2GAME.6FCC1BC0).
    ITEMCMD_BODYLOC_EXCHANGE_ITEM                   = 0x00000020, // Sends message # 09 (D2GAME.6FCC1BC0).
    ITEMCMD_CURSOR_PICKUP_ITEM                      = 0x00000040, // Sends message # 01 (D2GAME.6FCC46D0).
    ITEMCMD_INVENTORY_ADD_ITEM                      = 0x00000080, // Sends message # 04 (D2GAME.6FCC46D0).
    ITEMCMD_CURSOR_STACK_ITEM                       = 0x00000100, // Sends message # 10 (D2GAME.6FCC46D0).
    ITEMCMD_BODYLOC_ADD_ITEM                        = 0x00000200, // Sends message # 06 (D2GAME.6FCC1BC0).
    ITEMCMD_BELT_PUT_ITEM                           = 0x00000400, // Sends message # 13 (D2GAME.6FCC46D0).
    ITEMCMD_BELT_TAKE_ITEM                          = 0x00000800, // Sends message # 15 (D2GAME.6FCC46D0).
    ITEMCMD_BELT_EXCHANGE_ITEM                      = 0x00001000, // Sends message # 16 (D2GAME.6FCC46D0).
    ITEMCMD_BELT_ADD_ITEM                           = 0x00002000, // Sends message # 13 (D2GAME.6FCC46D0).
    ITEMCMD_INVENTORY_SET_ITEM                      = 0x00004000, // Sends message # 17 (D2GAME.6FCC1BC0).
    ITEMCMD_INVENTORY_MOVE_ITEM_TO_BODYLOC          = 0x00008000, // Sends message # 20 (D2GAME.6FCC1BC0).
    ITEMCMD_BODYLOC_EXCHANGE_OPPOSITE_ITEM          = 0x00010000, // Sends message # 07 (D2GAME.6FCC1BC0).
    ITEMCMD_20000                                   = 0x00020000, // Nothing in D2GAME.DLL checks or sets this.
    ITEMCMD_INVENTORY_EXCHANGE_ITEM                 = 0x00040000, // Sends message # 14 (D2GAME.6FCC46D0).
    ITEMCMD_80000                                   = 0x00080000, // Sends message # 22 (D2GAME.6FCC1BC0), nothing in D2GAME.DLL sets this.
    ITEMCMD_CURSOR_SET_ITEM                         = 0x00100000, // Sends message # 18 (D2GAME.6FCC46D0), Blizzard calls this ITEM_CMDFLAG_SETHANDITEM.
    ITEMCMD_BODYLOC_SWAP_ITEMS                      = 0x00200000  // Sends message # 23 (D2GAME.6FCC1BC0).
};
The various values for eBodyLoc, ePage, eExchangePage, ePreviousPage, eInventoryGrid and eInventoryGridType

Code: Select all

enum BODYLOC
{
    BODYLOC_NONE,                       // 0
    BODYLOC_HEAD,                       // 1
    BODYLOC_NECK,                       // 2
    BODYLOC_TORSO,                      // 3
    BODYLOC_R_ARM,                      // 4
    BODYLOC_L_ARM,                      // 5
    BODYLOC_R_RING,                     // 6
    BODYLOC_L_RING,                     // 7
    BODYLOC_BELT,                       // 8
    BODYLOC_FEET,                       // 9
    BODYLOC_GLOVES,                     // 10
    BODYLOC_SWAPPED_R_ARM,              // 11
    BODYLOC_SWAPPED_L_ARM,              // 12
    NUM_BODYLOCS
};

enum INVENTORY_PAGE_PLAYER
{
    INVENTORY_PAGE_PLAYER_INVENTORY,        // 0
    INVENTORY_PAGE_PLAYER_TRADE_RECEIVE,    // 1
    INVENTORY_PAGE_PLAYER_TRADE_GIVE,       // 2
    INVENTORY_PAGE_PLAYER_HORADRIC_CUBE,    // 3
    INVENTORY_PAGE_PLAYER_STASH,            // 4
    NUM_PLAYER_INVENTORY_PAGES
};

enum INVENTORY_PAGE_NPC
{
    INVENTORY_PAGE_NPC_ARMOR,               // 0
    INVENTORY_PAGE_NPC_WEAPON_1,            // 1
    INVENTORY_PAGE_NPC_WEAPON_2,            // 2 - INVENTORY_PAGE_NPC_MAGIC
    INVENTORY_PAGE_NPC_MISC,                // 3
    NUM_NPC_INVENTORY_PAGES
};

#define INVENTORY_PAGE_NONE                 ((BYTE)-1)

enum INVENTORY_GRID
{
    INVENTORY_GRID_BODYLOC,             // 0
    INVENTORY_GRID_BELT,                // 1
    INVENTORY_GRID_INVENTORY,           // 2
    NUM_INVENTORY_GRIDS
};

enum INVENTORY_GRID_TYPE
{
    INVENTORY_GRID_TYPE_NONE,           // 0
    INVENTORY_GRID_TYPE_INVENTORY,      // 1
    INVENTORY_GRID_TYPE_BELT,           // 2
    INVENTORY_GRID_TYPE_BODYLOC,        // 3
    INVENTORY_GRID_TYPE_SWAPPED,        // 4
    NUM_INVENTORY_GRID_TYPES
};

Inventory stuff itself to which these related:

Code: Select all

struct D2InventoryGrid
{
    D2Unit* pItem;                      // +00
    D2Unit* pLastItem;                  // +04
    BYTE bW;                            // +08
    BYTE bH;                            // +09
    WORD wUnused;                       // +0A
    D2Unit** hpItems;                   // +0C
};

struct D2Inventory
{
    DWORD dwMagic;                          // +00
    D2MemoryManager* hMemoryManager;        // +04
    D2Unit* pUnit;                          // +08
    D2Unit* pItem;                          // +0C
    D2Unit* pLastItem;                      // +10
    D2InventoryGrid* pGrids;                // +14
    int nGridCount;                         // +18
    DWORD dwPrimaryWeaponID;                // +1C
    D2Unit* pCursor;                        // +20
    DWORD dwID;                             // +24
    DWORD dwGemCount;                       // +28
    D2InventoryUpdateList* hUpdates;        // +2C
    D2InventoryUpdateList* hUpdatesLast;    // +30
    D2Corpse* pCorpse;                      // +34
    D2Corpse* pCorpseLast;                  // +38
    int nCorpseCount;                       // +3C
};

And some utility stuff to convert between grids and pages.

Code: Select all

__forceinline int _GetGridFromPage(BYTE ePage)
{
    // WRITTEN 2014.FEB.25 (by Nefarius)
    return (int)ePage + INVENTORY_GRID_INVENTORY;
}

__forceinline BYTE _GetPageFromGrid(int nGrid)
{
    // WRITTEN 2014.FEB.25 (by Nefarius)

    if (nGrid < INVENTORY_GRID_INVENTORY)
        return INVENTORY_PAGE_NONE;

    nGrid -= INVENTORY_GRID_INVENTORY;
    if (nGrid >= ((BYTE)-1))
        return INVENTORY_PAGE_NONE;
    else
        return (BYTE)nGrid;
}

#define GET_PAGE_FROM_GRID(n)                           _GetPageFromGrid((n))
#define GET_GRID_FROM_PAGE(n)                           _GetGridFromPage((n))

#define INVENTORY_GRID_DEFAULT                          (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_INVENTORY)
#define INVENTORY_GRID_TRADE_RECEIVE                    (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_TRADE_RECEIVE)
#define INVENTORY_GRID_TRADE_GIVE                       (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_TRADE_GIVE)
#define INVENTORY_GRID_HORADRIC_CUBE                    (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_HORADRIC_CUBE)
#define INVENTORY_GRID_STASH                            (INVENTORY_GRID_INVENTORY + INVENTORY_PAGE_PLAYER_STASH)

Here's an example of how one would go about using these values:

Code: Select all

BOOL __fastcall ITEMS_IsRemoveable(D2Unit* pItem)
{
    // WRITTEN 2014.MAY.31 (by Nefarius)
    // CHANGED 2015.MAR.16 (by Nefarius) - Raise error if pItemData is NULL.

    const DWORD dwMask = ITEMFLAG_IDENTIFIED|ITEMFLAG_CURSED;

    if (!UNIT_IS_ITEM(pItem))
        return FALSE;

    D2ItemData* pItemData;
    ASSERT(pItemData = pItem->pItemData);

    if (pItemData->dwPlayerID != -1)
    {
        // NOTE: We only want cursed items to become unremoveable when they're
        // also giving the player their stats. This means that we have to test
        // whenever they're identified, we also have to check whenever they're
        // equipped inside a bodyloc or, if the item is a charm, the inventory.

        if (dwMask == (pItemData->ItemFlags & dwMask))
        {
            BYTE eGridType;
            if ((eGridType = pItemData->eInventoryGridType) == INVENTORY_GRID_TYPE_BODYLOC)
                return FALSE;

            if (eGridType == INVENTORY_GRID_TYPE_INVENTORY)
            {
                if (ITEMS_IsA(pItem, ITEMTYPE_CHARM))
                {
                    if (pItemData->ePage == INVENTORY_PAGE_PLAYER_INVENTORY)
                        return FALSE;
                }
            }
        }
    }

    return TRUE;
}
And for completeness the item modes.

Code: Select all

enum ITEMMODE
{
    ITEMMODE_INVENTORY,                 // 0
    ITEMMODE_BODYLOC,                   // 1
    ITEMMODE_BELT,                      // 2
    ITEMMODE_ROOM,                      // 3
    ITEMMODE_CURSOR,                    // 4
    ITEMMODE_DROP,                      // 5
    ITEMMODE_SOCKET,                    // 6
    NUM_ITEMMODES
};
ah... my bad i must have misunderstood the code :oops: ... thank you for sharing this valuable info sir :)
" It's not the size of the dog in the fight, it's the size of the fight in the dog. "

~Mark Twain

User avatar
Lurix
Dark Alliance Beta Test
Champion of the Light
Posts: 496
Joined: Tue Aug 31, 2010 9:30 am
Location: Birmingham, UK
Bulgaria

Re: Node Pages and other d2common functions

Post by Lurix » Wed Jun 15, 2016 10:18 pm

Bookmarked...Someone has to start updating this viewtopic.php?f=8&t=22261 page, with all the info we`re getting lately.

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

Re: Node Pages and other d2common functions

Post by devurandom » Fri Dec 30, 2016 1:12 am

@Nefarius

Great information - Thank You !
also Thanks for all the info and contributions you've posted over the years.

;)


Edit:

Seems like D2ItemData +0x5C to +0x70 is a nested struct. Anyone Confirm?
Working with some D2Common functions that make use of that.

Code: Select all

struct D2ItemData
{
    int eQuality;                                       // +00
    D2Seed tModSeed;                                    // +04
    DWORD dwPlayerID;                                   // +0C
    DWORD dwModSeed;                                    // +10
    DWORD dwCMDFlags;                                   // +14
    DWORD dwItemFlags;                                  // +18
    DWORD dwReserved[2];                                // +1C
    int nPruneFrame;                                    // +24
    int nIndex;                                         // +28
    int nLevel;                                         // +2C
    WORD wItemVersion;                                  // +30
    WORD wRarePrefix;                                   // +32
    WORD wRareSuffix;                                   // +34
    WORD wAutoMagic;                                    // +36
    WORD wPrefix[MAXIMUM_MAGIC_PREFIXES_AND_SUFFIXES];  // +38
    WORD wSuffix[MAXIMUM_MAGIC_PREFIXES_AND_SUFFIXES];  // +3E
    BYTE eBodyLoc;                                      // +44
    BYTE ePage;                                         // +45
    BYTE eExchangePage;                                 // +46
    BYTE ePreviousPage;                                 // +47
    BYTE bGrade;                                        // +48 - New
    BYTE bVariant;                                      // +49
    char szPlayerName[MAXIMUM_CHARACTER_NAME_LENGTH];   // +4A
    WORD wRuneWordIndex;                                // +5A - New
    D2Inventory* hInventory;                            // +5C +00
    D2Unit* pPrevItem;                                  // +60 +04
    D2Unit* pNextItem;                                  // +64 +08
    BYTE eInventoryGrid;                                // +68 +0C (Equals eInventoryPage + 1, ePage + 3)
    BYTE eInventoryGridType;                            // +69 +0D
    D2Unit* pPrevItemInPage;                            // +6C +10
    D2Unit* pNextItemInPage;                            // +70 +14
};
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
Necrolis
Senior Admin
Throne
Posts: 9115
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
Contact:
South Africa

Hand-picked

Re: Node Pages and other d2common functions

Post by Necrolis » Wed Jan 04, 2017 9:20 pm

devurandom" wrote:
Seems like D2ItemData +0x5C to +0x70 is a nested struct. Anyone Confirm?
Working with some D2Common functions that make use of that.
From the simpler codegen pre 1.11 you can confirm this (there is a D2Commo ordinal that returns a pointer to this nested struct).
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

qwertyue
Posts: 10
Joined: Sun Jan 31, 2021 5:41 am

Re: Node Pages and other d2common functions

Post by qwertyue » Fri Sep 24, 2021 2:37 am

how to use itemmode?

Post Reply

Return to “Code Editing”