private void GenerateStrandedKerbal(int bodyID, string kerbalName)
        {
            //Add kerbal to crew roster.
            DarkLog.Debug("Spawning missing kerbal, name: " + kerbalName);
            ProtoCrewMember pcm = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned);

            pcm.name         = kerbalName;
            pcm.rosterStatus = ProtoCrewMember.RosterStatus.Assigned;
            //Create protovessel
            uint          newPartID    = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);
            CelestialBody contractBody = FlightGlobals.Bodies[bodyID];
            //Atmo: 10km above atmo, to half the planets radius out.
            //Non-atmo: 30km above ground, to half the planets radius out.
            double minAltitude   = FinePrint.Utilities.CelestialUtilities.GetMinimumOrbitalAltitude(contractBody, 1.1f);
            double maxAltitude   = minAltitude + contractBody.Radius * 0.5;
            Orbit  strandedOrbit = Orbit.CreateRandomOrbitAround(FlightGlobals.Bodies[bodyID], minAltitude, maxAltitude);

            ConfigNode[]      kerbalPartNode = new ConfigNode[1];
            ProtoCrewMember[] partCrew       = new ProtoCrewMember[1];
            partCrew[0]       = pcm;
            kerbalPartNode[0] = ProtoVessel.CreatePartNode("kerbalEVA", newPartID, partCrew);
            ConfigNode  protoVesselNode = ProtoVessel.CreateVesselNode(kerbalName, VesselType.EVA, strandedOrbit, 0, kerbalPartNode);
            ConfigNode  discoveryNode   = ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, double.PositiveInfinity, double.PositiveInfinity);
            ProtoVessel protoVessel     = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame);

            protoVessel.discoveryInfo = discoveryNode;
            //It's not supposed to be infinite, but you're crazy if you think I'm going to decipher the values field of the rescue node.
            HighLogic.CurrentGame.flightState.protoVessels.Add(protoVessel);
        }
Esempio n. 2
0
        /// <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);
        }
Esempio n. 3
0
        protected override void OnAccepted()
        {
            // Actually spawn the kerbals in the game world!
            foreach (KerbalData kerbal in kerbals)
            {
                LoggingUtil.LogVerbose(this, "Spawning a Kerbal named " + kerbal.name);

                if (kerbal.altitude == null)
                {
                    kerbal.altitude = LocationUtil.TerrainHeight(kerbal.latitude, kerbal.longitude, kerbal.body);
                }

                // Set additional info for landed kerbals
                if (kerbal.landed)
                {
                    Vector3d pos = kerbal.body.GetWorldSurfacePosition(kerbal.latitude, kerbal.longitude, kerbal.altitude.Value);

                    kerbal.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, kerbal.body);
                    kerbal.orbit.UpdateFromStateVectors(pos, kerbal.body.getRFrmVel(pos), kerbal.body, Planetarium.GetUniversalTime());
                    LoggingUtil.LogVerbose(typeof(SpawnKerbal), "kerbal generated, orbit = " + kerbal.orbit);
                }

                uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);

                // Create crew member array
                ProtoCrewMember[] crewArray = new ProtoCrewMember[1];
                crewArray[0] = kerbal.crewMember;

                // Create part nodes
                ConfigNode[] partNodes = new ConfigNode[1];
                partNodes[0] = ProtoVessel.CreatePartNode("kerbalEVA", flightId, crewArray);

                // Create additional nodes
                ConfigNode[]    additionalNodes = new ConfigNode[1];
                DiscoveryLevels discoveryLevel  = kerbal.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned;
                additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, UntrackedObjectClass.A, contract.TimeDeadline, contract.TimeDeadline);

                // Create the config node representation of the ProtoVessel
                ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(kerbal.name, VesselType.EVA, kerbal.orbit, 0, partNodes, additionalNodes);

                // Additional seetings for a landed Kerbal
                if (kerbal.landed)
                {
                    // Create the config node representation of the ProtoVessel
                    protoVesselNode.SetValue("sit", Vessel.Situations.LANDED.ToString());
                    protoVesselNode.SetValue("landed", true.ToString());
                    protoVesselNode.SetValue("lat", kerbal.latitude.ToString());
                    protoVesselNode.SetValue("lon", kerbal.longitude.ToString());
                    protoVesselNode.SetValue("alt", kerbal.altitude.ToString());
                }

                // Add vessel to the game
                HighLogic.CurrentGame.AddVessel(protoVesselNode);
            }
        }
Esempio n. 4
0
        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);
        }
