Пример #1
0
        internal void Load(XmlNode xmlSkillNode, bool blnLegacy = false)
        {
            if (xmlSkillNode == null)
            {
                return;
            }
            Timekeeper.Start("load_char_skills");

            if (!blnLegacy)
            {
                Timekeeper.Start("load_char_skills_groups");
                List <SkillGroup> lstLoadingSkillGroups = new List <SkillGroup>();
                using (XmlNodeList xmlGroupsList = xmlSkillNode.SelectNodes("groups/group"))
                    if (xmlGroupsList != null)
                    {
                        foreach (XmlNode xmlNode in xmlGroupsList)
                        {
                            SkillGroup objGroup = new SkillGroup(_objCharacter);
                            objGroup.Load(xmlNode);
                            lstLoadingSkillGroups.Add(objGroup);
                        }
                    }
                lstLoadingSkillGroups.Sort((i1, i2) => string.Compare(i2.DisplayName, i1.DisplayName, StringComparison.Ordinal));
                foreach (SkillGroup skillgroup in lstLoadingSkillGroups)
                {
                    SkillGroups.Add(skillgroup);
                }
                Timekeeper.Finish("load_char_skills_groups");

                Timekeeper.Start("load_char_skills_normal");
                //Load skills. Because sorting a BindingList is complicated we use a temporery normal list
                List <Skill> lstLoadingSkills = new List <Skill>();
                using (XmlNodeList xmlSkillsList = xmlSkillNode.SelectNodes("skills/skill"))
                    if (xmlSkillsList != null)
                    {
                        foreach (XmlNode xmlNode in xmlSkillsList)
                        {
                            Skill objSkill = Skill.Load(_objCharacter, xmlNode);
                            if (objSkill != null)
                            {
                                lstLoadingSkills.Add(objSkill);
                            }
                        }
                    }
                lstLoadingSkills.Sort(CompareSkills);

                foreach (Skill objSkill in lstLoadingSkills)
                {
                    string strName = objSkill.IsExoticSkill
                        ? $"{objSkill.Name} ({objSkill.DisplaySpecializationMethod(GlobalOptions.DefaultLanguage)})"
                        : objSkill.Name;
                    bool blnDoAddToDictionary = true;
                    _lstSkills.MergeInto(objSkill, CompareSkills, (objExistSkill, objNewSkill) =>
                    {
                        blnDoAddToDictionary = false;
                        if (objNewSkill.Base > objExistSkill.Base)
                        {
                            objExistSkill.Base = objNewSkill.Base;
                        }
                        if (objNewSkill.Karma > objExistSkill.Karma)
                        {
                            objExistSkill.Karma = objNewSkill.Karma;
                        }
                        objExistSkill.Specializations.MergeInto(objNewSkill.Specializations, (x, y) => x.Free == y.Free ? string.Compare(x.DisplayName(GlobalOptions.Language), y.DisplayName(GlobalOptions.Language), StringComparison.Ordinal) : (x.Free ? 1 : -1));
                    });
                    if (blnDoAddToDictionary)
                    {
                        _dicSkills.Add(strName, objSkill);
                    }
                }
                // TODO: Skill groups don't refresh their CanIncrease property correctly when the last of their skills is being added, as the total basse rating will be zero. Call this here to force a refresh.
                foreach (SkillGroup g in SkillGroups)
                {
                    g.OnPropertyChanged(nameof(SkillGroup.SkillList));
                }
                Timekeeper.Finish("load_char_skills_normal");

                Timekeeper.Start("load_char_skills_kno");
                using (XmlNodeList xmlSkillsList = xmlSkillNode.SelectNodes("knoskills/skill"))
                    if (xmlSkillsList != null)
                    {
                        foreach (XmlNode xmlNode in xmlSkillsList)
                        {
                            if (Skill.Load(_objCharacter, xmlNode) is KnowledgeSkill objSkill)
                            {
                                KnowledgeSkills.Add(objSkill);
                            }
                        }
                    }
                Timekeeper.Finish("load_char_skills_kno");

                Timekeeper.Start("load_char_knowsoft_buffer");
                // Knowsoft Buffer.
                using (XmlNodeList xmlSkillsList = xmlSkillNode.SelectNodes("skilljackknowledgeskills/skill"))
                    if (xmlSkillsList != null)
                    {
                        foreach (XmlNode xmlNode in xmlSkillsList)
                        {
                            string strName = string.Empty;
                            if (xmlNode.TryGetStringFieldQuickly("name", ref strName))
                            {
                                KnowsoftSkills.Add(new KnowledgeSkill(_objCharacter, strName));
                            }
                        }
                    }
                Timekeeper.Finish("load_char_knowsoft_buffer");
            }
            else
            {
                List <Skill> lstTempSkillList = new List <Skill>();
                using (XmlNodeList xmlSkillsList = xmlSkillNode.SelectNodes("skills/skill"))
                    if (xmlSkillsList != null)
                    {
                        foreach (XmlNode xmlNode in xmlSkillsList)
                        {
                            Skill objSkill = Skill.LegacyLoad(_objCharacter, xmlNode);
                            if (objSkill != null)
                            {
                                lstTempSkillList.Add(objSkill);
                            }
                        }
                    }

                if (lstTempSkillList.Count > 0)
                {
                    List <Skill> lstUnsortedSkills = new List <Skill>();

                    //Variable/Anon method as to not clutter anywhere else. Not sure if clever or stupid
                    bool OldSkillFilter(Skill skill)
                    {
                        if (skill.Rating > 0)
                        {
                            return(true);
                        }

                        if (skill.SkillCategory == "Resonance Active" && !_objCharacter.RESEnabled)
                        {
                            return(false);
                        }

                        //This could be more fine grained, but frankly i don't care
                        if (skill.SkillCategory == "Magical Active" && !_objCharacter.MAGEnabled)
                        {
                            return(false);
                        }

                        return(true);
                    }

                    foreach (Skill objSkill in lstTempSkillList)
                    {
                        if (objSkill is KnowledgeSkill objKnoSkill)
                        {
                            KnowledgeSkills.Add(objKnoSkill);
                        }
                        else if (OldSkillFilter(objSkill))
                        {
                            lstUnsortedSkills.Add(objSkill);
                        }
                    }

                    lstUnsortedSkills.Sort(CompareSkills);

                    foreach (Skill objSkill in lstUnsortedSkills)
                    {
                        _lstSkills.Add(objSkill);
                        _dicSkills.Add(objSkill.IsExoticSkill ? objSkill.Name + " (" + objSkill.DisplaySpecializationMethod(GlobalOptions.DefaultLanguage) + ')' : objSkill.Name, objSkill);
                    }

                    UpdateUndoList(xmlSkillNode);
                }
            }

            //This might give subtle bugs in the future,
            //but right now it needs to be run once when upgrading or it might crash.
            //As some didn't they crashed on loading skills.
            //After this have run, it won't (for the crash i'm aware)
            //TODO: Move it to the other side of the if someday?

            if (!_objCharacter.Created)
            {
                // zero out any skillgroups whose skills did not make the final cut
                foreach (SkillGroup objSkillGroup in SkillGroups)
                {
                    if (!objSkillGroup.SkillList.Any(x => SkillsDictionary.ContainsKey(x.Name)))
                    {
                        objSkillGroup.Base  = 0;
                        objSkillGroup.Karma = 0;
                    }
                }
            }

            //Workaround for probably breaking compability between earlier beta builds
            if (xmlSkillNode["skillptsmax"] == null)
            {
                xmlSkillNode = xmlSkillNode.OwnerDocument?["character"];
            }

            int intTmp = 0;

            if (xmlSkillNode.TryGetInt32FieldQuickly("skillptsmax", ref intTmp))
            {
                SkillPointsMaximum = intTmp;
            }
            if (xmlSkillNode.TryGetInt32FieldQuickly("skillgrpsmax", ref intTmp))
            {
                SkillGroupPointsMaximum = intTmp;
            }

            Timekeeper.Finish("load_char_skills");
        }
