Beispiel #1
0
        private void OnWindow(int windowId)
        {
            try
            {
                GUILayout.BeginVertical();

                // Get all modules of the selected part:
                String                         partTitle              = "";
                Part                           part                   = null;
                KRnDModule                     rndModule              = null;
                List <ModuleEngines>           engineModules          = null;
                ModuleRCS                      rcsModule              = null;
                ModuleReactionWheel            reactionWheelModule    = null;
                ModuleDeployableSolarPanel     solarPanelModule       = null;
                ModuleWheelBase                landingLegModule       = null;
                PartResource                   electricChargeResource = null;
                ModuleGenerator                generatorModule        = null;
                PartModule                     fissionGenerator       = null;
                List <ModuleResourceConverter> converterModules       = null;
                ModuleParachute                parachuteModule        = null;
                List <PartResource>            fuelResources          = null;
                if (selectedPart != null)
                {
                    foreach (AvailablePart aPart in PartLoader.LoadedPartsList)
                    {
                        if (aPart.partPrefab.name == selectedPart.name)
                        {
                            part      = aPart.partPrefab;
                            partTitle = aPart.title;
                            break;
                        }
                    }
                    if (part)
                    {
                        rndModule              = KRnD.getKRnDModule(part);
                        engineModules          = KRnD.getEngineModules(part);
                        rcsModule              = KRnD.getRcsModule(part);
                        reactionWheelModule    = KRnD.getReactionWheelModule(part);
                        solarPanelModule       = KRnD.getSolarPanelModule(part);
                        landingLegModule       = KRnD.getLandingLegModule(part);
                        electricChargeResource = KRnD.getChargeResource(part);
                        generatorModule        = KRnD.getGeneratorModule(part);
                        fissionGenerator       = KRnD.getFissionGeneratorModule(part);
                        converterModules       = KRnD.getConverterModules(part);
                        parachuteModule        = KRnD.getParachuteModule(part);
                        fuelResources          = KRnD.getFuelResources(part);
                    }
                }
                if (!part)
                {
                    // No part selected:
                    GUILayout.BeginArea(new Rect(10, 5, windowStyle.fixedWidth, 20));
                    GUILayout.Label("<b>Kerbal R&D: Select a part to improve</b>", labelStyle);
                    GUILayout.EndArea();
                    GUILayout.EndVertical();
                    GUI.DragWindow();
                    return;
                }
                else if (!rndModule)
                {
                    // Invalid part selected:
                    GUILayout.BeginArea(new Rect(10, 5, windowStyle.fixedWidth, 20));
                    GUILayout.Label("<b>Kerbal R&D: Select a different part to improve</b>", labelStyle);
                    GUILayout.EndArea();
                    GUILayout.EndVertical();
                    GUI.DragWindow();
                    return;
                }

                // Get stats of the current version of the selected part:
                KRnDUpgrade currentUpgrade;
                if (!KRnD.upgrades.TryGetValue(part.name, out currentUpgrade))
                {
                    currentUpgrade = new KRnDUpgrade();
                }
                String currentInfo = getPartInfo(part, currentUpgrade);

                // Create a copy of the part-stats which we can use to mock an upgrade further below:
                KRnDUpgrade nextUpgrade = currentUpgrade.clone();

                // Title:
                GUILayout.BeginArea(new Rect(10, 5, windowStyle.fixedWidth, 20));
                String version = rndModule.getVersion();
                if (version != "")
                {
                    version = " - " + version;
                }
                GUILayout.Label("<b>" + partTitle + version + "</b>", labelStyle);
                GUILayout.EndArea();

                // List with upgrade-options:
                float optionsWidth  = 100;
                float optionsHeight = windowStyle.fixedHeight - 30 - 30 - 20;
                GUILayout.BeginArea(new Rect(10, 30 + 20, optionsWidth, optionsHeight));

                List <String> options = new List <String>();
                options.Add("Dry Mass");
                options.Add("Max Temp");
                if (engineModules != null || rcsModule)
                {
                    options.Add("ISP Vac");
                    options.Add("ISP Atm");
                    options.Add("Fuel Flow");
                }
                if (reactionWheelModule != null)
                {
                    options.Add("Torque");
                }
                if (solarPanelModule != null)
                {
                    options.Add("Charge Rate");
                }
                if (landingLegModule != null)
                {
                    options.Add("Crash Tolerance");
                }
                if (electricChargeResource != null)
                {
                    options.Add("Battery");
                }
                if (fuelResources != null)
                {
                    options.Add("Fuel Pressure");
                }
                if (generatorModule || fissionGenerator)
                {
                    options.Add("Generator");
                }
                if (converterModules != null)
                {
                    options.Add("Converter");
                }
                if (parachuteModule)
                {
                    options.Add("Parachute");
                }
                if (this.selectedUpgradeOption >= options.Count)
                {
                    this.selectedUpgradeOption = 0;
                }
                this.selectedUpgradeOption = GUILayout.SelectionGrid(this.selectedUpgradeOption, options.ToArray(), 1, buttonStyle);
                GUILayout.EndArea();

                String           selectedUpgradeOption = options.ToArray()[this.selectedUpgradeOption];
                int              currentUpgradeCount   = 0;
                int              nextUpgradeCount      = 0;
                int              scienceCost           = 0;
                float            currentImprovement    = 0;
                float            nextImprovement       = 0;
                Func <Part, int> upgradeFunction       = null;
                if (selectedUpgradeOption == "ISP Vac")
                {
                    upgradeFunction     = KRnDGUI.UpgradeIspVac;
                    currentUpgradeCount = currentUpgrade.ispVac;
                    nextUpgradeCount    = ++nextUpgrade.ispVac;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.ispVac_improvement, rndModule.ispVac_improvementScale, currentUpgrade.ispVac);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.ispVac_improvement, rndModule.ispVac_improvementScale, nextUpgrade.ispVac);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.ispVac_scienceCost, rndModule.ispVac_costScale, nextUpgrade.ispVac);
                }
                else if (selectedUpgradeOption == "ISP Atm")
                {
                    upgradeFunction     = KRnDGUI.UpgradeIspAtm;
                    currentUpgradeCount = currentUpgrade.ispAtm;
                    nextUpgradeCount    = ++nextUpgrade.ispAtm;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.ispAtm_improvement, rndModule.ispAtm_improvementScale, currentUpgrade.ispAtm);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.ispAtm_improvement, rndModule.ispAtm_improvementScale, nextUpgrade.ispAtm);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.ispAtm_scienceCost, rndModule.ispAtm_costScale, nextUpgrade.ispAtm);
                }
                else if (selectedUpgradeOption == "Fuel Flow")
                {
                    upgradeFunction     = KRnDGUI.UpgradeFuelFlow;
                    currentUpgradeCount = currentUpgrade.fuelFlow;
                    nextUpgradeCount    = ++nextUpgrade.fuelFlow;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.fuelFlow_improvement, rndModule.fuelFlow_improvementScale, currentUpgrade.fuelFlow);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.fuelFlow_improvement, rndModule.fuelFlow_improvementScale, nextUpgrade.fuelFlow);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.fuelFlow_scienceCost, rndModule.fuelFlow_costScale, nextUpgrade.fuelFlow);
                }
                else if (selectedUpgradeOption == "Dry Mass")
                {
                    upgradeFunction     = KRnDGUI.UpgradeDryMass;
                    currentUpgradeCount = currentUpgrade.dryMass;
                    nextUpgradeCount    = ++nextUpgrade.dryMass;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.dryMass_improvement, rndModule.dryMass_improvementScale, currentUpgrade.dryMass);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.dryMass_improvement, rndModule.dryMass_improvementScale, nextUpgrade.dryMass);

                    // Scale science cost with original mass:
                    PartStats originalStats;
                    if (!KRnD.originalStats.TryGetValue(part.name, out originalStats))
                    {
                        throw new Exception("no original-stats for part '" + part.name + "'");
                    }
                    float scaleReferenceFactor = 1;
                    if (rndModule.dryMass_costScaleReference > 0)
                    {
                        scaleReferenceFactor = originalStats.mass / rndModule.dryMass_costScaleReference;
                    }
                    int scaledCost = (int)Math.Round(rndModule.dryMass_scienceCost * scaleReferenceFactor);
                    if (scaledCost < 1)
                    {
                        scaledCost = 1;
                    }
                    scienceCost = KRnD.calculateScienceCost(scaledCost, rndModule.dryMass_costScale, nextUpgrade.dryMass);
                }
                else if (selectedUpgradeOption == "Torque")
                {
                    upgradeFunction     = KRnDGUI.UpgradeTorque;
                    currentUpgradeCount = currentUpgrade.torque;
                    nextUpgradeCount    = ++nextUpgrade.torque;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.torque_improvement, rndModule.torque_improvementScale, currentUpgrade.torque);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.torque_improvement, rndModule.torque_improvementScale, nextUpgrade.torque);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.torque_scienceCost, rndModule.torque_costScale, nextUpgrade.torque);
                }
                else if (selectedUpgradeOption == "Charge Rate")
                {
                    upgradeFunction     = KRnDGUI.UpgradeChargeRate;
                    currentUpgradeCount = currentUpgrade.chargeRate;
                    nextUpgradeCount    = ++nextUpgrade.chargeRate;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.chargeRate_improvement, rndModule.chargeRate_improvementScale, currentUpgrade.chargeRate);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.chargeRate_improvement, rndModule.chargeRate_improvementScale, nextUpgrade.chargeRate);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.chargeRate_scienceCost, rndModule.chargeRate_costScale, nextUpgrade.chargeRate);
                }
                else if (selectedUpgradeOption == "Crash Tolerance")
                {
                    upgradeFunction     = KRnDGUI.UpgradeCrashTolerance;
                    currentUpgradeCount = currentUpgrade.crashTolerance;
                    nextUpgradeCount    = ++nextUpgrade.crashTolerance;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.crashTolerance_improvement, rndModule.crashTolerance_improvementScale, currentUpgrade.crashTolerance);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.crashTolerance_improvement, rndModule.crashTolerance_improvementScale, nextUpgrade.crashTolerance);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.crashTolerance_scienceCost, rndModule.crashTolerance_costScale, nextUpgrade.crashTolerance);
                }
                else if (selectedUpgradeOption == "Battery")
                {
                    upgradeFunction     = KRnDGUI.UpgradeBatteryCharge;
                    currentUpgradeCount = currentUpgrade.batteryCharge;
                    nextUpgradeCount    = ++nextUpgrade.batteryCharge;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.batteryCharge_improvement, rndModule.batteryCharge_improvementScale, currentUpgrade.batteryCharge);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.batteryCharge_improvement, rndModule.batteryCharge_improvementScale, nextUpgrade.batteryCharge);

                    // Scale science cost with original battery charge:
                    PartStats originalStats;
                    if (!KRnD.originalStats.TryGetValue(part.name, out originalStats))
                    {
                        throw new Exception("no origional-stats for part '" + part.name + "'");
                    }
                    double scaleReferenceFactor = 1;
                    if (rndModule.batteryCharge_costScaleReference > 0)
                    {
                        scaleReferenceFactor = originalStats.batteryCharge / rndModule.batteryCharge_costScaleReference;
                    }
                    int scaledCost = (int)Math.Round(rndModule.batteryCharge_scienceCost * scaleReferenceFactor);
                    if (scaledCost < 1)
                    {
                        scaledCost = 1;
                    }
                    scienceCost = KRnD.calculateScienceCost(scaledCost, rndModule.batteryCharge_costScale, nextUpgrade.batteryCharge);
                }
                else if (selectedUpgradeOption == "Fuel Pressure")
                {
                    upgradeFunction     = KRnDGUI.UpgradeFuelCapacity;
                    currentUpgradeCount = currentUpgrade.fuelCapacity;
                    nextUpgradeCount    = ++nextUpgrade.fuelCapacity;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.fuelCapacity_improvement, rndModule.fuelCapacity_improvementScale, currentUpgrade.fuelCapacity);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.fuelCapacity_improvement, rndModule.fuelCapacity_improvementScale, nextUpgrade.fuelCapacity);

                    // Scale science cost with original fuel capacity:
                    PartStats originalStats;
                    if (!KRnD.originalStats.TryGetValue(part.name, out originalStats))
                    {
                        throw new Exception("no origional-stats for part '" + part.name + "'");
                    }
                    double scaleReferenceFactor = 1;
                    if (rndModule.fuelCapacity_costScaleReference > 0)
                    {
                        scaleReferenceFactor = originalStats.fuelCapacitiesSum / rndModule.fuelCapacity_costScaleReference;
                    }
                    int scaledCost = (int)Math.Round(rndModule.fuelCapacity_scienceCost * scaleReferenceFactor);
                    if (scaledCost < 1)
                    {
                        scaledCost = 1;
                    }
                    scienceCost = KRnD.calculateScienceCost(scaledCost, rndModule.fuelCapacity_costScale, nextUpgrade.fuelCapacity);
                }
                else if (selectedUpgradeOption == "Generator")
                {
                    upgradeFunction     = KRnDGUI.UpgradeGeneratorEfficiency;
                    currentUpgradeCount = currentUpgrade.generatorEfficiency;
                    nextUpgradeCount    = ++nextUpgrade.generatorEfficiency;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.generatorEfficiency_improvement, rndModule.generatorEfficiency_improvementScale, currentUpgrade.generatorEfficiency);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.generatorEfficiency_improvement, rndModule.generatorEfficiency_improvementScale, nextUpgrade.generatorEfficiency);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.generatorEfficiency_scienceCost, rndModule.generatorEfficiency_costScale, nextUpgrade.generatorEfficiency);
                }
                else if (selectedUpgradeOption == "Converter")
                {
                    upgradeFunction     = KRnDGUI.UpgradeConverterEfficiency;
                    currentUpgradeCount = currentUpgrade.converterEfficiency;
                    nextUpgradeCount    = ++nextUpgrade.converterEfficiency;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.converterEfficiency_improvement, rndModule.converterEfficiency_improvementScale, currentUpgrade.converterEfficiency);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.converterEfficiency_improvement, rndModule.converterEfficiency_improvementScale, nextUpgrade.converterEfficiency);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.converterEfficiency_scienceCost, rndModule.converterEfficiency_costScale, nextUpgrade.converterEfficiency);
                }
                else if (selectedUpgradeOption == "Parachute")
                {
                    upgradeFunction     = KRnDGUI.UpgradeParachuteStrength;
                    currentUpgradeCount = currentUpgrade.parachuteStrength;
                    nextUpgradeCount    = ++nextUpgrade.parachuteStrength;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.parachuteStrength_improvement, rndModule.parachuteStrength_improvementScale, currentUpgrade.parachuteStrength);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.parachuteStrength_improvement, rndModule.parachuteStrength_improvementScale, nextUpgrade.parachuteStrength);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.parachuteStrength_scienceCost, rndModule.parachuteStrength_costScale, nextUpgrade.parachuteStrength);
                }
                else if (selectedUpgradeOption == "Max Temp")
                {
                    upgradeFunction     = KRnDGUI.UpgradeMaxTemperature;
                    currentUpgradeCount = currentUpgrade.maxTemperature;
                    nextUpgradeCount    = ++nextUpgrade.maxTemperature;
                    currentImprovement  = KRnD.calculateImprovementFactor(rndModule.maxTemperature_improvement, rndModule.maxTemperature_improvementScale, currentUpgrade.maxTemperature);
                    nextImprovement     = KRnD.calculateImprovementFactor(rndModule.maxTemperature_improvement, rndModule.maxTemperature_improvementScale, nextUpgrade.maxTemperature);
                    scienceCost         = KRnD.calculateScienceCost(rndModule.maxTemperature_scienceCost, rndModule.maxTemperature_costScale, nextUpgrade.maxTemperature);
                }
                else
                {
                    throw new Exception("unexpected option '" + selectedUpgradeOption + "'");
                }
                String newInfo = getPartInfo(part, nextUpgrade); // Calculate part-info if the selected stat was upgraded.
                newInfo = highlightChanges(currentInfo, newInfo);

                // Current stats:
                GUILayout.BeginArea(new Rect(10 + optionsWidth + 10, 30, windowStyle.fixedWidth, 20));
                GUILayout.Label("<color=#FFFFFF><b>Current:</b> " + currentUpgradeCount.ToString() + " (" + currentImprovement.ToString("+0.##%;-0.##%;-") + ")</color>", labelStyle);
                GUILayout.EndArea();

                float areaWidth  = (windowStyle.fixedWidth - 20 - optionsWidth) / 2;
                float areaHeight = optionsHeight;
                GUILayout.BeginArea(new Rect(10 + optionsWidth, 30 + 20, areaWidth, areaHeight));
                scrollPos = GUILayout.BeginScrollView(scrollPos, scrollStyle, GUILayout.Width(areaWidth), GUILayout.Height(areaHeight));

                GUILayout.Label(currentInfo, labelStyleSmall);
                GUILayout.EndScrollView();
                GUILayout.EndArea();

                // Next stats:
                GUILayout.BeginArea(new Rect(10 + optionsWidth + areaWidth + 10, 30, windowStyle.fixedWidth, 20));
                GUILayout.Label("<color=#FFFFFF><b>Next upgrade:</b> " + nextUpgradeCount.ToString() + " (" + nextImprovement.ToString("+0.##%;-0.##%;-") + ")</color>", labelStyle);
                GUILayout.EndArea();

                GUILayout.BeginArea(new Rect(10 + optionsWidth + areaWidth, 30 + 20, areaWidth, areaHeight));
                scrollPos = GUILayout.BeginScrollView(scrollPos, scrollStyle, GUILayout.Width(areaWidth), GUILayout.Height(areaHeight));
                GUILayout.Label(newInfo, labelStyleSmall);
                GUILayout.EndScrollView();
                GUILayout.EndArea();

                // Bottom-line (display only if the upgrade would have an effect):
                if (currentImprovement != nextImprovement)
                {
                    GUILayout.BeginArea(new Rect(10, windowStyle.fixedHeight - 25, windowStyle.fixedWidth, 30));
                    float currentScience = 0;
                    if (ResearchAndDevelopment.Instance != null)
                    {
                        currentScience = ResearchAndDevelopment.Instance.Science;
                    }
                    String color = "FF0000";
                    if (currentScience >= scienceCost)
                    {
                        color = "00FF00";
                    }
                    GUILayout.Label("<b>Science: <color=#" + color + ">" + scienceCost.ToString() + " / " + Math.Floor(currentScience).ToString() + "</color></b>", labelStyle);
                    GUILayout.EndArea();
                    if (currentScience >= scienceCost && ResearchAndDevelopment.Instance != null && upgradeFunction != null)
                    {
                        GUILayout.BeginArea(new Rect(windowStyle.fixedWidth - 110, windowStyle.fixedHeight - 30, 100, 30));
                        if (GUILayout.Button("Research", buttonStyle))
                        {
                            upgradeFunction(part);
                            ResearchAndDevelopment.Instance.AddScience(-scienceCost, TransactionReasons.RnDTechResearch);
                        }
                        GUILayout.EndArea();
                    }
                }

                GUILayout.EndVertical();
                GUI.DragWindow();
            }
            catch (Exception e)
            {
                Debug.LogError("[KRnD] GenerateWindow(): " + e.ToString());
            }
        }
