예제 #1
0
        public static PadConstructionStorageItem MigrateFromOldFacilityUpgrade(KSCItem kscItem, FacilityUpgradeStorageItem old)
        {
            var res = new PadConstructionStorageItem
            {
                launchpadID      = old.launchpadID,
                name             = old.commonName,
                progress         = old.progress,
                BP               = old.BP,
                cost             = old.cost,
                upgradeProcessed = old.UpgradeProcessed
            };

            kscItem.LaunchPads[res.launchpadID].level           = old.upgradeLevel;
            kscItem.LaunchPads[res.launchpadID].fractionalLevel = old.upgradeLevel;

            return(res);
        }
예제 #2
0
        private void TryMigrateStockKSC()
        {
            KSCItem stockKsc = KCTGameStates.KSCs.Find(k => string.Equals(k.KSCName, Utilities._legacyDefaultKscId, StringComparison.OrdinalIgnoreCase));

            if (KCTGameStates.KSCs.Count == 1)
            {
                // Rename the stock KSC to the new default (Cape)
                stockKsc.KSCName = Utilities._defaultKscId;
                Utilities.SetActiveKSC(stockKsc.KSCName);
                return;
            }

            if (stockKsc.IsEmpty)
            {
                // Nothing provisioned into the stock KSC so it's safe to just delete it
                KCTGameStates.KSCs.Remove(stockKsc);
                Utilities.SetActiveKSCToRSS();
                return;
            }

            int numOtherUsedKSCs = KCTGameStates.KSCs.Count(k => !k.IsEmpty && k != stockKsc);

            if (numOtherUsedKSCs == 0)
            {
                string  kscName    = Utilities.GetActiveRSSKSC() ?? Utilities._defaultKscId;
                KSCItem newDefault = KCTGameStates.KSCs.Find(k => string.Equals(k.KSCName, kscName, StringComparison.OrdinalIgnoreCase));
                if (newDefault != null)
                {
                    // Stock KSC isn't empty but the new default one is - safe to rename the stock and remove the old default item
                    stockKsc.KSCName = newDefault.KSCName;
                    KCTGameStates.KSCs.Remove(newDefault);
                    Utilities.SetActiveKSC(stockKsc);
                    return;
                }
            }

            // Can't really do anything if there's multiple KSCs in use.
            if (!Utilities.IsKSCSwitcherInstalled)
            {
                // Need to switch back to the legacy "Stock" KSC if KSCSwitcher isn't installed
                Utilities.SetActiveKSC(stockKsc.KSCName);
            }
        }
예제 #3
0
        public static double ParseBuildRateFormula(BuildListVessel.ListType type, int index, KSCItem KSC, int upgradeDelta)
        {
            //N = num upgrades, I = rate index, L = VAB/SPH upgrade level, R = R&D level
            int level = 0, upgrades = 0;
            var variables = new Dictionary <string, string>();

            if (PresetManager.Instance.ActivePreset.GeneralSettings.CommonBuildLine)
            {
                level = Utilities.GetBuildingUpgradeLevel(SpaceCenterFacility.VehicleAssemblyBuilding);
                if (KSC.VABUpgrades.Count > index)
                {
                    upgrades  = KSC.VABUpgrades[index];
                    upgrades += KSC.SPHUpgrades.Count > index ? KSC.SPHUpgrades[index] : 0;
                }
            }
            else
            {
                if (type == BuildListVessel.ListType.VAB)
                {
                    level = Utilities.GetBuildingUpgradeLevel(SpaceCenterFacility.VehicleAssemblyBuilding);
                    if (KSC.VABUpgrades.Count > index)
                    {
                        upgrades = KSC.VABUpgrades[index];
                    }
                }
                else if (type == BuildListVessel.ListType.SPH)
                {
                    level = Utilities.GetBuildingUpgradeLevel(SpaceCenterFacility.SpaceplaneHangar);
                    if (KSC.SPHUpgrades.Count > index)
                    {
                        upgrades = KSC.SPHUpgrades[index];
                    }
                }
            }
            upgrades += upgradeDelta;
            variables.Add("L", level.ToString());
            variables.Add("LM", level.ToString());
            variables.Add("N", upgrades.ToString());
            variables.Add("I", index.ToString());
            variables.Add("R", Utilities.GetBuildingUpgradeLevel(SpaceCenterFacility.ResearchAndDevelopment).ToString());
            int numNodes = 0;

            if (ResearchAndDevelopment.Instance != null)
            {
                numNodes = ResearchAndDevelopment.Instance.snapshot.GetData().GetNodes("Tech").Length;
            }
            variables.Add("S", numNodes.ToString());

            AddCrewVariables(variables);

            return(GetStandardFormulaValue("BuildRate", variables));
        }