Пример #2
0
        internal void Load(XmlNode skillNode, bool legacy = false)
        {
            if (skillNode == null)
            {
                return;
            }
            Timekeeper.Start("load_char_skills");

            if (!legacy)
            {
                Timekeeper.Start("load_char_skills_groups");
                List <SkillGroup> loadingSkillGroups = new List <SkillGroup>();
                foreach (XmlNode node in skillNode.SelectNodes("groups/group"))
                {
                    SkillGroup skillgroup = SkillGroup.Load(_character, node);
                    if (skillgroup != null)
                    {
                        loadingSkillGroups.Add(skillgroup);
                    }
                }
                loadingSkillGroups.Sort((i1, i2) => String.Compare(i2.DisplayName, i1.DisplayName, StringComparison.Ordinal));
                foreach (SkillGroup skillgroup in loadingSkillGroups)
                {
                    SkillGroups.Add(skillgroup);
                }
                Timekeeper.Finish("load_char_skills_groups");

                Timekeeper.Start("load_char_skills_normal");
                //Load skills. Because sorting a BindingList is complicated we use a temporery normal list
                List <Skill> loadingSkills = new List <Skill>();
                foreach (XmlNode node in skillNode.SelectNodes("skills/skill"))
                {
                    Skill skill = Skill.Load(_character, node);
                    if (skill != null)
                    {
                        loadingSkills.Add(skill);
                    }
                }
                loadingSkills.Sort(CompareSkills);


                foreach (Skill skill in loadingSkills)
                {
                    _skills.Add(skill);
                }
                Timekeeper.Finish("load_char_skills_normal");

                Timekeeper.Start("load_char_skills_kno");
                foreach (XmlNode node in skillNode.SelectNodes("knoskills/skill"))
                {
                    KnowledgeSkill skill = Skill.Load(_character, node) as KnowledgeSkill;
                    if (skill != null)
                    {
                        KnowledgeSkills.Add(skill);
                    }
                }
                Timekeeper.Finish("load_char_skills_kno");

                Timekeeper.Start("load_char_knowsoft_buffer");
                // Knowsoft Buffer.
                foreach (XmlNode objXmlSkill in skillNode.SelectNodes("skilljackknowledgeskills/skill"))
                {
                    string strName = string.Empty;
                    if (objXmlSkill.TryGetStringFieldQuickly("name", ref strName))
                    {
                        KnowsoftSkills.Add(new KnowledgeSkill(_character, strName));
                    }
                }
                Timekeeper.Finish("load_char_knowsoft_buffer");
            }
            else
            {
                List <Skill> tempSkillList = new List <Skill>();
                foreach (XmlNode node in skillNode.SelectNodes("skills/skill"))
                {
                    Skill skill = Skill.LegacyLoad(_character, node);
                    if (skill != null)
                    {
                        tempSkillList.Add(skill);
                    }
                }

                List <Skill> unsoredSkills = new List <Skill>();

                //Variable/Anon method as to not clutter anywhere else. Not sure if clever or stupid
                Predicate <Skill> oldSkillFilter = skill =>
                {
                    if (skill.Rating > 0)
                    {
                        return(true);
                    }

                    if (skill.SkillCategory == "Resonance Active" && !_character.RESEnabled)
                    {
                        return(false);
                    }

                    //This could be more fine grained, but frankly i don't care
                    if (skill.SkillCategory == "Magical Active" && !_character.MAGEnabled)
                    {
                        return(false);
                    }

                    return(true);
                };

                foreach (Skill skill in tempSkillList)
                {
                    KnowledgeSkill knoSkill = skill as KnowledgeSkill;
                    if (knoSkill != null)
                    {
                        KnowledgeSkills.Add(knoSkill);
                    }
                    else if (oldSkillFilter(skill))
                    {
                        unsoredSkills.Add(skill);
                    }
                }

                unsoredSkills.Sort(CompareSkills);

                unsoredSkills.ForEach(x => _skills.Add(x));

                UpdateUndoList(skillNode);
            }

            //This might give subtle bugs in the future,
            //but right now it needs to be run once when upgrading or it might crash.
            //As some didn't they crashed on loading skills.
            //After this have run, it won't (for the crash i'm aware)
            //TODO: Move it to the other side of the if someday?

            //remove skillgroups whose skills did not make the final cut
            for (var i = SkillGroups.Count - 1; i >= 0; i--)
            {
                if (!SkillGroups[i].GetEnumerable().Any(x => Skills.Contains(x)))
                {
                    SkillGroups.RemoveAt(i);
                    i--;
                }
            }

            //Workaround for probably breaking compability between earlier beta builds
            if (skillNode["skillptsmax"] == null)
            {
                skillNode = skillNode.OwnerDocument["character"];
            }

            int intTmp = 0;

            if (skillNode.TryGetInt32FieldQuickly("skillptsmax", ref intTmp))
            {
                SkillPointsMaximum = intTmp;
            }
            if (skillNode.TryGetInt32FieldQuickly("skillgrpsmax", ref intTmp))
            {
                SkillGroupPointsMaximum = intTmp;
            }
            skillNode.TryGetBoolFieldQuickly("uneducated", ref _blnUneducated);
            skillNode.TryGetBoolFieldQuickly("uncouth", ref _blnUncouth);
            skillNode.TryGetBoolFieldQuickly("schoolofhardknocks", ref _blnSchoolOfHardKnocks);
            skillNode.TryGetBoolFieldQuickly("collegeeducation", ref _blnCollegeEducation);
            skillNode.TryGetBoolFieldQuickly("jackofalltrades", ref _blnJackOfAllTrades);
            skillNode.TryGetBoolFieldQuickly("techschool", ref _blnTechSchool);
            skillNode.TryGetBoolFieldQuickly("linguist", ref _blnLinguist);

            Timekeeper.Finish("load_char_skills");
        }
