public Dictionary <int, D2Skill> GetSkillMap(D2Unit unit) { Dictionary <int, D2Skill> skills = new Dictionary <int, D2Skill>(); foreach (D2Skill skill in skillReader.EnumerateSkills(unit)) { int numberOfSkillPoints = skillReader.GetTotalNumberOfSkillPoints(skill); if (numberOfSkillPoints > 0) { D2SkillData skillData = skillReader.ReadSkillData(skill); if (skillData.ClassId >= 0 && skillData.ClassId <= 6) { string skillName = skillReader.GetSkillName((ushort)skillData.SkillId); int skillPoints = skill.numberOfSkillPoints; } } } return(skills); }
private string GetStatPropertyDescription(List <D2Stat> stats, D2Stat stat) { if (stat.LoStatID >= ItemStatCost.Length) { return(null); } var statCost = ItemStatCost[stat.LoStatID]; byte printFunction = statCost.DescFunc; byte printPosition = statCost.DescVal; ushort printDescription = statCost.DescStr2; ushort printStringId = statCost.DescStrPos; // Check if the group of the value is used. // Grouping of stats is for stats such as resistances and attribute bonuses. // E.g: "+6 light res, +6 fire res, +6 cold res, +6 psn res" becomes: "+6 All Res" if (statCost.DGrp != 0) { // Check if all stats in the group have the same value. // Only print first in the group if the group has the same values. // If the values in the group different, print them individually. bool lastOfGroup = false; bool groupIsSame = true; foreach (var groupStatCost in ItemStatCost) { if (groupStatCost.DGrp != statCost.DGrp) { continue; } int index = stats.FindIndex(x => x.LoStatID == groupStatCost.StatId); lastOfGroup = groupStatCost.StatId == stat.LoStatID; if (index < 0 || stats[index].Value != stat.Value) { groupIsSame = false; break; } } if (groupIsSame) { // Only print the last of equal groups. if (!lastOfGroup) { return(null); } printFunction = statCost.DGrpFunc; printPosition = statCost.DGrpVal; printStringId = statCost.DGrpStrPos; printDescription = statCost.DGrpStr2; } } // Gets the evaluated stat value, takes care of stats per player level, // value shifts, etc... int value = EvaluateStat(stat, statCost); int arguments; string format = null; switch (printFunction) { case 0x00: return(null); case 0x01: case 0x06: case 0x0C: if (printPosition == 1) { format = "{0:+#;-#;0} {1}"; } else if (printPosition == 2) { format = "{1} {0:+#;-#;0}"; } else { return(null); } break; case 0x02: case 0x07: if (printPosition == 1) { format = "{0}% {1}"; } else if (printPosition == 2) { format = "{1} {0}%"; } break; case 0x03: case 0x09: if (printPosition == 1) { format = "{0} {1}"; } else if (printPosition == 2) { format = "{1} {0}"; } else { return(stringReader.GetString(printStringId)); } break; case 0x04: case 0x08: if (printPosition == 1) { format = "+{0}% {1}"; } else if (printPosition == 2) { format = "{1} +{0}%"; } break; case 0x05: case 0x0A: value = (value * 0x64) >> 7; if (printPosition == 1) { format = "{0}% {1}"; } else if (printPosition == 2) { format = "{1} {0}%"; } break; case 0x0B: int quotient = 2500 / value; if (quotient <= 30) { format = stringReader.GetString(StringConstants.RepairsDurability); format = stringReader.ConvertCFormatString(format, out arguments); return(string.Format(format, value)); } else { int duration = (quotient + 12) / 25; format = stringReader.GetString(StringConstants.RepairsDurabilityN); format = stringReader.ConvertCFormatString(format, out arguments); return(string.Format(format, 1, duration)); } case 0x0D: { var characterData = GetCharacterData(stat.HiStatID); if (characterData == null) { return(null); } if (value == 0) { value = 1; } string allSkills = stringReader.GetString(characterData.AllSkillsStringId); if (allSkills == null) { return(null); } return(string.Format("+{0} {1}", value, allSkills)); } case 0x0E: { ushort characterId = (ushort)(stat.HiStatID >> 3); var characterData = GetCharacterData(characterId); if (characterData == null) { return(null); } ushort skillTab = (ushort)(stat.HiStatID & 0x7); if (skillTab > 2) { return(null); } ushort skillTabStringId = characterData.SkillTabStrings[skillTab]; format = stringReader.GetString(skillTabStringId); format = stringReader.ConvertCFormatString(format, out arguments); if (arguments != 1) { return(null); } string classRestriction = stringReader.GetString(characterData.StrClassOnly); return(string.Format(format, value) + " " + classRestriction); } case 0x14: case 0x15: if (printPosition == 1) { format = "-{0}% {1}"; } else if (printPosition == 2) { format = "{1} -{0}%"; } break; case 0x0F: { ushort skillIdentifier = (ushort)(stat.HiStatID >> (byte)globals.ItemSkillShift); uint skillLevel = stat.HiStatID & globals.ItemSkillMask; string skillName = skillReader.GetSkillName(skillIdentifier); if (skillName == null) { return(null); } format = stringReader.GetString(printStringId); format = stringReader.ConvertCFormatString(format, out arguments); if (format == null || arguments != 3) { return(null); } // Example: "10% Chance to cast level 3 Charged Bolt when struck". return(string.Format(format, value, skillLevel, skillName)); } case 0x10: { string skillName = skillReader.GetSkillName(stat.HiStatID); if (skillName == null) { return(null); } format = stringReader.GetString(printStringId); format = stringReader.ConvertCFormatString(format, out arguments); if (arguments != 2) { return(null); } return(string.Format(format, value, skillName)); } case 0x11: case 0x12: // Increased stat during time of day, this is not actually used on any ingame items, // so I'm gonna spare myself some work and ignore it. :) // Example: "+24% Cold Absorb (Increases during Nighttime)" return(null); case 0x13: format = stringReader.GetString(printStringId); format = stringReader.ConvertCFormatString(format, out arguments); if (arguments != 1) { return(null); } return(string.Format(format, stat.Value)); case 0x16: { format = stringReader.GetString(printStringId); // This is most likely unused in the real game. ushort monsterPropIndex = stat.HiStatID; if (stat.HiStatID >= globals.MonsterPropCount) { monsterPropIndex = 0; } IntPtr monsterTypeAddress = globals.MonsterTypes.Address + monsterPropIndex * 0xC; ushort monsterNameId = reader.ReadUInt16(monsterTypeAddress + 0xA); string monsterName = stringReader.GetString(monsterNameId); if (printPosition == 1) { return(string.Format("+{0}% {1}: {2}", value, format, monsterName)); } else if (printPosition == 2) { return(string.Format("{1} +{0}%: {2}", value, format, monsterName)); } else { return(null); } } case 0x17: // This is for affixes with bonus stats against specific monsters. // Assumed output: "+10% Attack Rating (versus:|against|vs) Skeletons" // This is actually not used ingame and we thus ignore it. // Note: HiStatID is the monster type id. return(null); case 0x18: { StringBuilder sb = new StringBuilder(); ushort skillIdentifier = (ushort)(stat.HiStatID >> (byte)globals.ItemSkillShift); uint skillLevel = stat.HiStatID & globals.ItemSkillMask; // Example: "Level 3" sb.Append(stringReader.GetString(StringConstants.ItemSkillLevel)); sb.Append(" "); sb.Append(skillLevel); sb.Append(" "); string skillName = skillReader.GetSkillName(skillIdentifier); if (skillName == null) { return(null); } // Example: "Level 3 Charged Bolt" sb.Append(skillName); sb.Append(" "); // Get skill charges. format = stringReader.GetString(printStringId); format = stringReader.ConvertCFormatString(format, out arguments); int maximumCharges = (value >> 8) & 0xFF; int currentCharges = (value & 0x0FF); // Example: "Level 3 Charged Bolt (27/27 Charges)" sb.AppendFormat(format, currentCharges, maximumCharges); return(sb.ToString()); } case 0x19: case 0x1A: // Probably unused ingame, but logic is pretty simple. value *= -1; if (value > 0) { goto case 0x01; } if (printPosition == 1) { format = "{0} {1}"; } else if (printPosition == 2) { format = "{1} {0}"; } else { return(null); } break; case 0x1B: { StringBuilder sb = new StringBuilder(0x100); sb.Append('+'); sb.Append(value); sb.Append(' '); sb.Append(stringReader.GetString(StringConstants.BonusTo)); sb.Append(' '); string skillName = skillReader.GetSkillName(stat.HiStatID); if (skillName == null) { return(null); } sb.Append(skillName); D2SkillData skillData = skillReader.GetSkillData(stat.HiStatID); if (skillData == null) { return(null); } if (skillData.ClassId < 7) { var characterData = GetCharacterData((ushort)skillData.ClassId); if (characterData != null) { sb.Append(' '); sb.Append(stringReader.GetString(characterData.StrClassOnly)); } } return(sb.ToString()); } case 0x1C: { // Note: Some unknown things are happening in this case, // but hopefully it should still work. StringBuilder sb = new StringBuilder(0x100); sb.Append('+'); sb.Append(value); sb.Append(' '); sb.Append(stringReader.GetString(StringConstants.BonusTo)); sb.Append(' '); string skillName = skillReader.GetSkillName(stat.HiStatID); if (skillName == null) { return(null); } sb.Append(skillName); return(sb.ToString()); } default: break; } if (format == null) { return(null); } string description = string.Format(format, value, stringReader.GetString(printStringId)); if (printFunction >= 0x6 && printFunction < 0xA || printFunction == 0x15) { string extraDescription; if (printDescription == 0x1506) { extraDescription = stringReader.GetString(0x2B53); } else { extraDescription = stringReader.GetString(printDescription); } // Example: ... + "(Increases with Character Level)" description += " " + extraDescription; } return(description); }