예제 #4
0
 public static double ParseBuildRateFormula(BuildListVessel.ListType type, int index, KSCItem KSC, bool UpgradedRates = false)
 {
     return(ParseBuildRateFormula(type, index, KSC, UpgradedRates ? 1 : 0));
 }
예제 #5
0
        public static double CalculateBuildTime(double cost, SpaceCenterFacility?facilityType, KSCItem KSC = null)
        {
            double bp        = CalculateBP(cost, facilityType);
            double rateTotal = Utilities.GetBothBuildRateSum(KSC ?? KCTGameStates.ActiveKSC);

            return(bp / rateTotal);
        }
예제 #6
0
        public override void OnLoad(ConfigNode node)
        {
            base.OnLoad(node);
            LoadTree();

            if (Utilities.CurrentGameIsMission())
            {
                return;
            }

            KCTDebug.Log("Reading from persistence.");
            KCTGameStates.KSCs.Clear();
            KCTGameStates.ActiveKSC = null;
            KCTGameStates.InitAndClearTechList();
            KCTGameStates.TechUpgradesTotal = 0;
            KCTGameStates.SciPointsTotal    = -1;
            KCT_GUI.ResetUpgradePointCounts();

            var        kctVS = new KCT_DataStorage();
            ConfigNode cn    = node.GetNode(kctVS.GetType().Name);

            if (cn != null)
            {
                ConfigNode.LoadObjectFromConfig(kctVS, cn);
            }

            bool foundStockKSC = false;

            foreach (ConfigNode ksc in node.GetNodes("KSC"))
            {
                string name       = ksc.GetValue("KSCName");
                var    loaded_KSC = new KSCItem(name);
                loaded_KSC.FromConfigNode(ksc);
                if (loaded_KSC != null && loaded_KSC.KSCName != null && loaded_KSC.KSCName.Length > 0)
                {
                    loaded_KSC.RDUpgrades[1] = KCTGameStates.TechUpgradesTotal;
                    if (KCTGameStates.KSCs.Find(k => k.KSCName == loaded_KSC.KSCName) == null)
                    {
                        KCTGameStates.KSCs.Add(loaded_KSC);
                    }
                    foundStockKSC |= string.Equals(loaded_KSC.KSCName, Utilities._legacyDefaultKscId, StringComparison.OrdinalIgnoreCase);
                }
            }

            Utilities.SetActiveKSCToRSS();
            if (foundStockKSC)
            {
                TryMigrateStockKSC();
            }

            var protoTechNodes      = new Dictionary <string, ProtoTechNode>(); // list of all the protoTechNodes that have been researched
            var inDevProtoTechNodes = new Dictionary <string, ProtoTechNode>(); // list of all the protoTechNodes that are being researched

            // get the TechList node containing the TechItems with the tech nodes currently being researched from KCT's ConfigNode
            if (node.GetNode("TechList") is ConfigNode tmp)
            {
                foreach (ConfigNode techNode in tmp.GetNodes("Tech"))
                {
                    var techStorageItem = new KCT_TechStorageItem();
                    ConfigNode.LoadObjectFromConfig(techStorageItem, techNode);
                    TechItem techItem = techStorageItem.ToTechItem();
                    techItem.ProtoNode = new ProtoTechNode(techNode.GetNode("ProtoNode"));
                    KCTGameStates.TechList.Add(techItem);

                    // save proto nodes that are in development
                    inDevProtoTechNodes.Add(techItem.ProtoNode.techID, techItem.ProtoNode);
                }
            }

            if (HighLogic.LoadedSceneIsEditor)
            {
                // get the nodes that have been researched from ResearchAndDevelopment
                protoTechNodes = Utilities.GetUnlockedProtoTechNodes();
                // iterate through all loaded parts to check if any of them should be experimental
                foreach (AvailablePart ap in PartLoader.LoadedPartsList)
                {
                    if (Utilities.PartIsUnlockedButNotPurchased(protoTechNodes, ap) || inDevProtoTechNodes.ContainsKey(ap.TechRequired))
                    {
                        Utilities.AddExperimentalPart(ap);
                    }
                }
            }

            KCTGameStates.ErroredDuringOnLoad.OnLoadFinish();
        }
