private void SmoothTangents()
        {
            var   floatCurve = new FloatCurve();
            float x, y, z, w;

            foreach (FloatString4 p in points)
            {
                float.TryParse(p.strings[0], out x);
                float.TryParse(p.strings[1], out y);
                float.TryParse(p.strings[2], out z);
                float.TryParse(p.strings[3], out w);
                floatCurve.Add(x, y);
            }
            for (int i = 0; i < floatCurve.Curve.length; i++)
            {
                floatCurve.Curve.SmoothTangents(i, 0);
            }
            points = new List <FloatString4>();
            ConfigNode node = new ConfigNode();

            floatCurve.Save(node);

            var keys = node.GetValuesList("key");

            foreach (var s in keys)
            {
                var values = s.Split(' ').ToList();
                points.Add(new FloatString4(
                               float.Parse(values[0]),
                               float.Parse(values[1]),
                               float.Parse(values[2]),
                               float.Parse(values[3])));
            }
            curveNeedsUpdate = true;
        }
        public static ConfigNode SerializeFloatCurve(string name, FloatCurve curve)
        {
            ConfigNode node = new ConfigNode();

            curve.Save(node);
            node.name = name;
            return(node);
        }
        void PrintCurve(FloatCurve curve, string name)
        {
            ConfigNode config = new ConfigNode();

            curve.Save(config);
            Debug.Log("AtmosphereTopLayer.PrintCurve", name);
            foreach (string key in config.GetValues("key"))
            {
                Debug.Log("AtmosphereTopLayer.PrintCurve", "key = " + key);
            }
        }
        // Readers

        List <double[]> ReadCurve(FloatCurve curve)
        {
            ConfigNode      config = new ConfigNode();
            List <double[]> list   = new List <double[]>();
            NumericCollectionParser <double> value = new NumericCollectionParser <double>();

            curve.Save(config);

            foreach (string k in config.GetValues("key"))
            {
                value.SetFromString(k);
                list.Add(value.Value.ToArray());
            }

            return(list);
        }
        static FloatCurve ChangeFloatCurve(float changeMult, FloatCurve atmosphereCurve)
        {
            FloatCurve newAtmoCurve = new FloatCurve();
            // First save to a config node.
            ConfigNode node = new ConfigNode();

            atmosphereCurve.Save(node);

            var keys = node.GetValuesList("key");

            foreach (var s in keys)
            {
                var values = s.Split(' ').ToList();
                newAtmoCurve.Add(float.Parse(values[0]), float.Parse(values[1]) * changeMult);
            }
            return(newAtmoCurve);
        }
        public virtual void DoConfig(ConfigNode cfg)
        {
            configMaxThrust = configMinThrust = configHeat = -1f;
            // Get thrusts
            if (config.HasValue(thrustRating))
            {
                float thr;
                if (float.TryParse(config.GetValue(thrustRating), out thr))
                    configMaxThrust = scale * thr;
            }
            if (config.HasValue("minThrust"))
            {
                float thr;
                if (float.TryParse(config.GetValue("minThrust"), out thr))
                    configMinThrust = scale * thr;
            }

            // Get, multiply heat
            if (cfg.HasValue("heatProduction"))
            {
                float heat;
                if(float.TryParse(cfg.GetValue("heatProduction"), out heat))
                    configHeat = (float)Math.Round(heat * RFSettings.Instance.heatMultiplier, 0);
            }

            // load throttle (for later)
            configThrottle = throttle;
            if (cfg.HasValue("throttle"))
                float.TryParse(cfg.GetValue("throttle"), out configThrottle);
            else if (configMinThrust >= 0f && configMaxThrust >= 0f)
                configThrottle = configMinThrust / configMaxThrust;

            float TLMassMult = 1.0f;

            float gimbal = -1f;
            if (cfg.HasValue("gimbalRange"))
                gimbal = float.Parse(cfg.GetValue("gimbalRange"));

            float cost = 0f;
            if (cfg.HasValue("cost"))
                cost = scale * float.Parse(cfg.GetValue("cost"));

            if (techLevel != -1)
            {
                // load techlevels
                TechLevel cTL = new TechLevel();
                cTL.Load(cfg, techNodes, engineType, techLevel);
                TechLevel oTL = new TechLevel();
                oTL.Load(cfg, techNodes, engineType, origTechLevel);

                // set atmosphereCurve
                if (cfg.HasValue("IspSL") && cfg.HasValue("IspV"))
                {
                    cfg.RemoveNode("atmosphereCurve");

                    ConfigNode curve = new ConfigNode("atmosphereCurve");

                    // get the multipliers
                    float ispSL = 1f, ispV = 1f;
                    float.TryParse(cfg.GetValue("IspSL"), out ispSL);
                    float.TryParse(cfg.GetValue("IspV"), out ispV);

                    // Mod the curve by the multipliers
                    FloatCurve newAtmoCurve = new FloatCurve();
                    newAtmoCurve = Utilities.Mod(cTL.AtmosphereCurve, ispSL, ispV);
                    newAtmoCurve.Save(curve);

                    cfg.AddNode(curve);
                }

                // set heatProduction
                if (configHeat > 0)
                {
                    configHeat = MassTL(configHeat);
                }

                // set thrust and throttle
                if (configMaxThrust >= 0)
                {
                    configMaxThrust = ThrustTL(configMaxThrust);
                    if (configMinThrust >= 0)
                    {
                        configMinThrust = ThrustTL(configMinThrust);
                    }
                    else if (thrustRating.Equals("thrusterPower"))
                    {
                        configMinThrust = configMaxThrust * 0.5f;
                    }
                    else
                    {
                        configMinThrust = configMaxThrust;
                        if (configThrottle > 1.0f)
                        {
                            if (techLevel >= configThrottle)
                                configThrottle = 1.0f;
                            else
                                configThrottle = -1.0f;
                        }
                        if (configThrottle >= 0.0f)
                        {
                            configThrottle = (float)((double)configThrottle * cTL.Throttle());
                            configMinThrust *= configThrottle;
                        }
                    }
                    configThrottle = configMinThrust / configMaxThrust;
                    if (origMass > 0)
                        TLMassMult = MassTL(1.0f);
                }
                // Don't want to change gimbals on TL-enabled engines willy-nilly
                // So we don't unless either a transform is specified, or we override.
                // We assume if it was specified in the CONFIG that we should use it anyway.
                if (gimbal < 0 && (!gimbalTransform.Equals("") || useGimbalAnyway))
                    gimbal = cTL.GimbalRange;
                if (gimbal >= 0)
                {
                    // allow local override of gimbal mult
                    if (cfg.HasValue("gimbalMult"))
                        gimbal *= float.Parse(cfg.GetValue("gimbalMult"));
                }

                // Cost (multiplier will be 1.0 if unspecified)
                cost = scale * CostTL(cost, cfg);
            }
            else
            {
                if (cfg.HasValue(thrustRating) && configThrottle > 0f && !cfg.HasValue("minThrust"))
                {
                    configMinThrust = configThrottle * configMaxThrust;
                }
            }

            // Now update the cfg from what we did.
            // thrust updates
            if(configMaxThrust >= 0f)
                cfg.SetValue(thrustRating, configMaxThrust.ToString("0.0000"));
            if(configMinThrust >= 0f)
                cfg.SetValue("minThrust", configMinThrust.ToString("0.0000")); // will be ignored by RCS, so what.

            // heat update
            if(configHeat >= 0f)
                cfg.SetValue("heatProduction", configHeat.ToString("0"));

            // mass change
            if (origMass > 0)
            {
                float ftmp;
                configMassMult = scale;
                if (cfg.HasValue("massMult"))
                    if (float.TryParse(cfg.GetValue("massMult"), out ftmp))
                        configMassMult *= ftmp;

                part.mass = origMass * configMassMult * RFSettings.Instance.EngineMassMultiplier * TLMassMult;
                massDelta = 0;
                if ((object)(part.partInfo) != null)
                    if ((object)(part.partInfo.partPrefab) != null)
                        massDelta = part.mass - part.partInfo.partPrefab.mass;
            }

            // KIDS integration
            if (cfg.HasNode("atmosphereCurve"))
            {
                ConfigNode newCurveNode = new ConfigNode("atmosphereCurve");
                FloatCurve oldCurve = new FloatCurve();
                oldCurve.Load(cfg.GetNode("atmosphereCurve"));
                FloatCurve newCurve = Utilities.Mod(oldCurve, ispSLMult, ispVMult);
                newCurve.Save(newCurveNode);
                cfg.RemoveNode("atmosphereCurve");
                cfg.AddNode(newCurveNode);
            }
            // gimbal change
            if (gimbal >= 0 && !cfg.HasValue("gimbalRange")) // if TL set a gimbal
            {
                // apply module-wide gimbal mult on top of any local ones
                cfg.AddValue("gimbalRange", (gimbal * gimbalMult).ToString("N4"));
            }
            if (cost != 0f)
            {
                if (cfg.HasValue("cost"))
                    cfg.SetValue("cost", cost.ToString("N3"));
                else
                    cfg.AddValue("cost", cost.ToString("N3"));
            }
        }
        public List<float> GetKeysFromFloatCurve(FloatCurve curve)
        {
            try
            {
                ConfigNode myConfigNode = new ConfigNode("CurveNode");
                curve.Save(myConfigNode);

                Debug.Log("Curve data acquired.");
                List<float> result = new List<float>(myConfigNode.values.Count * 2);
                for (int i = 0; i < myConfigNode.values.Count; ++i)
                {
                    string keyValue = myConfigNode.values[i].value;
                    Debug.Log(keyValue);
                    string[] keyValueParts = keyValue.Split(' ');
                    result.Add(Convert.ToSingle(keyValueParts[0]));
                    result.Add(Convert.ToSingle(keyValueParts[1]));
                }
                return result;
            }
            catch (Exception e)
            {
                Debug.Log(e.Message);
                return null;
            }
        }
        public static FloatCurve ModifyCurveKeys(FloatCurve initialCurve, float vacMult, float atmMult, bool extendToZero)
        {
            ConfigNode tempNode = new ConfigNode();

            initialCurve.Save(tempNode);

            string[] keyStrings = tempNode.GetValues("key");

            float maxTime, ispAtMaxTime, secondTime, ispAtSecondTime, maxPressure;
            maxTime = ispAtMaxTime = secondTime = ispAtSecondTime = maxPressure = 0;
            FloatCurve newAtmosphereCurve = new FloatCurve();

            maxTime = initialCurve.maxTime;

            for (int i = 0; i < keyStrings.Length; i++)
            {
                string[] splitKey = keyStrings[i].Split(' ');

                float scalar = vacMult + Convert.ToSingle(splitKey[0]) * (atmMult - vacMult);
                if (!extendToZero)
                    scalar = Mathf.Clamp(scalar, Mathf.Min(atmMult, vacMult), Mathf.Max(atmMult, vacMult));

                if (Convert.ToSingle(splitKey[0]) != 0)
                    newAtmosphereCurve.Add(Convert.ToSingle(splitKey[0]), Convert.ToSingle(splitKey[1]) * scalar, Convert.ToSingle(splitKey[2]) * scalar, Convert.ToSingle(splitKey[3]) * scalar);
                else
                    newAtmosphereCurve.Add(Convert.ToSingle(splitKey[0]), Convert.ToSingle(splitKey[1]) * scalar, 0, 0);

                if (i == keyStrings.Length - 2)
                {
                    secondTime = Convert.ToSingle(splitKey[0]);
                    ispAtSecondTime = Convert.ToSingle(splitKey[1]) * scalar;
                }
            }

            ispAtMaxTime = newAtmosphereCurve.Evaluate(maxTime);

            if (extendToZero && (ispAtSecondTime - ispAtMaxTime) >= 0.0001f)
            {
                maxPressure = maxTime + (0.01f - ispAtMaxTime) / (ispAtSecondTime - ispAtMaxTime) * (secondTime - maxTime);
                newAtmosphereCurve.Add(maxPressure, 0.01f, 0, 0);
            }

            return newAtmosphereCurve;
        }
