Item quality is stored in the cache entries.
Not sure if this is up to date or not (haven't gotten to this part of my rewrite yet)
Code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ItemInfo
{
public int EntryLength;
public int ClassId;
public int SubClassId;
public int Unk0;
public int DisplayInfoId;
public int Rarity;
public int TypeFlags;
public int BuyPrice;
public int Faction;
public int SellPrice;
public int EquipSlot;
public int AllowedClasses;
public int AllowedRaces;
public int ItemLevel;
public int RequiredLevel;
public int RequiredSkill;
public int RequiredSkillLevel;
public int RequireSpell;
public int RequiredHonorRank;
public int RequiredCityRank;
public int RequiredReputationFaction;
public int RequiredReputationRank;
public int UniqueCount;
public int MaxStackSize;
public int BagSlots;
public int NumberOfStats;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10, ArraySubType = UnmanagedType.I4)]
public int[] StatId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10, ArraySubType = UnmanagedType.I4)]
public int[] StatValue;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.I4)]
public int[] Unk1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.R4)]
public float[] DamageMin;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.R4)]
public float[] DamageMax;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.I4)]
public int[] DamageType;
public int ResistPhysical_Armor;
public int ResistHoly;
public int ResistFire;
public int ResistNature;
public int ResistFrost;
public int ResistShadow;
public int ResistArcane;
public int WeaponDelay;
public int AmmoType;
public float RangeModifier;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.I4)]
public int[] SpellId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.I4)]
public int[] SpellTriggerId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.I4)]
public int[] SpellCharges;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.I4)]
public int[] SpellCooldown;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.I4)]
public int[] SpellCategory;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.I4)]
public int[] SpellCategoryCooldown;
public int BondId;
[MarshalAs(UnmanagedType.LPStr)]
public string Description;
public int BookTextId;
public int BookPages;
public int BookStationaryId;
public int BeginQuestId;
public int LockPickSkillRequired;
public int MaterialId;
public int SheathId;
public int RandomPropertyId;
public int RandomPropertyId2;
public int BlockValue;
public int ItemSetId;
public int DurabilityValue;
public int ItemAreaId;
public int ItemMapId;
public int BagFamily;
public int totemCategory;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.I4)]
public int[] SocketColor;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.I4)]
public int[] SocketUnk;
public int SocketBonus;
public int GemProperties;
public int DisenchantSkillLevel;
public float ArmorDamageModifier;
public int ItemExtendedCost;
public int ItemLimitId;
public int Unk2;
[MarshalAs(UnmanagedType.LPStr)]
public string Name;
}
Code:
/// <summary>
/// Typedef for the virtual DbCache_GetInfoBlockById func. Some caches take extra params, but most (all) can
/// be passed the ID/Index of the cache, and then the rest passed as 0.
/// </summary>
/// <param name = "instance">'this' needs to be the specific cache type pointer</param>
/// <param name = "id">The ID to search</param>
/// <param name = "guid">A GUID to the cache object in question; if one exists.</param>
/// <param name = "a4"></param>
/// <param name = "a5"></param>
/// <param name = "a6"></param>
/// <returns>A pointer to an info block (struct) depending on the type of cache, and function pointer/cache pointer.</returns>
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate IntPtr GetInfoBlockByIdDelegate(IntPtr instance, int id, ref ulong guid, int a4, int a5, int a6);