예제 #7
0
        private static void DrawUpgradeWindow(int windowID)
        {
            int oldByModifier = _buyModifier;

            if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
            {
                _buyModifier = 5;
            }
            else if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
            {
                _buyModifier = 100;
            }
            else if (Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt))
            {
                _buyModifier = -1;
            }
            else
            {
                _buyModifier = 1;
            }

            bool isCostCacheInvalid = _buyModifier != oldByModifier;

            GUILayout.BeginVertical();
            GUILayout.BeginHorizontal();
            GUILayout.Label("Total Points:", GUILayout.Width(90));
            GUILayout.Label(TotalPoints.ToString());
            GUILayout.Label($"Available: {AvailablePoints}");
            GUILayout.EndHorizontal();

            bool combineSphAndVab = PresetManager.Instance.ActivePreset.GeneralSettings.CommonBuildLine;
            int  vabPoints        = Utilities.GetSpentUpgradesFor(SpaceCenterFacility.VehicleAssemblyBuilding);
            int  sphPoints        = Utilities.GetSpentUpgradesFor(SpaceCenterFacility.SpaceplaneHangar);

            if (combineSphAndVab)
            {
                vabPoints += sphPoints;
            }

            GUILayout.BeginHorizontal();
            GUILayout.Label("Points in VAB:", GUILayout.Width(90));
            GUILayout.Label(vabPoints.ToString());
            GUILayout.EndHorizontal();

            if (!combineSphAndVab)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("Points in SPH:", GUILayout.Width(90));
                GUILayout.Label(sphPoints.ToString());
                GUILayout.EndHorizontal();
            }

            GUILayout.BeginHorizontal();
            GUILayout.Label("Points in R&D:", GUILayout.Width(90));
            GUILayout.Label(Utilities.GetSpentUpgradesFor(SpaceCenterFacility.ResearchAndDevelopment).ToString());
            GUILayout.EndHorizontal();

            if (!string.IsNullOrEmpty(PresetManager.Instance.ActivePreset.FormulaSettings.UpgradesForScience) &&
                KCTGameStates.SciPointsTotal >= 0)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("Total science:", GUILayout.Width(90));
                GUILayout.Label(((int)KCTGameStates.SciPointsTotal).ToString());
                GUILayout.EndHorizontal();
            }

            if (Utilities.CurrentGameIsCareer())
            {
                if (_fundsCost == int.MinValue || isCostCacheInvalid)
                {
                    _fundsDelta = _buyModifier;
                    _fundsCost  = CalcPointCost(ref _fundsDelta, Funding.Instance.Funds, "UpgradeFunds", 1);
                }
                if (_fundsCost >= 0)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(_fundsDelta > 1 ? $"Buy {_fundsDelta} Points: " : "Buy 1 Point: ");
                    bool     canAfford = Funding.Instance.Funds >= _fundsCost;
                    GUIStyle style     = canAfford ? GUI.skin.button : GetCannotAffordStyle();
                    if (GUILayout.Button($"{Math.Round(_fundsCost, 0)} Funds", style, GUILayout.ExpandWidth(false)) && canAfford)
                    {
                        Utilities.SpendFunds(_fundsCost, TransactionReasons.None);
                        KCTGameStates.PurchasedUpgrades[1] += _fundsDelta;

                        _fundsCost = _spentPoints = _totalPoints = int.MinValue;
                    }
                    GUILayout.EndHorizontal();
                }
            }

            RenderPointResetSection();

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("VAB"))
            {
                _upgradeWindowHolder = 0; _upgradePosition.height = 1;
            }
            if (!combineSphAndVab && GUILayout.Button("SPH"))
            {
                _upgradeWindowHolder = 1; _upgradePosition.height = 1;
            }
            if (Utilities.CurrentGameHasScience() && GUILayout.Button("R&D"))
            {
                _upgradeWindowHolder = 2; _upgradePosition.height = 1;
            }
            GUILayout.EndHorizontal();

            KSCItem KSC = KCTGameStates.ActiveKSC;

            if (_upgradeWindowHolder == 0)    //VAB
            {
                RenderBuildRateSection(BuildListVessel.ListType.VAB, KSC);
            }

            if (_upgradeWindowHolder == 1)    //SPH
            {
                RenderBuildRateSection(BuildListVessel.ListType.SPH, KSC);
            }

            if (_upgradeWindowHolder == 2)    //R&D
            {
                RenderRnDSection(isCostCacheInvalid, KSC);
            }

            if (GUILayout.Button("Close"))
            {
                GUIStates.ShowUpgradeWindow = false;
                if (!IsPrimarilyDisabled)
                {
                    KCTGameStates.ToolbarControl?.SetTrue();
                    GUIStates.ShowBuildList = true;
                }
            }
            GUILayout.EndVertical();
            if (!Input.GetMouseButtonDown(1) && !Input.GetMouseButtonDown(2))
            {
                GUI.DragWindow();
            }
        }