Esempio n. 6
0
        private static void GenerateStrandedKerbal(int bodyId, string kerbalName)
        {
            //Add kerbal to crew roster.
            LunaLog.Log($"[LMP]: Spawning missing kerbal, Name: {kerbalName}");

            var pcm = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned);

            pcm.ChangeName(kerbalName);
            pcm.rosterStatus = ProtoCrewMember.RosterStatus.Assigned;

            //Create protovessel
            var newPartId    = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);
            var contractBody = FlightGlobals.Bodies[bodyId];

            //Atmo: 10km above atmo, to half the planets radius out.
            //Non-atmo: 30km above ground, to half the planets radius out.
            var minAltitude = CelestialUtilities.GetMinimumOrbitalDistance(contractBody, 1.1f);
            var maxAltitude = minAltitude + contractBody.Radius * 0.5;

            var strandedOrbit = Orbit.CreateRandomOrbitAround(FlightGlobals.Bodies[bodyId], minAltitude, maxAltitude);

            var kerbalPartNode = new[] { ProtoVessel.CreatePartNode("kerbalEVA", newPartId, pcm) };

            var protoVesselNode = ProtoVessel.CreateVesselNode(kerbalName, VesselType.EVA, strandedOrbit, 0,
                                                               kerbalPartNode);

            //It's not supposed to be infinite, but you're crazy if you think I'm going to decipher the values field of the rescue node.
            var discoveryNode = ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A,
                                                                double.PositiveInfinity,
                                                                double.PositiveInfinity);

            var protoVessel = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame)
            {
                discoveryInfo = discoveryNode
            };

            HighLogic.CurrentGame.flightState.protoVessels.Add(protoVessel);
        }
        protected override void OnAccepted()
        {
            // Actually spawn the kerbals in the game world!
            foreach (KerbalData kerbal in kerbals)
            {
                uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);

                // Create crew member array
                ProtoCrewMember[] crewArray = new ProtoCrewMember[1];
                crewArray[0] = kerbal.crewMember;

                // Create part nodes
                ConfigNode[] partNodes = new ConfigNode[1];
                partNodes[0] = ProtoVessel.CreatePartNode("kerbalEVA", flightId, crewArray);

                // Create additional nodes
                ConfigNode[]    additionalNodes = new ConfigNode[1];
                DiscoveryLevels discoveryLevel  = kerbal.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned;
                additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, UntrackedObjectClass.A, contract.TimeDeadline, contract.TimeDeadline);

                // Create the config node representation of the ProtoVessel
                ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(kerbal.name, VesselType.EVA, kerbal.orbit, 0, partNodes, additionalNodes);

                // Additional seetings for a landed Kerbal
                if (kerbal.landed)
                {
                    // Create the config node representation of the ProtoVessel
                    protoVesselNode.SetValue("sit", Vessel.Situations.LANDED.ToString());
                    protoVesselNode.SetValue("landed", true.ToString());
                    protoVesselNode.SetValue("lat", kerbal.latitude.ToString());
                    protoVesselNode.SetValue("lon", kerbal.longitude.ToString());
                    protoVesselNode.SetValue("alt", kerbal.altitude.ToString());
                }

                // Add vessel to the game
                HighLogic.CurrentGame.AddVessel(protoVesselNode);
            }
        }
Esempio n. 8
0
        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 + "!");
        }
