Exemplo n.º 1
0
        internal IEnumerator AirlaunchRoutine(AirlaunchParams launchParams, Guid vesselId, bool skipCountdown = false)
        {
            if (!skipCountdown)
            {
                yield return(_wfsTwo);
            }

            for (int i = 10; i > 0 && !skipCountdown; i--)
            {
                if (FlightGlobals.ActiveVessel == null || FlightGlobals.ActiveVessel.id != vesselId)
                {
                    ScreenMessages.PostScreenMessage("[KCT] Airlaunch cancelled", 5f, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Red);
                    yield break;
                }

                if (i == 1 && FlightGlobals.ActiveVessel.situation == Vessel.Situations.PRELAUNCH)
                {
                    // Make sure that the vessel situation transitions from Prelaunch to Landed before airlaunching
                    FlightGlobals.ActiveVessel.situation = Vessel.Situations.LANDED;
                }

                ScreenMessages.PostScreenMessage($"[KCT] Launching in {i}...", 1f, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Red);
                yield return(_wfsOne);
            }

            HyperEdit_Utilities.DoAirlaunch(launchParams);

            if (Utilities.IsPrincipiaInstalled)
            {
                StartCoroutine(ClobberPrincipia());
            }
        }
Exemplo n.º 2
0
        public static void DoAirlaunch(AirlaunchParams launchParams)
        {
            CelestialBody body   = FlightGlobals.currentMainBody;
            Vessel        vessel = FlightGlobals.ActiveVessel;

            // SpaceCenter.Instance.transform doesn't work correctly with RSS + KSCSwitcher installed
            PQSCity  ksc         = Utilities.FindKSC(body);
            Vector3d kscPosition = ksc.transform.position - body.position;
            Vector3d kscUp       = kscPosition.normalized;
            Vector3d kscEast     = Vector3d.Cross(body.angularVelocity, kscPosition).normalized;
            Vector3d kscNorth    = Vector3d.Cross(kscEast, kscUp);
            double   kscAltitude = kscPosition.magnitude - body.Radius;

            // From https://www.movable-type.co.uk/scripts/latlong-vectors.html#midpoint
            var δ = launchParams.KscDistance / body.Radius;
            var d = kscNorth * Math.Cos(Mathf.Deg2Rad * launchParams.KscAzimuth) + kscEast * Math.Sin(Mathf.Deg2Rad * launchParams.KscAzimuth);
            var teleportPosition = kscPosition * Math.Cos(δ) + body.Radius * d * Math.Sin(δ);

            teleportPosition += teleportPosition.normalized * (launchParams.Altitude - kscAltitude);

            Vector3d up               = teleportPosition.normalized;
            Vector3d east             = Vector3d.Cross(body.angularVelocity, teleportPosition).normalized;
            Vector3d north            = Vector3d.Cross(east, up);
            Vector3d teleportVelocity = Vector3d.Cross(body.angularVelocity, teleportPosition);

            teleportVelocity += (Math.Sin(Mathf.Deg2Rad * launchParams.LaunchAzimuth) * east + Math.Cos(Mathf.Deg2Rad * launchParams.LaunchAzimuth) * north) * launchParams.Velocity;

            // counter for the momentary fall when on rails
            teleportVelocity += up * (body.gravParameter / teleportPosition.sqrMagnitude / 2);

            teleportPosition = teleportPosition.xzy;
            teleportVelocity = teleportVelocity.xzy;

            Vector3d   to       = teleportPosition.xzy.normalized;
            Quaternion rotation = Quaternion.LookRotation(-to);

            rotation *= Quaternion.AngleAxis((float)launchParams.LaunchAzimuth, Vector3.back);

            Orbit orbit = vessel.orbitDriver.orbit.Clone();

            orbit.UpdateFromStateVectors(teleportPosition, teleportVelocity, body, Planetarium.GetUniversalTime());
            vessel.SetOrbit(orbit);
            vessel.SetRotation(rotation);

            ResetGroundContact(vessel);
        }
