/// <summary> /// Gets the orbit of this body around the sun. /// </summary> /// <returns>If the Sun, returns <c>null</c>. If a planet, returns its orbit. If a moon, /// returns its planet's orbit.</returns> /// <param name="body">The object whose motion around the Sun is desired.</param> private static Orbit getHeliocentricOrbit(CelestialBody body) { if (body.GetOrbitDriver() == null) { return(null); } else { Orbit orbit = body.GetOrbit(); Orbit parentOrbit = getHeliocentricOrbit(orbit.referenceBody); if (parentOrbit == null) { return(orbit); } else { return(parentOrbit); } } }
/// <summary> /// Returns the desired property of a known celestial body. /// </summary> /// /// <param name="planet">The exact, case-sensitive name of the celestial body. Assumes all /// loaded celestial bodies have unique names.</param> /// <param name="property">The short name of the property to recover. Must be one /// of ("rad", "soi", "sma", "per", "apo", "ecc", "inc", "ape", "lan", "mna0", "mnl0", /// "prot", "psun", "porb", "vesc", "vorb", "vmin", or "vmax"). /// The only properties supported for Sun are "rad", "soi", "prot", and "vesc".</param> /// <returns>The value of <c>property</c> appropriate for <c>planet</c>. Distances are given /// in meters, angles are given in degrees.</returns> /// /// <exception cref="ArgumentException">Thrown if no planet named <c>name</c> exists, or if /// <c>property</c> does not have one of the allowed values. The program state shapp remain /// unchanged in the event of an exception.</exception> protected static double getPlanetProperty(string planet, string property) { CelestialBody body = AsteroidManager.getPlanetByName(planet); switch (property.ToLower()) { case "rad": return(body.Radius); case "soi": return(body.sphereOfInfluence); case "prot": return(body.rotates ? body.rotationPeriod : double.PositiveInfinity); case "psol": if (body.solarRotationPeriod) { return(body.solarDayLength); } else { throw new ArgumentException( Localizer.Format("#autoLOC_CustomAsteroids_ErrorPlanetNoDay", planet), nameof(property)); } case "vesc": return(Math.Sqrt(2 * body.gravParameter / body.Radius)); default: if (body.GetOrbitDriver() == null) { throw new ArgumentException( Localizer.Format("#autoLOC_CustomAsteroids_ErrorPlanetNoOrbit", planet), nameof(planet)); } Orbit orbit = body.GetOrbit(); switch (property.ToLower()) { case "sma": return(orbit.semiMajorAxis); case "per": return(orbit.PeR); case "apo": return(orbit.ApR); case "ecc": return(orbit.eccentricity); case "inc": return(orbit.inclination); case "ape": return(orbit.argumentOfPeriapsis); case "lpe": // Ignore inclination: http://en.wikipedia.org/wiki/Longitude_of_periapsis return(orbit.LAN + orbit.argumentOfPeriapsis); case "lan": return(orbit.LAN); case "mna0": return(meanAnomalyAtUT(orbit, 0.0) * 180.0 / Math.PI); case "mnl0": return(anomalyToLong(meanAnomalyAtUT(orbit, 0.0) * 180.0 / Math.PI, orbit.inclination, orbit.argumentOfPeriapsis, orbit.LAN)); case "porb": return(orbit.period); case "vorb": // Need circumference of an ellipse; closed form does not exist double sum = orbit.semiMajorAxis + orbit.semiMinorAxis; double diff = orbit.semiMajorAxis - orbit.semiMinorAxis; double h = diff * diff / (sum * sum); double correction = 1.0; for (int n = 1; n < 10; n++) { double coeff = Util.DoubleFactorial(2 * n - 1) / (Math.Pow(2, n) * Util.Factorial(n)) / (2 * n - 1); correction += coeff * coeff * Math.Pow(h, n); } return(Math.PI * sum * correction / orbit.period); case "vmin": return(orbit.getOrbitalSpeedAtDistance(orbit.ApR)); case "vmax": return(orbit.getOrbitalSpeedAtDistance(orbit.PeR)); default: throw new ArgumentException( Localizer.Format("#autoLOC_CustomAsteroids_ErrorPlanetBadProperty", property), nameof(property)); } } }
private IEnumerator<YieldInstruction> LoadCB(ConfigNode node, CelestialBody body) { bool updateMass = false; //OnGui(); #region CBChanges print("Fixing CB " + node.name + " of radius " + body.Radius); guiMinor = "CelestialBody"; //OnGui(); double origRadius = body.Radius; double origAtmo = body.maxAtmosphereAltitude; #region CBMassRadius node.TryGetValue("bodyName", ref body.bodyName); node.TryGetValue("bodyDescription", ref body.bodyDescription); if (node.TryGetValue("Radius", ref body.Radius)) updateMass = true; print("Radius ratio: " + body.Radius / origRadius); if (node.TryGetValue("Mass", ref body.Mass)) { MassToOthers(body); } if (node.TryGetValue("GeeASL", ref body.GeeASL)) { GeeASLToOthers(body); updateMass = false; } if (node.TryGetValue("gravParameter", ref body.gravParameter)) { GravParamToOthers(body); updateMass = false; } #endregion #region CBAtmosphereTemperature node.TryGetValue("atmosphericAmbientColor", ref body.atmosphericAmbientColor); node.TryGetValue("atmosphere", ref body.atmosphere); node.TryGetValue("atmosphereScaleHeight", ref body.atmosphereScaleHeight); node.TryGetValue("atmosphereMultiplier", ref body.atmosphereMultiplier); node.TryGetValue("maxAtmosphereAltitude", ref body.maxAtmosphereAltitude); node.TryGetValue("staticPressureASL", ref body.staticPressureASL); node.TryGetValue("useLegacyAtmosphere", ref body.useLegacyAtmosphere); if (!body.useLegacyAtmosphere) { ConfigNode PCnode = node.GetNode("pressureCurve"); if (PCnode != null) { body.altitudeMultiplier = 1f; body.pressureMultiplier = 1f; AnimationCurve pressureCurve = Utils.LoadAnimationCurve(PCnode); if (pressureCurve != null) body.pressureCurve = pressureCurve; else { body.useLegacyAtmosphere = true; Debug.LogWarning("Unable to load pressureCurve data for " + body.name + ": Using legacy atmosphere"); } print("*RSS* finished with " + body.GetName() + ".pressureCurve (" + body.pressureCurve.keys.Length.ToString() + " keys)"); } else { print("*RSS* useLegacyAtmosphere = False but pressureCurve not found!"); } } if (node.HasNode("temperatureCurve")) { ConfigNode TCnode = node.GetNode("temperatureCurve"); if (TCnode != null) { AnimationCurve temperatureCurve = Utils.LoadAnimationCurve(TCnode); if (temperatureCurve != null) { body.temperatureCurve = temperatureCurve; // Following two lines corrects situations where planets without atmosphere's have these two fields zeroed out // Maybe think about making these configurable in the planet's config node? yes? no? meh? body.atmoshpereTemperatureMultiplier = 1f; body.altitudeMultiplier = 1f; print("*RSS* found and loaded temperatureCurve data for " + body.name); } } } #endregion #region CBRotation node.TryGetValue("rotationPeriod", ref body.rotationPeriod); node.TryGetValue("tidallyLocked", ref body.tidallyLocked); node.TryGetValue("initialRotation", ref body.initialRotation); node.TryGetValue("inverseRotation", ref body.inverseRotation); #endregion if (updateMass) GeeASLToOthers(body); /*if (node.HasValue("axialTilt")) { if (!body.inverseRotation && double.TryParse(node.GetValue("axialTilt"), out dtmp)) { CBRotationFixer.CBRotations.Add(body.name, new CBRotation(body.name, dtmp, body.rotationPeriod, body.initialRotation)); body.rotationPeriod = 0; } }*/ yield return null; #region CBOrbit ConfigNode onode = node.GetNode("Orbit"); if (body.orbitDriver != null && body.orbit != null && onode != null) { if (loadInfo.useEpoch) body.orbit.epoch = loadInfo.epoch; onode.TryGetValue("semiMajorAxis", ref body.orbit.semiMajorAxis); onode.TryGetValue("eccentricity", ref body.orbit.eccentricity); onode.TryGetValue("meanAnomalyAtEpoch", ref body.orbit.meanAnomalyAtEpoch); if (onode.TryGetValue("meanAnomalyAtEpochD", ref body.orbit.meanAnomalyAtEpoch)) body.orbit.meanAnomalyAtEpoch *= DEG2RAD; onode.TryGetValue("inclination", ref body.orbit.inclination); onode.TryGetValue("period", ref body.orbit.period); onode.TryGetValue("LAN", ref body.orbit.LAN); onode.TryGetValue("argumentOfPeriapsis", ref body.orbit.argumentOfPeriapsis); if (onode.HasValue("orbitColor")) { try { Vector4 col = KSPUtil.ParseVector4(onode.GetValue("orbitColor")); Color c = new Color(col.x, col.y, col.z, col.w); body.GetOrbitDriver().orbitColor = c; } catch (Exception e) { print("*RSS* Error parsing as color4: original text: " + onode.GetValue("orbitColor") + " --- exception " + e.Message); } } string bodyname = ""; if (onode.TryGetValue("referenceBody", ref bodyname)) { if (body.orbit.referenceBody == null || !body.orbit.referenceBody.Equals(bodyname)) { foreach (CelestialBody b in FlightGlobals.Bodies) { if (b.name.Equals(bodyname)) { if (body.orbit.referenceBody) { body.orbit.referenceBody.orbitingBodies.Remove(body); } b.orbitingBodies.Add(body); body.orbit.referenceBody = b; break; } } } } } yield return null; // SOI and HillSphere done at end body.CBUpdate(); #endregion #endregion #region SSPQSFade // Scaled space fader float SSFMult = 1.0f; float SSFStart = -1, SSFEnd = -1; node.TryGetValue("SSFStart", ref SSFStart); node.TryGetValue("SSFEnd", ref SSFEnd); node.TryGetValue("SSFMult", ref SSFMult); foreach (ScaledSpaceFader ssf in Resources.FindObjectsOfTypeAll(typeof(ScaledSpaceFader))) { if (ssf.celestialBody != null) { if (ssf.celestialBody.name.Equals(node.name)) { if (SSFStart >= 0) ssf.fadeStart = SSFStart; else ssf.fadeStart *= SSFMult; if (SSFEnd >= 0) ssf.fadeEnd = SSFEnd; else ssf.fadeEnd *= SSFMult; } } } // The CBT that fades out the PQS // Should probably do this as just another PQSMod, actually. foreach (PQSMod_CelestialBodyTransform c in Resources.FindObjectsOfTypeAll(typeof(PQSMod_CelestialBodyTransform))) { try { if (c.body != null) { if (c.body.name.Equals(node.name)) { print("Found CBT for " + node.name); node.TryGetValue("PQSdeactivateAltitude", ref c.deactivateAltitude); if (c.planetFade != null) { node.TryGetValue("PQSfadeStart", ref c.planetFade.fadeStart); node.TryGetValue("PQSfadeEnd", ref c.planetFade.fadeEnd); if (c.secondaryFades != null) { foreach (PQSMod_CelestialBodyTransform.AltitudeFade af in c.secondaryFades) { node.TryGetValue("PQSSecfadeStart", ref af.fadeStart); node.TryGetValue("PQSSecfadeEnd", ref af.fadeEnd); } } } } } } catch (Exception e) { print("CBT fix for " + node.name + " failed: " + e.Message); } } print("Did CBT for " + node.name); yield return null; #endregion #region Science // Science if (node.HasNode("CelestialBodyScienceParams")) { guiMinor = "Science"; //OnGui(); ConfigNode spNode = node.GetNode("CelestialBodyScienceParams"); if (body.scienceValues != null) { foreach (ConfigNode.Value val in spNode.values) { // meh, for now hard-code it. Saves worry of GIGO. /*if(body.scienceValues.GetType().GetField(val.name) != null) if(float.TryParse(val.value, out ftmp)) body.scienceValues.GetType().GetField(val.name).SetValue(*/ spNode.TryGetValue("LandedDataValue", ref body.scienceValues.LandedDataValue); spNode.TryGetValue("SplashedDataValue", ref body.scienceValues.SplashedDataValue); spNode.TryGetValue("FlyingLowDataValue", ref body.scienceValues.FlyingLowDataValue); spNode.TryGetValue("FlyingHighDataValue", ref body.scienceValues.FlyingHighDataValue); spNode.TryGetValue("InSpaceLowDataValue", ref body.scienceValues.InSpaceLowDataValue); spNode.TryGetValue("InSpaceHighDataValue", ref body.scienceValues.InSpaceHighDataValue); spNode.TryGetValue("RecoveryValue", ref body.scienceValues.RecoveryValue); spNode.TryGetValue("flyingAltitudeThreshold", ref body.scienceValues.flyingAltitudeThreshold); spNode.TryGetValue("spaceAltitudeThreshold", ref body.scienceValues.spaceAltitudeThreshold); } } guiMinor = ""; //OnGui(); } yield return null; #endregion }