Beispiel #9
0
        private void HandleVessel(Vessel vessel)
        {
            if (vessel == null)
            {
                return;
            }

            Debug.Log("Strategia: VesselValueImprover.HandleVessel");

            // Check for our trait
            bool needsIncrease = false;

            foreach (ProtoCrewMember pcm in VesselUtil.GetVesselCrew(vessel))
            {
                if (pcm.experienceTrait.Config.Name == trait)
                {
                    needsIncrease = true;
                    break;
                }
            }

            // Find all relevant parts
            foreach (Part p in vessel.parts)
            {
                foreach (PartModule m in p.Modules)
                {
                    switch (attribute)
                    {
                    case Attribute.ISP:
                        ModuleEngines engine = m as ModuleEngines;
                        if (engine != null)
                        {
                            FloatCurve curve = engine.atmosphereCurve;
                            ConfigNode node  = new ConfigNode();
                            curve.Save(node);

                            // Find and adjust the vacuum ISP
                            ConfigNode newNode = new ConfigNode();
                            foreach (ConfigNode.Value pair in node.values)
                            {
                                string[] values = pair.value.Split(new char[] { ' ' });
                                if (values[0] == "0")
                                {
                                    float value    = float.Parse(values[1]);
                                    float oldValue = value;
                                    SetValue(p.partInfo.name + "|" + engine.engineID, needsIncrease, ref value);
                                    values[1] = value.ToString("F1");
                                    newNode.AddValue(pair.name, string.Join(" ", values));
                                    Debug.Log("Setting ISP of " + p + " from " + oldValue + " to " + value);
                                }
                                else
                                {
                                    newNode.AddValue(pair.name, pair.value);
                                }
                            }
                            curve.Load(newNode);
                            engine.realIsp = curve.Evaluate(0);
                        }
                        break;

                    case Attribute.ParachuteDrag:
                        ModuleParachute parachute = m as ModuleParachute;
                        if (parachute != null)
                        {
                            SetValue(p.partName, needsIncrease, ref parachute.fullyDeployedDrag);
                        }
                        break;

                    case Attribute.StrutStrength:
                        CModuleStrut strut = m as CModuleStrut;
                        if (strut != null)
                        {
                            SetValue(p.partName + "_linear", needsIncrease, ref strut.linearStrength);
                            SetValue(p.partName + "_angular", needsIncrease, ref strut.angularStrength);
                        }
                        break;

                    case Attribute.ReactionWheelTorque:
                        ModuleReactionWheel reactionWheel = m as ModuleReactionWheel;
                        if (reactionWheel != null)
                        {
                            SetValue(p.partName + "_pitch", needsIncrease, ref reactionWheel.PitchTorque);
                            SetValue(p.partName + "_yaw", needsIncrease, ref reactionWheel.YawTorque);
                            SetValue(p.partName + "_roll", needsIncrease, ref reactionWheel.RollTorque);
                        }
                        break;
                    }
                }
            }
        }
        // Readers
        List<double[]> ReadCurve(FloatCurve curve)
        {
            ConfigNode config = new ConfigNode();
            List<double[]> list = new List<double[]>();
            NumericCollectionParser<double> value = new NumericCollectionParser<double>();

            curve.Save(config);

            foreach (string k in config.GetValues("key"))
            {
                value.SetFromString(k);
                list.Add(value.value.ToArray());
            }

            return list;
        }
 void PrintCurve(FloatCurve curve, string name)
 {
     ConfigNode config = new ConfigNode();
     curve.Save(config);
     Debug.Log(name);
     foreach (string key in config.GetValues("key"))
     {
         Debug.Log("key = " + key);
     }
 }
 public static FloatCurve Mod(FloatCurve fc, float sMult, float vMult)
 {
     //print("Modding this");
     ConfigNode curve = new ConfigNode("atmosphereCurve");
     fc.Save(curve);
     foreach (ConfigNode.Value k in curve.values)
     {
         string[] val = k.value.Split(' ');
         //print("Got string !" + k.value + ", split into " + val.Count() + " elements");
         float atmo = float.Parse(val[0]);
         float isp = float.Parse(val[1]);
         isp = isp * ((sMult * atmo) + (vMult * (1f - atmo))); // lerp between vac and SL
         val[1] = Math.Round(isp,1).ToString(); // round for neatness
         string newVal = "";
         foreach (string s in val)
             newVal += s + " ";
         k.value = newVal;
     }
     FloatCurve retCurve = new FloatCurve();
     retCurve.Load(curve);
     return retCurve;
 }
        virtual public void DoConfig(ConfigNode cfg)
        {
            // fix propellant ratios to not be rounded
            if (cfg.HasNode("PROPELLANT"))
            {
                foreach (ConfigNode pNode in cfg.GetNodes("PROPELLANT"))
                {
                    if (pNode.HasValue("ratio"))
                    {
                        double dtmp;
                        if (double.TryParse(pNode.GetValue("ratio"), out dtmp))
                            pNode.SetValue("ratio", (dtmp * 100.0).ToString());
                    }
                }
            }
            float heat = -1;
            if (cfg.HasValue("heatProduction")) // ohai amsi: allow heat production to be changed by multiplier
            {
                heat = (float)Math.Round(float.Parse(cfg.GetValue("heatProduction")) * heatMult, 0);
                cfg.SetValue("heatProduction", heat.ToString());
            }

            // load throttle (for later)
            curThrottle = throttle;
            if (cfg.HasValue("throttle"))
                float.TryParse(cfg.GetValue("throttle"), out curThrottle);
            else if(cfg.HasValue("minThrust") && cfg.HasValue("maxThrust"))
                curThrottle = float.Parse(cfg.GetValue("minThrust")) / float.Parse(cfg.GetValue("maxThrust"));
            float TLMassMult = 1.0f;
            if (techLevel != -1)
            {
                // load techlevels
                TechLevel cTL = new TechLevel();
                //print("For engine " + part.name + ", config " + configuration + ", max TL: " + TechLevel.MaxTL(cfg, techNodes, engineType));
                cTL.Load(cfg, techNodes, engineType, techLevel);
                TechLevel oTL = new TechLevel();
                oTL.Load(cfg, techNodes, engineType, origTechLevel);


                // set atmosphereCurve
                if (cfg.HasValue("IspSL") && cfg.HasValue("IspV"))
                {
                    cfg.RemoveNode("atmosphereCurve");
                    ConfigNode curve = new ConfigNode("atmosphereCurve");
                    float ispSL, ispV;
                    float.TryParse(cfg.GetValue("IspSL"), out ispSL);
                    float.TryParse(cfg.GetValue("IspV"), out ispV);
                    FloatCurve aC = new FloatCurve();
                    aC = Mod(cTL.atmosphereCurve, ispSL, ispV);
                    aC.Save(curve);
                    cfg.AddNode(curve);
                }

                // set heatProduction and dissipation
                if (heat > 0)
                {
                    cfg.SetValue("heatProduction", MassTL(heat).ToString("0"));
                    part.heatDissipation = 0.12f / MassTL(1.0f);
                }

                // set thrust and throttle
                if (cfg.HasValue(thrustRating))
                {
                    float thr;
                    float.TryParse(cfg.GetValue(thrustRating), out thr);
                    configMaxThrust = ThrustTL(thr);
                    cfg.SetValue(thrustRating, configMaxThrust.ToString("0.0000"));
                    if (cfg.HasValue("minThrust"))
                    {
                        float.TryParse(cfg.GetValue("minThrust"), out thr);
                        configMinThrust = ThrustTL(thr);
                        cfg.SetValue("minThrust", configMinThrust.ToString("0.0000"));
                    }
                    else
                    {
                        if (thrustRating.Equals("thrusterPower"))
                        {
                            configMinThrust = configMaxThrust * 0.5f;
                        }
                        else
                        {
                            configMinThrust = configMaxThrust;
                            if (curThrottle > 1.0f)
                            {
                                if (techLevel >= curThrottle)
                                    curThrottle = 1.0f;
                                else
                                    curThrottle = -1.0f;
                            }
                            if (curThrottle >= 0.0f)
                            {
                                curThrottle = (float)((double)curThrottle * cTL.Throttle());
                                configMinThrust *= curThrottle;
                            }
                            cfg.SetValue("minThrust", configMinThrust.ToString("0.0000"));
                        }
                    }
                    curThrottle = configMinThrust / configMaxThrust;
                    if(origMass > 0)
                         TLMassMult =  MassTL(1.0f);
                }
            }
            else
            {
                if(cfg.HasValue(thrustRating) && curThrottle > 0f && !cfg.HasValue("minThrust"))
                {
                    configMinThrust = curThrottle * float.Parse(cfg.GetValue(thrustRating));
                    cfg.SetValue("minThrust", configMinThrust.ToString("0.0000"));
                }
            }
            // mass change
            if (origMass > 0)
            {
                float ftmp;
                configMassMult = 1.0f;
                if (cfg.HasValue("massMult"))
                    if (float.TryParse(cfg.GetValue("massMult"), out ftmp))
                        configMassMult = ftmp;

                part.mass = origMass * configMassMult * massMult * TLMassMult;
            }
            // KIDS integration
            if(cfg.HasNode("atmosphereCurve"))
            {
                ConfigNode newCurveNode = new ConfigNode("atmosphereCurve");
                FloatCurve oldCurve = new FloatCurve();
                oldCurve.Load(cfg.GetNode("atmosphereCurve"));
                FloatCurve newCurve = Mod(oldCurve, ispSLMult, ispVMult);
                newCurve.Save(newCurveNode);
                cfg.RemoveNode("atmosphereCurve");
                cfg.AddNode(newCurveNode);
            }
        }
        public virtual void DoConfig(ConfigNode cfg)
        {
            // fix propellant ratios to not be rounded
            if (cfg.HasNode("PROPELLANT"))
            {
                foreach (ConfigNode pNode in cfg.GetNodes("PROPELLANT"))
                {
                    if (pNode.HasValue("ratio"))
                    {
                        double dtmp;
                        if (double.TryParse(pNode.GetValue("ratio"), out dtmp))
                            pNode.SetValue("ratio", (dtmp * 100.0).ToString());
                    }
                }
            }
            float heat = -1;
            if (cfg.HasValue("heatProduction")) // ohai amsi: allow heat production to be changed by multiplier
            {
                heat = (float)Math.Round(float.Parse(cfg.GetValue("heatProduction")) * heatMult, 0);
                cfg.SetValue("heatProduction", heat.ToString());
            }

            // load throttle (for later)
            curThrottle = throttle;
            if (cfg.HasValue("throttle"))
                float.TryParse(cfg.GetValue("throttle"), out curThrottle);
            else if(cfg.HasValue("minThrust") && cfg.HasValue("maxThrust"))
                curThrottle = float.Parse(cfg.GetValue("minThrust")) / float.Parse(cfg.GetValue("maxThrust"));
            float TLMassMult = 1.0f;

            float gimbal = -1f;
            if (cfg.HasValue("gimbalRange"))
                gimbal = float.Parse(cfg.GetValue("gimbalRange"));

            float cost = 0f;
            if(cfg.HasValue("cost"))
                cost = float.Parse(cfg.GetValue("cost"));

            if (techLevel != -1)
            {
                // load techlevels
                TechLevel cTL = new TechLevel();
                //print("For engine " + part.name + ", config " + configuration + ", max TL: " + TechLevel.MaxTL(cfg, techNodes, engineType));
                cTL.Load(cfg, techNodes, engineType, techLevel);
                TechLevel oTL = new TechLevel();
                oTL.Load(cfg, techNodes, engineType, origTechLevel);

                // set atmosphereCurve
                if (cfg.HasValue("IspSL") && cfg.HasValue("IspV"))
                {
                    cfg.RemoveNode("atmosphereCurve");
                    ConfigNode curve = new ConfigNode("atmosphereCurve");
                    float ispSL, ispV;
                    float.TryParse(cfg.GetValue("IspSL"), out ispSL);
                    float.TryParse(cfg.GetValue("IspV"), out ispV);
                    FloatCurve aC = new FloatCurve();
                    aC = Mod(cTL.AtmosphereCurve, ispSL, ispV);
                    aC.Save(curve);
                    cfg.AddNode(curve);
                }

                // set heatProduction and dissipation
                if (heat > 0)
                {
                    cfg.SetValue("heatProduction", MassTL(heat).ToString("0"));
                    part.heatDissipation = 0.12f / MassTL(1.0f);
                }

                // set thrust and throttle
                if (cfg.HasValue(thrustRating))
                {
                    float thr;
                    float.TryParse(cfg.GetValue(thrustRating), out thr);
                    configMaxThrust = ThrustTL(thr);
                    cfg.SetValue(thrustRating, configMaxThrust.ToString("0.0000"));
                    if (cfg.HasValue("minThrust"))
                    {
                        float.TryParse(cfg.GetValue("minThrust"), out thr);
                        configMinThrust = ThrustTL(thr);
                        cfg.SetValue("minThrust", configMinThrust.ToString("0.0000"));
                    }
                    else
                    {
                        if (thrustRating.Equals("thrusterPower"))
                        {
                            configMinThrust = configMaxThrust * 0.5f;
                        }
                        else
                        {
                            configMinThrust = configMaxThrust;
                            if (curThrottle > 1.0f)
                            {
                                if (techLevel >= curThrottle)
                                    curThrottle = 1.0f;
                                else
                                    curThrottle = -1.0f;
                            }
                            if (curThrottle >= 0.0f)
                            {
                                curThrottle = (float)((double)curThrottle * cTL.Throttle());
                                configMinThrust *= curThrottle;
                            }
                            cfg.SetValue("minThrust", configMinThrust.ToString("0.0000"));
                        }
                    }
                    curThrottle = configMinThrust / configMaxThrust;
                    if(origMass > 0)
                         TLMassMult =  MassTL(1.0f);
                }
                // Don't want to change gimbals on TL-enabled engines willy-nilly
                // So we don't unless either a transform is specified, or we override.
                // We assume if it was specified in the CONFIG that we should use it anyway.
                if (gimbal < 0 && (!gimbalTransform.Equals("") || useGimbalAnyway))
                    gimbal = cTL.GimbalRange;
                if (gimbal >= 0)
                {
                    // allow local override of gimbal mult
                    if (cfg.HasValue("gimbalMult"))
                        gimbal *= float.Parse(cfg.GetValue("gimbalMult"));
                }

                // Cost (multiplier will be 1.0 if unspecified)
                cost = CostTL(cost, cfg);
            }
            else
            {
                if(cfg.HasValue(thrustRating) && curThrottle > 0f && !cfg.HasValue("minThrust"))
                {
                    configMinThrust = curThrottle * float.Parse(cfg.GetValue(thrustRating));
                    cfg.SetValue("minThrust", configMinThrust.ToString("0.0000"));
                }
            }
            // mass change
            if (origMass > 0)
            {
                float ftmp;
                configMassMult = 1.0f;
                if (cfg.HasValue("massMult"))
                    if (float.TryParse(cfg.GetValue("massMult"), out ftmp))
                        configMassMult = ftmp;

                part.mass = origMass * configMassMult * massMult * TLMassMult;
                massDelta = 0;
                if((object)(part.partInfo) != null)
                    if((object)(part.partInfo.partPrefab) != null)
                        massDelta = part.mass - part.partInfo.partPrefab.mass;
            }
            // KIDS integration
            if(cfg.HasNode("atmosphereCurve"))
            {
                ConfigNode newCurveNode = new ConfigNode("atmosphereCurve");
                FloatCurve oldCurve = new FloatCurve();
                oldCurve.Load(cfg.GetNode("atmosphereCurve"));
                FloatCurve newCurve = Mod(oldCurve, ispSLMult, ispVMult);
                newCurve.Save(newCurveNode);
                cfg.RemoveNode("atmosphereCurve");
                cfg.AddNode(newCurveNode);
            }
            // gimbal change
            if (gimbal >= 0 && !cfg.HasValue("gimbalRange")) // if TL set a gimbal
            {
                // apply module-wide gimbal mult on top of any local ones
                cfg.AddValue("gimbalRange", (gimbal * gimbalMult).ToString("N4"));
            }
            if (cost != 0f)
            {
                if (cfg.HasValue("cost"))
                    cfg.SetValue("cost", cost.ToString("N3"));
                else
                    cfg.AddValue("cost", cost.ToString("N3"));
            }
        }