Пример #3
0
        public void Load(XmlNode xmlSavedCharacterNode)
        {
            Timekeeper.Start("load_char_attrib");
            foreach (CharacterAttrib objAttribute in AttributeList.Concat(SpecialAttributeList))
            {
                objAttribute.UnbindAttribute();
            }
            AttributeList.Clear();
            SpecialAttributeList.Clear();
            XmlDocument objXmlDocument  = XmlManager.Load(_objCharacter.IsCritter ? "critters.xml" : "metatypes.xml");
            XmlNode     xmlMetatypeNode = objXmlDocument.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + _objCharacter.Metatype + "\"]");
            XmlNode     xmlCharNode     = xmlMetatypeNode?.SelectSingleNode("metavariants/metavariant[name = \"" + _objCharacter.Metavariant + "\"]") ?? xmlMetatypeNode;
            // We only want to remake attributes for shifters in career mode, because they only get their second set of attributes when exporting from create mode into career mode
            XmlNode xmlCharNodeAnimalForm = _objCharacter.MetatypeCategory == "Shapeshifter" && _objCharacter.Created ? xmlMetatypeNode : null;

            foreach (string strAttribute in AttributeStrings)
            {
                XmlNodeList lstAttributeNodes = xmlSavedCharacterNode.SelectNodes("attributes/attribute[name = \"" + strAttribute + "\"]");
                // Couldn't find the appopriate attribute in the loaded file, so regenerate it from scratch.
                if (lstAttributeNodes == null || lstAttributeNodes.Count == 0 || xmlCharNodeAnimalForm != null && _objCharacter.LastSavedVersion < new Version("5.200.25"))
                {
                    CharacterAttrib objAttribute;
                    switch (CharacterAttrib.ConvertToAttributeCategory(strAttribute))
                    {
                    case CharacterAttrib.AttributeCategory.Special:
                        objAttribute = new CharacterAttrib(_objCharacter, strAttribute, CharacterAttrib.AttributeCategory.Special);
                        objAttribute = RemakeAttribute(objAttribute, xmlCharNode);
                        SpecialAttributeList.Add(objAttribute);
                        break;

                    case CharacterAttrib.AttributeCategory.Standard:
                        objAttribute = new CharacterAttrib(_objCharacter, strAttribute);
                        objAttribute = RemakeAttribute(objAttribute, xmlCharNode);
                        AttributeList.Add(objAttribute);
                        break;
                    }

                    if (xmlCharNodeAnimalForm == null)
                    {
                        continue;
                    }
                    objAttribute = new CharacterAttrib(_objCharacter, strAttribute, CharacterAttrib.AttributeCategory.Shapeshifter);
                    objAttribute = RemakeAttribute(objAttribute, xmlCharNodeAnimalForm);
                    switch (CharacterAttrib.ConvertToAttributeCategory(objAttribute.Abbrev))
                    {
                    case CharacterAttrib.AttributeCategory.Special:
                        SpecialAttributeList.Add(objAttribute);
                        break;

                    case CharacterAttrib.AttributeCategory.Standard:
                        AttributeList.Add(objAttribute);
                        break;
                    }
                }
                else
                {
                    foreach (XmlNode xmlAttributeNode in lstAttributeNodes)
                    {
                        CharacterAttrib att = new CharacterAttrib(_objCharacter, strAttribute);
                        att.Load(xmlAttributeNode);
                        switch (CharacterAttrib.ConvertToAttributeCategory(att.Abbrev))
                        {
                        case CharacterAttrib.AttributeCategory.Special:
                            SpecialAttributeList.Add(att);
                            break;

                        case CharacterAttrib.AttributeCategory.Standard:
                            AttributeList.Add(att);
                            break;
                        }
                    }
                }
            }

            Attributes = new ObservableCollection <CharacterAttrib>
            {
                _objCharacter.BOD,
                _objCharacter.AGI,
                _objCharacter.REA,
                _objCharacter.STR,
                _objCharacter.CHA,
                _objCharacter.INT,
                _objCharacter.LOG,
                _objCharacter.WIL,
                _objCharacter.EDG
            };
            if (_objCharacter.MAGEnabled)
            {
                Attributes.Add(_objCharacter.MAG);
                if (_objCharacter.Options.MysAdeptSecondMAGAttribute && _objCharacter.IsMysticAdept)
                {
                    Attributes.Add(_objCharacter.MAGAdept);
                }
            }
            if (_objCharacter.RESEnabled)
            {
                Attributes.Add(_objCharacter.RES);
            }
            if (_objCharacter.DEPEnabled)
            {
                Attributes.Add(_objCharacter.DEP);
            }
            ResetBindings();
            _objCharacter.RefreshAttributeBindings();
            Timekeeper.Finish("load_char_attrib");
        }
