Valhalla Legends Forums Archive | BnetDocs Research and Discussion | D2GS 0x9C - 0X9D Breakdown Take 2

AuthorMessageTime
E.T.
Unknowns:

  Unknown1
May be part of version... never seen those bits set.

  Runeword ID
The first 12 bits need to be shifted / added by a value depending on last 4 bits...
What is currently got is if second value is 5, subtract 26 is value is under 100, or 25.
Only seen one case where it wasn't 5 so I can't really say, but I tried a lot of runewords with which this works...

Also (more on these later):
A couple unknown action types, flags and other enum values.

[code]
(BYTE) Action
(BYTE) Length
(BYTE) Category
(DWORD) Item Unit ID

0x9D only:
  (BYTE) Owner Unit Type
  (DWORD) Owner Unit ID

(DWORD) Flags
(BYTE) Version
(2 bits) Unknown1
(3 bits) Destination

If Destination == 3 (Ground):
  (WORD) X
  (WORD) Y
Else:
  (4 bits) EquipmentLocation
  (4 bits) X
  (3 bits) Y
  (4 bits) Container

If Flags & Ear:
  (3 bits) Character Class
  (7 bits) Level
  (NULLSTRING*) Character Name
  END

(DWORD) Base Item Code

If Base Item == Gold
  (1 bit) Big Pile
  If Big Pile:
    (32 bits) Quantity
  Else:
    (12 bits) Quantity
  END

(3 bits) Used Sockets

If Flags & (SimpleItem | Gamble):
  END

(7 bits) Item Level
(4 bits) Item Quality

(1 bit) Has Graphic
If Has Graphic:
  (3 bits) Graphic

(1 bit) Has Color
If Has Color:
  (11 bits) Color

If Flags & Identified:
  Switch (Quality):
    Inferior:
      (3 bits) Inferior Prefix
    Superior:
      (3 bits) Superior Type
    Magic:
      (11 bits) Magic Prefix
      (11 bits) Magic Suffix
    Rare:
    Crafted:
      (8 bits) Rare Prefix
      (8 bits) Rare Suffix
    Set:
      (12 bits) Set ID
    Unique:
      (12 bits) Unique ID

If Quality == Rare || Crafted:
  For i=0; i<3; i++:
    (1 bit) Has Magic Prefix
    If Has Magic Prefix:
      (11 bits) Magic Prefix
    (1 bit) Has Magic Suffix
    If Has Magic Suffix:
      (11 bits) Magic Suffix
  Done

If Flags & Runeword:
  (16 bits) Runeword ID

If Flags & Personlized:
  (NULLSTRING*) Name

If BaseItem comes from Armor.txt:
  (ArmorClass saveBits) Armor Class + ArmorClass saveAdd

If BaseItem comes from Armor.txt or Weapon.txt:
  (MaxDurability savebits) Max Durability
  If Max Durability != 0:
    (Durability savebits) Durability

If Flags & Socketed:
  (NumSockets saveBits) Sockets

If BaseItem.Stackable:
  If BaseItem.Useable:
    (5 bits) Use
  (9 bits) Quantity

If Flags & Identified == 0:
  END

If Quality == Set:
  (5 bits) Set Bonuses

ReadStats

If Flag & Runeword:
  ReadStats

If Quality == Set:
  For i=0; i < 5; i++
    If SetBonuses & (1 << i):
      ReadStats
  Done
[/code]

*NULLSTRING: 7 bits per character.


ReadStats:

[code]
Repeat:
(9 bits) Stat ID
If Stat Id == 0x1FF:
  BREAK

If SaveParamBits != -1:
  Switch (Stat):
    ChargedSkill:
      (6 bits) Skill Level
      (10 bits) Skill
      (8 bits) Current Charges
      (8 bits) Max Charges
    SkillOnAttack:
    SkillOnKill:
    SkillOnDeath:
    SkillOnStriking:
    SkillOnLevelUp:
    SkillOnGetHit:
      (6 bits) Skill Level
      (10 bits) Skill
      (SaveBits) % Chance
    SkillTabBonus:
      (3 bits) Skill Tab
      (3 bits) Character Class
      (10 bits) Unknown
      (SaveBits) Bonus
    Default:
      (SaveParamBits) Param
      (SaveBits) Value

Else:
  If Stat.OpBase == Level:
    (SaveBits) Value / (1 << stat.OpParam) per Level
  Else:
    Switch (Stat):
      MinDamagePercent:
      MaxDamagePercent:
        (SaveBits) Min
        (SaveBits) Max
      FireMinDamage:
      LightMinDamage:
      MagicMinDamage:
        (SaveBits) Min
        ((Stat.Index+1).SaveBits) Max
      ColdMinDamage:
        (SaveBits) Min
        (ColdMaxDamage.SaveBits) Max
        (ColdLength.SaveBits) Length
      PoisonMinDamage:
        (SaveBits) Min
        (PoisonMaxDamage.SaveBits) Max
        (PoisonLength.SaveBits) Length
      ReplenishDurability:
      ReplenishQuantity:
        (SaveBits) 1 in 100 / Value seconds
      Default:
        (SaveBits) Value - (SaveAdd != -1 ? SaveAdd : 0)
Done
[/code]


Parsing stats:

Savebits and other "BaseStat" values associated with stat IDs come from itemstatcost.txt.

Another thing you may need to worry about is if the stat is signed or unsigned. For item stats, I don't think it would cause problems if you parse them all as signed, but that is not the case for all stats; some are unsigned and their value can be higher than a 32 signed integer will allow... the signed column in itemstatcost.txt determines if the stat is signed or not.