Beispiel #2
0
        public static string GetInfo(Part part)
        {
            float currentImprovement;

            KRnDUpgrade upgrade;

            if (!KRnD.upgrades.TryGetValue(part.name, out upgrade))
            {
                return("none");
            }

            var         rndModule = KRnD.getKRnDModule(part);
            KRnDUpgrade currentUpgrade;

            if (!KRnD.upgrades.TryGetValue(part.name, out currentUpgrade))
            {
                currentUpgrade = new KRnDUpgrade();
            }

            List <string> u = new List <string>();

            if (upgrade.ispVac > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.ispVac_improvement, rndModule.ispVac_improvementScale, currentUpgrade.ispVac);
                u.Add("Vacuum ISP: Level: " + upgrade.ispVac.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.ispAtm > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.ispAtm_improvement, rndModule.ispAtm_improvementScale, currentUpgrade.ispAtm);
                u.Add("ASL ISP: Level: " + upgrade.ispAtm.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.dryMass > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.dryMass_improvement, rndModule.dryMass_improvementScale, currentUpgrade.dryMass);
                u.Add("Dry Mass: Level: " + upgrade.dryMass.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.fuelFlow > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.fuelFlow_improvement, rndModule.fuelFlow_improvementScale, currentUpgrade.fuelFlow);
                u.Add("Fuel Flow: Level: " + upgrade.fuelFlow.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.torque > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.torque_improvement, rndModule.torque_improvementScale, currentUpgrade.torque);
                u.Add("Torque: Level: " + upgrade.torque.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            // WIP
            //if (upgrade.antPower > 0)
            //{
            //    currentImprovement = KRnD.calculateImprovementFactor(rndModule.antPower_improvement, rndModule.antPower_improvementScale, currentUpgrade.antPower);
            //    u.Add("Antenna Power: Level: " + upgrade.antPower.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            //}
            if (upgrade.harvester > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.harvester_improvement, rndModule.harvester_improvementScale, currentUpgrade.harvester);
                u.Add("Drill Efficiency: Level: " + upgrade.harvester.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.radiatorEfficiency > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.radiatorEfficiency_improvement, rndModule.radiatorEfficiency_improvementScale, currentUpgrade.radiatorEfficiency);
                u.Add("Radiator Efficiency: Level: " + upgrade.radiatorEfficiency.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.chargeRate > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.chargeRate_improvement, rndModule.chargeRate_improvementScale, currentUpgrade.chargeRate);
                u.Add("Charge Rate: Level: " + upgrade.chargeRate.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.crashTolerance > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.crashTolerance_improvement, rndModule.crashTolerance_improvementScale, currentUpgrade.crashTolerance);
                u.Add("Crash Tolerance: Level: " + upgrade.crashTolerance.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.batteryCharge > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.batteryCharge_improvement, rndModule.batteryCharge_improvementScale, currentUpgrade.batteryCharge);
                u.Add("Battery Chrg: Level: " + upgrade.batteryCharge.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.generatorEfficiency > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.generatorEfficiency_improvement, rndModule.generatorEfficiency_improvementScale, currentUpgrade.generatorEfficiency);
                u.Add("Generator Eff.: Level: " + upgrade.generatorEfficiency.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.converterEfficiency > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.converterEfficiency_improvement, rndModule.converterEfficiency_improvementScale, currentUpgrade.converterEfficiency);
                u.Add("Converter Efficiency: Level: " + upgrade.converterEfficiency.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.parachuteStrength > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.parachuteStrength_improvement, rndModule.parachuteStrength_improvementScale, currentUpgrade.parachuteStrength);
                u.Add("Chute Strh: Level: " + upgrade.parachuteStrength.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.maxTemperature > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.maxTemperature_improvement, rndModule.maxTemperature_improvementScale, currentUpgrade.maxTemperature);
                u.Add("Max Temp: Level: " + upgrade.maxTemperature.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (upgrade.ispVac > 0)
            {
                currentImprovement = KRnD.calculateImprovementFactor(rndModule.fuelCapacity_improvement, rndModule.fuelCapacity_improvementScale, currentUpgrade.fuelCapacity);
                u.Add("Fuel Capacity: Level: " + upgrade.fuelCapacity.ToString() + ", " + currentImprovement.ToString("+0.##%;-0.##%;-"));
            }
            if (u.Count == 0)
            {
                return("No upgrades applied");
            }


            return(String.Join("\n", u));
        }