private void UpdateGearInfo(bool blnUpdateMountCBOs = true)
        {
            if (_blnLoading)
            {
                return;
            }

            XPathNavigator xmlAccessory  = null;
            string         strSelectedId = lstAccessory.SelectedValue?.ToString();

            // Retrieve the information for the selected Accessory.
            if (!string.IsNullOrEmpty(strSelectedId))
            {
                xmlAccessory = _xmlBaseChummerNode.SelectSingleNode("accessories/accessory[id = " + strSelectedId.CleanXPath() + "]");
            }
            if (xmlAccessory == null)
            {
                lblRC.Visible            = false;
                lblRCLabel.Visible       = false;
                nudRating.Enabled        = false;
                nudRating.Visible        = false;
                lblRatingLabel.Visible   = false;
                lblRatingNALabel.Visible = false;
                lblMountLabel.Visible    = false;
                cboMount.Visible         = false;
                cboMount.Items.Clear();
                lblExtraMountLabel.Visible = false;
                cboExtraMount.Visible      = false;
                cboExtraMount.Items.Clear();
                lblAvailLabel.Visible  = false;
                lblAvail.Text          = string.Empty;
                lblCostLabel.Visible   = false;
                lblCost.Text           = string.Empty;
                lblTestLabel.Visible   = false;
                lblTest.Text           = string.Empty;
                lblSourceLabel.Visible = false;
                lblSource.Text         = string.Empty;
                lblSource.SetToolTip(string.Empty);
                return;
            }

            string strSpace = LanguageManager.GetString("String_Space");
            string strRC    = xmlAccessory.SelectSingleNode("rc")?.Value;

            if (!string.IsNullOrEmpty(strRC))
            {
                lblRC.Visible      = true;
                lblRCLabel.Visible = true;
                lblRC.Text         = strRC;
            }
            else
            {
                lblRC.Visible      = false;
                lblRCLabel.Visible = false;
            }
            if (int.TryParse(xmlAccessory.SelectSingleNode("rating")?.Value, out int intMaxRating) && intMaxRating > 0)
            {
                nudRating.Maximum = intMaxRating;
                if (chkHideOverAvailLimit.Checked)
                {
                    while (nudRating.Maximum > nudRating.Minimum && !xmlAccessory.CheckAvailRestriction(_objCharacter, nudRating.MaximumAsInt))
                    {
                        nudRating.Maximum -= 1;
                    }
                }
                if (chkShowOnlyAffordItems.Checked && !chkFreeItem.Checked)
                {
                    decimal decCostMultiplier = 1 + (nudMarkup.Value / 100.0m);
                    if (_setBlackMarketMaps.Contains(xmlAccessory.SelectSingleNode("category")?.Value))
                    {
                        decCostMultiplier *= 0.9m;
                    }
                    while (nudRating.Maximum > nudRating.Minimum && !xmlAccessory.CheckNuyenRestriction(_objCharacter.Nuyen, decCostMultiplier, nudRating.MaximumAsInt))
                    {
                        nudRating.Maximum -= 1;
                    }
                }
                nudRating.Enabled        = nudRating.Maximum != nudRating.Minimum;
                nudRating.Visible        = true;
                lblRatingLabel.Visible   = true;
                lblRatingNALabel.Visible = false;
            }
            else
            {
                lblRatingNALabel.Visible = true;
                nudRating.Enabled        = false;
                nudRating.Visible        = false;
                lblRatingLabel.Visible   = true;
            }

            if (blnUpdateMountCBOs)
            {
                string        strDataMounts = xmlAccessory.SelectSingleNode("mount")?.Value;
                List <string> strMounts     = new List <string>();
                if (!string.IsNullOrEmpty(strDataMounts))
                {
                    strMounts.AddRange(strDataMounts.SplitNoAlloc('/', StringSplitOptions.RemoveEmptyEntries));
                }

                strMounts.Add("None");

                List <string> strAllowed = new List <string>(_lstAllowedMounts)
                {
                    "None"
                };
                cboMount.Visible = true;
                cboMount.Items.Clear();
                foreach (string strCurrentMount in strMounts)
                {
                    if (!string.IsNullOrEmpty(strCurrentMount))
                    {
                        foreach (string strAllowedMount in strAllowed)
                        {
                            if (strCurrentMount == strAllowedMount)
                            {
                                cboMount.Items.Add(strCurrentMount);
                            }
                        }
                    }
                }

                cboMount.Enabled       = cboMount.Items.Count > 1;
                cboMount.SelectedIndex = 0;
                lblMountLabel.Visible  = true;

                List <string> strExtraMounts = new List <string>();
                string        strExtraMount  = xmlAccessory.SelectSingleNode("extramount")?.Value;
                if (!string.IsNullOrEmpty(strExtraMount))
                {
                    foreach (string strItem in strExtraMount.SplitNoAlloc('/', StringSplitOptions.RemoveEmptyEntries))
                    {
                        strExtraMounts.Add(strItem);
                    }
                }

                strExtraMounts.Add("None");

                cboExtraMount.Items.Clear();
                foreach (string strCurrentMount in strExtraMounts)
                {
                    if (!string.IsNullOrEmpty(strCurrentMount))
                    {
                        foreach (string strAllowedMount in strAllowed)
                        {
                            if (strCurrentMount == strAllowedMount)
                            {
                                cboExtraMount.Items.Add(strCurrentMount);
                            }
                        }
                    }
                }

                cboExtraMount.Enabled       = cboExtraMount.Items.Count > 1;
                cboExtraMount.SelectedIndex = 0;
                if (cboMount.SelectedItem.ToString() != "None" && cboExtraMount.SelectedItem.ToString() != "None" &&
                    cboMount.SelectedItem.ToString() == cboExtraMount.SelectedItem.ToString())
                {
                    cboExtraMount.SelectedIndex += 1;
                }
                cboExtraMount.Visible      = cboExtraMount.Enabled && cboExtraMount.SelectedItem.ToString() != "None";
                lblExtraMountLabel.Visible = cboExtraMount.Visible;
            }

            // Avail.
            // If avail contains "F" or "R", remove it from the string so we can use the expression.
            lblAvail.Text         = new AvailabilityValue(Convert.ToInt32(nudRating.Value), xmlAccessory.SelectSingleNode("avail")?.Value).ToString();
            lblAvailLabel.Visible = !string.IsNullOrEmpty(lblAvail.Text);

            if (!chkFreeItem.Checked)
            {
                string strCost = "0";
                if (xmlAccessory.TryGetStringFieldQuickly("cost", ref strCost))
                {
                    strCost = strCost.CheapReplace("Weapon Cost", () => _objParentWeapon.OwnCost.ToString(GlobalOptions.InvariantCultureInfo))
                              .CheapReplace("Weapon Total Cost", () => _objParentWeapon.MultipliableCost(null).ToString(GlobalOptions.InvariantCultureInfo))
                              .Replace("Rating", nudRating.Value.ToString(GlobalOptions.CultureInfo));
                }
                if (strCost.StartsWith("Variable(", StringComparison.Ordinal))
                {
                    decimal decMin;
                    decimal decMax = decimal.MaxValue;
                    strCost = strCost.TrimStartOnce("Variable(", true).TrimEndOnce(')');
                    if (strCost.Contains('-'))
                    {
                        string[] strValues = strCost.Split('-');
                        decimal.TryParse(strValues[0], NumberStyles.Any, GlobalOptions.InvariantCultureInfo, out decMin);
                        decimal.TryParse(strValues[1], NumberStyles.Any, GlobalOptions.InvariantCultureInfo, out decMax);
                    }
                    else
                    {
                        decimal.TryParse(strCost.FastEscape('+'), NumberStyles.Any, GlobalOptions.InvariantCultureInfo, out decMin);
                    }

                    if (decMax == decimal.MaxValue)
                    {
                        lblCost.Text = decMin.ToString(_objCharacter.Options.NuyenFormat, GlobalOptions.CultureInfo) + "¥+";
                    }
                    else
                    {
                        lblCost.Text = decMin.ToString(_objCharacter.Options.NuyenFormat, GlobalOptions.CultureInfo) + strSpace + '-'
                                       + strSpace + decMax.ToString(_objCharacter.Options.NuyenFormat, GlobalOptions.CultureInfo) + '¥';
                    }

                    lblTest.Text = _objCharacter.AvailTest(decMax, lblAvail.Text);
                }
                else
                {
                    object  objProcess = CommonFunctions.EvaluateInvariantXPath(strCost, out bool blnIsSuccess);
                    decimal decCost    = blnIsSuccess ? Convert.ToDecimal(objProcess, GlobalOptions.InvariantCultureInfo) : 0;

                    // Apply any markup.
                    decCost *= 1 + (nudMarkup.Value / 100.0m);

                    if (chkBlackMarketDiscount.Checked)
                    {
                        decCost *= 0.9m;
                    }
                    decCost *= _objParentWeapon.AccessoryMultiplier;
                    if (!string.IsNullOrEmpty(_objParentWeapon.DoubledCostModificationSlots))
                    {
                        string[] astrParentDoubledCostModificationSlots = _objParentWeapon.DoubledCostModificationSlots.Split('/', StringSplitOptions.RemoveEmptyEntries);
                        if (astrParentDoubledCostModificationSlots.Contains(cboMount.SelectedItem?.ToString()) ||
                            astrParentDoubledCostModificationSlots.Contains(cboExtraMount.SelectedItem?.ToString()))
                        {
                            decCost *= 2;
                        }
                    }

                    lblCost.Text = decCost.ToString(_objCharacter.Options.NuyenFormat, GlobalOptions.CultureInfo) + '¥';
                    lblTest.Text = _objCharacter.AvailTest(decCost, lblAvail.Text);
                }
            }
            else
            {
                lblCost.Text = (0.0m).ToString(_objCharacter.Options.NuyenFormat, GlobalOptions.CultureInfo) + '¥';
                lblTest.Text = _objCharacter.AvailTest(0, lblAvail.Text);
            }

            lblRatingLabel.Text = xmlAccessory.SelectSingleNode("ratinglabel") != null
                ? string.Format(GlobalOptions.CultureInfo, LanguageManager.GetString("Label_RatingFormat"),
                                LanguageManager.GetString(xmlAccessory.SelectSingleNode("ratinglabel").Value))
                : LanguageManager.GetString("Label_Rating");

            lblCostLabel.Visible = !string.IsNullOrEmpty(lblCost.Text);
            lblTestLabel.Visible = !string.IsNullOrEmpty(lblTest.Text);


            if (!chkBlackMarketDiscount.Checked)
            {
                chkBlackMarketDiscount.Checked = GlobalOptions.AssumeBlackMarket && _blnIsParentWeaponBlackMarketAllowed;
            }
            else if (!_blnIsParentWeaponBlackMarketAllowed)
            {
                //Prevent chkBlackMarketDiscount from being checked if the gear category doesn't match.
                chkBlackMarketDiscount.Checked = false;
            }

            chkBlackMarketDiscount.Enabled = _blnIsParentWeaponBlackMarketAllowed;
            string       strSource       = xmlAccessory.SelectSingleNode("source")?.Value ?? LanguageManager.GetString("String_Unknown");
            string       strPage         = xmlAccessory.SelectSingleNode("altpage")?.Value ?? xmlAccessory.SelectSingleNode("page")?.Value ?? LanguageManager.GetString("String_Unknown");
            SourceString objSourceString = new SourceString(strSource, strPage, GlobalOptions.Language, GlobalOptions.CultureInfo, _objCharacter);

            objSourceString.SetControl(lblSource);
            lblSourceLabel.Visible = !string.IsNullOrEmpty(lblSource.Text);
        }