Esempio n. 9
0
        protected override void OnAccepted()
        {
            // Actually spawn the kerbals in the game world!
            foreach (KerbalData kd in kerbals)
            {
                LoggingUtil.LogVerbose(this, "Spawning a Kerbal named " + kd.kerbal.name);

                // Generate the ProtoCrewMember
                kd.kerbal.GenerateKerbal();

                if (kd.altitude == null)
                {
                    kd.altitude = LocationUtil.TerrainHeight(kd.latitude, kd.longitude, kd.body);
                }

                // Set additional info for landed kerbals
                if (kd.landed)
                {
                    Vector3d pos = kd.body.GetWorldSurfacePosition(kd.latitude, kd.longitude, kd.altitude.Value);

                    kd.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, kd.body);
                    kd.orbit.UpdateFromStateVectors(pos, kd.body.getRFrmVel(pos), kd.body, Planetarium.GetUniversalTime());
                    LoggingUtil.LogVerbose(typeof(SpawnKerbal), "kerbal generated, orbit = " + kd.orbit);
                }
                else
                {
                    // Update the reference body in the orbit
                    kd.orbit.referenceBody = kd.body;
                }

                uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);

                // Create crew member array
                ProtoCrewMember[] crewArray = new ProtoCrewMember[1];
                crewArray[0] = kd.kerbal.pcm;

                // Create part nodes
                ConfigNode[] partNodes = new ConfigNode[1];
                partNodes[0] = ProtoVessel.CreatePartNode(kd.kerbal.gender == ProtoCrewMember.Gender.Male ? "kerbalEVA" : "kerbalEVAfemale",
                                                          flightId, crewArray);

                // Create additional nodes
                ConfigNode[]    additionalNodes = new ConfigNode[1];
                DiscoveryLevels discoveryLevel  = kd.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned;
                additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, UntrackedObjectClass.A, contract.TimeDeadline, contract.TimeDeadline);

                // Create the config node representation of the ProtoVessel
                ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(kd.kerbal.name, VesselType.EVA, kd.orbit, 0, partNodes, additionalNodes);

                // Additional seetings for a landed Kerbal
                if (kd.landed)
                {
                    bool splashed = kd.altitude.Value < 0.001 && kd.body.ocean;

                    // Add a bit of height for landed kerbals
                    if (!splashed)
                    {
                        kd.altitude += 0.2;
                    }

                    // Figure out the appropriate rotation
                    Vector3d   norm     = kd.body.GetRelSurfaceNVector(kd.latitude, kd.longitude);
                    Quaternion normal   = Quaternion.LookRotation(new Vector3((float)norm.x, (float)norm.y, (float)norm.z));
                    Quaternion rotation = Quaternion.FromToRotation(Vector3.up, Vector3.forward);
                    rotation = rotation * Quaternion.AngleAxis(kd.heading + 180, Vector3.up);

                    // Create the config node representation of the ProtoVessel
                    protoVesselNode.SetValue("sit", (splashed ? Vessel.Situations.SPLASHED : Vessel.Situations.LANDED).ToString());
                    protoVesselNode.SetValue("landed", (!splashed).ToString());
                    protoVesselNode.SetValue("splashed", splashed.ToString());
                    protoVesselNode.SetValue("lat", kd.latitude.ToString());
                    protoVesselNode.SetValue("lon", kd.longitude.ToString());
                    protoVesselNode.SetValue("alt", kd.altitude.ToString());
                    protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(normal * rotation));

                    // Set the normal vector relative to the surface
                    Vector3 nrm = (rotation * Vector3.forward);
                    protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z);
                }

                // Add vessel to the game
                HighLogic.CurrentGame.AddVessel(protoVesselNode);
            }
        }
