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);
        }
        public string GetSkillName(ushort skillIdentifier)
        {
            D2SkillData skillData = GetSkillData(skillIdentifier);

            if (skillData == null)
            {
                return(null);
            }

            // Skill description table (unknown).
            if (skillData.SkillDescriptionId == 0 || skillData.SkillDescriptionId >= globals.SkillDescriptionCount)
            {
                return(null);
            }
            IntPtr skillDescriptionAddress = globals.SkillDescriptions.Address + (int)skillData.SkillDescriptionId * 0x120;
            UInt16 skillNameID             = reader.ReadUInt16(skillDescriptionAddress + 8);

            if (skillNameID == 0)
            {
                return(null);
            }
            return(stringReader.GetString(skillNameID));
        }
Exemple #3
0
        private string GetStatPropertyDescription(List <D2Stat> stats, D2Stat stat, D2Unit unit)
        {
            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 unit (player) level,
            // value shifts, etc...
            int value = EvaluateStat(stat, statCost, unit);

            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(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 = GetString(StringConstants.RepairsDurability);
                    format = ConvertCFormatString(format, out arguments);
                    return(string.Format(format, value));
                }
                else
                {
                    int duration = (quotient + 12) / 25;
                    format = GetString(StringConstants.RepairsDurabilityN);
                    format = ConvertCFormatString(format, out arguments);
                    return(string.Format(format, 1, duration));
                }

            case 0x0D:
            {
                var characterId   = stat.HiStatID;
                var characterData = GetCharacterData(characterId);
                if (characterData == null)
                {
                    return(null);
                }
                if (value == 0)
                {
                    value = 1;
                }

                string allSkills = GetString(characterData.AllSkillsStringId);
                if (allSkills == null)
                {
                    return(null);
                }

                return(string.Format("+{0} {1}", value, allSkills));
            }

            case 0x0E:
            {
                var 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 = GetString(skillTabStringId);
                format = ConvertCFormatString(format, out arguments);
                if (arguments != 1)
                {
                    return(null);
                }

                string classRestriction = 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 = GetString(printStringId);
                format = 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 = GetString(printStringId);
                format = 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 = GetString(printStringId);
                format = ConvertCFormatString(format, out arguments);
                if (arguments != 1)
                {
                    return(null);
                }

                return(string.Format(format, stat.Value));

            case 0x16:
            {
                format = 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        = 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(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 = GetString(printStringId);
                format = 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(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);
                }

                // TODO: remove the magic 7. (without further checking: 0-6 refers to the character classes)
                if (skillData.ClassId < 7)
                {
                    var characterId   = (ushort)skillData.ClassId;
                    var characterData = GetCharacterData(characterId);
                    if (characterData != null)
                    {
                        sb.Append(' ');
                        sb.Append(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(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, GetString(printStringId));

            if (printFunction >= 0x6 && printFunction < 0xA || printFunction == 0x15)
            {
                string extraDescription;
                if (printDescription == 0x1506)
                {
                    extraDescription = GetString(0x2B53);
                }
                else
                {
                    extraDescription = GetString(printDescription);
                }

                // Example: ... + "(Increases with Character Level)"
                description += " " + extraDescription;
            }

            return(description);
        }