예제 #8
0
        private static void RenderRnDSection(bool isCostCacheInvalid, KSCItem KSC)
        {
            if (Config == null)
            {
                Config = new LRTRHomeWorldParameters();
                foreach (ConfigNode stg in GameDatabase.Instance.GetConfigNodes("HOMEWORLDPARAMETERS"))
                {
                    Config.Load(stg);
                }
            }
            double secondsPerDay = Config.hoursPerDay * 3600;

            int labelDelta = _buyModifier < 0 ? AvailablePoints : _buyModifier;

            GUILayout.BeginHorizontal();
            GUILayout.Label("R&D Upgrades");
            GUILayout.Label($"+{labelDelta} Point{(labelDelta == 1 ? "" : "s")}", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();

            if (_researchRate == int.MinValue || isCostCacheInvalid)
            {
                _researchDelta = _buyModifier < 0 ? AvailablePoints : _buyModifier;
                var variables = new Dictionary <string, string>()
                {
                    { "N", KSC.RDUpgrades[0].ToString() },
                    { "R", Utilities.GetBuildingUpgradeLevel(SpaceCenterFacility.ResearchAndDevelopment).ToString() }
                };
                MathParser.AddCrewVariables(variables);
                _researchRate = MathParser.GetStandardFormulaValue("Research", variables);

                variables["N"]  = (KSC.RDUpgrades[0] + _researchDelta).ToString();
                _upResearchRate = MathParser.GetStandardFormulaValue("Research", variables);
            }

            if (_researchRate >= 0)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label("Research");
                GUILayout.Label($"{Math.Round(_researchRate * secondsPerDay, 2)} sci/{secondsPerDay} BP");
                if (AvailablePoints > 0)
                {
                    bool     canAfford = AvailablePoints >= _researchDelta;
                    GUIStyle style     = canAfford ? GUI.skin.button : GetCannotAffordStyle();
                    if (GUILayout.Button($"+{Math.Round((_upResearchRate - _researchRate) * secondsPerDay, 2)}", style, GUILayout.Width(45)) && canAfford)
                    {
                        KSC.RDUpgrades[0] += _researchDelta;
                        _researchRate      = int.MinValue;
                        _fundsCost         = _spentPoints = _totalPoints = int.MinValue;
                    }
                }
                GUILayout.EndHorizontal();
            }

            double days = GameSettings.KERBIN_TIME ? 4 : 1;

            if (_nodeRate == int.MinValue || isCostCacheInvalid)
            {
                _nodeDelta  = _buyModifier < 0 ? AvailablePoints : _buyModifier;
                _nodeRate   = MathParser.ParseNodeRateFormula(0);
                _upNodeRate = MathParser.ParseNodeRateFormula(0, 0, _nodeDelta);
            }

            double sci       = secondsPerDay * _nodeRate;
            double sciPerDay = sci / days;

            GUILayout.BeginHorizontal();
            GUILayout.Label("Rate");
            bool usingPerYear = false;

            if (sciPerDay > 0.1)
            {
                GUILayout.Label(Math.Round(sciPerDay * 1000) / 1000 + " sci/day");
            }
            else
            {
                //Well, looks like we need sci/year instead
                GUILayout.Label(Math.Round(sciPerDay * Config.daysPerYear * 1000) / 1000 + " sci/yr");
                usingPerYear = true;
            }
            if (_upNodeRate != _nodeRate && AvailablePoints > 0)
            {
                bool everyKSCCanUpgrade = true;
                foreach (KSCItem ksc in KCTGameStates.KSCs)
                {
                    if (TotalPoints - Utilities.GetTotalSpentUpgrades(ksc) <= 0)
                    {
                        everyKSCCanUpgrade = false;
                        break;
                    }
                }
                if (everyKSCCanUpgrade)
                {
                    double upSciPerDay = secondsPerDay * _upNodeRate / days;
                    string buttonText  = $"{Math.Round(1000 * upSciPerDay) / 1000} sci/day";
                    if (usingPerYear)
                    {
                        buttonText = $"{Math.Round(upSciPerDay * Config.daysPerYear * 1000) / 1000} sci/yr";
                    }
                    bool     canAfford = AvailablePoints >= _nodeDelta;
                    GUIStyle style     = canAfford ? GUI.skin.button : GetCannotAffordStyle();
                    if (GUILayout.Button(buttonText, style, GUILayout.ExpandWidth(false)) && canAfford)
                    {
                        KCTGameStates.TechUpgradesTotal += _nodeDelta;
                        foreach (KSCItem ksc in KCTGameStates.KSCs)
                        {
                            ksc.RDUpgrades[1] = KCTGameStates.TechUpgradesTotal;
                        }

                        _nodeRate  = _upNodeRate = int.MinValue;
                        _fundsCost = _spentPoints = _totalPoints = int.MinValue;

                        foreach (TechItem tech in KCTGameStates.TechList)
                        {
                            tech.UpdateBuildRate(KCTGameStates.TechList.IndexOf(tech));
                        }
                    }
                }
            }
            GUILayout.EndHorizontal();
        }
