private static Planet GeneratePlanet(PlanetSeed seed, int planetNo, ref Star sun, bool useRandomTilt, string planetID, bool isMoon, SystemGenerationOptions genOptions) { var planet = new Planet(seed, sun, planetNo); planet.OrbitZone = Environment.OrbitalZone(sun.Luminosity, planet.SemiMajorAxisAU); planet.OrbitalPeriodDays = Environment.Period(planet.SemiMajorAxisAU, planet.MassSM, sun.Mass); if (useRandomTilt) { planet.AxialTiltDegrees = Environment.Inclination(planet.SemiMajorAxisAU); } planet.ExosphereTempKelvin = GlobalConstants.EARTH_EXOSPHERE_TEMP / Utilities.Pow2(planet.SemiMajorAxisAU / sun.EcosphereRadiusAU); planet.RMSVelocityCMSec = Environment.RMSVelocity(GlobalConstants.MOL_NITROGEN, planet.ExosphereTempKelvin); planet.CoreRadiusKM = Environment.KothariRadius(planet.DustMassSM, false, planet.OrbitZone); // Calculate the radius as a gas giant, to verify it will retain gas. // Then if mass > Earth, it's at least 5% gas and retains He, it's // some flavor of gas giant. planet.DensityGCC = Environment.EmpiricalDensity(planet.MassSM, planet.SemiMajorAxisAU, sun.EcosphereRadiusAU, true); planet.RadiusKM = Environment.VolumeRadius(planet.MassSM, planet.DensityGCC); planet.SurfaceAccelerationCMSec2 = Environment.Acceleration(planet.MassSM, planet.RadiusKM); planet.SurfaceGravityG = Environment.Gravity(planet.SurfaceAccelerationCMSec2); planet.MolecularWeightRetained = Environment.MinMolecularWeight(planet); // Is the planet a gas giant? if (((planet.MassSM * GlobalConstants.SUN_MASS_IN_EARTH_MASSES) > 1.0) && ((planet.GasMassSM / planet.MassSM) > 0.05) && (planet.MolecularWeightRetained <= 4.0)) { if ((planet.GasMassSM / planet.MassSM) < 0.20) { planet.Type = PlanetType.SubSubGasGiant; } else if ((planet.MassSM * GlobalConstants.SUN_MASS_IN_EARTH_MASSES) < 20.0) { planet.Type = PlanetType.SubGasGiant; } else { planet.Type = PlanetType.GasGiant; } } else // If not, it's rocky. { planet.RadiusKM = Environment.KothariRadius(planet.MassSM, false, planet.OrbitZone); planet.DensityGCC = Environment.VolumeDensity(planet.MassSM, planet.RadiusKM); planet.SurfaceAccelerationCMSec2 = Environment.Acceleration(planet.MassSM, planet.RadiusKM); planet.SurfaceGravityG = Environment.Gravity(planet.SurfaceAccelerationCMSec2); if ((planet.GasMassSM / planet.MassSM) > 0.000001) { var h2Mass = planet.GasMassSM * 0.85; var heMass = (planet.GasMassSM - h2Mass) * 0.999; var h2Life = Environment.GasLife(GlobalConstants.MOL_HYDROGEN, planet.ExosphereTempKelvin, planet.SurfaceGravityG, planet.RadiusKM); var heLife = Environment.GasLife(GlobalConstants.HELIUM, planet.ExosphereTempKelvin, planet.SurfaceGravityG, planet.RadiusKM); if (h2Life < sun.AgeYears) { var h2Loss = ((1.0 - (1.0 / Math.Exp(sun.AgeYears / h2Life))) * h2Mass); planet.GasMassSM -= h2Loss; planet.MassSM -= h2Loss; planet.SurfaceAccelerationCMSec2 = Environment.Acceleration(planet.MassSM, planet.RadiusKM); planet.SurfaceGravityG = Environment.Gravity(planet.SurfaceAccelerationCMSec2); } if (heLife < sun.AgeYears) { var heLoss = ((1.0 - (1.0 / Math.Exp(sun.AgeYears / heLife))) * heMass); planet.GasMassSM -= heLoss; planet.MassSM -= heLoss; planet.SurfaceAccelerationCMSec2 = Environment.Acceleration(planet.MassSM, planet.RadiusKM); planet.SurfaceGravityG = Environment.Gravity(planet.SurfaceAccelerationCMSec2); } } } planet.AngularVelocityRadSec = Environment.AngularVelocity(planet); planet.DayLengthHours = Environment.DayLength(planet.AngularVelocityRadSec, planet.OrbitalPeriodDays, planet.Eccentricity); planet.HasResonantPeriod = Environment.HasResonantPeriod(planet.AngularVelocityRadSec, planet.DayLengthHours, planet.OrbitalPeriodDays, planet.Eccentricity); planet.EscapeVelocityCMSec = Environment.EscapeVelocity(planet.MassSM, planet.RadiusKM); planet.HillSphereKM = Environment.SimplifiedHillSphereKM(sun.Mass, planet.MassSM, planet.SemiMajorAxisAU); if (planet.IsGasGiant) { planet.HasGreenhouseEffect = false; planet.VolatileGasInventory = GlobalConstants.INCREDIBLY_LARGE_NUMBER; planet.Atmosphere.SurfacePressure = GlobalConstants.INCREDIBLY_LARGE_NUMBER; planet.BoilingPointWaterKelvin = GlobalConstants.INCREDIBLY_LARGE_NUMBER; planet.SurfaceTempKelvin = GlobalConstants.INCREDIBLY_LARGE_NUMBER; planet.GreenhouseRiseKelvin = 0; planet.Albedo = Utilities.About(GlobalConstants.GAS_GIANT_ALBEDO, 0.1); planet.WaterCoverFraction = 1.0; planet.CloudCoverFraction = 1.0; planet.IceCoverFraction = 0.0; planet.SurfaceGravityG = Environment.Gravity(planet.SurfaceAccelerationCMSec2); planet.MolecularWeightRetained = Environment.MinMolecularWeight(planet); planet.SurfaceGravityG = GlobalConstants.INCREDIBLY_LARGE_NUMBER; } else { planet.SurfaceGravityG = Environment.Gravity(planet.SurfaceAccelerationCMSec2); planet.MolecularWeightRetained = Environment.MinMolecularWeight(planet); planet.HasGreenhouseEffect = Environment.Greenhouse(sun.EcosphereRadiusAU, planet.SemiMajorAxisAU); planet.VolatileGasInventory = Environment.VolatileInventory( planet.MassSM, planet.EscapeVelocityCMSec, planet.RMSVelocityCMSec, sun.Mass, planet.OrbitZone, planet.HasGreenhouseEffect, (planet.GasMassSM / planet.MassSM) > 0.000001); planet.Atmosphere.SurfacePressure = Environment.Pressure( planet.VolatileGasInventory, planet.RadiusKM, planet.SurfaceGravityG); planet.BoilingPointWaterKelvin = Math.Abs(planet.Atmosphere.SurfacePressure) < 0.001 ? 0.0 : Environment.BoilingPoint(planet.Atmosphere.SurfacePressure); // Sets: planet.surf_temp, planet.greenhs_rise, planet.albedo, planet.hydrosphere, // planet.cloud_cover, planet.ice_cover Environment.IterateSurfaceTemp(ref planet); CalculateGases(planet, genOptions.GasTable); planet.IsTidallyLocked = Environment.IsTidallyLocked(planet); // Assign planet type if (planet.Atmosphere.SurfacePressure < 1.0) { if (!isMoon && ((planet.MassSM * GlobalConstants.SUN_MASS_IN_EARTH_MASSES) < GlobalConstants.ASTEROID_MASS_LIMIT)) { planet.Type = PlanetType.Asteroids; } else { planet.Type = PlanetType.Barren; } } else if ((planet.Atmosphere.SurfacePressure > 6000.0) && (planet.MolecularWeightRetained <= 2.0)) // Retains Hydrogen { planet.Type = PlanetType.SubSubGasGiant; planet.Atmosphere.Composition = new List <Gas>(); } else { // Atmospheres: // TODO remove PlanetType enum entirely and replace it with a more flexible classification systme if (planet.WaterCoverFraction >= 0.95) // >95% water { planet.Type = PlanetType.Water; } else if (planet.IceCoverFraction >= 0.95) // >95% ice { planet.Type = PlanetType.Ice; } else if (planet.WaterCoverFraction > 0.05) // Terrestrial { planet.Type = PlanetType.Terrestrial; } else if (planet.MaxTempKelvin > planet.BoilingPointWaterKelvin) // Hot = Venusian { planet.Type = PlanetType.Venusian; } else if ((planet.GasMassSM / planet.MassSM) > 0.0001) // Accreted gas, but no greenhouse or liquid water make it an ice world { planet.Type = PlanetType.Ice; planet.IceCoverFraction = 1.0; } else if (planet.Atmosphere.SurfacePressure <= 250.0) // Thin air = Martian { planet.Type = PlanetType.Martian; } else if (planet.SurfaceTempKelvin < GlobalConstants.FREEZING_POINT_OF_WATER) { planet.Type = PlanetType.Ice; } else { planet.Type = PlanetType.Unknown; } } } // Generate moons planet.Moons = new List <Planet>(); if (!isMoon) { var curMoon = seed.FirstMoon; var n = 0; while (curMoon != null) { if (curMoon.Mass * GlobalConstants.SUN_MASS_IN_EARTH_MASSES > .000001) { curMoon.SemiMajorAxisAU = planet.SemiMajorAxisAU; curMoon.Eccentricity = planet.Eccentricity; n++; string moon_id = String.Format("{0}.{1}", planetID, n); var generatedMoon = GeneratePlanet(curMoon, n, ref sun, useRandomTilt, moon_id, true, genOptions); double roche_limit = 2.44 * planet.RadiusKM * Math.Pow((planet.DensityGCC / generatedMoon.DensityGCC), (1.0 / 3.0)); double hill_sphere = planet.SemiMajorAxisAU * GlobalConstants.KM_PER_AU * Math.Pow((planet.MassSM / (3.0 * sun.Mass)), (1.0 / 3.0)); if ((roche_limit * 3.0) < hill_sphere) { generatedMoon.MoonSemiMajorAxisAU = Utilities.RandomNumber(roche_limit * 1.5, hill_sphere / 2.0) / GlobalConstants.KM_PER_AU; generatedMoon.MoonEccentricity = Utilities.RandomEccentricity(); } else { generatedMoon.MoonSemiMajorAxisAU = 0; generatedMoon.MoonEccentricity = 0; } planet.Moons.Add(generatedMoon); } curMoon = curMoon.NextPlanet; } } return(planet); }