Esempio n. 1
0
        private void mnuSpecialPossessInanimate_Click(object sender, EventArgs e)
        {
            // Make sure the Spirit has been saved first.
            if (_blnIsDirty)
            {
                if (MessageBox.Show(LanguageManager.Instance.GetString("Message_PossessionSave"), LanguageManager.Instance.GetString("MessageTitle_Possession"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                    return;
            }

            // Prompt the user to select an inanimate Vessel.
            XmlDocument objVesselDoc = XmlManager.Instance.Load("vessels.xml");
            XmlNodeList objXmlMetatypeList = objVesselDoc.SelectNodes("/chummer/metatypes/metatype");
            List<ListItem> lstMetatype = new List<ListItem>();
            foreach (XmlNode objXmlMetatype in objXmlMetatypeList)
            {
                ListItem objItem = new ListItem();
                objItem.Value = objXmlMetatype["name"].InnerText;
                if (objXmlMetatype["translate"] != null)
                    objItem.Name = objXmlMetatype["translate"].InnerText;
                else
                    objItem.Name = objXmlMetatype["name"].InnerText;
                lstMetatype.Add(objItem);
            }

            frmSelectItem frmSelectVessel = new frmSelectItem();
            frmSelectVessel.GeneralItems = lstMetatype;
            frmSelectVessel.ShowDialog(this);

            if (frmSelectVessel.DialogResult == DialogResult.Cancel)
                return;

            // Load the Spirit's save file into a new Merge character.
            Character objMerge = new Character();
            objMerge.FileName = _objCharacter.FileName;
            objMerge.Load();
            objMerge.Possessed = true;
            objMerge.Alias = frmSelectVessel.SelectedItem + " (" + LanguageManager.Instance.GetString("String_Possessed") + ")";

            // Get the Node for the selected Vessel.
            XmlNode objSelected = objVesselDoc.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + frmSelectVessel.SelectedItem + "\"]");

            // Get the Attribute Modifiers for the Vessel.
            int intBOD = Convert.ToInt32(objSelected["bodmin"].InnerText);
            int intAGI = Convert.ToInt32(objSelected["agimin"].InnerText);
            int intREA = Convert.ToInt32(objSelected["reamin"].InnerText);
            int intSTR = Convert.ToInt32(objSelected["strmin"].InnerText);

            // Add the Attribute modifiers, making sure that none of them go below 1.
            int intSetBOD = objMerge.MAG.TotalValue + intBOD;
            int intSetAGI = objMerge.MAG.TotalValue + intAGI;
            int intSetREA = objMerge.MAG.TotalValue + intREA;
            int intSetSTR = objMerge.MAG.TotalValue + intSTR;

            objMerge.BOD.MetatypeMinimum += intBOD;
            if (objMerge.BOD.MetatypeMinimum < 1)
                objMerge.BOD.MetatypeMinimum = 1;
            objMerge.BOD.MetatypeMaximum += intBOD;
            if (objMerge.BOD.MetatypeMaximum < 1)
                objMerge.BOD.MetatypeMaximum = 1;
            objMerge.BOD.Value = intSetBOD;
            if (objMerge.BOD.Value < 1)
                objMerge.BOD.Value = 1;

            objMerge.AGI.MetatypeMinimum += intAGI;
            if (objMerge.AGI.MetatypeMinimum < 1)
                objMerge.AGI.MetatypeMinimum = 1;
            objMerge.AGI.MetatypeMaximum += intAGI;
            if (objMerge.AGI.MetatypeMaximum < 1)
                objMerge.AGI.MetatypeMaximum = 1;
            objMerge.AGI.Value = intSetAGI;
            if (objMerge.AGI.Value < 1)
                objMerge.AGI.Value = 1;

            objMerge.REA.MetatypeMinimum += intREA;
            if (objMerge.REA.MetatypeMinimum < 1)
                objMerge.REA.MetatypeMinimum = 1;
            objMerge.REA.MetatypeMaximum += intREA;
            if (objMerge.REA.MetatypeMaximum < 1)
                objMerge.REA.MetatypeMaximum = 1;
            objMerge.REA.Value = intSetREA;
            if (objMerge.REA.Value < 1)
                objMerge.REA.Value = 1;

            objMerge.STR.MetatypeMinimum += intSTR;
            if (objMerge.STR.MetatypeMinimum < 1)
                objMerge.STR.MetatypeMinimum = 1;
            objMerge.STR.MetatypeMaximum += intSTR;
            if (objMerge.STR.MetatypeMaximum < 1)
                objMerge.STR.MetatypeMaximum = 1;
            objMerge.STR.Value = intSetSTR;
            if (objMerge.STR.Value < 1)
                objMerge.STR.Value = 1;

            // Update the Movement if the Vessel has one.
            if (objSelected["movement"] != null)
                objMerge.Movement = objSelected["movement"].InnerText;

            // Add any additional Critter Powers the Vessel grants.
            if (objSelected["powers"] != null)
            {
                XmlDocument objXmlPowerDoc = XmlManager.Instance.Load("critterpowers.xml");
                foreach (XmlNode objXmlPower in objSelected.SelectNodes("powers/power"))
                {
                    XmlNode objXmlCritterPower = objXmlPowerDoc.SelectSingleNode("/chummer/powers/power[name = \"" + objXmlPower.InnerText + "\"]");
                    CritterPower objPower = new CritterPower(objMerge);
                    string strSelect = "";
                    int intRating = 0;
                    if (objXmlPower.Attributes["select"] != null)
                        strSelect = objXmlPower.Attributes["select"].InnerText;
                    if (objXmlPower.Attributes["rating"] != null)
                        intRating = Convert.ToInt32(objXmlPower.Attributes["rating"].InnerText);

                    TreeNode objDummy = new TreeNode();
                    objPower.Create(objXmlCritterPower, objMerge, objDummy, intRating, strSelect);

                    objMerge.CritterPowers.Add(objPower);
                }
            }

            // Give the Critter the Immunity to Normal Weapons Power if they don't already have it.
            bool blnHasImmunity = false;
            foreach (CritterPower objCritterPower in objMerge.CritterPowers)
            {
                if (objCritterPower.Name == "Immunity" && objCritterPower.Extra == "Normal Weapons")
                {
                    blnHasImmunity = true;
                    break;
                }
            }
            if (!blnHasImmunity)
            {
                XmlDocument objPowerDoc = new XmlDocument();
                objPowerDoc = XmlManager.Instance.Load("critterpowers.xml");
                XmlNode objPower = objPowerDoc.SelectSingleNode("/chummer/powers/power[name = \"Immunity\"]");

                CritterPower objCritterPower = new CritterPower(objMerge);
                TreeNode objDummy = new TreeNode();
                objCritterPower.Create(objPower, objMerge, objDummy, 0, "Normal Weapons");
                objMerge.CritterPowers.Add(objCritterPower);
            }

            // Add any Improvements the Vessel grants.
            if (objSelected["bonus"] != null)
            {
                ImprovementManager objMergeManager = new ImprovementManager(objMerge);
                objMergeManager.CreateImprovements(Improvement.ImprovementSource.Metatype, frmSelectVessel.SelectedItem, objSelected["bonus"], false, 1, frmSelectVessel.SelectedItem);
            }

            // Now that everything is done, save the merged character and open them.
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "Chummer5 Files (*.chum5)|*.chum5|All Files (*.*)|*.*";

            string strShowFileName = "";
            string[] strFile = _objCharacter.FileName.Split(Path.DirectorySeparatorChar);
            strShowFileName = strFile[strFile.Length - 1];

            if (strShowFileName == "")
                strShowFileName = _objCharacter.Alias;
            strShowFileName = strShowFileName.Replace(".chum5", string.Empty);

            strShowFileName += " (" + LanguageManager.Instance.GetString("String_Possessed") + ")";

            saveFileDialog.FileName = strShowFileName;

            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                objMerge.FileName = saveFileDialog.FileName;
                objMerge.Save();

                // Get the name of the file and destroy the references to the Vessel and the merged character.
                string strOpenFile = objMerge.FileName;
                objMerge = null;

                GlobalOptions.Instance.MainForm.LoadCharacter(strOpenFile);
            }
            else
            {
                // The save process was canceled, so drop everything.
                objMerge = null;
            }
        }
Esempio n. 2
0
        private void mnuSpecialPossess_Click(object sender, EventArgs e)
        {
            // Make sure the Spirit has been saved first.
            if (_blnIsDirty)
            {
                if (MessageBox.Show(LanguageManager.Instance.GetString("Message_PossessionSave"), LanguageManager.Instance.GetString("MessageTitle_Possession"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                    return;
            }

            // Prompt the user to select a save file to possess.
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "Chummer5 Files (*.chum5)|*.chum5|All Files (*.*)|*.*";

            if (openFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                Character objVessel = new Character();
                objVessel.FileName = openFileDialog.FileName;
                objVessel.Load();
                // Make sure the Vessel is in Career Mode.
                if (!objVessel.Created)
                {
                    MessageBox.Show(LanguageManager.Instance.GetString("Message_VesselInCareerMode"), LanguageManager.Instance.GetString("MessageTitle_Possession"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                    objVessel = null;
                    return;
                }

                // Load the Spirit's save file into a new Merge character.
                Character objMerge = new Character();
                objMerge.FileName = _objCharacter.FileName;
                objMerge.Load();
                objMerge.Possessed = true;
                objMerge.Alias = objVessel.Alias + " (" + LanguageManager.Instance.GetString("String_Possessed") + ")";

                // Give the Critter the Immunity to Normal Weapons Power if they don't already have it.
                bool blnHasImmunity = false;
                foreach (CritterPower objCritterPower in objMerge.CritterPowers)
                {
                    if (objCritterPower.Name == "Immunity" && objCritterPower.Extra == "Normal Weapons")
                    {
                        blnHasImmunity = true;
                        break;
                    }
                }
                if (!blnHasImmunity)
                {
                    XmlDocument objPowerDoc = new XmlDocument();
                    objPowerDoc = XmlManager.Instance.Load("critterpowers.xml");
                    XmlNode objPower = objPowerDoc.SelectSingleNode("/chummer/powers/power[name = \"Immunity\"]");

                    CritterPower objCritterPower = new CritterPower(objMerge);
                    TreeNode objDummy = new TreeNode();
                    objCritterPower.Create(objPower, objMerge, objDummy, 0, "Normal Weapons");
                    objMerge.CritterPowers.Add(objCritterPower);
                }

                // Add the Vessel's Physical Attributes to the Spirit's Force.
                objMerge.BOD.MetatypeMaximum = objVessel.BOD.Value + objMerge.MAG.TotalValue;
                objMerge.BOD.Value = objVessel.BOD.Value + objMerge.MAG.TotalValue;
                objMerge.AGI.MetatypeMaximum = objVessel.AGI.Value + objMerge.MAG.TotalValue;
                objMerge.AGI.Value = objVessel.AGI.Value + objMerge.MAG.TotalValue;
                objMerge.REA.MetatypeMaximum = objVessel.REA.Value + objMerge.MAG.TotalValue;
                objMerge.REA.Value = objVessel.REA.Value + objMerge.MAG.TotalValue;
                objMerge.STR.MetatypeMaximum = objVessel.STR.Value + objMerge.MAG.TotalValue;
                objMerge.STR.Value = objVessel.STR.Value + objMerge.MAG.TotalValue;

                // Copy any Lifestyles the Vessel has.
                foreach (Lifestyle objLifestyle in objVessel.Lifestyles)
                    objMerge.Lifestyles.Add(objLifestyle);

                // Copy any Armor the Vessel has.
                foreach (Armor objArmor in objVessel.Armor)
                {
                    objMerge.Armor.Add(objArmor);
                    CopyArmorImprovements(objVessel, objMerge, objArmor);
                }

                // Copy any Gear the Vessel has.
                foreach (Gear objGear in objVessel.Gear)
                {
                    objMerge.Gear.Add(objGear);
                    CopyGearImprovements(objVessel, objMerge, objGear);
                }

                // Copy any Cyberware/Bioware the Vessel has.
                foreach (Cyberware objCyberware in objVessel.Cyberware)
                {
                    objMerge.Cyberware.Add(objCyberware);
                    CopyCyberwareImprovements(objVessel, objMerge, objCyberware);
                }

                // Copy any Weapons the Vessel has.
                foreach (Weapon objWeapon in objVessel.Weapons)
                    objMerge.Weapons.Add(objWeapon);

                // Copy and Vehicles the Vessel has.
                foreach (Vehicle objVehicle in objVessel.Vehicles)
                    objMerge.Vehicles.Add(objVehicle);

                // Copy the character info.
                objMerge.Sex = objVessel.Sex;
                objMerge.Age = objVessel.Age;
                objMerge.Eyes = objVessel.Eyes;
                objMerge.Hair = objVessel.Hair;
                objMerge.Height = objVessel.Height;
                objMerge.Weight = objVessel.Weight;
                objMerge.Skin = objVessel.Skin;
                objMerge.Name = objVessel.Name;
                objMerge.StreetCred = objVessel.StreetCred;
                objMerge.BurntStreetCred = objVessel.BurntStreetCred;
                objMerge.Notoriety = objVessel.Notoriety;
                objMerge.PublicAwareness = objVessel.PublicAwareness;
                objMerge.Mugshot = objVessel.Mugshot;

                // Now that everything is done, save the merged character and open them.
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "Chummer5 Files (*.chum5)|*.chum5|All Files (*.*)|*.*";

                string strShowFileName = "";
                string[] strFile = _objCharacter.FileName.Split(Path.DirectorySeparatorChar);
                strShowFileName = strFile[strFile.Length - 1];

                if (strShowFileName == "")
                    strShowFileName = _objCharacter.Alias;
                strShowFileName = strShowFileName.Replace(".chum5", string.Empty);

                strShowFileName += " (" + LanguageManager.Instance.GetString("String_Possessed") + ")";

                saveFileDialog.FileName = strShowFileName;

                if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
                {
                    objMerge.FileName = saveFileDialog.FileName;
                    objMerge.Save();

                    // Get the name of the file and destroy the references to the Vessel and the merged character.
                    string strOpenFile = objMerge.FileName;
                    objMerge = null;
                    objVessel = null;

                    GlobalOptions.Instance.MainForm.LoadCharacter(strOpenFile);
                }
                else
                {
                    // The save process was canceled, so drop everything.
                    objMerge = null;
                    objVessel = null;
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Create a Critter, put them into Career Mode, link them, and open the newly-created Critter.
        /// </summary>
        /// <param name="strCritterName">Name of the Critter's Metatype.</param>
        /// <param name="intForce">Critter's Force.</param>
        private void CreateCritter(string strCritterName, int intForce)
        {
            // The Critter should use the same settings file as the character.
            Character objCharacter = new Character();
            objCharacter.SettingsFile = _objSpirit.CharacterObject.SettingsFile;

            // Override the defaults for the setting.
            objCharacter.IgnoreRules = true;
            objCharacter.IsCritter = true;
            objCharacter.BuildMethod = CharacterBuildMethod.Karma;
            objCharacter.BuildPoints = 0;

            if (txtCritterName.Text != string.Empty)
                objCharacter.Name = txtCritterName.Text;

            // Make sure that Running Wild is one of the allowed source books since most of the Critter Powers come from this book.
            bool blnRunningWild = false;
            blnRunningWild = (objCharacter.Options.Books.Contains("RW"));

            if (!blnRunningWild)
            {
                MessageBox.Show(LanguageManager.Instance.GetString("Message_Main_RunningWild"), LanguageManager.Instance.GetString("MessageTitle_Main_RunningWild"), MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            // Ask the user to select a filename for the new character.
            string strForce = LanguageManager.Instance.GetString("String_Force");
            if (_objSpirit.EntityType == SpiritType.Sprite)
                strForce = LanguageManager.Instance.GetString("String_Rating");
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "Chummer5 Files (*.chum5)|*.chum5|All Files (*.*)|*.*";
            saveFileDialog.FileName = strCritterName + " (" + strForce + " " + _objSpirit.Force.ToString() + ").chum5";
            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                string strFileName = saveFileDialog.FileName;
                objCharacter.FileName = strFileName;
            }
            else
                return;

            // Code from frmMetatype.
            ImprovementManager objImprovementManager = new ImprovementManager(objCharacter);
            XmlDocument objXmlDocument = XmlManager.Instance.Load("critters.xml");

            XmlNode objXmlMetatype = objXmlDocument.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + strCritterName + "\"]");

            // If the Critter could not be found, show an error and get out of here.
            if (objXmlMetatype == null)
            {
                MessageBox.Show(LanguageManager.Instance.GetString("Message_UnknownCritterType").Replace("{0}", strCritterName), LanguageManager.Instance.GetString("MessageTitle_SelectCritterType"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // Set Metatype information.
            if (strCritterName == "Ally Spirit")
            {
                objCharacter.BOD.AssignLimits(ExpressionToString(objXmlMetatype["bodmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["bodmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["bodaug"].InnerText, intForce, 0));
                objCharacter.AGI.AssignLimits(ExpressionToString(objXmlMetatype["agimin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["agimax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["agiaug"].InnerText, intForce, 0));
                objCharacter.REA.AssignLimits(ExpressionToString(objXmlMetatype["reamin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["reamax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["reaaug"].InnerText, intForce, 0));
                objCharacter.STR.AssignLimits(ExpressionToString(objXmlMetatype["strmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["strmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["straug"].InnerText, intForce, 0));
                objCharacter.CHA.AssignLimits(ExpressionToString(objXmlMetatype["chamin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["chamax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["chaaug"].InnerText, intForce, 0));
                objCharacter.INT.AssignLimits(ExpressionToString(objXmlMetatype["intmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["intmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["intaug"].InnerText, intForce, 0));
                objCharacter.LOG.AssignLimits(ExpressionToString(objXmlMetatype["logmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["logmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["logaug"].InnerText, intForce, 0));
                objCharacter.WIL.AssignLimits(ExpressionToString(objXmlMetatype["wilmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["wilmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["wilaug"].InnerText, intForce, 0));
                objCharacter.INI.AssignLimits(ExpressionToString(objXmlMetatype["inimin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["inimax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["iniaug"].InnerText, intForce, 0));
                objCharacter.MAG.AssignLimits(ExpressionToString(objXmlMetatype["magmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["magmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["magaug"].InnerText, intForce, 0));
                objCharacter.RES.AssignLimits(ExpressionToString(objXmlMetatype["resmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["resmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["resaug"].InnerText, intForce, 0));
                objCharacter.EDG.AssignLimits(ExpressionToString(objXmlMetatype["edgmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["edgmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["edgaug"].InnerText, intForce, 0));
                objCharacter.ESS.AssignLimits(ExpressionToString(objXmlMetatype["essmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["essmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["essaug"].InnerText, intForce, 0));
            }
            else
            {
                int intMinModifier = -3;
                if (objXmlMetatype["category"].InnerText == "Mutant Critters")
                    intMinModifier = 0;
                objCharacter.BOD.AssignLimits(ExpressionToString(objXmlMetatype["bodmin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["bodmin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["bodmin"].InnerText, intForce, 3));
                objCharacter.AGI.AssignLimits(ExpressionToString(objXmlMetatype["agimin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["agimin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["agimin"].InnerText, intForce, 3));
                objCharacter.REA.AssignLimits(ExpressionToString(objXmlMetatype["reamin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["reamin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["reamin"].InnerText, intForce, 3));
                objCharacter.STR.AssignLimits(ExpressionToString(objXmlMetatype["strmin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["strmin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["strmin"].InnerText, intForce, 3));
                objCharacter.CHA.AssignLimits(ExpressionToString(objXmlMetatype["chamin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["chamin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["chamin"].InnerText, intForce, 3));
                objCharacter.INT.AssignLimits(ExpressionToString(objXmlMetatype["intmin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["intmin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["intmin"].InnerText, intForce, 3));
                objCharacter.LOG.AssignLimits(ExpressionToString(objXmlMetatype["logmin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["logmin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["logmin"].InnerText, intForce, 3));
                objCharacter.WIL.AssignLimits(ExpressionToString(objXmlMetatype["wilmin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["wilmin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["wilmin"].InnerText, intForce, 3));
                objCharacter.INI.AssignLimits(ExpressionToString(objXmlMetatype["inimin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["inimax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["iniaug"].InnerText, intForce, 0));
                objCharacter.MAG.AssignLimits(ExpressionToString(objXmlMetatype["magmin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["magmin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["magmin"].InnerText, intForce, 3));
                objCharacter.RES.AssignLimits(ExpressionToString(objXmlMetatype["resmin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["resmin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["resmin"].InnerText, intForce, 3));
                objCharacter.EDG.AssignLimits(ExpressionToString(objXmlMetatype["edgmin"].InnerText, intForce, intMinModifier), ExpressionToString(objXmlMetatype["edgmin"].InnerText, intForce, 3), ExpressionToString(objXmlMetatype["edgmin"].InnerText, intForce, 3));
                objCharacter.ESS.AssignLimits(ExpressionToString(objXmlMetatype["essmin"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["essmax"].InnerText, intForce, 0), ExpressionToString(objXmlMetatype["essaug"].InnerText, intForce, 0));
            }

            // If we're working with a Critter, set the Attributes to their default values.
            objCharacter.BOD.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["bodmin"].InnerText, intForce, 0));
            objCharacter.AGI.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["agimin"].InnerText, intForce, 0));
            objCharacter.REA.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["reamin"].InnerText, intForce, 0));
            objCharacter.STR.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["strmin"].InnerText, intForce, 0));
            objCharacter.CHA.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["chamin"].InnerText, intForce, 0));
            objCharacter.INT.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["intmin"].InnerText, intForce, 0));
            objCharacter.LOG.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["logmin"].InnerText, intForce, 0));
            objCharacter.WIL.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["wilmin"].InnerText, intForce, 0));
            objCharacter.MAG.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["magmin"].InnerText, intForce, 0));
            objCharacter.RES.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["resmin"].InnerText, intForce, 0));
            objCharacter.EDG.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["edgmin"].InnerText, intForce, 0));
            objCharacter.ESS.Value = Convert.ToInt32(ExpressionToString(objXmlMetatype["essmax"].InnerText, intForce, 0));

            // Sprites can never have Physical Attributes or WIL.
            if (objXmlMetatype["category"].InnerText.EndsWith("Sprite"))
            {
                objCharacter.BOD.AssignLimits("0", "0", "0");
                objCharacter.AGI.AssignLimits("0", "0", "0");
                objCharacter.REA.AssignLimits("0", "0", "0");
                objCharacter.STR.AssignLimits("0", "0", "0");
                objCharacter.WIL.AssignLimits("0", "0", "0");
                objCharacter.INI.MetatypeMinimum = Convert.ToInt32(ExpressionToString(objXmlMetatype["inimax"].InnerText, intForce, 0));
                objCharacter.INI.MetatypeMaximum = Convert.ToInt32(ExpressionToString(objXmlMetatype["inimax"].InnerText, intForce, 0));
            }

            objCharacter.Metatype = strCritterName;
            objCharacter.MetatypeCategory = objXmlMetatype["category"].InnerText;
            objCharacter.Metavariant = "";
            objCharacter.MetatypeBP = 0;

            if (objXmlMetatype["movement"] != null)
                objCharacter.Movement = objXmlMetatype["movement"].InnerText;
            // Load the Qualities file.
            XmlDocument objXmlQualityDocument = XmlManager.Instance.Load("qualities.xml");

            // Determine if the Metatype has any bonuses.
            if (objXmlMetatype.InnerXml.Contains("bonus"))
                objImprovementManager.CreateImprovements(Improvement.ImprovementSource.Metatype, strCritterName, objXmlMetatype.SelectSingleNode("bonus"), false, 1, strCritterName);

            // Create the Qualities that come with the Metatype.
            foreach (XmlNode objXmlQualityItem in objXmlMetatype.SelectNodes("qualities/positive/quality"))
            {
                XmlNode objXmlQuality = objXmlQualityDocument.SelectSingleNode("/chummer/qualities/quality[name = \"" + objXmlQualityItem.InnerText + "\"]");
                TreeNode objNode = new TreeNode();
                List<Weapon> objWeapons = new List<Weapon>();
                List<TreeNode> objWeaponNodes = new List<TreeNode>();
                Quality objQuality = new Quality(objCharacter);
                string strForceValue = "";
                if (objXmlQualityItem.Attributes["select"] != null)
                    strForceValue = objXmlQualityItem.Attributes["select"].InnerText;
                QualitySource objSource = new QualitySource();
                objSource = QualitySource.Metatype;
                if (objXmlQualityItem.Attributes["removable"] != null)
                    objSource = QualitySource.MetatypeRemovable;
                objQuality.Create(objXmlQuality, objCharacter, objSource, objNode, objWeapons, objWeaponNodes, strForceValue);
                objCharacter.Qualities.Add(objQuality);

                // Add any created Weapons to the character.
                foreach (Weapon objWeapon in objWeapons)
                    objCharacter.Weapons.Add(objWeapon);
            }
            foreach (XmlNode objXmlQualityItem in objXmlMetatype.SelectNodes("qualities/negative/quality"))
            {
                XmlNode objXmlQuality = objXmlQualityDocument.SelectSingleNode("/chummer/qualities/quality[name = \"" + objXmlQualityItem.InnerText + "\"]");
                TreeNode objNode = new TreeNode();
                List<Weapon> objWeapons = new List<Weapon>();
                List<TreeNode> objWeaponNodes = new List<TreeNode>();
                Quality objQuality = new Quality(objCharacter);
                string strForceValue = "";
                if (objXmlQualityItem.Attributes["select"] != null)
                    strForceValue = objXmlQualityItem.Attributes["select"].InnerText;
                QualitySource objSource = new QualitySource();
                objSource = QualitySource.Metatype;
                if (objXmlQualityItem.Attributes["removable"] != null)
                    objSource = QualitySource.MetatypeRemovable;
                objQuality.Create(objXmlQuality, objCharacter, objSource, objNode, objWeapons, objWeaponNodes, strForceValue);
                objCharacter.Qualities.Add(objQuality);

                // Add any created Weapons to the character.
                foreach (Weapon objWeapon in objWeapons)
                    objCharacter.Weapons.Add(objWeapon);
            }

            // Add any Critter Powers the Metatype/Critter should have.
            XmlNode objXmlCritter = objXmlDocument.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + objCharacter.Metatype + "\"]");

            objXmlDocument = XmlManager.Instance.Load("critterpowers.xml");
            foreach (XmlNode objXmlPower in objXmlCritter.SelectNodes("powers/power"))
            {
                XmlNode objXmlCritterPower = objXmlDocument.SelectSingleNode("/chummer/powers/power[name = \"" + objXmlPower.InnerText + "\"]");
                TreeNode objNode = new TreeNode();
                CritterPower objPower = new CritterPower(objCharacter);
                string strForcedValue = "";
                int intRating = 0;

                if (objXmlPower.Attributes["rating"] != null)
                    intRating = Convert.ToInt32(objXmlPower.Attributes["rating"].InnerText);
                if (objXmlPower.Attributes["select"] != null)
                    strForcedValue = objXmlPower.Attributes["select"].InnerText;

                objPower.Create(objXmlCritterPower, objCharacter, objNode, intRating, strForcedValue);
                objCharacter.CritterPowers.Add(objPower);
            }

            // Set the Skill Ratings for the Critter.
            foreach (XmlNode objXmlSkill in objXmlCritter.SelectNodes("skills/skill"))
            {
                if (objXmlSkill.InnerText.Contains("Exotic"))
                {
                    Skill objExotic = new Skill(objCharacter);
                    objExotic.ExoticSkill = true;
                    objExotic.Attribute = "AGI";
                    if (objXmlSkill.Attributes["spec"] != null)
                    {
                        SkillSpecialization objSpec = new SkillSpecialization(objXmlSkill.Attributes["spec"].InnerText);
                        objExotic.Specializations.Add(objSpec);
                    }
                    if (Convert.ToInt32(ExpressionToString(objXmlSkill.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0)) > 6)
                        objExotic.RatingMaximum = Convert.ToInt32(ExpressionToString(objXmlSkill.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0));
                    objExotic.Rating = Convert.ToInt32(ExpressionToString(objXmlSkill.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0));
                    objExotic.Name = objXmlSkill.InnerText;
                    objCharacter.Skills.Add(objExotic);
                }
                else
                {
                    foreach (Skill objSkill in objCharacter.Skills)
                    {
                        if (objSkill.Name == objXmlSkill.InnerText)
                        {
                            if (objXmlSkill.Attributes["spec"] != null)
                            {
                                SkillSpecialization objSpec = new SkillSpecialization(objXmlSkill.Attributes["spec"].InnerText);
                                objSkill.Specializations.Add(objSpec);
                            }
                            if (Convert.ToInt32(ExpressionToString(objXmlSkill.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0)) > 6)
                                objSkill.RatingMaximum = Convert.ToInt32(ExpressionToString(objXmlSkill.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0));
                            objSkill.Rating = Convert.ToInt32(ExpressionToString(objXmlSkill.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0));
                            break;
                        }
                    }
                }
            }

            // Set the Skill Group Ratings for the Critter.
            foreach (XmlNode objXmlSkill in objXmlCritter.SelectNodes("skills/group"))
            {
                foreach (SkillGroup objSkill in objCharacter.SkillGroups)
                {
                    if (objSkill.Name == objXmlSkill.InnerText)
                    {
                        objSkill.RatingMaximum = Convert.ToInt32(ExpressionToString(objXmlSkill.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0));
                        objSkill.Rating = Convert.ToInt32(ExpressionToString(objXmlSkill.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0));
                        break;
                    }
                }
            }

            // Set the Knowledge Skill Ratings for the Critter.
            foreach (XmlNode objXmlSkill in objXmlCritter.SelectNodes("skills/knowledge"))
            {
                Skill objKnowledge = new Skill(objCharacter);
                objKnowledge.Name = objXmlSkill.InnerText;
                objKnowledge.KnowledgeSkill = true;
                if (objXmlSkill.Attributes["spec"] != null)
                {
                    SkillSpecialization objSpec = new SkillSpecialization(objXmlSkill.Attributes["spec"].InnerText);
                    objKnowledge.Specializations.Add(objSpec);
                }
                objKnowledge.SkillCategory = objXmlSkill.Attributes["category"].InnerText;
                if (Convert.ToInt32(objXmlSkill.Attributes["rating"].InnerText) > 6)
                    objKnowledge.RatingMaximum = Convert.ToInt32(objXmlSkill.Attributes["rating"].InnerText);
                objKnowledge.Rating = Convert.ToInt32(objXmlSkill.Attributes["rating"].InnerText);
                objCharacter.Skills.Add(objKnowledge);
            }

            // If this is a Critter with a Force (which dictates their Skill Rating/Maximum Skill Rating), set their Skill Rating Maximums.
            if (intForce > 0)
            {
                int intMaxRating = intForce;
                // Determine the highest Skill Rating the Critter has.
                foreach (Skill objSkill in objCharacter.Skills)
                {
                    if (objSkill.RatingMaximum > intMaxRating)
                        intMaxRating = objSkill.RatingMaximum;
                }

                // Now that we know the upper limit, set all of the Skill Rating Maximums to match.
                foreach (Skill objSkill in objCharacter.Skills)
                    objSkill.RatingMaximum = intMaxRating;
                foreach (SkillGroup objGroup in objCharacter.SkillGroups)
                    objGroup.RatingMaximum = intMaxRating;

                // Set the MaxSkillRating for the character so it can be used later when they add new Knowledge Skills or Exotic Skills.
                objCharacter.MaxSkillRating = intMaxRating;
            }

            // Add any Complex Forms the Critter comes with (typically Sprites)
            XmlDocument objXmlProgramDocument = XmlManager.Instance.Load("complexforms.xml");
            foreach (XmlNode objXmlComplexForm in objXmlCritter.SelectNodes("complexforms/complexform"))
            {
                string strForceValue = "";
                if (objXmlComplexForm.Attributes["select"] != null)
                    strForceValue = objXmlComplexForm.Attributes["select"].InnerText;
                XmlNode objXmlProgram = objXmlProgramDocument.SelectSingleNode("/chummer/complexforms/complexform[name = \"" + objXmlComplexForm.InnerText + "\"]");
                TreeNode objNode = new TreeNode();
                ComplexForm objProgram = new ComplexForm(objCharacter);
                objProgram.Create(objXmlProgram, objCharacter, objNode, strForceValue);
                objCharacter.ComplexForms.Add(objProgram);
            }

            // Add any Gear the Critter comes with (typically Programs for A.I.s)
            XmlDocument objXmlGearDocument = XmlManager.Instance.Load("gear.xml");
            foreach (XmlNode objXmlGear in objXmlCritter.SelectNodes("gears/gear"))
            {
                int intRating = 0;
                if (objXmlGear.Attributes["rating"] != null)
                    intRating = Convert.ToInt32(ExpressionToString(objXmlGear.Attributes["rating"].InnerText, Convert.ToInt32(nudForce.Value), 0));
                string strForceValue = "";
                if (objXmlGear.Attributes["select"] != null)
                    strForceValue = objXmlGear.Attributes["select"].InnerText;
                XmlNode objXmlGearItem = objXmlGearDocument.SelectSingleNode("/chummer/gears/gear[name = \"" + objXmlGear.InnerText + "\"]");
                TreeNode objNode = new TreeNode();
                Gear objGear = new Gear(objCharacter);
                List<Weapon> lstWeapons = new List<Weapon>();
                List<TreeNode> lstWeaponNodes = new List<TreeNode>();
                objGear.Create(objXmlGearItem, objCharacter, objNode, intRating, lstWeapons, lstWeaponNodes, strForceValue);
                objGear.Cost = "0";
                objGear.Cost3 = "0";
                objGear.Cost6 = "0";
                objGear.Cost10 = "0";
                objCharacter.Gear.Add(objGear);
            }

            // If this is a Mutant Critter, count up the number of Skill points they start with.
            if (objCharacter.MetatypeCategory == "Mutant Critters")
            {
                foreach (Skill objSkill in objCharacter.Skills)
                    objCharacter.MutantCritterBaseSkills += objSkill.Rating;
            }

            // Add the Unarmed Attack Weapon to the character.
            try
            {
                objXmlDocument = XmlManager.Instance.Load("weapons.xml");
                XmlNode objXmlWeapon = objXmlDocument.SelectSingleNode("/chummer/weapons/weapon[name = \"Unarmed Attack\"]");
                TreeNode objDummy = new TreeNode();
                Weapon objWeapon = new Weapon(objCharacter);
                objWeapon.Create(objXmlWeapon, objCharacter, objDummy, null, null, null);
                objCharacter.Weapons.Add(objWeapon);
            }
            catch
            {
            }

            objCharacter.Alias = strCritterName;
            objCharacter.Created = true;
            objCharacter.Save();

            string strOpenFile = objCharacter.FileName;
            objCharacter = null;

            // Link the newly-created Critter to the Spirit.
            _objSpirit.FileName = strOpenFile;
            if (_objSpirit.EntityType == SpiritType.Spirit)
                tipTooltip.SetToolTip(imgLink, LanguageManager.Instance.GetString("Tip_Spirit_OpenFile"));
            else
                tipTooltip.SetToolTip(imgLink, LanguageManager.Instance.GetString("Tip_Sprite_OpenFile"));
            FileNameChanged(this);

            GlobalOptions.Instance.MainForm.LoadCharacter(strOpenFile, true);
        }