public virtual void SetConfiguration(string newConfiguration = null, bool resetTechLevels = false) { if (newConfiguration == null) newConfiguration = configuration; ConfigSaveLoad(); ConfigNode newConfig = configs.Find (c => c.GetValue ("name").Equals (newConfiguration)); if (!UnlockedConfig(newConfig, part)) { if(newConfig == null) Debug.Log("*RFMEC* ERROR Can't find configuration " + newConfiguration + ", falling back to first tech-available config."); foreach(ConfigNode cfg in configs) if (UnlockedConfig(cfg, part)) { newConfig = cfg; newConfiguration = cfg.GetValue("name"); break; } } if (newConfig != null) { if (configuration != newConfiguration) { if(resetTechLevels) techLevel = origTechLevel; while (techLevel > 0) { if (TechLevel.CanTL(newConfig, techNodes, engineType, techLevel)) break; else --techLevel; } } // for asmi if (useConfigAsTitle) part.partInfo.title = configuration; configuration = newConfiguration; config = new ConfigNode("MODULE"); newConfig.CopyTo(config); config.name = "MODULE"; #if DEBUG print ("replacing " + type + " with:"); print (newConfig.ToString ()); #endif pModule = null; // get correct module pModule = GetSpecifiedModule(part, engineID, moduleIndex, type, useWeakType); if ((object)pModule == null) { Debug.Log("*RFMEC* Could not find appropriate module of type " + type + ", with ID=" + engineID + " and index " + moduleIndex); return; } Type mType = pModule.GetType(); config.SetValue("name", mType.Name); // clear all FloatCurves we need to clear (i.e. if our config has one, or techlevels are enabled) bool delAtmo = config.HasNode("atmosphereCurve") || techLevel >= 0; bool delDens = config.HasNode("atmCurve") || techLevel >= 0; bool delVel = config.HasNode("velCurve") || techLevel >= 0; foreach (FieldInfo field in mType.GetFields()) { if (field.FieldType == typeof(FloatCurve) && ((field.Name.Equals("atmosphereCurve") && delAtmo) || (field.Name.Equals("atmCurve") && delDens) || (field.Name.Equals("velCurve") && delVel))) { field.SetValue(pModule, new FloatCurve()); } } // clear propellant gauges foreach (FieldInfo field in mType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)) { if (field.FieldType == typeof(Dictionary<Propellant, VInfoBox>)) { Dictionary<Propellant, VInfoBox> boxes = (Dictionary<Propellant, VInfoBox>)(field.GetValue(pModule)); if (boxes == null) continue; foreach (VInfoBox v in boxes.Values) { if (v == null) //just in case... continue; try { part.stackIcon.RemoveInfo(v); } catch (Exception e) { Debug.Log("*RFMEC* Trying to remove info box: " + e.Message); } } boxes.Clear(); } } if (type.Equals("ModuleRCS") || type.Equals("ModuleRCSFX")) { ModuleRCS rcs = (ModuleRCS)pModule; if (rcs != null) { DoConfig(config); if (config.HasNode("PROPELLANT")) { rcs.propellants.Clear(); } pModule.Load(config); } } else { // is an ENGINE ModuleEngines mE = (ModuleEngines)pModule; if (mE != null) { if (config.HasNode("PROPELLANT")) { mE.propellants.Clear(); } } DoConfig(config); // Handle Engine Ignitor if (config.HasNode("ModuleEngineIgnitor")) { if (part.Modules.Contains("ModuleEngineIgnitor")) { ConfigNode eiNode = config.GetNode("ModuleEngineIgnitor"); if (eiNode.HasValue("ignitionsAvailable")) { int ignitions; if (int.TryParse(eiNode.GetValue("ignitionsAvailable"), out ignitions)) { ignitions = ConfigIgnitions(ignitions); eiNode.SetValue("ignitionsAvailable", ignitions.ToString()); if (eiNode.HasValue("ignitionsRemained")) eiNode.SetValue("ignitionsRemained", ignitions.ToString()); else eiNode.AddValue("ignitionsRemained", ignitions.ToString()); } } if (!HighLogic.LoadedSceneIsEditor && !(HighLogic.LoadedSceneIsFlight && vessel != null && vessel.situation == Vessel.Situations.PRELAUNCH)) // fix for prelaunch { int remaining = (int)(part.Modules["ModuleEngineIgnitor"].GetType().GetField("ignitionsRemained").GetValue(part.Modules["ModuleEngineIgnitor"])); if (eiNode.HasValue("ignitionsRemained")) eiNode.SetValue("ignitionsRemained", remaining.ToString()); else eiNode.AddValue("ignitionsRemained", remaining.ToString()); } ConfigNode tNode = new ConfigNode("MODULE"); eiNode.CopyTo(tNode); tNode.SetAddValue("name", "ModuleEngineIgnitor"); part.Modules["ModuleEngineIgnitor"].Load(tNode); } else // backwards compatible with EI nodes when using RF ullage etc. { ConfigNode eiNode = config.GetNode("ModuleEngineIgnitor"); if (eiNode.HasValue("ignitionsAvailable") && !config.HasValue("ignitions")) { config.AddValue("ignitions", eiNode.GetValue("ignitionsAvailable")); } if (eiNode.HasValue("useUllageSimulation") && !config.HasValue("ullage")) config.AddValue("ullage", eiNode.GetValue("useUllageSimulation")); if (eiNode.HasValue("isPressureFed") && !config.HasValue("pressureFed")) config.AddValue("pressureFed", eiNode.GetValue("isPressureFed")); if (!config.HasNode("IGNITOR_RESOURCE")) foreach (ConfigNode resNode in eiNode.GetNodes("IGNITOR_RESOURCE")) config.AddNode(resNode); } } if (config.HasValue("ignitions")) { int ignitions; if ((!HighLogic.LoadedSceneIsFlight || (vessel != null && vessel.situation == Vessel.Situations.PRELAUNCH))) { if (int.TryParse(config.GetValue("ignitions"), out ignitions)) { ignitions = ConfigIgnitions(ignitions); config.SetValue("ignitions", ignitions.ToString()); } } else config.RemoveValue("ignitions"); } if (pModule is ModuleEnginesRF) (pModule as ModuleEnginesRF).SetScale(1d); pModule.Load(config); } // fix for editor NaN if (part.Resources.Contains("ElectricCharge") && part.Resources["ElectricCharge"].maxAmount < 0.1) { // hacking around a KSP bug here part.Resources["ElectricCharge"].amount = 0; part.Resources["ElectricCharge"].maxAmount = 0.1; } // set gimbal if (config.HasValue("gimbalRange")) { float newGimbal = float.Parse(config.GetValue("gimbalRange")); for (int m = 0; m < part.Modules.Count; ++m) { if (part.Modules[m] is ModuleGimbal) { ModuleGimbal g = part.Modules[m] as ModuleGimbal; if (gimbalTransform.Equals("") || g.gimbalTransformName.Equals(gimbalTransform)) { g.gimbalRange = newGimbal; break; } } } } if (config.HasValue("cost")) configCost = scale * float.Parse(config.GetValue("cost")); else configCost = 0f; UpdateOtherModules(config); // GUI disabled for now - UpdateTweakableMenu(); // Finally, fire the modified event // more trouble than it is worth... /*if((object)(EditorLogic.fetch) != null && (object)(EditorLogic.fetch.ship) != null && HighLogic.LoadedSceneIsEditor) GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship);*/ // fire config modified event /*if(HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) EngineConfigChanged();*/ // do it manually List<Part> parts; if (HighLogic.LoadedSceneIsEditor && EditorLogic.fetch.ship != null) parts = EditorLogic.fetch.ship.parts; else if (HighLogic.LoadedSceneIsFlight && vessel != null) parts = vessel.parts; else parts = new List<Part>(); for (int i = parts.Count - 1; i >= 0; --i) parts[i].SendMessage("UpdateUsedBy"); SetupFX(); UpdateTFInterops(); // update TestFlight if it's installed if (config.HasValue("description")) configDescription = config.GetValue("description"); else configDescription = ""; } else { Debug.Log("*RFMEC* ERROR could not find configuration of name " + configuration + " and could find no fallback config."); Debug.Log("For part " + part.name + ", Current nodes:" + Utilities.PrintConfigs(configs)); } }
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.SetAddValue(thrustRating, configMaxThrust.ToString("0.0000")); if(configMinThrust >= 0f) cfg.SetAddValue("minThrust", configMinThrust.ToString("0.0000")); // will be ignored by RCS, so what. // heat update if(configHeat >= 0f) cfg.SetAddValue("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")); } }