Exemplo n.º 3
0
        private IEnumerator AirlaunchRoutine(AirlaunchParams launchParams, Guid vesselId)
        {
            yield return(new WaitForSeconds(2));

            for (int i = 10; i > 0; i--)
            {
                if (FlightGlobals.ActiveVessel == null || FlightGlobals.ActiveVessel.id != vesselId)
                {
                    ScreenMessages.PostScreenMessage("[KCT] Airlaunch cancelled", 5f, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Red);
                    yield break;
                }

                ScreenMessages.PostScreenMessage($"[KCT] Launching in {i}...", 1f, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Red);
                yield return(new WaitForSeconds(1));
            }

            HyperEdit_Utilities.DoAirlaunch(launchParams);
        }
Exemplo n.º 4
0
        private IEnumerator AirlaunchRoutine(AirlaunchParams launchParams, Guid vesselId)
        {
            yield return(wfsTwo); // new WaitForSeconds(2);

            for (int i = 10; i > 0; i--)
            {
                if (FlightGlobals.ActiveVessel == null || FlightGlobals.ActiveVessel.id != vesselId)
                {
                    ScreenMessages.PostScreenMessage("[KCT] Airlaunch cancelled", 5f, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Red);
                    yield break;
                }

                if (i == 1 && FlightGlobals.ActiveVessel.situation == Vessel.Situations.PRELAUNCH)
                {
                    // Make sure that the vessel situation transitions from Prelaunch to Landed before airlaunching
                    FlightGlobals.ActiveVessel.situation = Vessel.Situations.LANDED;
                }

                ScreenMessages.PostScreenMessage($"[KCT] Launching in {i}...", 1f, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Red);
                yield return(wfsOne); // new WaitForSeconds(1);
            }

            HyperEdit_Utilities.DoAirlaunch(launchParams);
        }