Пример #4
0
        public void LoadFromHeroLab(XmlNode xmlStatBlockBaseNode)
        {
            Timekeeper.Start("load_char_attrib");
            foreach (CharacterAttrib objAttribute in AttributeList.Concat(SpecialAttributeList))
            {
                objAttribute.UnbindAttribute();
            }
            AttributeList.Clear();
            SpecialAttributeList.Clear();
            XmlDocument objXmlDocument  = XmlManager.Load(_objCharacter.IsCritter ? "critters.xml" : "metatypes.xml");
            XmlNode     xmlMetatypeNode = objXmlDocument.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + _objCharacter.Metatype + "\"]");
            XmlNode     xmlCharNode     = xmlMetatypeNode?.SelectSingleNode("metavariants/metavariant[name = \"" + _objCharacter.Metavariant + "\"]") ?? xmlMetatypeNode;
            // We only want to remake attributes for shifters in career mode, because they only get their second set of attributes when exporting from create mode into career mode
            XmlNode xmlCharNodeAnimalForm = _objCharacter.MetatypeCategory == "Shapeshifter" && _objCharacter.Created ? xmlMetatypeNode : null;

            foreach (string strAttribute in AttributeStrings)
            {
                // First, remake the attribute
                CharacterAttrib objAttribute = new CharacterAttrib(_objCharacter, strAttribute);
                objAttribute = RemakeAttribute(objAttribute, xmlCharNode);
                switch (CharacterAttrib.ConvertToAttributeCategory(objAttribute.Abbrev))
                {
                case CharacterAttrib.AttributeCategory.Special:
                    SpecialAttributeList.Add(objAttribute);
                    break;

                case CharacterAttrib.AttributeCategory.Standard:
                    AttributeList.Add(objAttribute);
                    break;
                }
                if (xmlCharNodeAnimalForm != null)
                {
                    objAttribute = new CharacterAttrib(_objCharacter, strAttribute, CharacterAttrib.AttributeCategory.Shapeshifter);
                    objAttribute = RemakeAttribute(objAttribute, xmlCharNodeAnimalForm);
                    switch (CharacterAttrib.ConvertToAttributeCategory(objAttribute.Abbrev))
                    {
                    case CharacterAttrib.AttributeCategory.Special:
                        SpecialAttributeList.Add(objAttribute);
                        break;

                    case CharacterAttrib.AttributeCategory.Standard:
                        AttributeList.Add(objAttribute);
                        break;
                    }
                }

                // Then load in attribute karma levels (we'll adjust these later if the character is in Create mode)
                if (strAttribute == "ESS") // Not Essence though, this will get modified automatically instead of having its value set to the one HeroLab displays
                {
                    continue;
                }
                XmlNode xmlHeroLabAttributeNode = xmlStatBlockBaseNode.SelectSingleNode("attributes/attribute[@name = \"" + GetAttributeEnglishName(strAttribute) + "\"]");
                XmlNode xmlAttributeBaseNode    = xmlHeroLabAttributeNode?.SelectSingleNode("@base");
                if (xmlAttributeBaseNode != null &&
                    int.TryParse(xmlAttributeBaseNode.InnerText, out int intHeroLabAttributeBaseValue))
                {
                    int intAttributeMinimumValue = GetAttributeByName(strAttribute).MetatypeMinimum;
                    if (intHeroLabAttributeBaseValue != intAttributeMinimumValue)
                    {
                        objAttribute.Karma = intHeroLabAttributeBaseValue - intAttributeMinimumValue;
                    }
                }
            }

            if (!_objCharacter.Created && _objCharacter.BuildMethodHasSkillPoints)
            {
                // Allocate Attribute Points
                int             intAttributePointCount = _objCharacter.TotalAttributes;
                CharacterAttrib objAttributeToPutPointsInto;
                // First loop through attributes where costs can be 100% covered with points
                do
                {
                    objAttributeToPutPointsInto = null;
                    int intAttributeToPutPointsIntoTotalKarmaCost = 0;
                    foreach (CharacterAttrib objLoopAttribute in AttributeList)
                    {
                        if (objLoopAttribute.Karma == 0)
                        {
                            continue;
                        }
                        // Put points into the attribute with the highest total karma cost.
                        // In case of ties, pick the one that would need more points to cover it (the other one will hopefully get picked up at a later cycle)
                        int intLoopTotalKarmaCost = objLoopAttribute.TotalKarmaCost;
                        if (objAttributeToPutPointsInto == null || (objLoopAttribute.Karma <= intAttributePointCount &&
                                                                    (intLoopTotalKarmaCost > intAttributeToPutPointsIntoTotalKarmaCost ||
                                                                     (intLoopTotalKarmaCost == intAttributeToPutPointsIntoTotalKarmaCost && objLoopAttribute.Karma > objAttributeToPutPointsInto.Karma))))
                        {
                            objAttributeToPutPointsInto = objLoopAttribute;
                            intAttributeToPutPointsIntoTotalKarmaCost = intLoopTotalKarmaCost;
                        }
                    }

                    if (objAttributeToPutPointsInto != null)
                    {
                        objAttributeToPutPointsInto.Base  = objAttributeToPutPointsInto.Karma;
                        intAttributePointCount           -= objAttributeToPutPointsInto.Karma;
                        objAttributeToPutPointsInto.Karma = 0;
                    }
                } while (objAttributeToPutPointsInto != null && intAttributePointCount > 0);

                // If any points left over, then put them all into the attribute with the highest karma cost
                if (intAttributePointCount > 0 && AttributeList.Any(x => x.Karma != 0))
                {
                    int intHighestTotalKarmaCost = 0;
                    foreach (CharacterAttrib objLoopAttribute in AttributeList)
                    {
                        if (objLoopAttribute.Karma == 0)
                        {
                            continue;
                        }
                        // Put points into the attribute with the highest total karma cost.
                        // In case of ties, pick the one that would need more points to cover it (the other one will hopefully get picked up at a later cycle)
                        int intLoopTotalKarmaCost = objLoopAttribute.TotalKarmaCost;
                        if (objAttributeToPutPointsInto == null ||
                            intLoopTotalKarmaCost > intHighestTotalKarmaCost ||
                            (intLoopTotalKarmaCost == intHighestTotalKarmaCost && objLoopAttribute.Karma > objAttributeToPutPointsInto.Karma))
                        {
                            objAttributeToPutPointsInto = objLoopAttribute;
                            intHighestTotalKarmaCost    = intLoopTotalKarmaCost;
                        }
                    }

                    if (objAttributeToPutPointsInto != null)
                    {
                        objAttributeToPutPointsInto.Base   = intAttributePointCount;
                        objAttributeToPutPointsInto.Karma -= intAttributePointCount;
                    }
                }

                // Allocate Special Attribute Points
                intAttributePointCount = _objCharacter.TotalSpecial;
                // First loop through attributes where costs can be 100% covered with points
                do
                {
                    objAttributeToPutPointsInto = null;
                    int intAttributeToPutPointsIntoTotalKarmaCost = 0;
                    foreach (CharacterAttrib objLoopAttribute in SpecialAttributeList)
                    {
                        if (objLoopAttribute.Karma == 0)
                        {
                            continue;
                        }
                        // Put points into the attribute with the highest total karma cost.
                        // In case of ties, pick the one that would need more points to cover it (the other one will hopefully get picked up at a later cycle)
                        int intLoopTotalKarmaCost = objLoopAttribute.TotalKarmaCost;
                        if (objAttributeToPutPointsInto == null || (objLoopAttribute.Karma <= intAttributePointCount &&
                                                                    (intLoopTotalKarmaCost > intAttributeToPutPointsIntoTotalKarmaCost ||
                                                                     (intLoopTotalKarmaCost == intAttributeToPutPointsIntoTotalKarmaCost && objLoopAttribute.Karma > objAttributeToPutPointsInto.Karma))))
                        {
                            objAttributeToPutPointsInto = objLoopAttribute;
                            intAttributeToPutPointsIntoTotalKarmaCost = intLoopTotalKarmaCost;
                        }
                    }

                    if (objAttributeToPutPointsInto != null)
                    {
                        objAttributeToPutPointsInto.Base  = objAttributeToPutPointsInto.Karma;
                        intAttributePointCount           -= objAttributeToPutPointsInto.Karma;
                        objAttributeToPutPointsInto.Karma = 0;
                    }
                } while (objAttributeToPutPointsInto != null);

                // If any points left over, then put them all into the attribute with the highest karma cost
                if (intAttributePointCount > 0 && SpecialAttributeList.Any(x => x.Karma != 0))
                {
                    int intHighestTotalKarmaCost = 0;
                    foreach (CharacterAttrib objLoopAttribute in SpecialAttributeList)
                    {
                        if (objLoopAttribute.Karma == 0)
                        {
                            continue;
                        }
                        // Put points into the attribute with the highest total karma cost.
                        // In case of ties, pick the one that would need more points to cover it (the other one will hopefully get picked up at a later cycle)
                        int intLoopTotalKarmaCost = objLoopAttribute.TotalKarmaCost;
                        if (objAttributeToPutPointsInto == null ||
                            intLoopTotalKarmaCost > intHighestTotalKarmaCost ||
                            (intLoopTotalKarmaCost == intHighestTotalKarmaCost && objLoopAttribute.Karma > objAttributeToPutPointsInto.Karma))
                        {
                            objAttributeToPutPointsInto = objLoopAttribute;
                            intHighestTotalKarmaCost    = intLoopTotalKarmaCost;
                        }
                    }

                    if (objAttributeToPutPointsInto != null)
                    {
                        objAttributeToPutPointsInto.Base   = intAttributePointCount;
                        objAttributeToPutPointsInto.Karma -= intAttributePointCount;
                    }
                }
            }
            ResetBindings();
            _objCharacter.RefreshAttributeBindings();
            Timekeeper.Finish("load_char_attrib");
        }