Esempio n. 10
0
        protected bool CreateVessels()
        {
            if (vesselsCreated)
            {
                return(false);
            }

            String gameDataDir = KSPUtil.ApplicationRootPath;

            gameDataDir = gameDataDir.Replace("\\", "/");
            if (!gameDataDir.EndsWith("/"))
            {
                gameDataDir += "/";
            }
            gameDataDir += "GameData";

            // Spawn the vessel in the game world
            foreach (VesselData vesselData in vessels)
            {
                LoggingUtil.LogVerbose(this, "Spawning a vessel named '" + vesselData.name + "'");

                // Set additional info for landed vessels
                bool landed = false;
                if (!vesselData.orbiting)
                {
                    landed = true;
                    if (vesselData.altitude == null)
                    {
                        vesselData.altitude = LocationUtil.TerrainHeight(vesselData.latitude, vesselData.longitude, vesselData.body);
                    }

                    Vector3d pos = vesselData.body.GetWorldSurfacePosition(vesselData.latitude, vesselData.longitude, vesselData.altitude.Value);

                    vesselData.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, vesselData.body);
                    vesselData.orbit.UpdateFromStateVectors(pos, vesselData.body.getRFrmVel(pos), vesselData.body, Planetarium.GetUniversalTime());
                }
                else
                {
                    vesselData.orbit.referenceBody = vesselData.body;
                }

                ConfigNode[]         partNodes;
                UntrackedObjectClass sizeClass;
                ShipConstruct        shipConstruct = null;
                if (!string.IsNullOrEmpty(vesselData.craftURL))
                {
                    // Save the current ShipConstruction ship, otherwise the player will see the spawned ship next time they enter the VAB!
                    ConfigNode currentShip = ShipConstruction.ShipConfig;

                    shipConstruct = ShipConstruction.LoadShip(gameDataDir + "/" + vesselData.craftURL);
                    if (shipConstruct == null)
                    {
                        LoggingUtil.LogError(this, "ShipConstruct was null when tried to load '" + vesselData.craftURL +
                                             "' (usually this means the file could not be found).");
                        continue;
                    }

                    // Restore ShipConstruction ship
                    ShipConstruction.ShipConfig = currentShip;

                    // Set the name
                    if (string.IsNullOrEmpty(vesselData.name))
                    {
                        vesselData.name = shipConstruct.shipName;
                    }

                    // Set some parameters that need to be at the part level
                    uint missionID = (uint)Guid.NewGuid().GetHashCode();
                    uint launchID  = HighLogic.CurrentGame.launchID++;
                    foreach (Part p in shipConstruct.parts)
                    {
                        p.flightID  = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);
                        p.missionID = missionID;
                        p.launchID  = launchID;
                        p.flagURL   = vesselData.flagURL ?? HighLogic.CurrentGame.flagURL;

                        // Had some issues with this being set to -1 for some ships - can't figure out
                        // why.  End result is the vessel exploding, so let's just set it to a positive
                        // value.
                        p.temperature = 1.0;
                    }

                    foreach (CrewData cd in vesselData.crew)
                    {
                        bool success = false;

                        // Find a seat for the crew
                        Part part = shipConstruct.parts.Find(p => p.protoModuleCrew.Count < p.CrewCapacity);

                        // Add the crew member
                        if (part != null)
                        {
                            // Create the ProtoCrewMember
                            ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned);
                            if (cd.gender != null)
                            {
                                crewMember.gender = cd.gender.Value;
                            }
                            if (cd.name != null)
                            {
                                crewMember.name = cd.name;
                            }

                            // Add them to the part
                            success = part.AddCrewmemberAt(crewMember, part.protoModuleCrew.Count);
                        }

                        if (!success)
                        {
                            LoggingUtil.LogWarning(this, "Unable to add crew to vessel named '" + vesselData.name + "'.  Perhaps there's no room?");
                            break;
                        }
                    }

                    // Create a dummy ProtoVessel, we will use this to dump the parts to a config node.
                    // We can't use the config nodes from the .craft file, because they are in a
                    // slightly different format than those required for a ProtoVessel (seriously
                    // Squad?!?).
                    ConfigNode  empty       = new ConfigNode();
                    ProtoVessel dummyProto  = new ProtoVessel(empty, null);
                    Vessel      dummyVessel = new Vessel();
                    dummyVessel.parts    = shipConstruct.parts;
                    dummyProto.vesselRef = dummyVessel;

                    // Create the ProtoPartSnapshot objects and then initialize them
                    foreach (Part p in shipConstruct.parts)
                    {
                        dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto));
                    }
                    foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots)
                    {
                        p.storePartRefs();
                    }

                    // Create the ship's parts
                    partNodes = dummyProto.protoPartSnapshots.Select <ProtoPartSnapshot, ConfigNode>(GetNodeForPart).ToArray();

                    // Estimate an object class, numbers are based on the in game description of the
                    // size classes.
                    float size = shipConstruct.shipSize.magnitude / 2.0f;
                    if (size < 4.0f)
                    {
                        sizeClass = UntrackedObjectClass.A;
                    }
                    else if (size < 7.0f)
                    {
                        sizeClass = UntrackedObjectClass.B;
                    }
                    else if (size < 12.0f)
                    {
                        sizeClass = UntrackedObjectClass.C;
                    }
                    else if (size < 18.0f)
                    {
                        sizeClass = UntrackedObjectClass.D;
                    }
                    else
                    {
                        sizeClass = UntrackedObjectClass.E;
                    }
                }
                else
                {
                    // Create crew member array
                    ProtoCrewMember[] crewArray = new ProtoCrewMember[vesselData.crew.Count];
                    int i = 0;
                    foreach (CrewData cd in vesselData.crew)
                    {
                        // Create the ProtoCrewMember
                        ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned);
                        if (cd.name != null)
                        {
                            crewMember.name = cd.name;
                        }

                        crewArray[i++] = crewMember;
                    }

                    // Create part nodes
                    uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);
                    partNodes    = new ConfigNode[1];
                    partNodes[0] = ProtoVessel.CreatePartNode(vesselData.craftPart.name, flightId, crewArray);

                    // Default the size class
                    sizeClass = UntrackedObjectClass.A;

                    // Set the name
                    if (string.IsNullOrEmpty(vesselData.name))
                    {
                        vesselData.name = vesselData.craftPart.name;
                    }
                }

                // Create additional nodes
                ConfigNode[]    additionalNodes = new ConfigNode[1];
                DiscoveryLevels discoveryLevel  = vesselData.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned;
                additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, sizeClass, contract.TimeDeadline, contract.TimeDeadline);

                // Create the config node representation of the ProtoVessel
                ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(vesselData.name, vesselData.vesselType, vesselData.orbit, 0, partNodes, additionalNodes);

                // Additional seetings for a landed vessel
                if (!vesselData.orbiting)
                {
                    Vector3d norm = vesselData.body.GetRelSurfaceNVector(vesselData.latitude, vesselData.longitude);

                    double terrainHeight = 0.0;
                    if (vesselData.body.pqsController != null)
                    {
                        terrainHeight = vesselData.body.pqsController.GetSurfaceHeight(norm) - vesselData.body.pqsController.radius;
                    }
                    bool splashed = landed && terrainHeight < 0.001;

                    // Create the config node representation of the ProtoVessel
                    // Note - flying is experimental, and so far doesn't work
                    protoVesselNode.SetValue("sit", (splashed ? Vessel.Situations.SPLASHED : landed ?
                                                     Vessel.Situations.LANDED : Vessel.Situations.FLYING).ToString());
                    protoVesselNode.SetValue("landed", (landed && !splashed).ToString());
                    protoVesselNode.SetValue("splashed", splashed.ToString());
                    protoVesselNode.SetValue("lat", vesselData.latitude.ToString());
                    protoVesselNode.SetValue("lon", vesselData.longitude.ToString());
                    protoVesselNode.SetValue("alt", vesselData.altitude.ToString());
                    protoVesselNode.SetValue("landedAt", vesselData.body.name);

                    // Figure out the additional height to subtract
                    float lowest = float.MaxValue;
                    if (shipConstruct != null)
                    {
                        foreach (Part p in shipConstruct.parts)
                        {
                            foreach (Collider collider in p.GetComponentsInChildren <Collider>())
                            {
                                if (collider.gameObject.layer != 21 && collider.enabled)
                                {
                                    lowest = Mathf.Min(lowest, collider.bounds.min.y);
                                }
                            }
                        }
                    }
                    else
                    {
                        foreach (Collider collider in vesselData.craftPart.partPrefab.GetComponentsInChildren <Collider>())
                        {
                            if (collider.gameObject.layer != 21 && collider.enabled)
                            {
                                lowest = Mathf.Min(lowest, collider.bounds.min.y);
                            }
                        }
                    }

                    if (lowest == float.MaxValue)
                    {
                        lowest = 0;
                    }

                    // Figure out the surface height and rotation
                    Quaternion normal   = Quaternion.LookRotation(new Vector3((float)norm.x, (float)norm.y, (float)norm.z));
                    Quaternion rotation = Quaternion.identity;
                    float      heading  = vesselData.heading;
                    if (shipConstruct == null)
                    {
                        rotation = rotation * Quaternion.FromToRotation(Vector3.up, Vector3.back);
                    }
                    else if (shipConstruct.shipFacility == EditorFacility.SPH)
                    {
                        rotation = rotation * Quaternion.FromToRotation(Vector3.forward, -Vector3.forward);
                        heading += 180.0f;
                    }
                    else
                    {
                        rotation = rotation * Quaternion.FromToRotation(Vector3.up, Vector3.forward);
                    }

                    rotation = rotation * Quaternion.AngleAxis(heading, Vector3.back);
                    rotation = rotation * Quaternion.AngleAxis(vesselData.roll, Vector3.down);
                    rotation = rotation * Quaternion.AngleAxis(vesselData.pitch, Vector3.left);

                    // Set the height and rotation
                    if (landed || splashed)
                    {
                        float hgt = (shipConstruct != null ? shipConstruct.parts[0] : vesselData.craftPart.partPrefab).localRoot.attPos0.y - lowest;
                        hgt += vesselData.height;
                        protoVesselNode.SetValue("hgt", hgt.ToString());
                    }
                    protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(rotation * normal));

                    // Set the normal vector relative to the surface
                    Vector3 nrm = (rotation * Vector3.forward);
                    protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z);

                    protoVesselNode.SetValue("prst", false.ToString());
                }

                // Add vessel to the game
                ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode);

                // Store the id for later use
                vesselData.id = protoVessel.vesselRef.id;

                // Associate it so that it can be used in contract parameters
                ContractVesselTracker.Instance.AssociateVessel(vesselData.name, protoVessel.vesselRef);
            }

            vesselsCreated = true;
            return(true);
        }