예제 #9
0
        private static void RenderBuildRateSection(BuildListVessel.ListType type, KSCItem KSC)
        {
            List <int>    upgrades = type == BuildListVessel.ListType.VAB ? KSC.VABUpgrades : KSC.SPHUpgrades;
            List <double> rates    = type == BuildListVessel.ListType.VAB ? KSC.VABRates : KSC.SPHRates;

            GUILayout.BeginHorizontal();
            GUILayout.Label(type.ToString() + " Upgrades");
            GUILayout.Label($"+{(_buyModifier < 0 ? "MAX" : _buyModifier.ToString())} Point{(_buyModifier == 1 ? "" : "s")}", GUILayout.ExpandWidth(false));
            GUILayout.EndHorizontal();
            _scrollPos = GUILayout.BeginScrollView(_scrollPos, GUILayout.Height((upgrades.Count + 1) * 26 + 5), GUILayout.MaxHeight(1 * Screen.height / 4));
            GUILayout.BeginVertical();
            for (int i = 0; i < rates.Count; i++)
            {
                int pointsDelta = _buyModifier;
                if (pointsDelta < 0)
                {
                    if (i == 0)
                    {
                        pointsDelta = AvailablePoints;
                    }
                    else if (i > rates.Count)
                    {
                        pointsDelta = 0;
                    }
                    else
                    {
                        pointsDelta = 1;
                        while (pointsDelta < AvailablePoints && Utilities.GetBuildRate(i, type, KSC, pointsDelta + 1) <= rates[i - 1])
                        {
                            pointsDelta++;
                        }
                    }
                }
                double rate          = Utilities.GetBuildRate(i, type, KSC);
                double upgraded      = Utilities.GetBuildRate(i, type, KSC, true);
                double deltaUpgraded = Utilities.GetBuildRate(i, type, KSC, pointsDelta);
                GUILayout.BeginHorizontal();
                GUILayout.Label($"Rate {i + 1}");
                GUILayout.Label($"{rate} BP/s");
                if (AvailablePoints > 0 && (i == 0 || upgraded <= Utilities.GetBuildRate(i - 1, type, KSC)) && upgraded - rate > 0)
                {
                    bool     canAfford = AvailablePoints >= pointsDelta && (i == 0 || deltaUpgraded <= Utilities.GetBuildRate(i - 1, type, KSC));
                    GUIStyle style     = canAfford ? GUI.skin.button : GetCannotAffordStyle();
                    if (GUILayout.Button($"+{Math.Round(deltaUpgraded - rate, 3)}", style, GUILayout.Width(55)) && canAfford)
                    {
                        if (i >= upgrades.Count)
                        {
                            upgrades.Add(pointsDelta);
                        }
                        else
                        {
                            upgrades[i] += pointsDelta;
                        }

                        KSC.RecalculateBuildRates();
                        KSC.RecalculateUpgradedBuildRates();
                        _fundsCost = _spentPoints = _totalPoints = int.MinValue;
                    }
                }
                GUILayout.EndHorizontal();
            }

            GUILayout.EndVertical();
            GUILayout.EndScrollView();
        }