Exemple #2
0
        private async void lstDrug_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_blnLoading)
            {
                return;
            }
            _blnLoading = true;
            XPathNavigator xmlDrug       = null;
            string         strSelectedId = await lstDrug.DoThreadSafeFuncAsync(x => x.SelectedValue?.ToString());

            if (!string.IsNullOrEmpty(strSelectedId))
            {
                // Retrieve the information for the selected piece of Drug.
                xmlDrug = _xmlBaseDrugDataNode.SelectSingleNode(_strNodeXPath + "[id = " + strSelectedId.CleanXPath() + ']');
            }
            string strForceGrade;

            if (xmlDrug != null)
            {
                strForceGrade = xmlDrug.SelectSingleNode("forcegrade")?.Value;
                // If the piece has a Rating value, enable the Rating control, otherwise, disable it and set its value to 0.
                XPathNavigator xmlRatingNode = xmlDrug.SelectSingleNode("rating");
                if (xmlRatingNode != null)
                {
                    string strMinRating = xmlDrug.SelectSingleNode("minrating")?.Value;
                    int    intMinRating = 1;
                    // Not a simple integer, so we need to start mucking around with strings
                    if (!string.IsNullOrEmpty(strMinRating) && !int.TryParse(strMinRating, out intMinRating))
                    {
                        strMinRating = await strMinRating
                                       .CheapReplaceAsync("MaximumSTR",
                                                          () => (ParentVehicle != null
                                                                        ? Math.Max(1, ParentVehicle.TotalBody * 2)
                                                                        : _objCharacter.STR.TotalMaximum)
                                                          .ToString(GlobalSettings.InvariantCultureInfo))
                                       .CheapReplaceAsync("MaximumAGI",
                                                          () => (ParentVehicle != null
                                                                        ? Math.Max(1, ParentVehicle.Pilot * 2)
                                                                        : _objCharacter.AGI.TotalMaximum)
                                                          .ToString(GlobalSettings.InvariantCultureInfo))
                                       .CheapReplaceAsync("MinimumSTR",
                                                          () => (ParentVehicle?.TotalBody ?? 3).ToString(
                                                              GlobalSettings.InvariantCultureInfo))
                                       .CheapReplaceAsync("MinimumAGI",
                                                          () => (ParentVehicle?.Pilot ?? 3).ToString(
                                                              GlobalSettings.InvariantCultureInfo));

                        object objProcess = CommonFunctions.EvaluateInvariantXPath(strMinRating, out bool blnIsSuccess);
                        intMinRating = blnIsSuccess ? ((double)objProcess).StandardRound() : 1;
                    }
                    await nudRating.DoThreadSafeAsync(x => x.Minimum = intMinRating);

                    string strMaxRating = xmlRatingNode.Value;
                    int    intMaxRating = 0;
                    // Not a simple integer, so we need to start mucking around with strings
                    if (!string.IsNullOrEmpty(strMaxRating) && !int.TryParse(strMaxRating, out intMaxRating))
                    {
                        strMaxRating = await strMaxRating
                                       .CheapReplaceAsync("MaximumSTR",
                                                          () => (ParentVehicle != null
                                                                        ? Math.Max(1, ParentVehicle.TotalBody * 2)
                                                                        : _objCharacter.STR.TotalMaximum)
                                                          .ToString(GlobalSettings.InvariantCultureInfo))
                                       .CheapReplaceAsync("MaximumAGI",
                                                          () => (ParentVehicle != null
                                                                        ? Math.Max(1, ParentVehicle.Pilot * 2)
                                                                        : _objCharacter.AGI.TotalMaximum)
                                                          .ToString(GlobalSettings.InvariantCultureInfo))
                                       .CheapReplaceAsync("MinimumSTR",
                                                          () => (ParentVehicle?.TotalBody ?? 3).ToString(
                                                              GlobalSettings.InvariantCultureInfo))
                                       .CheapReplaceAsync("MinimumAGI",
                                                          () => (ParentVehicle?.Pilot ?? 3).ToString(
                                                              GlobalSettings.InvariantCultureInfo));

                        object objProcess = CommonFunctions.EvaluateInvariantXPath(strMaxRating, out bool blnIsSuccess);
                        intMaxRating = blnIsSuccess ? ((double)objProcess).StandardRound() : 1;
                    }
                    await nudRating.DoThreadSafeAsync(x => x.Maximum = intMaxRating);

                    if (await chkHideOverAvailLimit.DoThreadSafeFuncAsync(x => x.Checked))
                    {
                        int intAvailModifier = strForceGrade == "None" ? 0 : _intAvailModifier;
                        await nudRating.DoThreadSafeAsync(x =>
                        {
                            while (x.Maximum > intMinRating &&
                                   !xmlDrug.CheckAvailRestriction(_objCharacter, x.MaximumAsInt,
                                                                  intAvailModifier))
                            {
                                --x.Maximum;
                            }
                        });
                    }

                    if (await chkShowOnlyAffordItems.DoThreadSafeFuncAsync(x => x.Checked) && !await chkFree.DoThreadSafeFuncAsync(x => x.Checked))
                    {
                        decimal decCostMultiplier = 1 + nudMarkup.Value / 100.0m;
                        if (await chkBlackMarketDiscount.DoThreadSafeFuncAsync(x => x.Checked))
                        {
                            decCostMultiplier *= 0.9m;
                        }
                        await nudRating.DoThreadSafeAsync(x =>
                        {
                            while (x.Maximum > intMinRating &&
                                   !xmlDrug.CheckNuyenRestriction(_objCharacter.Nuyen, decCostMultiplier,
                                                                  x.MaximumAsInt))
                            {
                                --x.Maximum;
                            }
                        });
                    }

                    await nudRating.DoThreadSafeAsync(x =>
                    {
                        x.Value   = x.Minimum;
                        x.Enabled = x.Minimum != x.Maximum;
                        x.Visible = true;
                    });

                    await lblRatingNALabel.DoThreadSafeAsync(x => x.Visible = false);

                    await lblRatingLabel.DoThreadSafeAsync(x => x.Visible = true);
                }
                else
                {
                    await lblRatingLabel.DoThreadSafeAsync(x => x.Visible = true);

                    await lblRatingNALabel.DoThreadSafeAsync(x => x.Visible = true);

                    await nudRating.DoThreadSafeAsync(x =>
                    {
                        x.Minimum = 0;
                        x.Value   = 0;
                        x.Visible = false;
                    });
                }

                string strSource = xmlDrug.SelectSingleNode("source")?.Value ?? await LanguageManager.GetStringAsync("String_Unknown");

                string strPage = (await xmlDrug.SelectSingleNodeAndCacheExpressionAsync("altpage"))?.Value ?? xmlDrug.SelectSingleNode("page")?.Value ?? await LanguageManager.GetStringAsync("String_Unknown");

                SourceString objSource = await SourceString.GetSourceStringAsync(strSource, strPage, GlobalSettings.Language,
                                                                                 GlobalSettings.CultureInfo, _objCharacter);

                await objSource.SetControlAsync(lblSource);

                await lblSourceLabel.DoThreadSafeAsync(x => x.Visible = !string.IsNullOrEmpty(objSource.ToString()));

                Grade objForcedGrade = null;
                if (!string.IsNullOrEmpty(strForceGrade))
                {
                    // Force the Drug to be a particular Grade.
                    await cboGrade.DoThreadSafeAsync(x =>
                    {
                        if (x.Enabled)
                        {
                            x.Enabled = false;
                        }
                    });

                    objForcedGrade = _lstGrades.Find(x => x.Name == strForceGrade);
                    strForceGrade  = objForcedGrade?.SourceId.ToString("D", GlobalSettings.InvariantCultureInfo);
                }
                else
                {
                    await cboGrade.DoThreadSafeAsync(x => x.Enabled = !_blnLockGrade);

                    if (_blnLockGrade)
                    {
                        strForceGrade  = _objForcedGrade?.SourceId.ToString("D", GlobalSettings.InvariantCultureInfo) ?? cboGrade.SelectedValue?.ToString();
                        objForcedGrade = _objForcedGrade ?? _lstGrades.Find(x => x.SourceId.ToString("D", GlobalSettings.InvariantCultureInfo) == strForceGrade);
                    }
                }

                bool blnCanBlackMarketDiscount = _setBlackMarketMaps.Contains(xmlDrug.SelectSingleNode("category")?.Value);
                await chkBlackMarketDiscount.DoThreadSafeAsync(x =>
                {
                    x.Enabled = blnCanBlackMarketDiscount;
                    if (!x.Checked)
                    {
                        x.Checked = GlobalSettings.AssumeBlackMarket && blnCanBlackMarketDiscount;
                    }
                    else if (!blnCanBlackMarketDiscount)
                    {
                        //Prevent chkBlackMarketDiscount from being checked if the category doesn't match.
                        x.Checked = false;
                    }
                });

                // We may need to rebuild the Grade list since Cultured Bioware is not allowed to select Standard (Second-Hand) as Grade and ForceGrades can change.
                await PopulateGrades(xmlDrug.SelectSingleNode("nosecondhand") != null || !await cboGrade.DoThreadSafeFuncAsync(x => x.Enabled) && objForcedGrade?.SecondHand != true, false, strForceGrade);

                /*
                 * string strNotes = xmlDrug.SelectSingleNode("altnotes")?.Value ?? xmlDrug.SelectSingleNode("notes")?.Value;
                 * if (!string.IsNullOrEmpty(strNotes))
                 * {
                 *  await lblDrugNotesLabel.DoThreadSafeAsync(x => x.Visible = true);
                 *  await lblDrugNotes.DoThreadSafeAsync(x =>
                 *  {
                 *      x.Text = strNotes;
                 *      x.Visible = true;
                 *  });
                 * }
                 * else
                 * {
                 *  await lblDrugNotes.DoThreadSafeAsync(x => x.Visible = false);
                 *  await lblDrugNotesLabel.DoThreadSafeAsync(x => x.Visible = false);
                 * }*/
                await tlpRight.DoThreadSafeAsync(x => x.Visible = true);
            }
            else
            {
                await tlpRight.DoThreadSafeAsync(x => x.Visible = false);

                await cboGrade.DoThreadSafeAsync(x => x.Enabled = !_blnLockGrade);

                strForceGrade = string.Empty;
                Grade objForcedGrade = null;
                if (_blnLockGrade)
                {
                    strForceGrade = _objForcedGrade?.SourceId.ToString("D", GlobalSettings.InvariantCultureInfo) ?? await cboGrade.DoThreadSafeFuncAsync(x => x.SelectedValue?.ToString());

                    objForcedGrade = _objForcedGrade ?? _lstGrades.Find(x => x.SourceId.ToString("D", GlobalSettings.InvariantCultureInfo) == strForceGrade);
                }
                await PopulateGrades(_blnLockGrade && objForcedGrade?.SecondHand != true, false, strForceGrade);

                await chkBlackMarketDiscount.DoThreadSafeAsync(x => x.Checked = false);
            }
            _blnLoading = false;
            await UpdateDrugInfo();
        }
        private void lstDrug_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_blnLoading)
            {
                return;
            }
            _blnLoading = true;
            XPathNavigator xmlDrug       = null;
            string         strSelectedId = lstDrug.SelectedValue?.ToString();

            if (!string.IsNullOrEmpty(strSelectedId))
            {
                // Retrieve the information for the selected piece of Drug.
                xmlDrug = _xmlBaseDrugDataNode.SelectSingleNode(_strNodeXPath + "[id = \"" + strSelectedId + "\"]");
            }
            string strForceGrade;

            if (xmlDrug != null)
            {
                strForceGrade = xmlDrug.SelectSingleNode("forcegrade")?.Value;
                // If the piece has a Rating value, enable the Rating control, otherwise, disable it and set its value to 0.
                XPathNavigator xmlRatingNode = xmlDrug.SelectSingleNode("rating");
                if (xmlRatingNode != null)
                {
                    string strMinRating = xmlDrug.SelectSingleNode("minrating")?.Value;
                    int    intMinRating = 1;
                    // Not a simple integer, so we need to start mucking around with strings
                    if (!string.IsNullOrEmpty(strMinRating) && !int.TryParse(strMinRating, out intMinRating))
                    {
                        strMinRating = strMinRating.CheapReplace("MaximumSTR", () => (ParentVehicle != null ? Math.Max(1, ParentVehicle.TotalBody * 2) : _objCharacter.STR.TotalMaximum).ToString(GlobalOptions.InvariantCultureInfo))
                                       .CheapReplace("MaximumAGI", () => (ParentVehicle != null ? Math.Max(1, ParentVehicle.Pilot * 2) : _objCharacter.AGI.TotalMaximum).ToString(GlobalOptions.InvariantCultureInfo))
                                       .CheapReplace("MinimumSTR", () => (ParentVehicle?.TotalBody ?? 3).ToString(GlobalOptions.InvariantCultureInfo))
                                       .CheapReplace("MinimumAGI", () => (ParentVehicle?.Pilot ?? 3).ToString(GlobalOptions.InvariantCultureInfo));

                        object objProcess = CommonFunctions.EvaluateInvariantXPath(strMinRating, out bool blnIsSuccess);
                        intMinRating = blnIsSuccess ? ((double)objProcess).StandardRound() : 1;
                    }
                    nudRating.Minimum = intMinRating;

                    string strMaxRating = xmlRatingNode.Value;
                    int    intMaxRating = 0;
                    // Not a simple integer, so we need to start mucking around with strings
                    if (!string.IsNullOrEmpty(strMaxRating) && !int.TryParse(strMaxRating, out intMaxRating))
                    {
                        strMaxRating = strMaxRating.CheapReplace("MaximumSTR", () => (ParentVehicle != null ? Math.Max(1, ParentVehicle.TotalBody * 2) : _objCharacter.STR.TotalMaximum).ToString(GlobalOptions.InvariantCultureInfo))
                                       .CheapReplace("MaximumAGI", () => (ParentVehicle != null ? Math.Max(1, ParentVehicle.Pilot * 2) : _objCharacter.AGI.TotalMaximum).ToString(GlobalOptions.InvariantCultureInfo))
                                       .CheapReplace("MinimumSTR", () => (ParentVehicle?.TotalBody ?? 3).ToString(GlobalOptions.InvariantCultureInfo))
                                       .CheapReplace("MinimumAGI", () => (ParentVehicle?.Pilot ?? 3).ToString(GlobalOptions.InvariantCultureInfo));

                        object objProcess = CommonFunctions.EvaluateInvariantXPath(strMaxRating, out bool blnIsSuccess);
                        intMaxRating = blnIsSuccess ? ((double)objProcess).StandardRound() : 1;
                    }
                    nudRating.Maximum = intMaxRating;
                    if (chkHideOverAvailLimit.Checked)
                    {
                        int intAvailModifier = strForceGrade == "None" ? 0 : _intAvailModifier;
                        while (nudRating.Maximum > intMinRating && !xmlDrug.CheckAvailRestriction(_objCharacter, nudRating.MaximumAsInt, intAvailModifier))
                        {
                            nudRating.Maximum -= 1;
                        }
                    }

                    if (chkShowOnlyAffordItems.Checked && !chkFree.Checked)
                    {
                        decimal decCostMultiplier = 1 + nudMarkup.Value / 100.0m;
                        if (chkBlackMarketDiscount.Checked)
                        {
                            decCostMultiplier *= 0.9m;
                        }
                        while (nudRating.Maximum > intMinRating && !xmlDrug.CheckNuyenRestriction(_objCharacter.Nuyen, decCostMultiplier, nudRating.MaximumAsInt))
                        {
                            nudRating.Maximum -= 1;
                        }
                    }
                    nudRating.Value          = nudRating.Minimum;
                    nudRating.Enabled        = nudRating.Minimum != nudRating.Maximum;
                    nudRating.Visible        = true;
                    lblRatingNALabel.Visible = false;
                    lblRatingLabel.Visible   = true;
                }
                else
                {
                    lblRatingLabel.Visible   = true;
                    lblRatingNALabel.Visible = true;
                    nudRating.Minimum        = 0;
                    nudRating.Value          = 0;
                    nudRating.Visible        = false;
                }

                string strSource = xmlDrug.SelectSingleNode("source")?.Value ?? LanguageManager.GetString("String_Unknown");
                string strPage   = xmlDrug.SelectSingleNode("altpage")?.Value ?? xmlDrug.SelectSingleNode("page")?.Value ?? LanguageManager.GetString("String_Unknown");
                string strSpace  = LanguageManager.GetString("String_Space");
                lblSource.Text = CommonFunctions.LanguageBookShort(strSource) + strSpace + strPage;
                lblSource.SetToolTip(CommonFunctions.LanguageBookLong(strSource) + strSpace + LanguageManager.GetString("String_Page") + ' ' + strPage);
                lblSourceLabel.Visible = !string.IsNullOrEmpty(lblSource.Text);

                Grade objForcedGrade = null;
                if (!string.IsNullOrEmpty(strForceGrade))
                {
                    // Force the Drug to be a particular Grade.
                    if (cboGrade.Enabled)
                    {
                        cboGrade.Enabled = false;
                    }
                    objForcedGrade = _lstGrades.FirstOrDefault(x => x.Name == strForceGrade);
                    strForceGrade  = objForcedGrade?.SourceId.ToString("D", GlobalOptions.InvariantCultureInfo);
                }
                else
                {
                    cboGrade.Enabled = !_blnLockGrade;
                    if (_blnLockGrade)
                    {
                        strForceGrade  = _objForcedGrade?.SourceId.ToString("D", GlobalOptions.InvariantCultureInfo) ?? cboGrade.SelectedValue?.ToString();
                        objForcedGrade = _objForcedGrade ?? _lstGrades.FirstOrDefault(x => x.SourceId.ToString("D", GlobalOptions.InvariantCultureInfo) == strForceGrade);
                    }
                }

                chkBlackMarketDiscount.Enabled = _objCharacter.BlackMarketDiscount;

                if (!chkBlackMarketDiscount.Checked)
                {
                    chkBlackMarketDiscount.Checked = GlobalOptions.AssumeBlackMarket &&
                                                     _setBlackMarketMaps.Contains(xmlDrug.SelectSingleNode("category")
                                                                                  ?.Value);
                }
                else if (!_setBlackMarketMaps.Contains(xmlDrug.SelectSingleNode("category")?.Value))
                {
                    //Prevent chkBlackMarketDiscount from being checked if the gear category doesn't match.
                    chkBlackMarketDiscount.Checked = false;
                }

                // We may need to rebuild the Grade list since Cultured Bioware is not allowed to select Standard (Second-Hand) as Grade and ForceGrades can change.
                PopulateGrades(xmlDrug.SelectSingleNode("nosecondhand") != null || !cboGrade.Enabled && objForcedGrade?.SecondHand != true, false, strForceGrade);

                /*
                 * string strNotes = xmlDrug.SelectSingleNode("altnotes")?.Value ?? xmlDrug.SelectSingleNode("notes")?.Value;
                 * if (!string.IsNullOrEmpty(strNotes))
                 * {
                 *  lblDrugNotes.Visible = true;
                 *  lblDrugNotesLabel.Visible = true;
                 *  lblDrugNotes.Text = strNotes;
                 * }
                 * else
                 * {
                 *  lblDrugNotes.Visible = false;
                 *  lblDrugNotesLabel.Visible = false;
                 * }*/
            }
            else
            {
                lblRatingLabel.Visible   = false;
                lblRatingNALabel.Visible = false;
                nudRating.Minimum        = 0;
                nudRating.Value          = 0;
                nudRating.Visible        = false;
                cboGrade.Enabled         = !_blnLockGrade;
                strForceGrade            = string.Empty;
                Grade objForcedGrade = null;
                if (_blnLockGrade)
                {
                    strForceGrade  = _objForcedGrade?.SourceId.ToString("D", GlobalOptions.InvariantCultureInfo) ?? cboGrade.SelectedValue?.ToString();
                    objForcedGrade = _objForcedGrade ?? _lstGrades.FirstOrDefault(x => x.SourceId.ToString("D", GlobalOptions.InvariantCultureInfo) == strForceGrade);
                }
                PopulateGrades(_blnLockGrade && objForcedGrade?.SecondHand != true, false, strForceGrade);
                chkBlackMarketDiscount.Checked = false;
                lblSourceLabel.Visible         = false;
                lblSource.Text = string.Empty;
                lblSource.SetToolTip(string.Empty);
            }
            _blnLoading = false;
            UpdateDrugInfo();
        }
        private async ValueTask UpdateGearInfo(bool blnUpdateMountComboBoxes = true)
        {
            if (_blnLoading)
            {
                return;
            }

            XPathNavigator xmlAccessory  = null;
            string         strSelectedId = await lstAccessory.DoThreadSafeFuncAsync(x => x.SelectedValue?.ToString());

            // Retrieve the information for the selected Accessory.
            if (!string.IsNullOrEmpty(strSelectedId))
            {
                xmlAccessory = _xmlBaseChummerNode.SelectSingleNode("accessories/accessory[id = " + strSelectedId.CleanXPath() + ']');
            }
            if (xmlAccessory == null)
            {
                await tlpRight.DoThreadSafeAsync(x => x.Visible = false);

                return;
            }

            string strRC = xmlAccessory.SelectSingleNode("rc")?.Value;

            if (!string.IsNullOrEmpty(strRC))
            {
                await lblRCLabel.DoThreadSafeAsync(x => x.Visible = true);

                await lblRC.DoThreadSafeAsync(x =>
                {
                    x.Visible = true;
                    x.Text    = strRC;
                });
            }
            else
            {
                await lblRC.DoThreadSafeAsync(x => x.Visible = false);

                await lblRCLabel.DoThreadSafeAsync(x => x.Visible = false);
            }
            if (int.TryParse(xmlAccessory.SelectSingleNode("rating")?.Value, out int intMaxRating) && intMaxRating > 0)
            {
                await nudRating.DoThreadSafeAsync(x => x.Maximum = intMaxRating);

                if (await chkHideOverAvailLimit.DoThreadSafeFuncAsync(x => x.Checked))
                {
                    await nudRating.DoThreadSafeAsync(x =>
                    {
                        while (x.Maximum > x.Minimum &&
                               !xmlAccessory.CheckAvailRestriction(_objCharacter, x.MaximumAsInt))
                        {
                            --x.Maximum;
                        }
                    });
                }
                if (await chkShowOnlyAffordItems.DoThreadSafeFuncAsync(x => x.Checked) && !await chkFreeItem.DoThreadSafeFuncAsync(x => x.Checked))
                {
                    decimal decCostMultiplier = 1 + (await nudMarkup.DoThreadSafeFuncAsync(x => x.Value) / 100.0m);
                    if (_setBlackMarketMaps.Contains(xmlAccessory.SelectSingleNode("category")?.Value))
                    {
                        decCostMultiplier *= 0.9m;
                    }
                    await nudRating.DoThreadSafeAsync(x =>
                    {
                        while (x.Maximum > x.Minimum &&
                               !xmlAccessory.CheckNuyenRestriction(_objCharacter.Nuyen, decCostMultiplier,
                                                                   x.MaximumAsInt))
                        {
                            --x.Maximum;
                        }
                    });
                }

                await nudRating.DoThreadSafeAsync(x =>
                {
                    x.Enabled = nudRating.Maximum != nudRating.Minimum;
                    x.Visible = true;
                });

                await lblRatingLabel.DoThreadSafeAsync(x => x.Visible = true);

                await lblRatingNALabel.DoThreadSafeAsync(x => x.Visible = false);
            }
            else
            {
                await lblRatingNALabel.DoThreadSafeAsync(x => x.Visible = true);

                await nudRating.DoThreadSafeAsync(x =>
                {
                    x.Enabled = false;
                    x.Visible = false;
                });

                await lblRatingLabel.DoThreadSafeAsync(x => x.Visible = true);
            }

            if (blnUpdateMountComboBoxes)
            {
                string        strDataMounts = xmlAccessory.SelectSingleNode("mount")?.Value;
                List <string> strMounts     = new List <string>(1);
                if (!string.IsNullOrEmpty(strDataMounts))
                {
                    strMounts.AddRange(strDataMounts.SplitNoAlloc('/', StringSplitOptions.RemoveEmptyEntries));
                }

                strMounts.Add("None");

                List <string> strAllowed = new List <string>(_lstAllowedMounts)
                {
                    "None"
                };
                string strSelectedMount = await cboMount.DoThreadSafeFuncAsync(x =>
                {
                    x.Visible = true;
                    x.Items.Clear();
                    foreach (string strCurrentMount in strMounts)
                    {
                        if (!string.IsNullOrEmpty(strCurrentMount))
                        {
                            foreach (string strAllowedMount in strAllowed)
                            {
                                if (strCurrentMount == strAllowedMount)
                                {
                                    x.Items.Add(strCurrentMount);
                                }
                            }
                        }
                    }

                    x.Enabled       = x.Items.Count > 1;
                    x.SelectedIndex = 0;
                    return(x.SelectedItem.ToString());
                });

                await lblMountLabel.DoThreadSafeAsync(x => x.Visible = true);

                List <string> strExtraMounts = new List <string>(1);
                string        strExtraMount  = xmlAccessory.SelectSingleNode("extramount")?.Value;
                if (!string.IsNullOrEmpty(strExtraMount))
                {
                    foreach (string strItem in strExtraMount.SplitNoAlloc('/', StringSplitOptions.RemoveEmptyEntries))
                    {
                        strExtraMounts.Add(strItem);
                    }
                }

                strExtraMounts.Add("None");

                await cboExtraMount.DoThreadSafeFuncAsync(x =>
                {
                    x.Items.Clear();
                    foreach (string strCurrentMount in strExtraMounts)
                    {
                        if (!string.IsNullOrEmpty(strCurrentMount))
                        {
                            foreach (string strAllowedMount in strAllowed)
                            {
                                if (strCurrentMount == strAllowedMount)
                                {
                                    x.Items.Add(strCurrentMount);
                                }
                            }
                        }
                    }

                    x.Enabled       = x.Items.Count > 1;
                    x.SelectedIndex = 0;
                    if (strSelectedMount != "None" && x.SelectedItem.ToString() != "None" &&
                        strSelectedMount == x.SelectedItem.ToString())
                    {
                        ++x.SelectedIndex;
                    }
                    x.Visible = x.Enabled && x.SelectedItem.ToString() != "None";
                    return(x.Visible);
                }).ContinueWith(y => lblExtraMountLabel.DoThreadSafeAsync(x => x.Visible = y.Result)).Unwrap();
            }

            int intRating = await nudRating.DoThreadSafeFuncAsync(x => x.ValueAsInt);

            // Avail.
            // If avail contains "F" or "R", remove it from the string so we can use the expression.
            string strAvail
                = new AvailabilityValue(intRating, xmlAccessory.SelectSingleNode("avail")?.Value)
                  .ToString();
            await lblAvail.DoThreadSafeAsync(x => x.Text = strAvail);

            await lblAvailLabel.DoThreadSafeAsync(x => x.Visible = !string.IsNullOrEmpty(strAvail));

            if (!await chkFreeItem.DoThreadSafeFuncAsync(x => x.Checked))
            {
                string strCost = "0";
                if (xmlAccessory.TryGetStringFieldQuickly("cost", ref strCost))
                {
                    strCost = (await strCost.CheapReplaceAsync("Weapon Cost",
                                                               () => _objParentWeapon.OwnCost.ToString(GlobalSettings.InvariantCultureInfo))
                               .CheapReplaceAsync("Weapon Total Cost",
                                                  () => _objParentWeapon.MultipliableCost(null)
                                                  .ToString(GlobalSettings.InvariantCultureInfo)))
                              .Replace("Rating", intRating.ToString(GlobalSettings.CultureInfo));
                }
                if (strCost.StartsWith("Variable(", StringComparison.Ordinal))
                {
                    decimal decMin;
                    decimal decMax = decimal.MaxValue;
                    strCost = strCost.TrimStartOnce("Variable(", true).TrimEndOnce(')');
                    if (strCost.Contains('-'))
                    {
                        string[] strValues = strCost.Split('-');
                        decimal.TryParse(strValues[0], NumberStyles.Any, GlobalSettings.InvariantCultureInfo, out decMin);
                        decimal.TryParse(strValues[1], NumberStyles.Any, GlobalSettings.InvariantCultureInfo, out decMax);
                    }
                    else
                    {
                        decimal.TryParse(strCost.FastEscape('+'), NumberStyles.Any, GlobalSettings.InvariantCultureInfo, out decMin);
                    }

                    if (decMax == decimal.MaxValue)
                    {
                        await lblCost.DoThreadSafeAsync(
                            x => x.Text = decMin.ToString(_objCharacter.Settings.NuyenFormat,
                                                          GlobalSettings.CultureInfo) + "¥+");
                    }
                    else
                    {
                        string strSpace = await LanguageManager.GetStringAsync("String_Space");

                        await lblCost.DoThreadSafeAsync(
                            x => x.Text = decMin.ToString(_objCharacter.Settings.NuyenFormat,
                                                          GlobalSettings.CultureInfo) + strSpace + '-'
                            + strSpace + decMax.ToString(_objCharacter.Settings.NuyenFormat,
                                                         GlobalSettings.CultureInfo) + '¥');
                    }

                    await lblTest.DoThreadSafeAsync(x => x.Text = _objCharacter.AvailTest(decMax, strAvail));
                }
                else
                {
                    object  objProcess = CommonFunctions.EvaluateInvariantXPath(strCost, out bool blnIsSuccess);
                    decimal decCost    = blnIsSuccess ? Convert.ToDecimal(objProcess, GlobalSettings.InvariantCultureInfo) : 0;

                    // Apply any markup.
                    decCost *= 1 + (await nudMarkup.DoThreadSafeFuncAsync(x => x.Value) / 100.0m);

                    if (await chkBlackMarketDiscount.DoThreadSafeFuncAsync(x => x.Checked))
                    {
                        decCost *= 0.9m;
                    }
                    decCost *= _objParentWeapon.AccessoryMultiplier;
                    if (!string.IsNullOrEmpty(_objParentWeapon.DoubledCostModificationSlots))
                    {
                        string[] astrParentDoubledCostModificationSlots = _objParentWeapon.DoubledCostModificationSlots.Split('/', StringSplitOptions.RemoveEmptyEntries);
                        if (astrParentDoubledCostModificationSlots.Contains(await cboMount.DoThreadSafeFuncAsync(x => x.SelectedItem?.ToString())) ||
                            astrParentDoubledCostModificationSlots.Contains(await cboExtraMount.DoThreadSafeFuncAsync(x => x.SelectedItem?.ToString())))
                        {
                            decCost *= 2;
                        }
                    }

                    await lblCost.DoThreadSafeAsync(x => x.Text = decCost.ToString(_objCharacter.Settings.NuyenFormat, GlobalSettings.CultureInfo) + '¥');

                    await lblTest.DoThreadSafeAsync(x => x.Text = _objCharacter.AvailTest(decCost, strAvail));
                }
            }
            else
            {
                await lblCost.DoThreadSafeAsync(x => x.Text = (0.0m).ToString(_objCharacter.Settings.NuyenFormat, GlobalSettings.CultureInfo) + '¥');

                await lblTest.DoThreadSafeAsync(x => x.Text = _objCharacter.AvailTest(0, strAvail));
            }

            XPathNavigator xmlAccessoryRatingLabel = xmlAccessory.SelectSingleNode("ratinglabel");
            string         strRatingLabel          = xmlAccessoryRatingLabel != null
                ? string.Format(GlobalSettings.CultureInfo, await LanguageManager.GetStringAsync("Label_RatingFormat"),
                                await LanguageManager.GetStringAsync(xmlAccessoryRatingLabel.Value))
                : await LanguageManager.GetStringAsync("Label_Rating");

            await lblRatingLabel.DoThreadSafeAsync(x => x.Text = strRatingLabel);

            await lblCost.DoThreadSafeFuncAsync(x => x.Text)
            .ContinueWith(y => lblCostLabel.DoThreadSafeAsync(x => x.Visible = !string.IsNullOrEmpty(y.Result)))
            .Unwrap();

            await lblTest.DoThreadSafeFuncAsync(x => x.Text)
            .ContinueWith(y => lblTestLabel.DoThreadSafeAsync(x => x.Visible = !string.IsNullOrEmpty(y.Result)))
            .Unwrap();

            await chkBlackMarketDiscount.DoThreadSafeAsync(x =>
            {
                x.Enabled = _blnIsParentWeaponBlackMarketAllowed;
                if (!x.Checked)
                {
                    x.Checked = GlobalSettings.AssumeBlackMarket && _blnIsParentWeaponBlackMarketAllowed;
                }
                else if (!_blnIsParentWeaponBlackMarketAllowed)
                {
                    //Prevent chkBlackMarketDiscount from being checked if the gear category doesn't match.
                    x.Checked = false;
                }
            });

            string strSource = xmlAccessory.SelectSingleNode("source")?.Value ?? await LanguageManager.GetStringAsync("String_Unknown");

            string strPage = (await xmlAccessory.SelectSingleNodeAndCacheExpressionAsync("altpage"))?.Value ?? xmlAccessory.SelectSingleNode("page")?.Value ?? await LanguageManager.GetStringAsync("String_Unknown");

            SourceString objSourceString = await SourceString.GetSourceStringAsync(strSource, strPage, GlobalSettings.Language, GlobalSettings.CultureInfo, _objCharacter);

            await objSourceString.SetControlAsync(lblSource);

            await lblSourceLabel.DoThreadSafeAsync(x => x.Visible = !string.IsNullOrEmpty(objSourceString.ToString()));

            await tlpRight.DoThreadSafeAsync(x => x.Visible = true);
        }