Exemplo n.º 5
0
        public void Start()
        {
            if (KCT_Utilities.CurrentGameIsMission())
            {
                return;
            }

            KCTDebug.Log("Start called");

            // Subscribe to events from KSP and other mods
            if (!KCT_Events.instance.subscribedToEvents)
            {
                KCT_Events.instance.SubscribeToEvents();
            }

            KCT_GameStates.settings.Save(); //Save the settings file, with defaults if it doesn't exist
            KCT_PresetManager.Instance.SaveActiveToSaveData();

            // Ghetto event queue
            if (HighLogic.LoadedScene == GameScenes.EDITOR)
            {
                InvokeRepeating("EditorRecalculation", 1, 1);

                KCT_GUI.buildRateForDisplay = null;
                if (!KCT_GUI.PrimarilyDisabled)
                {
                    KCT_Utilities.RecalculateEditorBuildTime(EditorLogic.fetch.ship);
                }
            }

            if (KCT_GUI.PrimarilyDisabled)
            {
                if (InputLockManager.GetControlLock("KCTLaunchLock") == ControlTypes.EDITOR_LAUNCH)
                {
                    InputLockManager.RemoveControlLock("KCTLaunchLock");
                }
            }

            KACWrapper.InitKACWrapper();

            if (!KCT_PresetManager.Instance.ActivePreset.generalSettings.Enabled)
            {
                if (InputLockManager.GetControlLock("KCTKSCLock") == ControlTypes.KSC_FACILITIES)
                {
                    InputLockManager.RemoveControlLock("KCTKSCLock");
                }
                return;
            }

            //Begin primary mod functions

            KCT_GameStates.UT = Planetarium.GetUniversalTime();

            KCT_GUI.guiDataSaver.Load();

            switch (HighLogic.LoadedScene)
            {
            case GameScenes.EDITOR:

                //if (HighLogic.LoadedSceneIsEditor)
            {
                KCT_GUI.hideAll();
                if (!KCT_GUI.PrimarilyDisabled)
                {
                    KCT_GUI.showEditorGUI = KCT_GameStates.showWindows[1];
                    if (KCT_GUI.showEditorGUI)
                    {
                        KCT_GUI.ClickOn();
                    }
                    else
                    {
                        KCT_GUI.ClickOff();
                    }
                }
            }
            break;

            case GameScenes.SPACECENTER:
                //else if (HighLogic.LoadedScene == GameScenes.SPACECENTER)
            {
                bool shouldStart = KCT_GUI.showFirstRun;
                KCT_GUI.hideAll();
                if (!shouldStart)
                {
                    KCT_GUI.showBuildList = KCT_GameStates.showWindows[0];
                    if (KCT_GUI.showBuildList)
                    {
                        KCT_GUI.ClickOn();
                    }
                    else
                    {
                        KCT_GUI.ClickOff();
                    }
                }
                KCT_GUI.showFirstRun = shouldStart;
            }
            break;

            case GameScenes.FLIGHT:
                if (/*HighLogic.LoadedSceneIsFlight && */ FlightGlobals.ActiveVessel.situation == Vessel.Situations.PRELAUNCH &&
                    FlightGlobals.ActiveVessel.GetCrewCount() == 0 && KCT_GameStates.launchedCrew.Count > 0)
                {
                    KerbalRoster roster = HighLogic.CurrentGame.CrewRoster;

                    for (int i = 0; i < FlightGlobals.ActiveVessel.parts.Count; i++)
                    {
                        Part p = FlightGlobals.ActiveVessel.parts[i];
                        //KCTDebug.Log("craft: " + p.craftID);
                        KCTDebug.LogError("Part being tested: " + p.partInfo.title);
                        {
                            CrewedPart cP = KCT_GameStates.launchedCrew.Find(part => part.partID == p.craftID);
                            if (cP == null)
                            {
                                continue;
                            }
                            List <ProtoCrewMember> crewList = cP.crewList;
                            KCTDebug.LogError("cP.crewList.Count: " + cP.crewList.Count);
                            foreach (ProtoCrewMember crewMember in crewList)
                            {
                                if (crewMember != null)
                                {
                                    ProtoCrewMember finalCrewMember = crewMember;
                                    if (crewMember.type == ProtoCrewMember.KerbalType.Crew)
                                    {
                                        finalCrewMember = roster.Crew.FirstOrDefault(c => c.name == crewMember.name);
                                    }
                                    else if (crewMember.type == ProtoCrewMember.KerbalType.Tourist)
                                    {
                                        finalCrewMember = roster.Tourist.FirstOrDefault(c => c.name == crewMember.name);
                                    }
                                    if (finalCrewMember == null)
                                    {
                                        KCTDebug.LogError("Error when assigning " + crewMember.name + " to " + p.partInfo.name + ". Cannot find Kerbal in list.");
                                        continue;
                                    }
                                    try
                                    {
                                        KCTDebug.Log("Assigning " + finalCrewMember.name + " to " + p.partInfo.name);
                                        if (p.AddCrewmember(finalCrewMember))    //p.AddCrewmemberAt(finalCrewMember, crewList.IndexOf(crewMember)))
                                        {
                                            finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Assigned;
                                            if (finalCrewMember.seat != null)
                                            {
                                                finalCrewMember.seat.SpawnCrew();
                                            }
                                        }
                                        else
                                        {
                                            KCTDebug.LogError("Error when assigning " + crewMember.name + " to " + p.partInfo.name);
                                            finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Available;
                                            continue;
                                        }
                                    }
                                    catch
                                    {
                                        KCTDebug.LogError("Error when assigning " + crewMember.name + " to " + p.partInfo.name);
                                        finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Available;
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                    KCT_GameStates.launchedCrew.Clear();
                }
                //if (HighLogic.LoadedSceneIsFlight)
                {
                    KCT_GUI.hideAll();
                    if (KCT_GameStates.launchedVessel != null && FlightGlobals.ActiveVessel != null && FlightGlobals.ActiveVessel.situation == Vessel.Situations.PRELAUNCH)
                    {
                        KCT_GameStates.launchedVessel.KSC = null;     //it's invalid now
                        KCTDebug.Log("Attempting to remove launched vessel from build list");
                        bool removed = KCT_GameStates.launchedVessel.RemoveFromBuildList();
                        if (removed)     //Only do these when the vessel is first removed from the list
                        {
                            //Add the cost of the ship to the funds so it can be removed again by KSP
                            KCT_Utilities.AddFunds(KCT_GameStates.launchedVessel.cost, TransactionReasons.VesselRollout);
                            FlightGlobals.ActiveVessel.vesselName = KCT_GameStates.launchedVessel.shipName;
                        }

                        KCT_Recon_Rollout rollout = KCT_GameStates.ActiveKSC.Recon_Rollout.FirstOrDefault(r => r.associatedID == KCT_GameStates.launchedVessel.id.ToString());
                        if (rollout != null)
                        {
                            KCT_GameStates.ActiveKSC.Recon_Rollout.Remove(rollout);
                        }

                        KCT_AirlaunchPrep alPrep = KCT_GameStates.ActiveKSC.AirlaunchPrep.FirstOrDefault(r => r.associatedID == KCT_GameStates.launchedVessel.id.ToString());
                        if (alPrep != null)
                        {
                            KCT_GameStates.ActiveKSC.AirlaunchPrep.Remove(alPrep);
                        }

                        AirlaunchParams alParams = KCT_GameStates.AirlaunchParams;
                        if (alParams != null && alParams.KCTVesselId == KCT_GameStates.launchedVessel.id &&
                            (!alParams.KSPVesselId.HasValue || alParams.KSPVesselId == FlightGlobals.ActiveVessel.id))
                        {
                            if (!alParams.KSPVesselId.HasValue)
                            {
                                alParams.KSPVesselId = FlightGlobals.ActiveVessel.id;
                            }
                            StartCoroutine(AirlaunchRoutine(alParams, FlightGlobals.ActiveVessel.id));
                        }
                    }
                }
                break;
            }

            ratesUpdated = false;
            KCTDebug.Log("Start finished");

            wfsOne  = new WaitForSeconds(1f);
            wfsTwo  = new WaitForSeconds(2f);
            wfsHalf = new WaitForSeconds(0.5f);

            DelayedStart();

            UpdateTechlistIconColor();
            StartCoroutine(HandleEditorButton_Coroutine());
        }
Exemplo n.º 6
0
        public void Start()
        {
            KCTDebug.Log("Start called");
            if (Utilities.CurrentGameIsMission())
            {
                return;
            }

            // Subscribe to events from KSP and other mods
            if (!KCTEvents.Instance.SubscribedToEvents)
            {
                KCTEvents.Instance.SubscribeToEvents();
            }

            if (KCTGameStates.IsFirstStart)
            {
                PresetManager.Instance.SaveActiveToSaveData();
            }

            // Ghetto event queue
            if (HighLogic.LoadedScene == GameScenes.EDITOR)
            {
                InvokeRepeating("EditorRecalculation", 1, 1);

                KCT_GUI.BuildRateForDisplay = null;
                if (!KCT_GUI.IsPrimarilyDisabled)
                {
                    Utilities.RecalculateEditorBuildTime(EditorLogic.fetch.ship);
                }
            }

            if (KCT_GUI.IsPrimarilyDisabled &&
                InputLockManager.GetControlLock("KCTLaunchLock") == ControlTypes.EDITOR_LAUNCH)
            {
                InputLockManager.RemoveControlLock("KCTLaunchLock");
            }

            KACWrapper.InitKACWrapper();

            if (!PresetManager.Instance.ActivePreset.GeneralSettings.Enabled)
            {
                if (InputLockManager.GetControlLock("KCTKSCLock") == ControlTypes.KSC_FACILITIES)
                {
                    InputLockManager.RemoveControlLock("KCTKSCLock");
                }
                return;
            }

            //Begin primary mod functions

            KCTGameStates.UT = Utilities.GetUT();

            KCT_GUI.GuiDataSaver.Load();
            KCT_GUI.GUIStates.HideAllNonMainWindows();

            if (!HighLogic.LoadedSceneIsFlight)
            {
                bool b = KCTGameStates.SimulationParams.BuildSimulatedVessel;
                KCTGameStates.SimulationParams.Reset();
                if (b && KCTGameStates.LaunchedVessel != null)
                {
                    Utilities.AddVesselToBuildList(KCTGameStates.LaunchedVessel);
                }
            }

            switch (HighLogic.LoadedScene)
            {
            case GameScenes.EDITOR:
                KCT_GUI.HideAll();
                if (!KCT_GUI.IsPrimarilyDisabled)
                {
                    KCT_GUI.GUIStates.ShowEditorGUI = KCTGameStates.ShowWindows[1];
                    if (KCTGameStates.EditorShipEditingMode)
                    {
                        KCT_GUI.EnsureEditModeIsVisible();
                    }
                    else if (KCT_GUI.GUIStates.ShowEditorGUI)
                    {
                        KCT_GUI.ToggleVisibility(true);
                    }
                    else
                    {
                        KCT_GUI.ToggleVisibility(false);
                    }
                }
                break;

            case GameScenes.SPACECENTER:
                bool shouldStart = KCT_GUI.GUIStates.ShowFirstRun;
                KCT_GUI.HideAll();
                KCTGameStates.ClearVesselEditMode();
                if (!shouldStart)
                {
                    KCT_GUI.GUIStates.ShowBuildList = KCTGameStates.ShowWindows[0];
                    if (KCT_GUI.GUIStates.ShowBuildList)
                    {
                        KCT_GUI.ToggleVisibility(true);
                    }
                    else
                    {
                        KCT_GUI.ToggleVisibility(false);
                    }
                }
                KCT_GUI.GUIStates.ShowFirstRun = shouldStart;
                break;

            case GameScenes.TRACKSTATION:
                KCTGameStates.ClearVesselEditMode();
                break;

            case GameScenes.FLIGHT:
                if (!KCTGameStates.IsSimulatedFlight &&
                    FlightGlobals.ActiveVessel.situation == Vessel.Situations.PRELAUNCH &&
                    FlightGlobals.ActiveVessel.GetCrewCount() == 0 && KCTGameStates.LaunchedCrew.Count > 0)
                {
                    KerbalRoster roster = HighLogic.CurrentGame.CrewRoster;

                    for (int i = 0; i < FlightGlobals.ActiveVessel.parts.Count; i++)
                    {
                        Part p = FlightGlobals.ActiveVessel.parts[i];
                        KCTDebug.Log("Part being tested: " + p.partInfo.title);
                        {
                            CrewedPart cp = KCTGameStates.LaunchedCrew.Find(part => part.PartID == p.craftID);
                            if (cp == null)
                            {
                                continue;
                            }
                            List <ProtoCrewMember> crewList = cp.CrewList;
                            KCTDebug.Log("cP.crewList.Count: " + cp.CrewList.Count);
                            foreach (ProtoCrewMember crewMember in crewList)
                            {
                                if (crewMember != null)
                                {
                                    ProtoCrewMember finalCrewMember = crewMember;
                                    if (crewMember.type == ProtoCrewMember.KerbalType.Crew)
                                    {
                                        finalCrewMember = roster.Crew.FirstOrDefault(c => c.name == crewMember.name);
                                    }
                                    else if (crewMember.type == ProtoCrewMember.KerbalType.Tourist)
                                    {
                                        finalCrewMember = roster.Tourist.FirstOrDefault(c => c.name == crewMember.name);
                                    }
                                    if (finalCrewMember == null)
                                    {
                                        KCTDebug.LogError($"Error when assigning {crewMember.name} to {p.partInfo.name}. Cannot find Kerbal in list.");
                                        continue;
                                    }
                                    try
                                    {
                                        KCTDebug.Log($"Assigning {finalCrewMember.name } to {p.partInfo.name}");
                                        if (p.AddCrewmember(finalCrewMember))
                                        {
                                            finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Assigned;
                                            if (finalCrewMember.seat != null)
                                            {
                                                finalCrewMember.seat.SpawnCrew();
                                            }
                                        }
                                        else
                                        {
                                            KCTDebug.LogError($"Error when assigning {crewMember.name} to {p.partInfo.name}");
                                            finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Available;
                                            continue;
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        KCTDebug.LogError($"Error when assigning {crewMember.name} to {p.partInfo.name}: {ex}");
                                        finalCrewMember.rosterStatus = ProtoCrewMember.RosterStatus.Available;
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                    KCTGameStates.LaunchedCrew.Clear();
                }

                KCT_GUI.HideAll();
                if (!KCTGameStates.IsSimulatedFlight && KCTGameStates.LaunchedVessel != null && FlightGlobals.ActiveVessel?.situation == Vessel.Situations.PRELAUNCH)
                {
                    KCTGameStates.LaunchedVessel.KSC = null;     //it's invalid now
                    KCTDebug.Log("Attempting to remove launched vessel from build list");
                    bool removed = KCTGameStates.LaunchedVessel.RemoveFromBuildList();
                    if (removed)     //Only do these when the vessel is first removed from the list
                    {
                        //Add the cost of the ship to the funds so it can be removed again by KSP
                        Utilities.AddFunds(KCTGameStates.LaunchedVessel.Cost, TransactionReasons.VesselRollout);
                        FlightGlobals.ActiveVessel.vesselName = KCTGameStates.LaunchedVessel.ShipName;
                    }

                    ReconRollout rollout = KCTGameStates.ActiveKSC.Recon_Rollout.FirstOrDefault(r => r.AssociatedID == KCTGameStates.LaunchedVessel.Id.ToString());
                    if (rollout != null)
                    {
                        KCTGameStates.ActiveKSC.Recon_Rollout.Remove(rollout);
                    }

                    AirlaunchPrep alPrep = KCTGameStates.ActiveKSC.AirlaunchPrep.FirstOrDefault(r => r.AssociatedID == KCTGameStates.LaunchedVessel.Id.ToString());
                    if (alPrep != null)
                    {
                        KCTGameStates.ActiveKSC.AirlaunchPrep.Remove(alPrep);
                    }

                    AirlaunchParams alParams = KCTGameStates.AirlaunchParams;
                    if (alParams != null && alParams.KCTVesselId == KCTGameStates.LaunchedVessel.Id &&
                        (!alParams.KSPVesselId.HasValue || alParams.KSPVesselId == FlightGlobals.ActiveVessel.id))
                    {
                        if (!alParams.KSPVesselId.HasValue)
                        {
                            alParams.KSPVesselId = FlightGlobals.ActiveVessel.id;
                        }
                        StartCoroutine(AirlaunchRoutine(alParams, FlightGlobals.ActiveVessel.id));
                    }
                }
                break;
            }

            _ratesUpdated = false;
            KCTDebug.Log("Start finished");

            _wfsOne  = new WaitForSeconds(1f);
            _wfsTwo  = new WaitForSeconds(2f);
            _wfsHalf = new WaitForSeconds(0.5f);

            DelayedStart();

            UpdateTechlistIconColor();
            StartCoroutine(HandleEditorButton_Coroutine());
        }
Exemplo n.º 7
0
        public static void DrawAirlaunchWindow(int windowID)
        {
            if (_airlaunchParams == null)
            {
                _airlaunchParams = new AirlaunchParams();
                var lvl = AirlaunchTechLevel.GetCurrentLevel();
                if (lvl != null)
                {
                    _sKscDistance = (lvl.MaxKscDistance / 1000).ToString();
                    _sAltitude    = lvl.MaxAltitude.ToString();
                    _sVelocity    = lvl.MaxVelocity.ToString();
                }
            }

            GUILayout.BeginVertical();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Distance from Space Center: ", GUILayout.ExpandWidth(true));
            _sKscDistance = GUILayout.TextField(_sKscDistance, GUILayout.MaxWidth(70f));
            GUILayout.Label("km", GUILayout.Width(25f));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Azimuth from Space Center: ", GUILayout.ExpandWidth(true));
            _sKscAzimuth = GUILayout.TextField(_sKscAzimuth, GUILayout.MaxWidth(70f));
            GUILayout.Label("°", GUILayout.Width(25f));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Launch azimuth: ", GUILayout.ExpandWidth(true));
            _sAzimuth = GUILayout.TextField(_sAzimuth, GUILayout.MaxWidth(70f));
            GUILayout.Label("°", GUILayout.Width(25f));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Altitude from SL: ", GUILayout.ExpandWidth(true));
            _sAltitude = GUILayout.TextField(_sAltitude, GUILayout.MaxWidth(70f));
            GUILayout.Label("m", GUILayout.Width(25f));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Velocity: ", GUILayout.ExpandWidth(true));
            _sVelocity = GUILayout.TextField(_sVelocity, GUILayout.MaxWidth(70f));
            GUILayout.Label("m/s", GUILayout.Width(25f));
            GUILayout.EndHorizontal();

            if (_errorMsg != null)
            {
                if (_orangeText == null)
                {
                    _orangeText = new GUIStyle(GUI.skin.label);
                    _orangeText.normal.textColor = XKCDColors.Orange;
                }

                GUILayout.Label(_errorMsg, _orangeText);
            }

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Launch"))
            {
                HandleLaunch();
            }
            if (GUILayout.Button("Cancel"))
            {
                _centralWindowPosition.width = 150;
                _centralWindowPosition.x     = (Screen.width - 150) / 2;
                GUIStates.ShowAirlaunch      = false;
                GUIStates.ShowBuildList      = true;
                _errorMsg = null;
            }
            GUILayout.EndHorizontal();

            GUILayout.EndVertical();

            if (!Input.GetMouseButtonDown(1) && !Input.GetMouseButtonDown(2))
            {
                GUI.DragWindow();
            }
            ClampWindow(ref _airlaunchWindowPosition, strict: true);
        }