/// <summary> /// Creates a new asteroid from the specific asteroid set. The asteroid will be given /// appropriate properties as specified in the set's config node, and added to the game as /// an untracked object. /// </summary> /// <remarks>Based heavily on Kopernicus's <c>DiscoverableObjects.SpawnAsteroid</c> by /// ThomasKerman. Thanks for reverse-engineering everything!</remarks> /// /// <param name="group">The set to which the asteroid belongs.</param> /// <returns>The asteroid that was added.</returns> /// /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot /// generate valid data. The program state will be unchanged in the event of an /// exception.</exception> /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> is /// null.</exception> private ProtoVessel spawnAsteroid(AsteroidSet group) { Orbit orbit = makeOrbit(group); string name = makeName(group); UntrackedObjectClass size = group.drawAsteroidSize(); ConfigNode [] partList = makeAsteroidParts(group); ConfigNode [] extraNodes = new ConfigNode [] { new ConfigNode("ACTIONGROUPS"), makeDiscoveryInfo(group, size), makeVesselModules(group, partList, size), }; // Stock spawner reports its module name, so do the same for custom spawns Debug.Log($"[{GetType ().Name}]: " + Localizer.Format("#autoLOC_CustomAsteroids_LogSpawn", name, group)); ConfigNode vessel = ProtoVessel.CreateVesselNode(name, VesselType.SpaceObject, orbit, 0, partList, extraNodes); ProtoVessel newVessel = HighLogic.CurrentGame.AddVessel(vessel); // For some reason you can always retrieve a CometVessel for any Vessel; check parts instead if (isComet(partList)) { GameEvents.onCometSpawned.Fire(newVessel.vesselRef); } else { GameEvents.onAsteroidSpawned.Fire(newVessel.vesselRef); } return(newVessel); }
/// <summary> /// Generates tracking station info appropriate for the chosen set. /// </summary> /// /// <param name="group">The set to which the asteroid belongs.</param> /// <param name="size">The asteroid's size class.</param> /// <returns>A ConfigNode storing the asteroid's DiscoveryInfo object.</returns> /// /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot /// generate valid data. The program state will be unchanged in the event of an /// exception.</exception> /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> is /// null.</exception> private static ConfigNode makeDiscoveryInfo(AsteroidSet group, UntrackedObjectClass size) { Tuple <double, double> lifetimes = group.drawTrackingTime(); ConfigNode trackingInfo = ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetimes.Item1, lifetimes.Item2); return(trackingInfo); }
private ConfigNode createAnomalyVessel(WBISpaceAnomaly anomaly) { // Generate vessel name string vesselName = DiscoverableObjectsUtil.GenerateAsteroidName(); string prefix = Localizer.Format("#autoLOC_6001923"); prefix = prefix.Replace(" <<1>>", ""); vesselName = vesselName.Replace(prefix, "UNK-"); vesselName = vesselName.Replace("- ", "-"); // Generate orbit Orbit orbit = generateOrbit(anomaly); // Create part nodes ConfigNode[] partNodes = new ConfigNode[] { ProtoVessel.CreatePartNode(anomaly.partName, 0) }; // Determine lifetime double minLifetime = anomaly.minLifetime; double maxLifetime = anomaly.maxLifetime; if (minLifetime < 0) { minLifetime = double.MaxValue; maxLifetime = double.MaxValue; } // Setup object class UntrackedObjectClass objectClass = UntrackedObjectClass.A; Enum.TryParse(anomaly.sizeClass, out objectClass); // Create discovery and additional nodes. ConfigNode discoveryNode = ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Presence, objectClass, minLifetime, maxLifetime); ConfigNode[] additionalNodes = new ConfigNode[] { new ConfigNode("ACTIONGROUPS"), discoveryNode }; // Create vessel node ConfigNode vesselNode = ProtoVessel.CreateVesselNode(vesselName, VesselType.SpaceObject, orbit, 0, partNodes, additionalNodes); // Add vessel node to the game. HighLogic.CurrentGame.AddVessel(vesselNode); // Get vessel ID if (vesselNode.HasValue("persistentId")) { anomaly.vesselId = vesselNode.GetValue("persistentId"); } return(vesselNode); }
/// <summary> /// Generates tracking station info appropriate for the chosen set. /// </summary> /// /// <param name="group">The set to which the asteroid belongs.</param> /// <returns>A ConfigNode storing the asteroid's DiscoveryInfo object.</returns> /// /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot /// generate valid data. The program state will be unchanged in the event of an /// exception.</exception> /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> is /// null.</exception> private static ConfigNode makeDiscoveryInfo(AsteroidSet group) { Pair <float, float> trackTimes = AsteroidManager.getOptions().getUntrackedTimes(); double lifetime = UnityEngine.Random.Range(trackTimes.first, trackTimes.second) * SECONDS_PER_EARTH_DAY; double maxLifetime = trackTimes.second * SECONDS_PER_EARTH_DAY; UntrackedObjectClass size = (UntrackedObjectClass)(int) (stockSizeCurve.Evaluate(UnityEngine.Random.Range(0.0f, 1.0f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length); ConfigNode trackingInfo = ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime); return(trackingInfo); }
public void SpawnAsteroid(Asteroid asteroid, UInt32 seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type Int32 type = Random.Range(0, 3); if (type == 0 && asteroid.Location.Around.Count != 0) { // Around Location.AroundLoader[] around = GetProbabilityList(asteroid.Location.Around, asteroid.Location.Around.Select(a => a.Probability.Value).ToList()).ToArray(); Location.AroundLoader loader = around[Random.Range(0, around.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { referenceBody = body, eccentricity = loader.Eccentricity, semiMajorAxis = loader.SemiMajorAxis, inclination = loader.Inclination, LAN = loader.LongitudeOfAscendingNode, argumentOfPeriapsis = loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = loader.MeanAnomalyAtEpoch, epoch = loader.Epoch }; orbit.Init(); } else if (type == 1 && asteroid.Location.Nearby.Count != 0) { // Nearby Location.NearbyLoader[] nearby = GetProbabilityList(asteroid.Location.Nearby, asteroid.Location.Nearby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.NearbyLoader loader = nearby[Random.Range(0, nearby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { eccentricity = body.orbit.eccentricity + loader.Eccentricity, semiMajorAxis = body.orbit.semiMajorAxis * loader.SemiMajorAxis, inclination = body.orbit.inclination + loader.Inclination, LAN = body.orbit.LAN * loader.LongitudeOfAscendingNode, argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * loader.MeanAnomalyAtEpoch, epoch = body.orbit.epoch, referenceBody = body.orbit.referenceBody }; orbit.Init(); } else if (type == 2 && asteroid.Location.Flyby.Count != 0) { // Flyby Location.FlybyLoader[] flyby = GetProbabilityList(asteroid.Location.Flyby, asteroid.Location.Flyby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.FlybyLoader loader = flyby[Random.Range(0, flyby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(loader.MinDuration, loader.MaxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus] No new objects this time. (Probability is " + asteroid.Probability.Value + "%)"); return; } // Name String asteroidName = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime Double lifetime = Random.Range(asteroid.MinUntrackedLifetime, asteroid.MaxUntrackedLifetime) * 24d * 60d * 60d; Double maxLifetime = asteroid.MaxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)(Int32)(asteroid.Size.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length); // Spawn ConfigNode vessel = null; vessel = ProtoVessel.CreateVesselNode( asteroidName, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.UniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); }
public void SpawnAsteroid(Asteroid asteroid, UInt32 seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type Int32 type = Random.Range(0, 3); if (type == 0 && asteroid.Location.Around.Count != 0) { // Around Location.AroundLoader[] around = GetProbabilityList(asteroid.Location.Around, asteroid.Location.Around.Select(a => a.Probability.Value).ToList()).ToArray(); Location.AroundLoader loader = around[Random.Range(0, around.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { referenceBody = body, eccentricity = loader.Eccentricity, semiMajorAxis = loader.SemiMajorAxis, inclination = loader.Inclination, LAN = loader.LongitudeOfAscendingNode, argumentOfPeriapsis = loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = loader.MeanAnomalyAtEpoch, epoch = loader.Epoch }; orbit.Init(); } else if (type == 1 && asteroid.Location.Nearby.Count != 0) { // Nearby Location.NearbyLoader[] nearby = GetProbabilityList(asteroid.Location.Nearby, asteroid.Location.Nearby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.NearbyLoader loader = nearby[Random.Range(0, nearby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { eccentricity = body.orbit.eccentricity + loader.Eccentricity, semiMajorAxis = body.orbit.semiMajorAxis * loader.SemiMajorAxis, inclination = body.orbit.inclination + loader.Inclination, LAN = body.orbit.LAN * loader.LongitudeOfAscendingNode, argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * loader.MeanAnomalyAtEpoch, epoch = body.orbit.epoch, referenceBody = body.orbit.referenceBody }; orbit.Init(); } else if (type == 2 && asteroid.Location.Flyby.Count != 0) { // Flyby Location.FlybyLoader[] flyby = GetProbabilityList(asteroid.Location.Flyby, asteroid.Location.Flyby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.FlybyLoader loader = flyby[Random.Range(0, flyby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(loader.MinDuration, loader.MaxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus] No new objects this time. (Probability is " + asteroid.Probability.Value + "%)"); return; } // Name String asteroidName = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime Double lifetime = Random.Range(asteroid.MinUntrackedLifetime, asteroid.MaxUntrackedLifetime) * 24d * 60d * 60d; Double maxLifetime = asteroid.MaxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)(Int32)(asteroid.Size.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length); // Spawn ConfigNode vessel = null; #if (KSP_VERSION_1_10_1 || KSP_VERSION_1_11_1) if (Random.Range(0, 100) > RuntimeUtility.KopernicusConfig.CometPercentage) { #endif vessel = ProtoVessel.CreateVesselNode( asteroidName, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.UniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); #if (KSP_VERSION_1_10_1 || KSP_VERSION_1_11_1) } else { float fragmentDynamicPressureModifier = 0f; bool optimizedCollider = false; CometOrbitType cometType = CometManager.GenerateWeightedCometType(); Orbit cometOrbit = cometType.CalculateHomeOrbit(); UntrackedObjectClass randomObjClass = cometType.GetRandomObjClass(); CometDefinition cometDef = CometManager.GenerateDefinition(cometType, randomObjClass, (int)seed); ConfigNode configNode = cometDef.CreateVesselNode(optimizedCollider, fragmentDynamicPressureModifier, hasName: false); ConfigNode configNode2 = ProtoVessel.CreatePartNode("PotatoComet", seed); uint value = 0u; configNode2.TryGetValue("persistentId", ref value); configNode.AddValue("cometPartId", value); ConfigNode configNode3 = new ConfigNode("VESSELMODULES"); configNode3.AddNode(configNode); vessel = ProtoVessel.CreateVesselNode(DiscoverableObjectsUtil.GenerateCometName(), VesselType.SpaceObject, cometOrbit, 0, new ConfigNode[1] { configNode2 }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Presence, randomObjClass, lifetime, maxLifetime), configNode3); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); } #endif }
// Spawn the actual asteroid public void SpawnAsteroid(Asteroid asteroid, uint seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type int type = Random.Range(0, 3); if (type == 0 && asteroid.location.around.Count != 0) { // Around IEnumerable <Location.AroundLoader> arounds = GetProbabilityList(asteroid.location.around, asteroid.location.around.Select(a => a.probability.value)); Location.AroundLoader around = arounds.ElementAt(Random.Range(0, arounds.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == around.body); if (!body) { return; } if (around.reached && !ReachedBody(body)) { return; } orbit = new Orbit(); orbit.referenceBody = body; orbit.eccentricity = around.eccentricity; orbit.semiMajorAxis = around.semiMajorAxis; orbit.inclination = around.inclination; orbit.LAN = around.longitudeOfAscendingNode; orbit.argumentOfPeriapsis = around.argumentOfPeriapsis; orbit.meanAnomalyAtEpoch = around.meanAnomalyAtEpoch; orbit.epoch = around.epoch; orbit.Init(); } else if (type == 1 && asteroid.location.nearby.Count != 0) { // Nearby IEnumerable <Location.NearbyLoader> nearbys = GetProbabilityList(asteroid.location.nearby, asteroid.location.nearby.Select(a => a.probability.value)); Location.NearbyLoader nearby = nearbys.ElementAt(Random.Range(0, nearbys.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == nearby.body); if (!body) { return; } if (nearby.reached && !ReachedBody(body)) { return; } orbit = new Orbit(); orbit.eccentricity = body.orbit.eccentricity + nearby.eccentricity; orbit.semiMajorAxis = body.orbit.semiMajorAxis * nearby.semiMajorAxis; orbit.inclination = body.orbit.inclination + nearby.inclination; orbit.LAN = body.orbit.LAN * nearby.longitudeOfAscendingNode; orbit.argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * nearby.argumentOfPeriapsis; orbit.meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * nearby.meanAnomalyAtEpoch; orbit.epoch = body.orbit.epoch; orbit.referenceBody = body.orbit.referenceBody; orbit.Init(); } else if (type == 2 && asteroid.location.flyby.Count != 0) { // Flyby IEnumerable <Location.FlybyLoader> flybys = GetProbabilityList(asteroid.location.flyby, asteroid.location.flyby.Select(a => a.probability.value)); Location.FlybyLoader flyby = flybys.ElementAt(Random.Range(0, flybys.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == flyby.body); if (!body) { return; } if (flyby.reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(flyby.minDuration, flyby.maxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus]: No new objects this time. (Probablility is " + asteroid.probability.value + "%)"); return; } // Name string name = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime double lifetime = Random.Range(asteroid.minUntrackedLifetime, asteroid.maxUntrackedLifetime) * 24d * 60d * 60d; double maxLifetime = asteroid.maxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)((int)(asteroid.size.curve.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length)); // Spawn ConfigNode vessel = ProtoVessel.CreateVesselNode( name, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed, new ProtoCrewMember[0] ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.uniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus]: New object found near " + body.name + ": " + protoVessel.vesselName + "!"); }
/// <summary> /// Generates any vessel modules needed by a particular asteroid. /// </summary> /// <param name="group">The asteroid group to which the asteroid belongs.</param> /// <param name="partList">The part(s) from which the asteroid is made.</param> /// <param name="size">The asteroid's size class.</param> /// <returns>A <c>VesselModules</c> node containing all vessel modules besides /// the defaults (currently <c>FlightIntegrator</c> and <c>AxisGroupModule</c>).</returns> /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> or <c>partList</c> is /// null.</exception> /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot generate /// valid data, or if <c>partList</c> does not contain exactly one part, or contains an /// unsupported part. The program state will be unchanged in the event of an exception.</exception> private ConfigNode makeVesselModules(AsteroidSet group, ConfigNode[] partList, UntrackedObjectClass size) { if (partList.Length != 1) { throw new InvalidOperationException( Localizer.Format("#autoLOC_CustomAsteroids_ErrorMultiParts", partList)); } ConfigNode wrapper = new ConfigNode("VESSELMODULES"); // CometVessel seems to be removed if there's no ModuleComet, but filter just in case if (isComet(partList)) { string cometType = group.getCometOrbit(); bool cometName = group.getUseCometName(); CometOrbitType stockClass = CometManager.GetCometOrbitType(cometType); if (stockClass is null) { throw new InvalidOperationException(Localizer.Format("#autoLOC_CustomAsteroids_ErrorNoCometType", cometType)); } // As far as I can tell the object class is used to scale the activity level ConfigNode moduleComet = CometManager.GenerateDefinition(stockClass, size, new System.Random().Next()) .CreateVesselNode(false, 0.0f, !cometName); wrapper.AddNode(moduleComet); } return(wrapper); }
/// <summary>Updates the asteroid size</summary> /// /// <param name="size">The asteroid class (A-E)</param> /// public extern void SetUntrackedObjectSize (UntrackedObjectClass size);
/// <summary>Returns asteroid size displayed in map view</summary> /// /// <param name="sizeClass">The asteroid type to label</param> /// /// <returns>The asteroid class printed beneath an untracked asteroid. /// /// <example>"C (Medium)"</example> /// /// If not a valid value of UntrackedObjectClass, returns "???" /// </returns> public static extern string GetSizeClassSizes(UntrackedObjectClass sizeClass);
/// <summary>Returns long description of asteroid type</summary> /// /// <param name="sizeClass">The asteroid type to label</param> /// /// <returns>The asteroid class explanation printed on the tracking station's info panel. /// /// <example>"Class C Objects are about average-sized..."</example> /// /// If not a valid value of UntrackedObjectClass, returns "This seems to be a non-standard size class. Who knows what it'll look like?" /// </returns> public static extern string GetSizeClassDescription(UntrackedObjectClass sizeClass);
/// <summary>Updates the asteroid size</summary> /// /// <param name="size">The asteroid class (A-E)</param> /// public extern void SetUntrackedObjectSize(UntrackedObjectClass size);