Пример #5
0
        public void Create(XmlNode charNode, int intValue, int intMinModifier = 0, int intMaxModifier = 0)
        {
            Timekeeper.Start("create_char_attrib");
            foreach (CharacterAttrib objAttribute in AttributeList.Concat(SpecialAttributeList))
            {
                objAttribute.UnbindAttribute();
            }
            AttributeList.Clear();
            SpecialAttributeList.Clear();

            foreach (string strAttribute in AttributeStrings)
            {
                CharacterAttrib objAttribute;
                switch (CharacterAttrib.ConvertToAttributeCategory(strAttribute))
                {
                case CharacterAttrib.AttributeCategory.Special:
                    objAttribute = new CharacterAttrib(_objCharacter, strAttribute, CharacterAttrib.AttributeCategory.Special);
                    SpecialAttributeList.Add(objAttribute);
                    break;

                case CharacterAttrib.AttributeCategory.Standard:
                    objAttribute = new CharacterAttrib(_objCharacter, strAttribute);
                    AttributeList.Add(objAttribute);
                    break;
                }
            }

            _objCharacter.BOD.AssignLimits(CommonFunctions.ExpressionToString(charNode["bodmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["bodmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["bodaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.AGI.AssignLimits(CommonFunctions.ExpressionToString(charNode["agimin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["agimax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["agiaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.REA.AssignLimits(CommonFunctions.ExpressionToString(charNode["reamin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["reamax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["reaaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.STR.AssignLimits(CommonFunctions.ExpressionToString(charNode["strmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["strmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["straug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.CHA.AssignLimits(CommonFunctions.ExpressionToString(charNode["chamin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["chamax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["chaaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.INT.AssignLimits(CommonFunctions.ExpressionToString(charNode["intmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["intmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["intaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.LOG.AssignLimits(CommonFunctions.ExpressionToString(charNode["logmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["logmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["logaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.WIL.AssignLimits(CommonFunctions.ExpressionToString(charNode["wilmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["wilmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["wilaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.MAG.AssignLimits(CommonFunctions.ExpressionToString(charNode["magmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["magmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["magaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.RES.AssignLimits(CommonFunctions.ExpressionToString(charNode["resmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["resmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["resaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.EDG.AssignLimits(CommonFunctions.ExpressionToString(charNode["edgmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["edgmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["edgaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.DEP.AssignLimits(CommonFunctions.ExpressionToString(charNode["depmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["depmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["depaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.MAGAdept.AssignLimits(CommonFunctions.ExpressionToString(charNode["magmin"]?.InnerText, intValue, intMinModifier), CommonFunctions.ExpressionToString(charNode["magmax"]?.InnerText, intValue, intMaxModifier), CommonFunctions.ExpressionToString(charNode["magaug"]?.InnerText, intValue, intMaxModifier));
            _objCharacter.ESS.AssignLimits(CommonFunctions.ExpressionToString(charNode["essmin"]?.InnerText, intValue, 0), CommonFunctions.ExpressionToString(charNode["essmax"]?.InnerText, intValue, 0), CommonFunctions.ExpressionToString(charNode["essaug"]?.InnerText, intValue, 0));

            Attributes = new ObservableCollection <CharacterAttrib>
            {
                _objCharacter.BOD,
                _objCharacter.AGI,
                _objCharacter.REA,
                _objCharacter.STR,
                _objCharacter.CHA,
                _objCharacter.INT,
                _objCharacter.LOG,
                _objCharacter.WIL,
                _objCharacter.EDG
            };
            if (_objCharacter.MAGEnabled)
            {
                Attributes.Add(_objCharacter.MAG);
                if (_objCharacter.Options.MysAdeptSecondMAGAttribute && _objCharacter.IsMysticAdept)
                {
                    Attributes.Add(_objCharacter.MAGAdept);
                }
            }
            if (_objCharacter.RESEnabled)
            {
                Attributes.Add(_objCharacter.RES);
            }
            if (_objCharacter.DEPEnabled)
            {
                Attributes.Add(_objCharacter.DEP);
            }
            ResetBindings();
            _objCharacter.RefreshAttributeBindings();
            Timekeeper.Finish("create_char_attrib");
        }
Пример #6
0
        public void Load(XmlDocument xmlDoc)
        {
            Timekeeper.Start("load_char_attrib");
            AttributeList.Clear();
            SpecialAttributeList.Clear();
            XmlDocument    objXmlDocument = XmlManager.Load(_character.IsCritter ? "critters.xml" : "metatypes.xml");
            XPathNavigator nav            = objXmlDocument.CreateNavigator();
            XmlNode        objCharNode    = objXmlDocument.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + _character.Metatype + "\"]/metavariants/metavariant[name = \"" + _character.Metavariant + "\"]")
                                            ?? objXmlDocument.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + _character.Metatype + "\"]");
            XmlNode objCharNodeAnimalForm = null;

            // We only want to remake attributes for shifters in career mode, because they only get their second set of attributes when exporting from create mode into career mode
            if (_character.MetatypeCategory == "Shapeshifter" && _character.Created)
            {
                objCharNodeAnimalForm = objXmlDocument.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + _character.Metatype + "\"]");
            }
            foreach (string s in AttributeStrings)
            {
                XmlNodeList attNodeList = xmlDoc.SelectNodes("/character/attributes/attribute[name = \"" + s + "\"]");
                // Couldn't find the appopriate attribute in the loaded file, so regenerate it from scratch.
                if (attNodeList.Count == 0)
                {
                    CharacterAttrib att = new CharacterAttrib(_character, s);
                    att = RemakeAttribute(att, objCharNode, nav);
                    switch (att.ConvertToAttributeCategory(att.Abbrev))
                    {
                    case CharacterAttrib.AttributeCategory.Special:
                        SpecialAttributeList.Add(att);
                        break;

                    case CharacterAttrib.AttributeCategory.Standard:
                        AttributeList.Add(att);
                        break;
                    }
                    if (objCharNodeAnimalForm != null)
                    {
                        att = new CharacterAttrib(_character, s, CharacterAttrib.AttributeCategory.Shapeshifter);
                        att = RemakeAttribute(att, objCharNodeAnimalForm, nav);
                        switch (att.ConvertToAttributeCategory(att.Abbrev))
                        {
                        case CharacterAttrib.AttributeCategory.Special:
                            SpecialAttributeList.Add(att);
                            break;

                        case CharacterAttrib.AttributeCategory.Standard:
                            AttributeList.Add(att);
                            break;
                        }
                    }
                }
                else
                {
                    foreach (XmlNode attNode in attNodeList)
                    {
                        CharacterAttrib att = new CharacterAttrib(_character, s);
                        att.Load(attNode);
                        switch (att.ConvertToAttributeCategory(att.Abbrev))
                        {
                        case CharacterAttrib.AttributeCategory.Special:
                            SpecialAttributeList.Add(att);
                            break;

                        case CharacterAttrib.AttributeCategory.Standard:
                            AttributeList.Add(att);
                            break;
                        }
                    }
                }
            }
            ResetBindings();
            Timekeeper.Finish("load_char_attrib");
        }
Пример #7
0
        internal void Load(XmlNode skillNode, bool legacy = false)
        {
            if (skillNode == null)
            {
                return;
            }
            Timekeeper.Start("load_char_skills");

            if (!legacy)
            {
                Timekeeper.Start("load_char_skills_groups");
                List <SkillGroup> loadingSkillGroups = new List <SkillGroup>();
                foreach (XmlNode node in skillNode.SelectNodes("groups/group"))
                {
                    SkillGroup skillgroup = SkillGroup.Load(_character, node);
                    if (skillgroup != null)
                    {
                        loadingSkillGroups.Add(skillgroup);
                    }
                }
                loadingSkillGroups.Sort((i1, i2) => String.Compare(i2.DisplayName, i1.DisplayName, StringComparison.Ordinal));
                foreach (SkillGroup skillgroup in loadingSkillGroups)
                {
                    SkillGroups.Add(skillgroup);
                }
                Timekeeper.Finish("load_char_skills_groups");

                Timekeeper.Start("load_char_skills_normal");
                //Load skills. Because sorting a BindingList is complicated we use a temporery normal list
                List <Skill> loadingSkills = new List <Skill>();
                foreach (XmlNode node in skillNode.SelectNodes("skills/skill"))
                {
                    Skill skill = Skill.Load(_character, node);
                    if (skill != null)
                    {
                        loadingSkills.Add(skill);
                    }
                }
                loadingSkills.Sort(CompareSkills);


                foreach (Skill skill in loadingSkills)
                {
                    _skills.Add(skill);
                    _dicSkills.Add(skill.IsExoticSkill ? skill.Name + " (" + skill.DisplaySpecialization + ")" : skill.Name, skill);
                }
                Timekeeper.Finish("load_char_skills_normal");

                Timekeeper.Start("load_char_skills_kno");
                foreach (XmlNode node in skillNode.SelectNodes("knoskills/skill"))
                {
                    if (Skill.Load(_character, node) is KnowledgeSkill skill)
                    {
                        KnowledgeSkills.Add(skill);
                    }
                }
                Timekeeper.Finish("load_char_skills_kno");

                Timekeeper.Start("load_char_knowsoft_buffer");
                // Knowsoft Buffer.
                foreach (XmlNode objXmlSkill in skillNode.SelectNodes("skilljackknowledgeskills/skill"))
                {
                    string strName = string.Empty;
                    if (objXmlSkill.TryGetStringFieldQuickly("name", ref strName))
                    {
                        KnowsoftSkills.Add(new KnowledgeSkill(_character, strName));
                    }
                }
                Timekeeper.Finish("load_char_knowsoft_buffer");
            }
            else
            {
                List <Skill> tempSkillList = new List <Skill>();
                foreach (XmlNode node in skillNode.SelectNodes("skills/skill"))
                {
                    Skill skill = Skill.LegacyLoad(_character, node);
                    if (skill != null)
                    {
                        tempSkillList.Add(skill);
                    }
                }

                if (tempSkillList.Count > 0)
                {
                    List <Skill> unsoredSkills = new List <Skill>();

                    //Variable/Anon method as to not clutter anywhere else. Not sure if clever or stupid
                    bool oldSkillFilter(Skill skill)
                    {
                        if (skill.Rating > 0)
                        {
                            return(true);
                        }

                        if (skill.SkillCategory == "Resonance Active" && !_character.RESEnabled)
                        {
                            return(false);
                        }

                        //This could be more fine grained, but frankly i don't care
                        if (skill.SkillCategory == "Magical Active" && !_character.MAGEnabled)
                        {
                            return(false);
                        }

                        return(true);
                    }

                    foreach (Skill skill in tempSkillList)
                    {
                        if (skill is KnowledgeSkill knoSkill)
                        {
                            KnowledgeSkills.Add(knoSkill);
                        }
                        else if (oldSkillFilter(skill))
                        {
                            unsoredSkills.Add(skill);
                        }
                    }

                    unsoredSkills.Sort(CompareSkills);

                    foreach (Skill objSkill in unsoredSkills)
                    {
                        _skills.Add(objSkill);
                        _dicSkills.Add(objSkill.IsExoticSkill ? objSkill.Name + " (" + objSkill.DisplaySpecialization + ")" : objSkill.Name, objSkill);
                    }

                    UpdateUndoList(skillNode);
                }
            }

            //This might give subtle bugs in the future,
            //but right now it needs to be run once when upgrading or it might crash.
            //As some didn't they crashed on loading skills.
            //After this have run, it won't (for the crash i'm aware)
            //TODO: Move it to the other side of the if someday?

            if (!_character.Created)
            {
                // zero out any skillgroups whose skills did not make the final cut
                foreach (SkillGroup objSkillGroup in SkillGroups)
                {
                    if (!objSkillGroup.SkillList.Any(x => SkillsDictionary.ContainsKey(x.Name)))
                    {
                        objSkillGroup.Base  = 0;
                        objSkillGroup.Karma = 0;
                    }
                }
            }

            //Workaround for probably breaking compability between earlier beta builds
            if (skillNode["skillptsmax"] == null)
            {
                skillNode = skillNode.OwnerDocument["character"];
            }

            int intTmp = 0;

            if (skillNode.TryGetInt32FieldQuickly("skillptsmax", ref intTmp))
            {
                SkillPointsMaximum = intTmp;
            }
            if (skillNode.TryGetInt32FieldQuickly("skillgrpsmax", ref intTmp))
            {
                SkillGroupPointsMaximum = intTmp;
            }

            Timekeeper.Finish("load_char_skills");
        }
Пример #8
0
        public void Load(XmlNode xmlSavedCharacterNode)
        {
            Timekeeper.Start("load_char_attrib");
            foreach (CharacterAttrib objAttribute in AttributeList.Concat(SpecialAttributeList))
            {
                objAttribute.UnbindAttribute();
            }
            AttributeList.Clear();
            SpecialAttributeList.Clear();
            XmlDocument objXmlDocument  = XmlManager.Load(_objCharacter.IsCritter ? "critters.xml" : "metatypes.xml");
            XmlNode     xmlMetatypeNode = objXmlDocument.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + _objCharacter.Metatype + "\"]");
            XmlNode     xmlCharNode     = xmlMetatypeNode?.SelectSingleNode("metavariants/metavariant[name = \"" + _objCharacter.Metavariant + "\"]") ?? xmlMetatypeNode;
            // We only want to remake attributes for shifters in career mode, because they only get their second set of attributes when exporting from create mode into career mode
            XmlNode xmlCharNodeAnimalForm = _objCharacter.MetatypeCategory == "Shapeshifter" && _objCharacter.Created ? xmlMetatypeNode : null;

            foreach (string strAttribute in AttributeStrings)
            {
                XmlNodeList lstAttributeNodes = xmlSavedCharacterNode.SelectNodes("attributes/attribute[name = \"" + strAttribute + "\"]");
                // Couldn't find the appopriate attribute in the loaded file, so regenerate it from scratch.
                if (lstAttributeNodes == null || lstAttributeNodes.Count == 0)
                {
                    CharacterAttrib objAttribute = new CharacterAttrib(_objCharacter, strAttribute);
                    objAttribute = RemakeAttribute(objAttribute, xmlCharNode);
                    switch (CharacterAttrib.ConvertToAttributeCategory(objAttribute.Abbrev))
                    {
                    case CharacterAttrib.AttributeCategory.Special:
                        SpecialAttributeList.Add(objAttribute);
                        break;

                    case CharacterAttrib.AttributeCategory.Standard:
                        AttributeList.Add(objAttribute);
                        break;
                    }
                    if (xmlCharNodeAnimalForm != null)
                    {
                        objAttribute = new CharacterAttrib(_objCharacter, strAttribute, CharacterAttrib.AttributeCategory.Shapeshifter);
                        objAttribute = RemakeAttribute(objAttribute, xmlCharNodeAnimalForm);
                        switch (CharacterAttrib.ConvertToAttributeCategory(objAttribute.Abbrev))
                        {
                        case CharacterAttrib.AttributeCategory.Special:
                            SpecialAttributeList.Add(objAttribute);
                            break;

                        case CharacterAttrib.AttributeCategory.Standard:
                            AttributeList.Add(objAttribute);
                            break;
                        }
                    }
                }
                else
                {
                    foreach (XmlNode xmlAttributeNode in lstAttributeNodes)
                    {
                        CharacterAttrib att = new CharacterAttrib(_objCharacter, strAttribute);
                        att.Load(xmlAttributeNode);
                        switch (CharacterAttrib.ConvertToAttributeCategory(att.Abbrev))
                        {
                        case CharacterAttrib.AttributeCategory.Special:
                            SpecialAttributeList.Add(att);
                            break;

                        case CharacterAttrib.AttributeCategory.Standard:
                            AttributeList.Add(att);
                            break;
                        }
                    }
                }
            }
            ResetBindings();
            Timekeeper.Finish("load_char_attrib");
        }
Пример #9
0
        internal void Load(XmlNode skillNode, bool legacy = false)
        {
            Timekeeper.Start("load_char_skills");

            if (!legacy)
            {
                Timekeeper.Start("load_char_skills_groups");
                (from XmlNode node in skillNode.SelectNodes("groups/group") let @group = SkillGroup.Load(_character, node) where @group != null orderby @group.DisplayName descending select @group).ForEach(x => SkillGroups.Add(x));

                Timekeeper.Finish("load_char_skills_groups");

                Timekeeper.Start("load_char_skills_normal");
                //Load skills. Because sorting a BindingList is complicated we use a temporery normal list
                List <Skill> loadingSkills = (from XmlNode node in skillNode.SelectNodes("skills/skill") let skill = Skill.Load(_character, node) where skill != null select skill).ToList();

                loadingSkills.Sort(CompareSkills);


                foreach (Skill skill in loadingSkills)
                {
                    _skills.Add(skill);
                }
                Timekeeper.Finish("load_char_skills_normal");

                Timekeeper.Start("load_char_skills_kno");
                List <KnowledgeSkill> knoSkills = (from XmlNode node in skillNode.SelectNodes("knoskills/skill") let skill = (KnowledgeSkill)Skill.Load(_character, node) where skill != null select skill).ToList();


                foreach (KnowledgeSkill skill in knoSkills)
                {
                    KnowledgeSkills.Add(skill);
                }
                Timekeeper.Finish("load_char_skills_kno");

                Timekeeper.Start("load_char_knowsoft_buffer");
                // Knowsoft Buffer.
                XmlNodeList objXmlKnowsoftBuffer = skillNode.SelectNodes("skilljackknowledgeskills/skill");
                foreach (XmlNode objXmlSkill in objXmlKnowsoftBuffer)
                {
                    string strName = objXmlSkill["name"].InnerText;
                    KnowsoftSkills.Add(new KnowledgeSkill(_character, strName));
                }
                Timekeeper.Finish("load_char_knowsoft_buffer");
            }
            else
            {
                XmlNodeList oldskills = skillNode.SelectNodes("skills/skill");

                List <Skill> tempoerySkillList = (from XmlNode node in oldskills let skill = Skill.LegacyLoad(_character, node) where skill != null select skill).ToList();

                List <Skill> unsoredSkills = new List <Skill>();

                //Variable/Anon method as to not clutter anywhere else. Not sure if clever or stupid
                Predicate <Skill> oldSkillFilter = skill =>
                {
                    if (skill.Rating > 0)
                    {
                        return(true);
                    }

                    if (skill.SkillCategory == "Resonance Active" && !_character.RESEnabled)
                    {
                        return(false);
                    }

                    //This could be more fine grained, but frankly i don't care
                    if (skill.SkillCategory == "Magical Active" && !_character.MAGEnabled)
                    {
                        return(false);
                    }


                    return(true);
                };

                foreach (Skill skill in tempoerySkillList)
                {
                    KnowledgeSkill knoSkill = skill as KnowledgeSkill;
                    if (knoSkill != null)
                    {
                        KnowledgeSkills.Add(knoSkill);
                    }
                    else if (oldSkillFilter(skill))
                    {
                        unsoredSkills.Add(skill);
                    }
                }

                unsoredSkills.Sort(CompareSkills);

                unsoredSkills.ForEach(x => _skills.Add(x));

                UpdateUndoList(skillNode);

                //remove skillgroups whose skills did not make the final cut
                for (var i = SkillGroups.Count - 1; i >= 0; i--)
                {
                    if (SkillGroups[i].GetEnumerable().Any(x => Skills.Contains(x)))
                    {
                        continue;
                    }

                    SkillGroups.RemoveAt(i);
                }
            }

            //Workaround for probably breaking compability between earlier beta builds
            if (skillNode["skillptsmax"] == null)
            {
                skillNode = skillNode.OwnerDocument["character"];
            }

            SkillPointsMaximum      = Convert.ToInt32(skillNode["skillptsmax"].InnerText);
            SkillGroupPointsMaximum = Convert.ToInt32(skillNode["skillgrpsmax"].InnerText);
            skillNode.TryGetField("uneducated", out _blnUneducated);
            skillNode.TryGetField("uncouth", out _blnUncouth);
            skillNode.TryGetField("schoolofhardknocks", out _blnSchoolOfHardKnocks);
            skillNode.TryGetField("collegeeducation", out _blnCollegeEducation);
            skillNode.TryGetField("jackofalltrades", out _blnJackOfAllTrades);
            skillNode.TryGetField("techschool", out _blnTechSchool);
            skillNode.TryGetField("linguist", out _blnLinguist);

            Timekeeper.Finish("load_char_skills");
        }