예제 #10
0
        public override void OnLoad(ConfigNode node)
        {
            try
            {
                base.OnLoad(node);
                LoadTree();

                if (Utilities.CurrentGameIsMission())
                {
                    return;
                }

                KCTDebug.Log("Reading from persistence.");
                KCTGameStates.KSCs.Clear();
                KCTGameStates.ActiveKSC = null;
                KCTGameStates.InitAndClearTechList();
                KCTGameStates.TechUpgradesTotal = 0;
                KCTGameStates.SciPointsTotal    = -1;
                KCT_GUI.ResetUpgradePointCounts();

                var kctVS = new KCT_DataStorage();
                if (node.GetNode(kctVS.GetType().Name) is ConfigNode cn)
                {
                    ConfigNode.LoadObjectFromConfig(kctVS, cn);
                }

                bool foundStockKSC = false;
                foreach (ConfigNode ksc in node.GetNodes("KSC"))
                {
                    string name       = ksc.GetValue("KSCName");
                    var    loaded_KSC = new KSCItem(name);
                    loaded_KSC.FromConfigNode(ksc);
                    if (loaded_KSC?.KSCName?.Length > 0)
                    {
                        loaded_KSC.RDUpgrades[1] = KCTGameStates.TechUpgradesTotal;
                        if (KCTGameStates.KSCs.Find(k => k.KSCName == loaded_KSC.KSCName) == null)
                        {
                            KCTGameStates.KSCs.Add(loaded_KSC);
                        }
                        foundStockKSC |= string.Equals(loaded_KSC.KSCName, Utilities._legacyDefaultKscId, StringComparison.OrdinalIgnoreCase);
                    }
                }

                Utilities.SetActiveKSCToRSS();
                if (foundStockKSC)
                {
                    TryMigrateStockKSC();
                }

                var protoTechNodes      = new Dictionary <string, ProtoTechNode>(); // list of all the protoTechNodes that have been researched
                var inDevProtoTechNodes = new Dictionary <string, ProtoTechNode>(); // list of all the protoTechNodes that are being researched

                // get the TechList node containing the TechItems with the tech nodes currently being researched from KCT's ConfigNode
                if (node.GetNode("TechList") is ConfigNode tmp)
                {
                    foreach (ConfigNode techNode in tmp.GetNodes("Tech"))
                    {
                        var techStorageItem = new KCT_TechStorageItem();
                        ConfigNode.LoadObjectFromConfig(techStorageItem, techNode);
                        TechItem techItem = techStorageItem.ToTechItem();
                        techItem.ProtoNode = new ProtoTechNode(techNode.GetNode("ProtoNode"));
                        KCTGameStates.TechList.Add(techItem);

                        // save proto nodes that are in development
                        inDevProtoTechNodes.Add(techItem.ProtoNode.techID, techItem.ProtoNode);
                    }
                }
                if (HighLogic.LoadedSceneIsEditor)
                {
                    // get the nodes that have been researched from ResearchAndDevelopment
                    protoTechNodes = Utilities.GetUnlockedProtoTechNodes();
                    // iterate through all loaded parts to check if any of them should be experimental
                    foreach (AvailablePart ap in PartLoader.LoadedPartsList)
                    {
                        if (Utilities.PartIsUnlockedButNotPurchased(protoTechNodes, ap) || inDevProtoTechNodes.ContainsKey(ap.TechRequired))
                        {
                            Utilities.AddExperimentalPart(ap);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                KCTGameStates.ErroredDuringOnLoad = true;
                Debug.LogError("[KCT] ERROR! An error while KCT loading data occurred. Things will be seriously broken!");
                PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "errorPopup", "Error Loading KCT Data", "ERROR! An error occurred while loading KCT data. Things will be seriously broken! Please report this error to LRTR GitHub and attach the log file. The game will be UNPLAYABLE in this state!", "Understood", false, HighLogic.UISkin);
            }
        }