コード例 #1
0
        protected override void OnParameterLoad(ConfigNode node)
        {
            monolithDiscovered = ConfigNodeUtil.ParseValue <bool>(node, "monolithDiscovered");
            currentState       = ConfigNodeUtil.ParseValue <MonolithState>(node, "currentState");
            starJeb            = ConfigNodeUtil.ParseValue <Vessel>(node, "starJeb", (Vessel)null);
            candidate          = ConfigNodeUtil.ParseValue <Vessel>(node, "candidate", starJeb);
            starJebName        = ConfigNodeUtil.ParseValue <string>(node, "starJebName", "");
            candidateName      = ConfigNodeUtil.ParseValue <string>(node, "candidateName", "");
            if (node.HasValue("velocity.x"))
            {
                float x = ConfigNodeUtil.ParseValue <float>(node, "velocity.x");
                float y = ConfigNodeUtil.ParseValue <float>(node, "velocity.y");
                float z = ConfigNodeUtil.ParseValue <float>(node, "velocity.z");
                velocity = new Vector3(x, y, z);
            }
            if (node.HasNode("PROGRESS_TREE_BACKUP"))
            {
                progressTreeBackup = node.GetNode("PROGRESS_TREE_BACKUP");
            }

            stepTime = Time.fixedTime;

            ParameterDelegate <string> .OnDelegateContainerLoad(node);

            CreateDelegates();
        }
コード例 #2
0
        protected void ReturnEVA(Vessel parent, Vessel eva)
        {
            if (currentState <= MonolithState.EVA && eva != null && candidate == eva)
            {
                candidate     = null;
                candidateName = "";
                currentState  = MonolithState.STARTED;

                // Remove the approach parameter, as the name may change
                if (ParameterCount == 2)
                {
                    RemoveParameter(GetParameter(1));
                }

                // Force a display update
                ContractConfigurator.ContractConfigurator.OnParameterChange.Fire(Root, this);
            }
        }
