{ this.action = (ItemActionType) data[1]; this.category = (ItemCategory) data[3]; this.uid = BitConverter.ToUInt32(data, 4); int pOffset = data[0] == 0x9d ? 13 : 8; this.flags = (ItemFlag) BitConverter.ToUInt32(data, pOffset); //TODO: figure if there's more info in there this.version = (GameVersion) data[pOffset += 4]; pOffset++; if (this.action == ItemActionType.AddToGround || this.action == ItemActionType.DropToGround || this.action == ItemActionType.OnGround) { this.x = BitConverter.ToUInt16(data, pOffset); this.y = BitConverter.ToUInt16(data, pOffset += 2); //TODO: change to walk coords // converting these coordinates: // P: coordinate from packet; W: walking coordinate; c: constant // 32*W + c == P // I just took a look at it on the fly, will examine that later, but for // now a good value for c seems to be -131028 (got that from the first calculation and // it works fine... maximum difference I got between the calculated coordinates // and the ones I took from Packet 0x03 was around 10 walking coordinate units) // I guess the constant will be c = -131072 = -2^17... that would make more sense. pOffset += 2; //TODO: Unknown bit pOffset = pOffset * 8 + 1; this.container = (ItemContainer) ByteConverter.GetBits(data, ref pOffset, 4); } else { this.container = (ItemContainer) (data[pOffset+2] & 0x0F); pOffset = pOffset * 8; this.destination = (ItemDestination) ByteConverter.GetBits(data, ref pOffset, 5); this.location = (EquipmentLocation) ByteConverter.GetBits(data, ref pOffset, 4); this.x = (ushort) ByteConverter.GetBits(data, ref pOffset, 4); this.y = (ushort) ByteConverter.GetBits(data, ref pOffset, 3); //TODO: Unknown nibble pOffset += 4; } if ((this.flags & ItemFlag.Ear) == ItemFlag.Ear) { this.baseItem = BaseItem.Get(BaseItems.Ear); this.charClass = (CharacterClass) ByteConverter.GetBits(data, ref pOffset, 3); this.level = (ushort) ByteConverter.GetBits(data, ref pOffset, 7); System.Text.StringBuilder builder = new System.Text.StringBuilder(); int mChar; while ((mChar = ByteConverter.GetBits(data, ref pOffset, 7)) != 0) builder.Append((char) mChar); this.name = builder.ToString(); return; } this.baseItem = BaseItem.GetByCode(this.category, String.Concat( (char) ByteConverter.GetBits(data, ref pOffset, 8), (char) ByteConverter.GetBits(data, ref pOffset, 8), (char) ByteConverter.GetBits(data, ref pOffset, 8) )); //TODO: Unknown nibble pOffset += 4; if (this.baseItem.Id == BaseItems.Gold) { // TODO: haven't tried yet to figure out what this is //ByteConverter.GetBits(data, pOffset, 4); pOffset += 4; // 1 indicates that we have a big pile of gold // This might not be the 100% correct number of bits but it works correctly as long as // it just is "ordinary" gold (perhaps there are mods out there with "uber gold" or s.th. like that^^) if (ByteConverter.GetBits(data, ref pOffset, 1) == 1) this.quantity = ByteConverter.GetBits(data, ref pOffset, 20); else this.quantity = ByteConverter.GetBits(data, ref pOffset, 18); this.offset = pOffset; return; } // Buffer to container mapping (sanitize NPC tabs IDs and coords, changed belt location to X, Y, etc.) if ((this.flags & ItemFlag.InStore) == ItemFlag.InStore // Flag is not always set for shop items !?! || this.action == ItemActionType.AddToShop || this.action == ItemActionType.RemoveFromShop) { int buff = (int)this.container | 0x80; if (this.y < 2 && (buff == 0x83 || buff == 0x85 || buff == 0x89)) { buff -= 1; this.y += 8; } this.container = (ItemContainer) buff; } else if (this.container == ItemContainer.Equipment) { if (this.location == EquipmentLocation.NotApplicable) { if ((this.Flags & ItemFlag.InSocket) == ItemFlag.InSocket) this.container = ItemContainer.Item; else { this.container = ItemContainer.Belt; this.y = this.x / 4; this.x = this.x % 4; } } else { // Hides them in dump... not needed anyway this.y = -1; this.x = -1; } } // TODO: I don't know what this is (always 2 ??) this.unknown1 = (byte) ByteConverter.GetBits(data, ref pOffset, 4); // Used Sockets : 3 if ((this.flags & ItemFlag.Socketed) == ItemFlag.Socketed) this.usedSockets = (byte) ByteConverter.GetBits(data, pOffset, 3); pOffset += 3; // Ends here if Simple or Gamble Item if ((this.flags & ItemFlag.SimpleItem) == ItemFlag.SimpleItem || (this.flags & ItemFlag.Gamble) == ItemFlag.Gamble) { this.offset = pOffset; return; } // ILevel : 7 this.level = (byte) ByteConverter.GetBits(data, ref pOffset, 7); // Quality : 4 this.quality = (ItemQuality) ByteConverter.GetBits(data, ref pOffset, 4); // Graphic : 1 : 3 if (ByteConverter.GetBits(data, ref pOffset, 1) == 1) this.graphic = ByteConverter.GetBits(data, ref pOffset, 3); //TODO: ClassInfo : 1 : 11 if (ByteConverter.GetBits(data, ref pOffset, 1) == 1) this.classInfo = ByteConverter.GetBits(data, ref pOffset, 11); // Quality information if ((this.flags & ItemFlag.Identified) == ItemFlag.Identified) { switch(this.quality) { case ItemQuality.Inferior: this.prefix = new ItemAffix(ItemAffixType.InferiorPrefix, ByteConverter.GetBits(data, ref pOffset, 3)); break; case ItemQuality.Superior: this.prefix = new ItemAffix(ItemAffixType.SuperiorPrefix, 0); //TODO: quality type ? whether to show prefix (e.g. off for runewords) ? pOffset += 3; break; case ItemQuality.Magic: this.prefix = new ItemAffix(ItemAffixType.MagicPrefix, ByteConverter.GetBits(data, ref pOffset, 11)); this.suffix = new ItemAffix(ItemAffixType.MagicSuffix, ByteConverter.GetBits(data, ref pOffset, 11)); break; case ItemQuality.Rare: case ItemQuality.Crafted: this.prefix = new ItemAffix(ItemAffixType.RarePrefix, ByteConverter.GetBits(data, ref pOffset, 8)); this.suffix = new ItemAffix(ItemAffixType.RareSuffix, ByteConverter.GetBits(data, ref pOffset, 8)); for (int i=0; i < 3; i++) { if (ByteConverter.GetBits(data, ref pOffset, 1) == 1) this.magicPrefixes[i] = new ItemAffix(ItemAffixType.MagicPrefix, ByteConverter.GetBits(data, ref pOffset, 11)); if (ByteConverter.GetBits(data, ref pOffset, 1) == 1 ) this.magicSuffixes[i] = new ItemAffix(ItemAffixType.MagicSuffix, ByteConverter.GetBits(data, ref pOffset, 11)); } break; case ItemQuality.Set: case ItemQuality.Unique: //TODO: unique set id ByteConverter.GetBits(data, ref pOffset, 12); break; } } // Personalized Name : 7 * (NULLSTRING Length) if ((this.Flags & ItemFlag.Personalized) == ItemFlag.Personalized) { System.Text.StringBuilder builder = new System.Text.StringBuilder(); int mChar; while ((mChar = ByteConverter.GetBits(data, ref pOffset, 7)) != 0) builder.Append((char) mChar); this.name = builder.ToString(); } // Runeword Info : 16 if ((this.Flags & ItemFlag.Runeword) == ItemFlag.Runeword) { //TODO: runeword id ByteConverter.GetBits(data, ref pOffset, 12); //UNKNOWN: this might also be the number of stat's the current set hold? (read this somewhere) //this.extraMods = (int) ByteConverter.GetBits(data, ref pOffset, 4); } // Defense : 11 if (this.baseItem is BaseArmor) this.defense = ByteConverter.GetBits(data, ref pOffset, 11) - 10; //if (this.baseItem.NoDurability != 1) if (this.baseItem is BaseArmor || this.baseItem is BaseWeapon) { this.maxDurability = ByteConverter.GetBits(data, ref pOffset, 8); //todo, if this is 0 it is indestructible by default (PB)? Stat=zod for zoded? //what about Stormshield, etc..? UNTESTED -> (indestructible) if (this.MaxDurability > 0) { this.currentDurability = ByteConverter.GetBits(data, ref pOffset, 8); //TODO: unknown. Indestructible bit ?? ByteConverter.GetBits(data, ref pOffset, 1); } } // Total Sockets : 4 if ((this.Flags & ItemFlag.Socketed) == ItemFlag.Socketed) this.sockets = ByteConverter.GetBits(data, ref pOffset, 4); // Useable : 5; Quantity : 9 if (this.baseItem.Stackable == 1) { if (this.baseItem.Useable == 1) { //TODO: figure what this is for (tp tome = 0, id tome = 1...) this.use = ByteConverter.GetBits(data, ref pOffset, 5); } this.quantity = (ushort) ByteConverter.GetBits(data, ref pOffset, 9); } // Extra Set Mods (Item's Set Bonuses) if (this.Quality == ItemQuality.Set) this.extraMods = ByteConverter.GetBits(data, ref pOffset, 5); if ((this.Flags & ItemFlag.Identified) != ItemFlag.Identified) { this.offset = pOffset; return; } int maxOffset = data.Length * 8 - 9; bool skipFirstEnd = (this.flags & ItemFlag.Runeword) == ItemFlag.Runeword; while (pOffset < maxOffset) { int statID = ByteConverter.GetBits(data, ref pOffset, 9); if (statID == 0x1FF) { if (skipFirstEnd) { skipFirstEnd = false; continue; } break; } if (statID < 0 || (int) StatType.Invalid <= statID) { //TODO: something about it... or remove... pOffset -= 9; break; } ItemStat stat = ReadStat(ref data, ref pOffset, BaseStat.Get(statID)); if (stat != null) this.stats.Add(stat); else break; } if (extraMods > 0) { this.setBonuses = new System.Collections.ArrayList(); while (extraMods-- > 0) { int statID = ByteConverter.GetBits(data, ref pOffset, 9); if (statID == 0x1FF) break; if (statID < 0 || (int) StatType.Invalid <= statID) { //TODO: something about it... or remove... pOffset -= 9; break; } ItemStat stat = ReadStat(ref data, ref pOffset, BaseStat.Get(statID)); if (stat != null) this.setBonuses.Add(stat); else break; } } this.offset = pOffset; }