Fields description:

  Destination
I call it that instead of Location not to be confused with my Equipment Location enum or, more importantly, the Container and X, Y fields, which are not necessarly related. See there is not really a "now" in item action packets, but rather a before and an after: the destination is always where the item will end up, but the rest of the info may be about where it previously was, depending on action type.

E.g. picking an item from inventory means both removing it from there and adding to cursor:
Action:            RemoveFromContainer (5)
Destination:        Cursor (4)
Container:          Inventory (2)
X:                  1
Y:                  1

Values:
Unspecified  = 0
Equipment    = 1
Belt        = 2
Ground      = 3
Cursor      = 4
Item        = 6

If 0, the destination can be determined from the action type / and or container fields instead...
5 and 7 are unknown, if used...

  Base Item Code
This is a DWORD built from the 3 letters item codes, with space as the filler character. One could build it such:
For int i = 0; i < 4; i++:
  id |= (i < code.Length ? code[ i].CharCode : 0x20) << ( i*8 );

  Gold
If amount is larger than 4095, the Big Pile bit will be set and the value will be 32 bits in length instead of 12.
The game will only displays up to 9 characters (999 999 999, 30 bits) but will parse and show the first numbers only if it's longer...
The 32nd bit is the sign; the client will indeed display negative piles of gold.

  Durability
Even items marked NoDurability have one, it just normally isn't used...
0 Max Durability means the item is indestructible and doesn't have a current Durablity.

  Graphic
Set on items having a variable graphic like rings and charms.

  Color
Set on items having a variable color like some class specific items (sorceress orbs...)

  Set Bonuses
This is a bit field, each bit indicating if there are bonus stats for (offset + 2) items of the set worn.


Edit: Corrected set bonuses information.
Edit2: Added extra information and simplified description a bit.
Edit3: Corrected used sockets info: bits are present even if Socketed flag is not set...
Edit4: Corrected the gold, color and unidentified rare information, cleaned up info some more and added some field descriptions.
Edit5: Corrected Item Code and noted that quality specific info should only be read if item is identified.
February 12, 2007, 10:43 PM
UserLoser
I might look into updating the D2GS stuff aswell as UDP game stuff sometime soon, thanks for the input.
February 12, 2007, 11:55 PM
K
You can parse items using several excel files found inside Patch_D2.mpq or d2exp.mpq.  I was actually just implementing some of this again as I was porting my d2 single player character editor to mono/gtk#, and the format is the same.

The most important files are
data\global\excel\ItemStatCost.txt - tells you the number of bits for each magical property (save bits), what to subtract to get the actual value of the property (add bits), and if there are additional bits (save param bits).

Keep in mind that if you find some magical properties (ie, + min cold dmg, + max cold dmg, +min fire dmg, + max dmg %, etc), the next 9 bit code will be missing and should be assumed to be the next property in the list (+ max cold dmg, cold duration, +max file dmg, +min dmg%).

You can find magical properties in data\global\excel\UniqueItems.txt - look up the name / image of a unique item given it's Unique Item ID.  (start at line 0, do not count the line that says "Expansion")


Edit:  From what I've looked at, the set_bonus_count is a bitfield with each bit indicating that there is an additional magical property list.

I handle it like so:
[code]
// where prop_lists is a list of lists of magical properties.
for(int i = 0; i < 5; ++i)
  if ((set_bitfield & (1 << i)) != 0) // if the bit is set, read a magical property list
  {
      // read properties until we find 0x1ff as the property code
      prop_lists.Add(MagicalPropertyDatabase.ReadList(bitreader));
    }
[/code]

February 13, 2007, 8:45 AM
E.T.
Oh yes that's it, thanks. Each bit indicates if there are bonuses for the next number of set items worn (starting at 2, up to 6.)

        SetItem:            Tal Rasha's Adjudication
        SetBonuses:        , , (Faster Cast Rate: 10), ,

1 mod for 4 items

        SetItem:            Tal Rasha's Howling Wind
        SetBonuses:        (Faster Cast Rate: 10), , , ,

1 mod for 2 items

        SetItem:            Tal Rasha's Horadric Crest

no mods

        SetItem:            Tal Rasha's Lidless Eye
        SetBonuses:        (+1 To Sorceress Skills), (Passive Fire Pierce: 15), (Passive Lightning Pierce: 15), (Passive Cold Mastery: 15),

1 mod for 2, 3, 4 and 5 items

        SetItem:            Tal Rasha's Fire-Spun Cloth
        SetBonuses:        (Armor Class: 60), (Faster Cast Rate: 10), , ,

1 mod for 2 and 3 items

I'll update the description later...
February 14, 2007, 1:07 AM
Ringo
[quote author=UserLoser link=topic=16303.msg164673#msg164673 date=1171324503]
I might look into updating the D2GS stuff aswell as UDP game stuff sometime soon, thanks for the input.
[/quote]
afaik, they dont need updating, they need adding :)
I remember krad putting 1.09 D2GS C > S Packets on bnet docs, and not my 1.10/1.11 research found here
Also, my UDP research I posted a year or so ago, is also good and indate and needs adding to Bnet docs.
I remember arta saying these things dont get added over night :P
That was a few years ago :)
Thats partly why all my main research now goes onto a private forum, and not this one  :-\
February 15, 2007, 8:11 PM
E.T.
I corrected the gold, color and unidentified rare information, cleaned up info some more and added some field descriptions.

Ringo: that's too bad. I guess forums do as well for reference and your research threads helped me a lot to get started anyways...
February 16, 2007, 3:31 AM

Search