Esempio n. 11
0
        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
        }
Esempio n. 12
0
        // 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 + "!");
        }
Esempio n. 13
0
        private void GenerateStrandedKerbal(ConfigNode contractNode)
        {
            if (contractNode.GetValue("state") == "Active")
            {
                DarkLog.Debug("Generating stranded kerbal/compound contract");
                int recoveryType     = int.Parse(contractNode.GetValue("recoveryType"));
                int bodyID           = int.Parse(contractNode.GetValue("targetBody"));
                int recoveryLocation = int.Parse(contractNode.GetValue("recoveryLocation"));
                int contractSeed     = int.Parse(contractNode.GetValue("seed"));

                bool recoveringKerbal = recoveryType == 1 || recoveryType == 3;
                bool recoveringPart   = recoveryType == 2 || recoveryType == 3;

                System.Random generator = new System.Random(contractSeed);

                // RECOVERY TYPES:
                // 0: None
                // 1: Kerbal
                // 2: Part
                // 3: Compound

                // Generate vessel part
                string        partName         = contractNode.GetValue("partName");
                string[]      contractValues   = contractNode.GetValue("values").Split(',');
                double        contractDeadline = double.Parse(contractValues[1]);
                uint          newPartID        = uint.Parse(contractNode.GetValue("partID"));
                CelestialBody contractBody     = FlightGlobals.Bodies[bodyID];

                List <string> vesselDescriptionList;
                if (recoveringKerbal)
                {
                    vesselDescriptionList = new List <string>
                    {
                        "Shipwreck",
                        "Wreckage",
                        "Pod",
                        "Capsule",
                        "Derelict",
                        "Heap",
                        "Hulk",
                        "Craft",
                        "Debris",
                        "Scrap"
                    };
                }
                else
                {
                    vesselDescriptionList = new List <string>
                    {
                        "Prototype",
                        "Device",
                        "Part",
                        "Module",
                        "Unit",
                        "Component"
                    };
                }
                string vesselDescription = vesselDescriptionList[generator.Next(0, vesselDescriptionList.Count)];

                Orbit strandedOrbit;
                // Low orbit
                if (recoveryLocation != 1)
                {
                    // High orbit
                    if (recoveryLocation != 2)
                    {
                        strandedOrbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, contractBody);
                    }
                    else
                    {
                        strandedOrbit = FinePrint.Utilities.OrbitUtilities.GenerateOrbit(contractSeed, contractBody, FinePrint.Utilities.OrbitType.RANDOM,
                                                                                         FinePrint.ContractDefs.Recovery.HighOrbitDifficulty, FinePrint.ContractDefs.Recovery.HighOrbitDifficulty, 0.0);
                    }
                }
                else
                {
                    double minAltitude = FinePrint.Utilities.CelestialUtilities.GetMinimumOrbitalDistance(contractBody, 1f) - contractBody.Radius;
                    strandedOrbit = Orbit.CreateRandomOrbitAround(contractBody, contractBody.Radius + minAltitude * 1.1000000238418579, contractBody.Radius + minAltitude * 1.25);
                    strandedOrbit.meanAnomalyAtEpoch = generator.NextDouble() * 2.0 * Math.PI;
                }

                ConfigNode configNode = null;

                if (recoveringKerbal)
                {
                    DarkLog.Debug("We want to recover a kerbal, so let's do it");
                    string kerbalName   = contractNode.GetValue("kerbalName");
                    int    kerbalGender = int.Parse(contractNode.GetValue("gender"));

                    string vesselName = FinePrint.Utilities.StringUtilities.PossessiveString(FinePrint.Utilities.StringUtilities.ShortKerbalName(kerbalName)) +
                                        " " + vesselDescription;

                    // Recovery Locations:
                    // 0: None,
                    // 1: Low Orbit,
                    // 2: High Orbit,
                    // 3: Surface

                    ProtoCrewMember pcm = null;
                    if (!HighLogic.CurrentGame.CrewRoster.Exists(kerbalName))
                    {
                        DarkLog.Debug("Spawning missing kerbal, name: " + kerbalName);
                        pcm = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned);
                        pcm.ChangeName(kerbalName);
                        pcm.gender       = (ProtoCrewMember.Gender)kerbalGender;
                        pcm.rosterStatus = ProtoCrewMember.RosterStatus.Assigned;
                        pcm.seat         = null;
                        pcm.seatIdx      = -1;
                        //Add kerbal to crew roster.
                    }
                    else
                    {
                        pcm = HighLogic.CurrentGame.CrewRoster[kerbalName];
                    }

                    // Spawn lone kerbal
                    if (partName == "kerbalEVA")
                    {
                        configNode = ProtoVessel.CreateVesselNode(kerbalName, VesselType.EVA, strandedOrbit, 0, new ConfigNode[]
                        {
                            CreateProcessedPartNode(partName, newPartID, new ProtoCrewMember[]
                            {
                                pcm
                            })
                        }, new ConfigNode[]
                        {
                            ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, contractDeadline * 2, contractDeadline * 2)
                        });
                        configNode.AddValue("prst", true);
                        ProtoVessel pv = HighLogic.CurrentGame.AddVessel(configNode);
                        VesselWorker.fetch.LoadVessel(configNode, pv.vesselID, false);
                        NetworkWorker.fetch.SendVesselProtoMessage(pv, false, false);
                    }
                    // Spawn kerbal in capsule/pod
                    else
                    {
                        configNode = ProtoVessel.CreateVesselNode(vesselName, (recoveryLocation != 3) ? VesselType.Ship : VesselType.Lander, strandedOrbit, 0, new ConfigNode[]
                        {
                            CreateProcessedPartNode(partName, newPartID, new ProtoCrewMember[]
                            {
                                pcm
                            })
                        }, new ConfigNode[]
                        {
                            new ConfigNode("ACTIONGROUPS"),
                            ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, contractDeadline * 2, contractDeadline * 2)
                        });
                        configNode.AddValue("prst", true);
                        ProtoVessel pv = HighLogic.CurrentGame.AddVessel(configNode);
                        VesselWorker.fetch.LoadVessel(configNode, pv.vesselID, false);
                        NetworkWorker.fetch.SendVesselProtoMessage(pv, false, false);
                    }
                }
            }
        }
        protected void CreateVessels()
        {
            if (vesselsCreated)
            {
                return;
            }

            String gameDataDir = KSPUtil.ApplicationRootPath;

            gameDataDir = gameDataDir.Replace("\\", "/");
            if (!gameDataDir.EndsWith("/"))
            {
                gameDataDir += "/";
            }
            gameDataDir += "GameData";

            // Spawn the vessel in the game world
            foreach (VesselData vesselData in vessels)
            {
                LoggingUtil.LogVerbose(this, "Spawning a vessel named '" + vesselData.name + "'");

                // Save the current ShipConstruction ship, otherwise the player will see the spawned ship next time they enter the VAB!
                ConfigNode currentShip = ShipConstruction.ShipConfig;

                ShipConstruct shipConstruct = ShipConstruction.LoadShip(gameDataDir + "/" + vesselData.craftURL);
                if (shipConstruct == null)
                {
                    LoggingUtil.LogError(this, "ShipConstruct was null when tried to load '" + vesselData.craftURL +
                                         "' (usually this means the file could not be found).");
                    continue;
                }

                // Restore ShipConstruction ship
                ShipConstruction.ShipConfig = currentShip;

                // Set the name
                if (string.IsNullOrEmpty(vesselData.name))
                {
                    vesselData.name = shipConstruct.shipName;
                }

                // Set some parameters that need to be at the part level
                uint flightId  = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState);
                uint missionID = (uint)Guid.NewGuid().GetHashCode();
                uint launchID  = HighLogic.CurrentGame.launchID++;
                foreach (Part p in shipConstruct.parts)
                {
                    p.flightID  = flightId;
                    p.missionID = missionID;
                    p.launchID  = launchID;
                    p.flagURL   = vesselData.flagURL ?? HighLogic.CurrentGame.flagURL;
                }

                // Assign crew to the vessel
                foreach (CrewData cd in vesselData.crew)
                {
                    bool success = false;

                    // Find a seat for the crew
                    Part part = shipConstruct.parts.Find(p => p.protoModuleCrew.Count < p.CrewCapacity);

                    // Add the crew member
                    if (part != null)
                    {
                        // Create the ProtoCrewMember
                        ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned);
                        if (cd.name != null)
                        {
                            crewMember.name = cd.name;
                        }

                        // Add them to the part
                        success = part.AddCrewmemberAt(crewMember, part.protoModuleCrew.Count);
                    }

                    if (!success)
                    {
                        LoggingUtil.LogWarning(this, "Unable to add crew to vessel named '" + vesselData.name + "'.  Perhaps there's no room?");
                        break;
                    }
                }

                // Set additional info for landed kerbals
                if (vesselData.landed)
                {
                    if (vesselData.altitude == null)
                    {
                        vesselData.altitude = LocationUtil.TerrainHeight(vesselData.latitude, vesselData.longitude, vesselData.body);
                    }

                    Vector3d pos = vesselData.body.GetWorldSurfacePosition(vesselData.latitude, vesselData.longitude, vesselData.altitude.Value);

                    vesselData.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, vesselData.body);
                    vesselData.orbit.UpdateFromStateVectors(pos, vesselData.body.getRFrmVel(pos), vesselData.body, Planetarium.GetUniversalTime());
                    LoggingUtil.LogDebug(this, "vesselData generated, orbit = " + vesselData.orbit);
                }

                // Create a dummy ProtoVessel, we will use this to dump the parts to a config node.
                // We can't use the config nodes from the .craft file, because they are in a
                // slightly different format than those required for a ProtoVessel (seriously
                // Squad?!?).
                ConfigNode  empty       = new ConfigNode();
                ProtoVessel dummyProto  = new ProtoVessel(empty, null);
                Vessel      dummyVessel = new Vessel();
                dummyVessel.parts    = shipConstruct.parts;
                dummyProto.vesselRef = dummyVessel;

                // Create the ProtoPartSnapshot objects and then initialize them
                foreach (Part p in shipConstruct.parts)
                {
                    dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto));
                }
                foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots)
                {
                    p.storePartRefs();
                }

                // Estimate an object class, numbers are based on the in game description of the
                // size classes.
                float size = shipConstruct.shipSize.magnitude / 2.0f;
                UntrackedObjectClass sizeClass;
                if (size < 4.0f)
                {
                    sizeClass = UntrackedObjectClass.A;
                }
                else if (size < 7.0f)
                {
                    sizeClass = UntrackedObjectClass.B;
                }
                else if (size < 12.0f)
                {
                    sizeClass = UntrackedObjectClass.C;
                }
                else if (size < 18.0f)
                {
                    sizeClass = UntrackedObjectClass.D;
                }
                else
                {
                    sizeClass = UntrackedObjectClass.E;
                }

                // Create the ship's parts
                ConfigNode[] partNodes = dummyProto.protoPartSnapshots.Select <ProtoPartSnapshot, ConfigNode>(GetNodeForPart).ToArray();

                // Create additional nodes
                ConfigNode[]    additionalNodes = new ConfigNode[1];
                DiscoveryLevels discoveryLevel  = vesselData.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned;
                additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, sizeClass, contract.TimeDeadline, contract.TimeDeadline);

                // Create the config node representation of the ProtoVessel
                ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(vesselData.name, vesselData.vesselType, vesselData.orbit, 0, partNodes, additionalNodes);

                // Additional seetings for a landed vessel
                if (vesselData.landed)
                {
                    // Create the config node representation of the ProtoVessel
                    protoVesselNode.SetValue("sit", Vessel.Situations.LANDED.ToString());
                    protoVesselNode.SetValue("landed", true.ToString());
                    protoVesselNode.SetValue("lat", vesselData.latitude.ToString());
                    protoVesselNode.SetValue("lon", vesselData.longitude.ToString());
                    protoVesselNode.SetValue("alt", vesselData.altitude.ToString());
                    protoVesselNode.SetValue("landedAt", vesselData.body.name);

                    // Figure out the additional heigh to subtract
                    float lowest = float.MaxValue;
                    foreach (Part p in shipConstruct.parts)
                    {
                        foreach (Collider collider in p.GetComponentsInChildren <Collider>())
                        {
                            if (collider.gameObject.layer != 21 && collider.enabled)
                            {
                                lowest = Mathf.Min(lowest, collider.bounds.min.y);
                            }
                        }
                    }

                    // Figure out the surface height and rotation
                    Vector3d   norm     = vesselData.body.GetRelSurfaceNVector(vesselData.latitude, vesselData.longitude);
                    Quaternion rotation = Quaternion.FromToRotation(Vector3.forward, Vector3.up) *
                                          Quaternion.LookRotation(new Vector3((float)norm.x, (float)norm.y, (float)norm.z));
                    protoVesselNode.SetValue("hgt", (shipConstruct.parts[0].localRoot.attPos0.y - lowest).ToString());
                    protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(rotation));
                }

                // Add vessel to the game
                ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode);

                // Store the id for later use
                vesselData.id = protoVessel.vesselRef.id;

                // Associate it so that it can be used in contract parameters
                ContractVesselTracker.Instance.AssociateVessel(vesselData.name, protoVessel.vesselRef);
            }

            vesselsCreated = true;
        }