コード例 #3
0
        protected bool CheckParameters(MonolithState paramState)
        {
            if (paramState < currentState)
            {
                return(true);
            }

            // StarJeb not active vessel
            if (starJeb != null && FlightGlobals.ActiveVessel != starJeb ||
                candidate != null && FlightGlobals.ActiveVessel != candidate)
            {
                stepTime = Time.fixedTime;
                return(false);
            }

            // Create the velocity change handler
            if (velHdlr == null)
            {
                LoggingUtil.LogDebug(this, "Adding VelocityHandler");
                velHdlr       = MapView.MapCamera.gameObject.AddComponent <VelocityHandler>();
                velHdlr.param = this;
            }

            switch (currentState)
            {
            case MonolithState.STARTED:
                // Look for an eva
                if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.vesselType == VesselType.EVA)
                {
                    candidate     = FlightGlobals.ActiveVessel;
                    candidateName = candidate.vesselName;
                    LoggingUtil.LogDebug(this, "Got an eva, starJeb = " + candidate.vesselName);
                    nextState();
                    return(true);
                }
                return(false);

            case MonolithState.EVA:
            {
                Vessel discovery         = ContractVesselTracker.Instance.GetAssociatedVessel("Discovery One");
                float  discoveryDistance = discovery == null ? 10000 : Vector3.Distance(discovery.transform.position, candidate.transform.position);

                if (distance < 10000 && discoveryDistance > distance && Time.fixedTime - stepTime > 10.0f || distance < MONOLITH_TOO_CLOSE)
                {
                    // Store Star Jeb's name
                    starJeb     = candidate;
                    starJebName = candidateName;
                    PersistentDataStore.Instance.Store <string>("starJebName", starJebName);

                    // Store Star Jeb's friend's name
                    ProtoCrewMember protoStarJeb = candidate.GetVesselCrew().First();
                    if (discovery != null)
                    {
                        string          trait      = protoStarJeb.experienceTrait.TypeName == "Scientist" ? "Pilot" : "Scientist";
                        ProtoCrewMember notStarJeb = discovery.GetVesselCrew().Where(pcm => pcm.experienceTrait.TypeName == trait).FirstOrDefault();
                        if (notStarJeb != null)
                        {
                            PersistentDataStore.Instance.Store <string>("notStarJebName", notStarJeb.name);
                        }
                    }
                    candidate = null;
                    nextState();

                    // Set the right image (male vs. female) for the end sequence
                    ConfiguredContract contract  = Root as ConfiguredContract;
                    DialogBox          dialogBox = contract.Behaviours.Select(b => b as DialogBox).Where(b => b != null).FirstOrDefault();
                    if (dialogBox != null)
                    {
                        FieldInfo detailsField = typeof(DialogBox).GetFields(BindingFlags.Instance | BindingFlags.NonPublic).
                                                 Where(fi => fi.FieldType == typeof(List <DialogBox.DialogDetail>)).First();
                        DialogBox.DialogDetail detail       = ((List <DialogBox.DialogDetail>)detailsField.GetValue(dialogBox)).First();
                        DialogBox.ImageSection starJebImage = detail.sections.First() as DialogBox.ImageSection;
                        starJebImage.imageURL = protoStarJeb.gender == ProtoCrewMember.Gender.Male ?
                                                "ContractPacks/AnomalySurveyor/Images/starjeb.dds.noload" :
                                                "ContractPacks/AnomalySurveyor/Images/starjeb_female.dds.noload";
                    }

                    return(true);
                }
            }
                return(false);

            case MonolithState.FULL_OF_STARS1:
            {
                // Backup progress tracking
                progressTreeBackup = new ConfigNode("PROGRESS_TREE_BACKUP");
                ProgressTracking.Instance.OnSave(progressTreeBackup);

                // Give the first kick away from Jool - this one using regular velocity change
                CelestialBody jool = FlightGlobals.Bodies.Where(b => b.name == "Jool").First();

                // Find closest point on the jool-monolith line, and throw us away from that (so we don't hit either)
                Vector3 line    = monolith.transform.position - jool.transform.position;
                float   t       = Vector3.Dot(line, (starJeb.transform.position - jool.transform.position)) / Vector3.Dot(line, line);
                Vector3 closest = jool.transform.position + line * t;

                velocity  = (starJeb.transform.position - (t > 1.0 ? jool.transform.position : closest)).normalized;
                velocity += new Vector3(0.0f, 0.1f, 0.0f);
                velocity *= 15000;
                LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                nextState();

                // Camera to target jool
                FlightCamera.SetTarget(starJeb.transform);
                FlightCamera.fetch.SetCamCoordsFromPosition((starJeb.transform.position - jool.transform.position).normalized * 25.0f);
            }
                return(false);

            case MonolithState.FULL_OF_STARS2:
                if (Time.fixedTime - stepTime > 4.0f)
                {
                    // Give the second kick away from Jool - these using anti-kraken velocity change
                    CelestialBody jool = FlightGlobals.Bodies.Where(b => b.name == "Jool").First();
                    velocity  = (starJeb.transform.position - jool.transform.position).normalized;
                    velocity += new Vector3(0.0f, 0.1f, 0.0f);
                    velocity *= 1500000;
                    LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS3:
                if (Time.fixedTime - stepTime > 3.0f)
                {
                    // Give the third kick away from Jool
                    CelestialBody jool = FlightGlobals.Bodies.Where(b => b.name == "Jool").First();
                    velocity  = (starJeb.transform.position - jool.transform.position).normalized;
                    velocity *= 20000000;
                    LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS4:
                if (Time.fixedTime - stepTime > 2.0f)
                {
                    // Give the fourth and final kick away from Jool
                    CelestialBody jool = FlightGlobals.Bodies.Where(b => b.name == "Jool").First();
                    velocity  = (starJeb.transform.position - jool.transform.position).normalized;
                    velocity *= 200000000;
                    LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS5:
                if (Time.fixedTime - stepTime > 2.0f)
                {
                    // Move along
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS_DRES1:
            {
                // Visit Dres
                CelestialBody dres = FlightGlobals.Bodies.Where(b => b.name == "Dres").First();

                // Determine which side the sun is on - makes for a better show
                CelestialBody sun       = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                Vector3       sunnySide = sun.transform.position - dres.transform.position;
                sunnySide.x = 0.0f;
                sunnySide.y = 1;         // Move across the top of the planet
                sunnySide.z = Math.Sign(sunnySide.z);

                // Set position for starjeb
                float distance = 4.0f * (float)dres.Radius;
                starJeb.SetPosition(dres.transform.position + new Vector3(distance, (float)dres.Radius, (float)dres.Radius * sunnySide.z));

                velocity  = (dres.transform.position - starJeb.transform.position + sunnySide * ((float)dres.Radius)).normalized;
                velocity *= distance / 3.0f;
                LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                starJeb.SetWorldVelocity(dres.getRFrmVel(starJeb.transform.position));
                nextState();
            }
                return(false);

            case MonolithState.FULL_OF_STARS_DRES2:
            {
                // Camera to target Dres - do this on a seperate update to allow KSP to catch up
                CelestialBody dres = FlightGlobals.Bodies.Where(b => b.name == "Dres").First();
                FlightCamera.SetTarget(starJeb.transform);
                FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + (starJeb.transform.position - dres.transform.position).normalized * 10.0f);

                // Make sure that the camera gets fixed
                if (Time.fixedTime - stepTime > 0.1f)
                {
                    nextState();
                }
            }
                return(false);

            case MonolithState.FULL_OF_STARS_DRES3:
                if (Time.fixedTime - stepTime > 5.5f)
                {
                    // Done with Dres
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS_DUNA1:
            {
                // Start between the sun and Duna
                CelestialBody duna      = FlightGlobals.Bodies.Where(b => b.name == "Duna").First();
                CelestialBody sun       = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                Vector3       sunnySide = sun.transform.position - duna.transform.position;
                sunnySide.Normalize();

                // Set us up a nice 4 radiuses away...
                float distance = 4.0f * (float)duna.Radius;
                starJeb.SetPosition(duna.transform.position + sunnySide * distance);

                // Go straight at Duna
                velocity  = (duna.transform.position - starJeb.transform.position).normalized;
                velocity *= distance / 3.0f;
                LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);

                // Now offset him down so he doesn't actually hit Duna...
                starJeb.SetPosition(starJeb.transform.position + new Vector3(0.0f, -((float)duna.Radius + 55000), 0.0f));
                starJeb.SetWorldVelocity(duna.getRFrmVel(starJeb.transform.position));

                nextState();
            }
                return(false);

            case MonolithState.FULL_OF_STARS_DUNA2:
            {
                // Camera to target Duna - do this on a seperate update to allow KSP to catch up
                CelestialBody duna = FlightGlobals.Bodies.Where(b => b.name == "Duna").First();
                FlightCamera.SetTarget(starJeb.transform);
                FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + (starJeb.transform.position - duna.transform.position).normalized * 25.0f);

                // Make sure that the camera gets fixed
                if (Time.fixedTime - stepTime > 0.1f)
                {
                    nextState();
                }
            }
                return(false);

            case MonolithState.FULL_OF_STARS_DUNA3:
                if (Time.fixedTime - stepTime > 5.5f)
                {
                    // Done with Duna
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS_EELOO1:
            {
                // Start perpendicular to the sun and Eeloo
                CelestialBody eeloo = FlightGlobals.Bodies.Where(b => b.name == "Eeloo").First();
                CelestialBody sun   = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                Vector3       perp  = eeloo.transform.position - sun.transform.position;
                float         tmp   = perp.x;
                perp.x = -perp.z;
                perp.z = tmp;
                perp.Normalize();

                // Set us up a nice 4 radiuses away...
                float distance = 4.0f * (float)eeloo.Radius;
                starJeb.SetPosition(eeloo.transform.position + perp * distance);

                // Determine which side the sun is on - makes for a better show
                Vector3 sunnySide = sun.transform.position - eeloo.transform.position;
                sunnySide.Normalize();

                // Go straight at Eeloo
                velocity  = (eeloo.transform.position - starJeb.transform.position).normalized;
                velocity *= distance / 3.0f;
                LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);

                // Now offset him down so he doesn't actually hit Eeloo...
                starJeb.SetPosition(starJeb.transform.position + sunnySide * ((float)eeloo.Radius * 1.5f));
                starJeb.SetWorldVelocity(eeloo.getRFrmVel(starJeb.transform.position));

                nextState();
            }
                return(false);

            case MonolithState.FULL_OF_STARS_EELOO2:
            {
                // This time won't target directly towards Eeloo, as the player will have some idea
                // what is up by now.
                CelestialBody eeloo       = FlightGlobals.Bodies.Where(b => b.name == "Eeloo").First();
                CelestialBody sun         = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                Vector3       awayFromSun = sun.transform.position - eeloo.transform.position;
                awayFromSun.Normalize();

                FlightCamera.SetTarget(starJeb.transform);
                FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + awayFromSun * 50.0f);

                // Make sure that the camera gets fixed
                if (Time.fixedTime - stepTime > 0.1f)
                {
                    nextState();
                }
            }
                return(false);

            case MonolithState.FULL_OF_STARS_EELOO3:
                if (Time.fixedTime - stepTime > 5.5f)
                {
                    velocity = null;

                    // Done with Eeloo
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS_EVE1:
            {
                CelestialBody eve            = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                Vector3       targetPosition = Destination.Value;
                Vector3       normal         = eve.GetSurfaceNVector(eveLatitude, eveLongitude);
                startDistance = 10000000f;
                Vector3 start = targetPosition + normal * startDistance;

                starJeb.SetPosition(start);
                nextState();
            }
                return(false);

            case MonolithState.FULL_OF_STARS_EVE2:
            {
                // Camera straight towards Eve - we're going in!
                CelestialBody eve         = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                Vector3       awayFromEve = starJeb.transform.position - eve.transform.position;
                awayFromEve.Normalize();

                FlightCamera.SetTarget(starJeb.transform);
                FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + awayFromEve * 15.0f);

                // Make sure that the camera gets fixed
                if (Time.fixedTime - stepTime > 0.1f)
                {
                    nextState();
                }
            }
                return(false);

            case MonolithState.FULL_OF_STARS_EVE3:
                // Wait until we've held the position for a split second
                if (Time.fixedTime - stepTime >= 9.3f)
                {
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS_EVE4:
                // Give the player a bit to get settled, then let the fun begins
                if (Time.fixedTime - stepTime >= 15.0f)
                {
                    // Spawn some asteroids
                    CelestialBody eve = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                    ScenarioDiscoverableObjects asteroidSpawner = (ScenarioDiscoverableObjects)HighLogic.CurrentGame.scenarios.Find(
                        s => s.moduleRef is ScenarioDiscoverableObjects).moduleRef;
                    System.Random random = new System.Random();

                    // Spawn some more asteroids
                    for (int i = 0; i < ASTEROID_COUNT; i++)
                    {
                        asteroidSpawner.SpawnAsteroid();
                    }

                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS_EVE5:
                // Wait a full second after spawning the asteroids - we're not allowed to pull
                // them off rails until they've been active a bit
                if (Time.fixedTime - stepTime > 1.0f)
                {
                    // Spawn some asteroids
                    CelestialBody eve    = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                    System.Random random = new System.Random();

                    foreach (Vessel asteroid in FlightGlobals.Vessels.Where(v => v.vesselType == VesselType.SpaceObject).Reverse().Take(ASTEROID_COUNT))
                    {
                        // Set the position
                        double r         = random.NextDouble() * 0.02 + 0.002;
                        double theta     = random.NextDouble() * 2.0 * Math.PI;
                        double latitude  = starJeb.latitude + r * Math.Sin(theta);
                        double longitude = starJeb.longitude + r * Math.Cos(theta);
                        double altitude  = starJeb.altitude + 100 + random.NextDouble() * 200;
                        asteroid.SetPosition(eve.GetWorldSurfacePosition(latitude, longitude, altitude));
                        asteroid.ChangeWorldVelocity(asteroid.GetSrfVelocity());
                        asteroid.Load();
                        asteroid.GoOffRails();
                    }
                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS_EVE6:
            {
                // Determine if there's an asteroid about to kill us
                CelestialBody eve            = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                bool          killerAsteroid = FlightGlobals.Vessels.Where(v => v.mainBody == eve && v.vesselType == VesselType.SpaceObject &&
                                                                           Vector3.Distance(starJeb.transform.position, v.transform.position) < 5.5 * ((int)v.DiscoveryInfo.objectSize + 1)).Any();

                if (killerAsteroid || Time.fixedTime - stepTime > 20.0f)
                {
                    foreach (Vessel asteroid in FlightGlobals.Vessels.Where(v => v.vesselType == VesselType.SpaceObject).Reverse().Take(ASTEROID_COUNT))
                    {
                        asteroid.Die();
                    }
                    nextState();
                }
            }
                return(false);

            case MonolithState.FULL_OF_STARS_KERBIN1:
            {
                CheatOptions.NoCrashDamage = false;

                // Start between the sun and Kerbin
                CelestialBody kerbin    = FlightGlobals.Bodies.Where(b => b.name == "Kerbin").First();
                CelestialBody sun       = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                Vector3       sunnySide = sun.transform.position - kerbin.transform.position;
                sunnySide.Normalize();

                // Set us up a nice 4 radiuses away...
                float distance = 4.0f * (float)kerbin.Radius;
                starJeb.SetPosition(kerbin.transform.position + sunnySide * distance);

                // Orient him properly
                KerbalEVA  keva           = starJeb.FindPartModulesImplementing <KerbalEVA>().First();
                MethodInfo rotationMethod = typeof(KerbalEVA).GetMethod("correctGroundedRotation", BindingFlags.Instance | BindingFlags.NonPublic);
                starJeb.packed = true;
                rotationMethod.Invoke(keva, new object[] { });
                starJeb.packed = false;

                // Hardcode an orbital velocity, because it's late and I'm tired
                starJeb.SetWorldVelocity(kerbin.getRFrmVel(starJeb.transform.position).normalized * 1085);

                nextState();
            }
                return(false);

            case MonolithState.FULL_OF_STARS_KERBIN2:
            {
                // Camera to target kerbin - do this on a seperate update to allow KSP to catch up
                CelestialBody kerbin = FlightGlobals.Bodies.Where(b => b.name == "Kerbin").First();
                FlightCamera.SetTarget(starJeb.transform);
                FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + (starJeb.transform.position - kerbin.transform.position).normalized * 10.0f);

                starJeb.SetRotation(FlightCamera.fetch.transform.rotation * Quaternion.AngleAxis(180.0f, FlightCamera.fetch.transform.up));

                // Make sure that the camera gets fixed
                if (Time.fixedTime - stepTime > 0.1f)
                {
                    nextState();
                }
            }
                return(false);

            case MonolithState.FULL_OF_STARS_KERBIN3:
                if (Time.fixedTime - stepTime > 2.0f)
                {
                    // Turn into star jeb
                    CelestialBody kerbin = FlightGlobals.Bodies.Where(b => b.name == "Kerbin").First();

                    starJeb.vesselName = "The Star Jeb";
                    Undress(starJeb.gameObject);
                    FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + (starJeb.transform.position - kerbin.transform.position).normalized * 1.5f);

                    nextState();
                }
                return(false);

            case MonolithState.FULL_OF_STARS_KERBIN4:
                if (Time.fixedTime - stepTime < 15.0f)
                {
                    CelestialBody kerbin       = FlightGlobals.Bodies.Where(b => b.name == "Kerbin").First();
                    Vector3       camDirection = starJeb.transform.position + (starJeb.transform.position - kerbin.transform.position).normalized;
                }
                else
                {
                    nextState();

                    monolith.Die();
                    monolith = null;

                    starJeb.Die();
                    starJeb = null;

                    Vessel discovery = ContractVesselTracker.Instance.GetAssociatedVessel("Discovery One");
                    FlightGlobals.ForceSetActiveVessel(discovery);
                }
                return(false);

            case MonolithState.FULL_OF_STARS_FINAL:
                nextState();
                return(true);

            default:
                return(false);
            }
        }
        protected void ReturnEVA(Vessel parent, Vessel eva)
        {
            if (currentState <= MonolithState.EVA && eva != null && candidate == eva)
            {
                candidate = null;
                candidateName = "";
                currentState = MonolithState.STARTED;

                // Remove the approach parameter, as the name may change
                if (ParameterCount == 2)
                {
                    RemoveParameter(GetParameter(1));
                }

                // Force a display update
                ContractConfigurator.ContractConfigurator.OnParameterChange.Fire(Root, this);
            }
        }
        protected override void OnParameterLoad(ConfigNode node)
        {
            monolithDiscovered = ConfigNodeUtil.ParseValue<bool>(node, "monolithDiscovered");
            currentState = ConfigNodeUtil.ParseValue<MonolithState>(node, "currentState");
            starJeb = ConfigNodeUtil.ParseValue<Vessel>(node, "starJeb", (Vessel)null);
            candidate = ConfigNodeUtil.ParseValue<Vessel>(node, "candidate", starJeb);
            starJebName = ConfigNodeUtil.ParseValue<string>(node, "starJebName", "");
            candidateName = ConfigNodeUtil.ParseValue<string>(node, "candidateName", "");
            if (node.HasValue("velocity.x"))
            {
                float x = ConfigNodeUtil.ParseValue<float>(node, "velocity.x");
                float y = ConfigNodeUtil.ParseValue<float>(node, "velocity.y");
                float z = ConfigNodeUtil.ParseValue<float>(node, "velocity.z");
                velocity = new Vector3(x, y, z);
            }
            if (node.HasNode("PROGRESS_TREE_BACKUP"))
            {
                progressTreeBackup = node.GetNode("PROGRESS_TREE_BACKUP");
            }

            stepTime = Time.fixedTime;

            ParameterDelegate<string>.OnDelegateContainerLoad(node);
            CreateDelegates();
        }
        protected bool CheckParameters(MonolithState paramState)
        {
            if (paramState < currentState)
            {
                return true;
            }

            // StarJeb not active vessel
            if (starJeb != null && FlightGlobals.ActiveVessel != starJeb ||
                candidate != null && FlightGlobals.ActiveVessel != candidate)
            {
                stepTime = Time.fixedTime;
                return false;
            }

            // Create the velocity change handler
            if (velHdlr == null)
            {
                LoggingUtil.LogDebug(this, "Adding VelocityHandler");
                velHdlr = MapView.MapCamera.gameObject.AddComponent<VelocityHandler>();
                velHdlr.param = this;
            }

            switch (currentState)
            {
                case MonolithState.STARTED:
                    // Look for an eva
                    if (FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.vesselType == VesselType.EVA)
                    {
                        candidate = FlightGlobals.ActiveVessel;
                        candidateName = candidate.vesselName;
                        LoggingUtil.LogDebug(this, "Got an eva, starJeb = " + candidate.vesselName);
                        nextState();
                        return true;
                    }
                    return false;
                case MonolithState.EVA:
                    {
                        Vessel discovery = ContractVesselTracker.Instance.GetAssociatedVessel("Discovery One");
                        float discoveryDistance = discovery == null ? 10000 : Vector3.Distance(discovery.transform.position, candidate.transform.position);

                        if (distance < 10000 && discoveryDistance > distance && Time.fixedTime - stepTime > 10.0f || distance < MONOLITH_TOO_CLOSE)
                        {
                            // Store Star Jeb's name
                            starJeb = candidate;
                            starJebName = candidateName;
                            PersistentDataStore.Instance.Store<string>("starJebName", starJebName);

                            // Store Star Jeb's friend's name
                            ProtoCrewMember protoStarJeb = candidate.GetVesselCrew().First();
                            if (discovery != null)
                            {
                                string trait = protoStarJeb.experienceTrait.TypeName == "Scientist" ? "Pilot" : "Scientist";
                                ProtoCrewMember notStarJeb = discovery.GetVesselCrew().Where(pcm => pcm.experienceTrait.TypeName == trait).FirstOrDefault();
                                if (notStarJeb != null)
                                {
                                    PersistentDataStore.Instance.Store<string>("notStarJebName", notStarJeb.name);
                                }
                            }
                            candidate = null;
                            nextState();

                            // Set the right image (male vs. female) for the end sequence
                            ConfiguredContract contract = Root as ConfiguredContract;
                            DialogBox dialogBox = contract.Behaviours.Select(b => b as DialogBox).Where(b => b != null).FirstOrDefault();
                            if (dialogBox != null)
                            {
                                FieldInfo detailsField = typeof(DialogBox).GetFields(BindingFlags.Instance | BindingFlags.NonPublic).
                                    Where(fi => fi.FieldType == typeof(List<DialogBox.DialogDetail>)).First();
                                DialogBox.DialogDetail detail = ((List<DialogBox.DialogDetail>)detailsField.GetValue(dialogBox)).First();
                                DialogBox.ImageSection starJebImage = detail.sections.First() as DialogBox.ImageSection;
                                starJebImage.imageURL = protoStarJeb.gender == ProtoCrewMember.Gender.Male ?
                                    "ContractPacks/AnomalySurveyor/Images/starjeb.dds.noload" :
                                    "ContractPacks/AnomalySurveyor/Images/starjeb_female.dds.noload";
                            }

                            return true;
                        }
                    }
                    return false;
                case MonolithState.FULL_OF_STARS1:
                    {
                        // Backup progress tracking
                        progressTreeBackup = new ConfigNode("PROGRESS_TREE_BACKUP");
                        ProgressTracking.Instance.OnSave(progressTreeBackup);

                        // Give the first kick away from Jool - this one using regular velocity change
                        CelestialBody jool = FlightGlobals.Bodies.Where(b => b.name == "Jool").First();

                        // Find closest point on the jool-monolith line, and throw us away from that (so we don't hit either)
                        Vector3 line = monolith.transform.position - jool.transform.position;
                        float t = Vector3.Dot(line, (starJeb.transform.position - jool.transform.position)) / Vector3.Dot(line, line);
                        Vector3 closest = jool.transform.position + line * t;

                        velocity = (starJeb.transform.position - (t > 1.0 ? jool.transform.position : closest)).normalized;
                        velocity += new Vector3(0.0f, 0.1f, 0.0f);
                        velocity *= 15000;
                        LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                        nextState();

                        // Camera to target jool
                        FlightCamera.fetch.setTarget(starJeb.transform);
                        FlightCamera.fetch.SetCamCoordsFromPosition((starJeb.transform.position - jool.transform.position).normalized * 25.0f);
                    }
                    return false;
                case MonolithState.FULL_OF_STARS2:
                    if (Time.fixedTime - stepTime > 4.0f)
                    {
                        // Give the second kick away from Jool - these using anti-kraken velocity change
                        CelestialBody jool = FlightGlobals.Bodies.Where(b => b.name == "Jool").First();
                        velocity = (starJeb.transform.position - jool.transform.position).normalized;
                        velocity += new Vector3(0.0f, 0.1f, 0.0f);
                        velocity *= 1500000;
                        LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS3:
                    if (Time.fixedTime - stepTime > 3.0f)
                    {
                        // Give the third kick away from Jool
                        CelestialBody jool = FlightGlobals.Bodies.Where(b => b.name == "Jool").First();
                        velocity = (starJeb.transform.position - jool.transform.position).normalized;
                        velocity *= 20000000;
                        LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS4:
                    if (Time.fixedTime - stepTime > 2.0f)
                    {
                        // Give the fourth and final kick away from Jool
                        CelestialBody jool = FlightGlobals.Bodies.Where(b => b.name == "Jool").First();
                        velocity = (starJeb.transform.position - jool.transform.position).normalized;
                        velocity *= 200000000;
                        LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS5:
                    if (Time.fixedTime - stepTime > 2.0f)
                    {
                        // Move along
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_DRES1:
                    {
                        // Visit Dres
                        CelestialBody dres = FlightGlobals.Bodies.Where(b => b.name == "Dres").First();

                        // Determine which side the sun is on - makes for a better show
                        CelestialBody sun = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                        Vector3 sunnySide = sun.transform.position - dres.transform.position;
                        sunnySide.x = 0.0f;
                        sunnySide.y = 1; // Move across the top of the planet
                        sunnySide.z = Math.Sign(sunnySide.z);

                        // Set position for starjeb
                        float distance = 4.0f * (float)dres.Radius;
                        starJeb.SetPosition(dres.transform.position + new Vector3(distance, (float)dres.Radius, (float)dres.Radius * sunnySide.z));

                        velocity = (dres.transform.position - starJeb.transform.position + sunnySide * ((float)dres.Radius)).normalized;
                        velocity *= distance / 3.0f;
                        LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);
                        starJeb.SetWorldVelocity(dres.getRFrmVel(starJeb.transform.position));
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_DRES2:
                    {
                        // Camera to target Dres - do this on a seperate update to allow KSP to catch up
                        CelestialBody dres = FlightGlobals.Bodies.Where(b => b.name == "Dres").First();
                        FlightCamera.fetch.setTarget(starJeb.transform);
                        FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + (starJeb.transform.position - dres.transform.position).normalized * 10.0f);

                        // Make sure that the camera gets fixed
                        if (Time.fixedTime - stepTime > 0.1f)
                        {
                            nextState();
                        }
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_DRES3:
                    if (Time.fixedTime - stepTime > 5.5f)
                    {
                        // Done with Dres
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_DUNA1:
                    {
                        // Start between the sun and Duna
                        CelestialBody duna = FlightGlobals.Bodies.Where(b => b.name == "Duna").First();
                        CelestialBody sun = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                        Vector3 sunnySide = sun.transform.position - duna.transform.position;
                        sunnySide.Normalize();

                        // Set us up a nice 4 radiuses away...
                        float distance = 4.0f * (float)duna.Radius;
                        starJeb.SetPosition(duna.transform.position + sunnySide * distance);

                        // Go straight at Duna
                        velocity = (duna.transform.position - starJeb.transform.position).normalized;
                        velocity *= distance / 3.0f;
                        LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);

                        // Now offset him down so he doesn't actually hit Duna...
                        starJeb.SetPosition(starJeb.transform.position + new Vector3(0.0f, -((float)duna.Radius + 55000), 0.0f));
                        starJeb.SetWorldVelocity(duna.getRFrmVel(starJeb.transform.position));

                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_DUNA2:
                    {
                        // Camera to target Duna - do this on a seperate update to allow KSP to catch up
                        CelestialBody duna = FlightGlobals.Bodies.Where(b => b.name == "Duna").First();
                        FlightCamera.fetch.setTarget(starJeb.transform);
                        FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + (starJeb.transform.position - duna.transform.position).normalized * 25.0f);

                        // Make sure that the camera gets fixed
                        if (Time.fixedTime - stepTime > 0.1f)
                        {
                            nextState();
                        }
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_DUNA3:
                    if (Time.fixedTime - stepTime > 5.5f)
                    {
                        // Done with Duna
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EELOO1:
                    {
                        // Start perpendicular to the sun and Eeloo
                        CelestialBody eeloo = FlightGlobals.Bodies.Where(b => b.name == "Eeloo").First();
                        CelestialBody sun = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                        Vector3 perp = eeloo.transform.position - sun.transform.position;
                        float tmp = perp.x;
                        perp.x = -perp.z;
                        perp.z = tmp;
                        perp.Normalize();

                        // Set us up a nice 4 radiuses away...
                        float distance = 4.0f * (float)eeloo.Radius;
                        starJeb.SetPosition(eeloo.transform.position + perp * distance);

                        // Determine which side the sun is on - makes for a better show
                        Vector3 sunnySide = sun.transform.position - eeloo.transform.position;
                        sunnySide.Normalize();

                        // Go straight at Eeloo
                        velocity = (eeloo.transform.position - starJeb.transform.position).normalized;
                        velocity *= distance / 3.0f;
                        LoggingUtil.LogDebug(this, "kick magnitude will be: " + velocity);

                        // Now offset him down so he doesn't actually hit Eeloo...
                        starJeb.SetPosition(starJeb.transform.position + sunnySide * ((float)eeloo.Radius * 1.5f));
                        starJeb.SetWorldVelocity(eeloo.getRFrmVel(starJeb.transform.position));

                        nextState();

                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EELOO2:
                    {
                        // This time won't target directly towards Eeloo, as the player will have some idea
                        // what is up by now.
                        CelestialBody eeloo = FlightGlobals.Bodies.Where(b => b.name == "Eeloo").First();
                        CelestialBody sun = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                        Vector3 awayFromSun = sun.transform.position - eeloo.transform.position;
                        awayFromSun.Normalize();

                        FlightCamera.fetch.setTarget(starJeb.transform);
                        FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + awayFromSun * 50.0f);

                        // Make sure that the camera gets fixed
                        if (Time.fixedTime - stepTime > 0.1f)
                        {
                            nextState();
                        }
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EELOO3:
                    if (Time.fixedTime - stepTime > 5.5f)
                    {
                        velocity = null;

                        // Done with Eeloo
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EVE1:
                    {
                        CelestialBody eve = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                        Vector3 targetPosition = Destination.Value;
                        Vector3 normal = eve.GetSurfaceNVector(eveLatitude, eveLongitude);
                        startDistance = 10000000f;
                        Vector3 start = targetPosition + normal * startDistance;

                        starJeb.SetPosition(start);
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EVE2:
                    {
                        // Camera straight towards Eve - we're going in!
                        CelestialBody eve = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                        Vector3 awayFromEve = starJeb.transform.position - eve.transform.position;
                        awayFromEve.Normalize();

                        FlightCamera.fetch.setTarget(starJeb.transform);
                        FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + awayFromEve * 15.0f);

                        // Make sure that the camera gets fixed
                        if (Time.fixedTime - stepTime > 0.1f)
                        {
                            nextState();
                        }
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EVE3:
                    // Wait until we've held the position for a split second
                    if (Time.fixedTime - stepTime >= 9.3f)
                    {
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EVE4:
                    // Give the player a bit to get settled, then let the fun begins
                    if (Time.fixedTime - stepTime >= 15.0f)
                    {
                        // Spawn some asteroids
                        CelestialBody eve = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                        ScenarioDiscoverableObjects asteroidSpawner = (ScenarioDiscoverableObjects)HighLogic.CurrentGame.scenarios.Find(
                            s => s.moduleRef is ScenarioDiscoverableObjects).moduleRef;
                        System.Random random = new System.Random();

                        // Spawn some more asteroids
                        for (int i = 0; i < ASTEROID_COUNT; i++)
                        {
                            asteroidSpawner.SpawnAsteroid();
                        }

                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EVE5:
                    // Wait a full second after spawning the asteroids - we're not allowed to pull
                    // them off rails until they've been active a bit
                    if (Time.fixedTime - stepTime > 1.0f)
                    {
                        // Spawn some asteroids
                        CelestialBody eve = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                        System.Random random = new System.Random();

                        foreach (Vessel asteroid in FlightGlobals.Vessels.Where(v => v.vesselType == VesselType.SpaceObject).Reverse().Take(ASTEROID_COUNT))
                        {
                            // Set the position
                            double r = random.NextDouble() * 0.02 + 0.002;
                            double theta = random.NextDouble() * 2.0 * Math.PI;
                            double latitude = starJeb.latitude + r * Math.Sin(theta);
                            double longitude = starJeb.longitude + r * Math.Cos(theta);
                            double altitude = starJeb.altitude + 100 + random.NextDouble() * 200;
                            asteroid.SetPosition(eve.GetWorldSurfacePosition(latitude, longitude, altitude));
                            asteroid.ChangeWorldVelocity(asteroid.GetSrfVelocity());
                            asteroid.Load();
                            asteroid.GoOffRails();
                        }
                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_EVE6:
                    {
                        // Determine if there's an asteroid about to kill us
                        CelestialBody eve = FlightGlobals.Bodies.Where(b => b.name == "Eve").First();
                        bool killerAsteroid = FlightGlobals.Vessels.Where(v => v.mainBody == eve && v.vesselType == VesselType.SpaceObject &&
                            Vector3.Distance(starJeb.transform.position, v.transform.position) < 5.5 * ((int)v.DiscoveryInfo.objectSize + 1)).Any();

                        if (killerAsteroid || Time.fixedTime - stepTime > 20.0f)
                        {
                            foreach (Vessel asteroid in FlightGlobals.Vessels.Where(v => v.vesselType == VesselType.SpaceObject).Reverse().Take(ASTEROID_COUNT))
                            {
                                asteroid.Die();
                            }
                            nextState();
                        }
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_KERBIN1:
                    {
                        CheatOptions.NoCrashDamage = false;

                        // Start between the sun and Kerbin
                        CelestialBody kerbin = FlightGlobals.Bodies.Where(b => b.name == "Kerbin").First();
                        CelestialBody sun = FlightGlobals.Bodies.Where(b => b.name == "Sun").First();
                        Vector3 sunnySide = sun.transform.position - kerbin.transform.position;
                        sunnySide.Normalize();

                        // Set us up a nice 4 radiuses away...
                        float distance = 4.0f * (float)kerbin.Radius;
                        starJeb.SetPosition(kerbin.transform.position + sunnySide * distance);

                        // Orient him properly
                        KerbalEVA keva = starJeb.FindPartModulesImplementing<KerbalEVA>().First();
                        MethodInfo rotationMethod = typeof(KerbalEVA).GetMethod("correctGroundedRotation", BindingFlags.Instance | BindingFlags.NonPublic);
                        starJeb.packed = true;
                        rotationMethod.Invoke(keva, new object[] { });
                        starJeb.packed = false;

                        // Hardcode an orbital velocity, because it's late and I'm tired
                        starJeb.SetWorldVelocity(kerbin.getRFrmVel(starJeb.transform.position).normalized * 1085);

                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_KERBIN2:
                    {
                        // Camera to target kerbin - do this on a seperate update to allow KSP to catch up
                        CelestialBody kerbin = FlightGlobals.Bodies.Where(b => b.name == "Kerbin").First();
                        FlightCamera.fetch.setTarget(starJeb.transform);
                        FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + (starJeb.transform.position - kerbin.transform.position).normalized * 10.0f);

                        starJeb.SetRotation(FlightCamera.fetch.transform.rotation * Quaternion.AngleAxis(180.0f, FlightCamera.fetch.transform.up));

                        // Make sure that the camera gets fixed
                        if (Time.fixedTime - stepTime > 0.1f)
                        {
                            nextState();
                        }
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_KERBIN3:
                    if (Time.fixedTime - stepTime > 2.0f)
                    {
                        // Turn into star jeb
                        CelestialBody kerbin = FlightGlobals.Bodies.Where(b => b.name == "Kerbin").First();

                        starJeb.vesselName = "The Star Jeb";
                        Undress(starJeb.gameObject);
                        FlightCamera.fetch.SetCamCoordsFromPosition(starJeb.transform.position + (starJeb.transform.position - kerbin.transform.position).normalized * 1.5f);

                        nextState();
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_KERBIN4:
                    if (Time.fixedTime - stepTime < 15.0f)
                    {
                        CelestialBody kerbin = FlightGlobals.Bodies.Where(b => b.name == "Kerbin").First();
                        Vector3 camDirection = starJeb.transform.position + (starJeb.transform.position - kerbin.transform.position).normalized;
                    }
                    else
                    {
                        nextState();

                        monolith.Die();
                        monolith = null;

                        starJeb.Die();
                        starJeb = null;

                        Vessel discovery = ContractVesselTracker.Instance.GetAssociatedVessel("Discovery One");
                        FlightGlobals.ForceSetActiveVessel(discovery);
                    }
                    return false;
                case MonolithState.FULL_OF_STARS_FINAL:
                    nextState();
                    return true;
                default:
                    return false;
            }
        }