Beispiel #1
0
 void stop_aerobraking()
 {
     if (UseBrakes)
     {
         VSL.BrakesOn(false);
     }
     if (UseChutes && VSL.OnPlanetParams.ParachutesActive)
     {
         VSL.OnPlanetParams.CutActiveParachutes();
     }
 }
Beispiel #2
0
 void do_aerobraking_if_requested(bool full = false)
 {
     if (VSL.vessel.staticPressurekPa > 0)
     {
         if (UseBrakes)
         {
             VSL.BrakesOn();
         }
         if (UseChutes &&
             VSL.OnPlanetParams.HaveUsableParachutes &&
             (full || !VSL.OnPlanetParams.ParachutesActive))
         {
             VSL.OnPlanetParams.ActivateParachutesASAP();
         }
     }
 }
        IEnumerator <YieldInstruction> measure_area_with_brakes_and_run(Callback action)
        {
            var brakes = VSL.vessel.ActionGroups[KSPActionGroup.Brakes];

            VSL.BrakesOn();
            brakes_measured_timer.Reset();
            AreaWithBrakes = BoundsSideAreas.MinComponentF();
            while (!brakes_measured_timer.TimePassed)
            {
                TCAGui.Status(0.1, "Testing aero-brakes...");
                var min_area = BoundsSideAreas.MinComponentF();
                if (min_area > AreaWithBrakes)
                {
                    AreaWithBrakes = min_area;
                    brakes_measured_timer.Reset();
                }
                yield return(null);
            }
            if (!brakes)
            {
                VSL.BrakesOn(false);
            }
            action();
        }
Beispiel #4
0
        protected override void Update()
        {
            //update state
            if (was_landed && !VSL.LandedOrSplashed)
            {
                stage = Stage.JustTookoff; GearTimer.Reset(); StopAction.Reset();
            }
            else if (VSL.LandedOrSplashed && !was_landed)
            {
                stage = Stage.JustLanded1;
            }
            was_landed = VSL.LandedOrSplashed;
            switch (stage)
            {
            case Stage.JustLanded1:
                working();
                srf_normal = Vector3.zero;
                CFG.HF.OnIfNot(HFlight.Level);
                VSL.BrakesOn();
                LandedTimer.RunIf(() => stage = Stage.JustLanded2,
                                  VSL.HorizontalSpeed < C.MinHSpeed);
                break;

            case Stage.JustLanded2:
                if (ATC != null)
                {
                    if (srf_normal.IsZero())
                    {
                        RaycastHit hit;
                        if (Physics.Raycast(VSL.Physics.wCoM, -VSL.Physics.Up, out hit, VSL.Geometry.D, Radar.RadarMask))
                        {
                            if (hit.collider != null && !hit.normal.IsZero())
                            {
                                srf_normal = -hit.normal;
                                break;
                            }
                        }
                        stage = Stage.Landed;
                        break;
                    }
                    working();
                    CFG.HF.Off();
                    CFG.AT.OnIfNot(Attitude.Custom);
                    ATC.SetThrustDirW(srf_normal);
                    LandedTimer.RunIf(() => { stage = Stage.Landed; CFG.AT.Off(); },
                                      VSL.Physics.NoRotation || VSL.Controls.AttitudeError < 1);
                    break;
                }
                stage = Stage.Landed;
                break;

            case Stage.JustTookoff:
                working();
                StopAction.Run();
                GearTimer.RunIf(() =>
                {
                    VSL.BrakesOn(false);
                    VSL.GearOn(false);
                    stage = Stage.Flying;
                }, VSL.Altitude.Relative > 2 * VSL.Geometry.H);
                break;

            case Stage.Landed:
                if (CFG.VerticalCutoff <= 0)
                {
                    working(false);
                }
                else
                {
                    var avSqr = VSL.vessel.angularVelocity.sqrMagnitude;
                    if (VSL.HorizontalSpeed < C.MaxHSpeed &&
                        avSqr > C.MinAngularVelocity)
                    {
                        working();
                        CFG.HF.OnIfNot(HFlight.Level);
                        if (avSqr > C.GearOffAngularVelocity &&
                            VSL.OnPlanetParams.DTWR > C.MinDTWR)
                        {
                            VSL.GearOn(false);
                        }
                    }
                    else
                    {
                        working(false);
                    }
                }
                break;

            case Stage.Flying:
                working(false);
                if (!VSL.vessel.ActionGroups[KSPActionGroup.Gear])
                {
                    if (VSL.VerticalSpeed.Relative < 0 &&
                        VSL.HorizontalSpeed < C.GearOnMaxHSpeed &&
                        (!CFG.AT || !VSL.Altitude.AboveGround || VSL.Engines.Thrust.IsZero()) &&
                        VSL.Altitude.Relative +
                        VSL.VerticalSpeed.Relative * (VSL.OnPlanetParams.GearDeployTime + C.GearOnTime)
                        < C.GearOnAtH * VSL.Geometry.H)
                    {
                        VSL.GearOn();
                        VSL.BrakesOn();
                    }
                }
                else if (VSL.OnPlanetParams.GearDeploying)
                {
                    if (VSC != null)
                    {
                        VSC.SetpointOverride = Utils.ClampH((C.GearOnAtH * VSL.Geometry.H - VSL.Altitude.Relative) /
                                                            (VSL.OnPlanetParams.GearDeployTime + C.GearOnTime), 0);
                    }
                }
                else
                {
                    GearTimer.RunIf(() =>
                    {
                        VSL.GearOn(false);
                        VSL.BrakesOn(false);
                    },
                                    VSL.VerticalSpeed.Relative > 5 ||
                                    VSL.HorizontalSpeed > C.GearOnMaxHSpeed ||
                                    VSL.VerticalSpeed.Relative > 0 && VSL.Altitude.Relative > VSL.Geometry.H * 5);
                }
                break;
            }
        }
Beispiel #5
0
        protected bool do_land()
        {
            if (VSL.LandedOrSplashed)
            {
                THR.Throttle = 0;
                SetTarget();
                ClearStatus();
                CFG.AP2.Off();
                return(true);
            }
            VSL.Engines.ActivateEngines();
            if (VSL.Engines.MaxThrustM.Equals(0) && !VSL.Engines.HaveNextStageEngines)
            {
                landing_stage = LandingStage.HardLanding;
            }
            landing_deadzone = VSL.Geometry.D + CFG.Target.AbsRadius;
            if (VSL.vessel.dynamicPressurekPa > 0)
            {
                if (!dP_up_timer.RunIf(VSL.Controls.AttitudeError > last_Err ||
                                       Mathf.Abs(VSL.Controls.AttitudeError - last_Err) < 0.01f))
                {
                    dP_down_timer.RunIf(VSL.Controls.AttitudeError < last_Err &&
                                        VSL.vessel.dynamicPressurekPa < last_dP);
                }
            }
            else
            {
                dP_threshold = LTRJ.MaxDPressure;
            }
            rel_dP   = VSL.vessel.dynamicPressurekPa / dP_threshold;
            last_Err = VSL.Controls.AttitudeError;
            float    rel_Ve;
            double   terminal_velocity;
            Vector3d brake_pos, brake_vel, obt_vel;

            switch (landing_stage)
            {
            case LandingStage.Wait:
                Status("Preparing for deceleration...");
                THR.Throttle = 0;
                update_trajectory();
                nose_to_target();
                rel_altitude_if_needed();
                obt_vel   = VesselOrbit.getOrbitalVelocityAtUT(trajectory.BrakeStartUT);
                brake_pos = VesselOrbit.getRelativePositionAtUT(trajectory.BrakeStartUT);
                brake_vel = corrected_brake_velocity(obt_vel, brake_pos);
                brake_vel = corrected_brake_direction(brake_vel, brake_pos.xzy);
                CFG.AT.OnIfNot(Attitude.Custom);
                ATC.SetThrustDirW(brake_vel);
                VSL.Info.Countdown = trajectory.BrakeEndUT - VSL.Physics.UT - 1
                                     - Math.Max(MatchVelocityAutopilot.BrakingOffset((float)obt_vel.magnitude, VSL, out VSL.Info.TTB),
                                                LTRJ.MinBrakeOffset * (1 - Utils.ClampH(Body.atmDensityASL, 1)));
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                if (obstacle_ahead(trajectory) > 0)
                {
                    decelerate(true); break;
                }
                if (VSL.Info.Countdown <= rel_dP)
                {
                    decelerate(false); break;
                }
                if (VSL.Controls.CanWarp)
                {
                    VSL.Controls.WarpToTime = VSL.Physics.UT + VSL.Info.Countdown;
                }
                else
                {
                    VSL.Controls.StopWarp();
                }
                break;

            case LandingStage.Decelerate:
                rel_altitude_if_needed();
                update_trajectory();
                nose_to_target();
                if (Working)
                {
                    Status("red", "Possible collision detected.");
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                    Executor.Execute(VSL.Physics.Up * 10);
                    if (obstacle_ahead(trajectory) > 0)
                    {
                        CollisionTimer.Reset(); break;
                    }
                    if (!CollisionTimer.TimePassed)
                    {
                        break;
                    }
                    start_landing();
                    break;
                }
                else
                {
                    Status("white", "Decelerating. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    compute_terminal_velocity();
                    if (VSL.Controls.HaveControlAuthority)
                    {
                        DecelerationTimer.Reset();
                    }
                    if (Vector3d.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.WorldPos(Body) - VSL.Physics.wCoM) < 0)
                    {
                        if (Executor.Execute(-VSL.vessel.srf_velocity, LTRJ.BrakeEndSpeed))
                        {
                            break;
                        }
                    }
                    else if (!DecelerationTimer.TimePassed &&
                             trajectory.DistanceToTarget > landing_deadzone &&
                             Vector3d.Dot(CFG.Target.VectorTo(trajectory.SurfacePoint, Body), VSL.HorizontalSpeed.Vector) > 0)
                    {
                        brake_vel = corrected_brake_velocity(VesselOrbit.vel, VesselOrbit.pos);
                        brake_vel = corrected_brake_direction(brake_vel, VesselOrbit.pos.xzy);
                        //this is nice smoothing, but is dangerous on a low decending trajectory
                        VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        if (VSL.Info.Countdown - VSL.Torque.MaxCurrent.TurnTime - VSL.vessel.dynamicPressurekPa > VSL.Info.TTB)
                        {
                            brake_vel = brake_vel.normalized * VSL.HorizontalSpeed.Absolute * Utils.ClampH(trajectory.DistanceToTarget / CFG.Target.DistanceTo(VSL.vessel), 1);
                        }
                        if (Executor.Execute(-brake_vel, (float)Utils.ClampL(LTRJ.BrakeEndSpeed * Body.GeeASL, GLB.THR.MinDeltaV)))
                        {
                            break;
                        }
                    }
                }
                landing_stage = LandingStage.Coast;
                break;

            case LandingStage.Coast:
                Status("white", "Coasting. Landing site error: {0}", Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                THR.Throttle = 0;
                update_trajectory();
                nose_to_target();
                setup_for_deceleration();
                terminal_velocity = compute_terminal_velocity();
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                correct_landing_site();
                VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                VSL.Info.Countdown -= Math.Max(VSL.Info.TTB + VSL.Torque.NoEngines.TurnTime + VSL.vessel.dynamicPressurekPa, TRJ.ManeuverOffset);
                if (VSL.Info.Countdown <= 0)
                {
                    Working = false;
                    rel_Ve  = VSL.Engines.RelVeASL;
                    if (rel_Ve <= 0)
                    {
                        Message(10, "Not enough thrust to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    if (!(VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                    {
                        Message(10, "Lacking control authority to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve);
                    if (!CheatOptions.InfinitePropellant &&
                        (fuel_needed >= fuel_left ||
                         VSL.Engines.MaxHoverTimeASL(fuel_left - fuel_needed) < LTRJ.HoverTimeThreshold))
                    {
                        Message(10, "Not enough fuel to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    landing_stage = LandingStage.SoftLanding;
                }
                break;

            case LandingStage.HardLanding:
                Status("yellow", "Emergency Landing...");
                set_destination_vector();
                update_trajectory();
                VSL.BrakesOn();
                CFG.BR.Off();
                setup_for_deceleration();
                terminal_velocity = compute_terminal_velocity();
                if (VSL.Engines.MaxThrustM > 0 &&
                    (VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                {
                    rel_Ve = VSL.Engines.RelVeASL;
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = rel_Ve > 0? VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve) : fuel_left * 2;
                    VSL.Info.Countdown -= fuel_left > fuel_needed?
                                          VSL.Engines.TTB((float)terminal_velocity) :
                                              VSL.Engines.TTB(VSL.Engines.DeltaV(fuel_left));

                    if ((VSL.Info.Countdown < 0 &&
                         (!VSL.OnPlanetParams.HaveParachutes ||
                          VSL.OnPlanetParams.ParachutesActive && VSL.OnPlanetParams.ParachutesDeployed)))
                    {
                        THR.Throttle = VSL.VerticalSpeed.Absolute < -5? 1 : VSL.OnPlanetParams.GeeVSF;
                    }
                    else
                    {
                        THR.Throttle = 0;
                    }
                    Status("yellow", "Not enough fuel to land properly.\nWill deceletate as much as possible before impact...");
                }
                if (Body.atmosphere && VSL.OnPlanetParams.HaveUsableParachutes)
                {
                    VSL.OnPlanetParams.ActivateParachutes();
                    if (!VSL.OnPlanetParams.ParachutesActive)
                    {
                        ATC.SetCustomRotationW(VSL.Geometry.MaxAreaDirection, VSL.Physics.Up);
                        StageTimer.RunIf(Body.atmosphere &&                         //!VSL.Controls.HaveControlAuthority &&
                                         VSL.vessel.currentStage - 1 > VSL.OnPlanetParams.NearestParachuteStage &&
                                         VSL.vessel.dynamicPressurekPa > LTRJ.DropBallastThreshold * PressureASL &&
                                         VSL.vessel.mach > LTRJ.MachThreshold);
                        if (CFG.AutoParachutes)
                        {
                            Status("yellow", "Waiting for safe speed to deploy parachutes.\n" +
                                   "Trying to decelerate using drag...");
                        }
                        else
                        {
                            Status("red", "Automatic parachute deployment is disabled.\nActivate parachutes manually when needed.");
                        }
                    }
                }
                if (!VSL.OnPlanetParams.HaveParachutes &&
                    !VSL.Engines.HaveNextStageEngines &&
                    (VSL.Engines.MaxThrustM.Equals(0) || !VSL.Controls.HaveControlAuthority))
                {
                    if (Body.atmosphere)
                    {
                        ATC.SetCustomRotationW(VSL.Geometry.MaxAreaDirection, VSL.Physics.Up);
                    }
                    Status("red", "Crash is imminent.\nImpact speed: {0}", Utils.formatBigValue((float)terminal_velocity, "m/s"));
                }
                break;

            case LandingStage.SoftLanding:
                THR.Throttle = 0;
                set_destination_vector();
                update_trajectory();
                setup_for_deceleration();
                compute_terminal_velocity();
                nose_to_target();
                if (Working)
                {
                    Status("white", "Final deceleration. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    ATC.SetThrustDirW(correction_direction());
                    if (VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        var brake_spd  = Mathf.Max(VSL.HorizontalSpeed.Absolute, -VSL.VerticalSpeed.Absolute);
                        var min_thrust = Utils.Clamp(brake_spd / (VSL.Engines.MaxAccel - VSL.Physics.G) /
                                                     Utils.ClampL((float)VSL.Info.Countdown, 0.01f),
                                                     VSL.OnPlanetParams.GeeVSF, 1);
                        THR.Throttle = Utils.Clamp(brake_spd / LTRJ.BrakeThrustThreshod, min_thrust, 1);
                    }
                    else
                    {
                        THR.Throttle = 1;
                    }
                    if (VSL.vessel.srfSpeed > LTRJ.BrakeEndSpeed)
                    {
                        Working = THR.Throttle.Equals(1) || VSL.Info.Countdown < 10;
                        break;
                    }
                }
                else
                {
                    var turn_time = VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError);
                    correct_attitude_with_thrusters(turn_time);
                    correct_landing_site();
                    VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                    VSL.Info.Countdown -= VSL.Info.TTB + turn_time + LTRJ.FinalBrakeOffset;
                    if (VSL.Controls.InvAlignmentFactor > 0.5)
                    {
                        Status("white", "Final deceleration: correcting attitude.\nLanding site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    }
                    else
                    {
                        Status("white", "Final deceleration: waiting for the burn.\nLanding site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    }
                    Working = VSL.Info.Countdown <= 0 || VSL.vessel.srfSpeed < LTRJ.BrakeEndSpeed;
                    break;
                }
                THR.Throttle = 0;
                if (CFG.Target.DistanceTo(VSL.vessel) - VSL.Geometry.R > LTRJ.Dtol)
                {
                    approach();
                }
                else
                {
                    land();
                }
                break;

            case LandingStage.Approach:
                Status("Approaching the target...");
                set_destination_vector();
                if (!CFG.Nav[Navigation.GoToTarget])
                {
                    land();
                }
                break;

            case LandingStage.Land:
                set_destination_vector();
                break;
            }
            return(false);
        }
Beispiel #6
0
 protected override void Update()
 {
     if (!IsActive)
     {
         return;
     }
     //update state
     if (last_state && !VSL.LandedOrSplashed)
     {
         tookoff = true; landed = false; GearTimer.Reset(); StopAction.Reset();
     }
     else if (VSL.LandedOrSplashed && !last_state)
     {
         landed = true; tookoff = false;
     }
     last_state = VSL.LandedOrSplashed;
     //just landed
     if (landed)
     {
         working();
         CFG.HF.OnIfNot(HFlight.Level);
         VSL.BrakesOn();
         LandedTimer.RunIf(() => landed = false,
                           VSL.HorizontalSpeed < TLA.MinHSpeed);
     }
     //just took off
     else if (tookoff)
     {
         working();
         StopAction.Run();
         GearTimer.RunIf(() =>
         {
             VSL.BrakesOn(false);
             VSL.GearOn(false);
             tookoff = false;
         }, VSL.Altitude.Relative > TLA.GearOnAtH + VSL.Geometry.H);
     }
     //moving on the ground
     else if (VSL.LandedOrSplashed)
     {
         var avSqr = VSL.vessel.angularVelocity.sqrMagnitude;
         if (VSL.HorizontalSpeed < TLA.MaxHSpeed &&
             avSqr > TLA.MinAngularVelocity)
         {
             working();
             CFG.HF.OnIfNot(HFlight.Level);
             if (avSqr > TLA.GearOffAngularVelocity &&
                 VSL.OnPlanetParams.DTWR > TLA.MinDTWR)
             {
                 VSL.GearOn(false);
             }
         }
         else
         {
             working(false);
         }
     }
     //if flying, check if trying to land and deploy the gear
     else
     {
         working(false);
         //if the gear is on, nothing to do; and autopilot takes precedence
         if (!VSL.vessel.ActionGroups[KSPActionGroup.Gear])
         {
             //check boundary conditions
             GearTimer.RunIf(() =>
             {
                 VSL.GearOn();
                 VSL.BrakesOn();
             },
                             VSL.VerticalSpeed.Relative < 0 &&
                             VSL.HorizontalSpeed < TLA.GearOnMaxHSpeed &&
                             VSL.Altitude.Relative + VSL.VerticalSpeed.Relative * (TLA.GearOnTime + TLA.GearTimer) < TLA.GearOnAtH * VSL.Geometry.H);
         }
         else
         {
             GearTimer.RunIf(() =>
             {
                 VSL.GearOn(false);
                 VSL.BrakesOn(false);
             },
                             VSL.VerticalSpeed.Relative > 5 ||
                             VSL.HorizontalSpeed > TLA.GearOnMaxHSpeed ||
                             VSL.VerticalSpeed.Relative > 0 && VSL.Altitude.Relative > VSL.Geometry.H * 5);
         }
     }
 }
Beispiel #7
0
        protected bool do_land()
        {
            if (VSL.LandedOrSplashed)
            {
                stop_aerobraking();
                THR.Throttle = 0;
                SetTarget();
                ClearStatus();
                CFG.AP2.Off();
                return(true);
            }
            update_trajectory();
            VSL.Engines.ActivateEngines();
            NoEnginesTimer.RunIf(VSL.Engines.MaxThrustM.Equals(0) && !VSL.Engines.HaveNextStageEngines);
            landing_deadzone = VSL.Geometry.D + CFG.Target.AbsRadius;
            if (VSL.vessel.dynamicPressurekPa > 0)
            {
                if (!dP_up_timer.RunIf(VSL.Controls.AttitudeError > last_Err ||
                                       Mathf.Abs(VSL.Controls.AttitudeError - last_Err) < 0.01f))
                {
                    dP_down_timer.RunIf(VSL.Controls.AttitudeError < last_Err &&
                                        VSL.vessel.dynamicPressurekPa < last_dP);
                }
            }
            else
            {
                dP_threshold = LTRJ.MaxDPressure;
            }
            rel_dP   = VSL.vessel.dynamicPressurekPa / dP_threshold;
            last_Err = VSL.Controls.AttitudeError;
            float    rel_Ve;
            Vector3d brake_pos, brake_vel, obt_vel;
            var      vessel_within_range   = CFG.Target.DistanceTo(VSL.vessel) < LTRJ.Dtol;
            var      vessel_after_target   = Vector3.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.VectorTo(VSL.vessel)) >= 0;
            var      target_within_range   = trajectory.DistanceToTarget < LTRJ.Dtol;
            var      landing_before_target = trajectory.DeltaR > 0;
            var      terminal_velocity     = compute_terminal_velocity();;

            switch (landing_stage)
            {
            case LandingStage.Wait:
                Status("Preparing for deceleration...");
                THR.Throttle = 0;
                nose_to_target();
                rel_altitude_if_needed();
                obt_vel   = VesselOrbit.getOrbitalVelocityAtUT(trajectory.BrakeStartUT);
                brake_pos = VesselOrbit.getRelativePositionAtUT(trajectory.BrakeStartUT);
                brake_vel = corrected_brake_velocity(obt_vel, brake_pos);
                brake_vel = corrected_brake_direction(brake_vel, brake_pos.xzy);
                CFG.AT.OnIfNot(Attitude.Custom);
                ATC.SetThrustDirW(brake_vel);
                var offset = MatchVelocityAutopilot.BrakingOffset((float)obt_vel.magnitude, VSL, out VSL.Info.TTB);
                offset             = Mathf.Lerp(VSL.Info.TTB, offset, Utils.Clamp(VSL.Engines.TMR - 0.1f, 0, 1));
                VSL.Info.Countdown = trajectory.BrakeEndUT - VSL.Physics.UT - 1
                                     - Math.Max(offset, LTRJ.MinBrakeOffset * (1 - Utils.ClampH(Body.atmDensityASL, 1)));
                correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                if (obstacle_ahead(trajectory) > 0)
                {
                    decelerate(true); break;
                }
                if (VSL.Info.Countdown <= rel_dP ||
                    will_overheat(trajectory.GetAtmosphericCurve(5, VSL.Physics.UT + TRJ.ManeuverOffset)))
                {
                    decelerate(false); break;
                }
                if (VSL.Controls.CanWarp)
                {
                    VSL.Controls.WarpToTime = VSL.Physics.UT + VSL.Info.Countdown;
                }
                else
                {
                    VSL.Controls.StopWarp();
                }
                if (CorrectTarget && VSL.Info.Countdown < CorrectionOffset)
                {
                    scan_for_landing_site();
                }
                break;

            case LandingStage.Decelerate:
                rel_altitude_if_needed();
                CFG.BR.Off();
                if (Working)
                {
                    Status("red", "Possible collision detected.");
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                    Executor.Execute(VSL.Physics.Up * 10);
                    if (obstacle_ahead(trajectory) > 0)
                    {
                        CollisionTimer.Reset(); break;
                    }
                    if (!CollisionTimer.TimePassed)
                    {
                        break;
                    }
                    start_landing();
                    break;
                }
                else
                {
                    Status("white", "Decelerating. Landing site error: {0}",
                           Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                    if (CorrectTarget)
                    {
                        scan_for_landing_site();
                    }
                    do_aerobraking_if_requested();
                    if (VSL.Controls.HaveControlAuthority)
                    {
                        DecelerationTimer.Reset();
                    }
                    if (Vector3d.Dot(VSL.HorizontalSpeed.Vector, CFG.Target.WorldPos(Body) - VSL.Physics.wCoM) < 0)
                    {
                        if (Executor.Execute(-VSL.vessel.srf_velocity, LTRJ.BrakeEndSpeed))
                        {
                            break;
                        }
                    }
                    else if (!DecelerationTimer.TimePassed &&
                             trajectory.DistanceToTarget > landing_deadzone &&
                             Vector3d.Dot(CFG.Target.VectorTo(trajectory.SurfacePoint, Body), VSL.HorizontalSpeed.Vector) > 0)
                    {
                        THR.Throttle = 0;
                        brake_vel    = corrected_brake_velocity(VesselOrbit.vel, VesselOrbit.pos);
                        brake_vel    = corrected_brake_direction(brake_vel, VesselOrbit.pos.xzy);
                        VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        var aerobraking = rel_dP > 0 && VSL.OnPlanetParams.ParachutesActive;
                        if (!vessel_after_target)
                        {
                            var overheating = rel_dP > 0 &&
                                              VSL.vessel.Parts.Any(p =>
                                                                   p.temperature / p.maxTemp > PhysicsGlobals.TemperatureGaugeThreshold ||
                                                                   p.skinTemperature / p.skinMaxTemp > PhysicsGlobals.TemperatureGaugeThreshold);
                            if (!overheating)
                            {
                                ATC.SetThrustDirW(brake_vel);
                                THR.Throttle = CFG.Target.DistanceTo(VSL.vessel) > trajectory.DistanceToTarget?
                                               (float)Utils.ClampH(trajectory.DistanceToTarget / LTRJ.Dtol / 2, 1) : 1;
                            }
                            else
                            {
                                THR.Throttle = 1;
                            }
                        }
                        if (THR.Throttle > 0 || aerobraking)
                        {
                            break;
                        }
                    }
                }
                if (landing_before_target ||
                    target_within_range && !vessel_within_range)
                {
                    stop_aerobraking();
                }
                landing_stage = LandingStage.Coast;
                break;

            case LandingStage.Coast:
                Status("white", "Coasting. Landing site error: {0}", Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                THR.Throttle = 0;
                nose_to_target();
                setup_for_deceleration();
                if (correct_landing_site())
                {
                    correct_attitude_with_thrusters(VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError));
                }
                if (landing_before_target ||
                    target_within_range && !vessel_within_range)
                {
                    stop_aerobraking();
                }
                VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                VSL.Info.Countdown -= Math.Max(VSL.Info.TTB + VSL.Torque.NoEngines.TurnTime + VSL.vessel.dynamicPressurekPa, ManeuverOffset);
                if (VSL.Info.Countdown > 0)
                {
                    if (THR.Throttle.Equals(0))
                    {
                        warp_to_coundown();
                    }
                }
                else
                {
                    Working = false;
                    rel_Ve  = VSL.Engines.RelVeASL;
                    if (rel_Ve <= 0)
                    {
                        Message(10, "Not enough thrust for powered landing.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    if (!(VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                    {
                        Message(10, "Lacking control authority to land properly.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
                        break;
                    }
                    var fuel_left         = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed       = VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve);
                    var needed_hover_time = LandASAP? LTRJ.HoverTimeThreshold / 5 : LTRJ.HoverTimeThreshold;
                    if (!CheatOptions.InfinitePropellant &&
                        (fuel_needed >= fuel_left ||
                         VSL.Engines.MaxHoverTimeASL(fuel_left - fuel_needed) < needed_hover_time))
                    {
                        Message(10, "Not enough fuel for powered landing.\nPerforming emergency landing...");
                        landing_stage = LandingStage.HardLanding;
//						Log("Hard Landing. Trajectory:\n{}", trajectory);//debug
                        break;
                    }
                    landing_stage = LandingStage.SoftLanding;
//					Log("Soft Landing. Trajectory:\n{}", trajectory);//debug
                }
                break;

            case LandingStage.HardLanding:
                Status("yellow", VSL.OnPlanetParams.ParachutesActive?
                       "Landing on parachutes..." : "Emergency Landing...");
                set_destination_vector();
                CFG.BR.Off();
                var not_too_hot = VSL.vessel.externalTemperature < VSL.Physics.MinMaxTemperature;
                if (not_too_hot)
                {
                    setup_for_deceleration();
                }

                if (VSL.Engines.MaxThrustM > 0 &&
                    (VSL.Controls.HaveControlAuthority || VSL.Torque.HavePotentialControlAuthority))
                {
                    rel_Ve = VSL.Engines.RelVeASL;
                    var fuel_left   = VSL.Engines.GetAvailableFuelMass();
                    var fuel_needed = rel_Ve > 0? VSL.Engines.FuelNeeded((float)terminal_velocity, rel_Ve) : fuel_left * 2;
                    VSL.Info.Countdown -= fuel_left > fuel_needed?
                                          VSL.Engines.TTB((float)terminal_velocity) :
                                              VSL.Engines.TTB(VSL.Engines.DeltaV(fuel_left));

                    if ((VSL.Info.Countdown < 0 &&
                         (!VSL.OnPlanetParams.HaveParachutes ||
                          VSL.OnPlanetParams.ParachutesActive && VSL.OnPlanetParams.ParachutesDeployed)))
                    {
                        THR.Throttle = VSL.VerticalSpeed.Absolute < -5? 1 : VSL.OnPlanetParams.GeeVSF;
                    }
                    else if (VSL.Info.Countdown > 0.5f)
                    {
                        THR.Throttle = 0;
                    }
                    Status("yellow", "Not enough fuel for powered landing.\nWill deceletate as much as possible before impact.");
                }
                if (Body.atmosphere && VSL.OnPlanetParams.HaveUsableParachutes)
                {
                    if (vessel_within_range || vessel_after_target ||
                        trajectory.BrakeEndUT - VSL.Physics.UT < LTRJ.ParachutesDeployOffset)
                    {
                        VSL.OnPlanetParams.ActivateParachutesASAP();
                    }
                    else
                    {
                        VSL.OnPlanetParams.ActivateParachutesBeforeUnsafe();
                    }
                    if (!VSL.OnPlanetParams.ParachutesActive)
                    {
                        //don't push our luck when it's too hot outside
                        if (not_too_hot)
                        {
                            brake_with_drag();
                        }
                        else
                        {
                            CFG.AT.Off();
                            CFG.StabilizeFlight = false;
                            VSL.vessel.ActionGroups.SetGroup(KSPActionGroup.SAS, false);
                        }
                        StageTimer.RunIf(Body.atmosphere &&                         //!VSL.Controls.HaveControlAuthority &&
                                         VSL.vessel.currentStage - 1 > VSL.OnPlanetParams.NearestParachuteStage &&
                                         VSL.vessel.dynamicPressurekPa > LTRJ.DropBallastThreshold * PressureASL &&
                                         VSL.vessel.mach > LTRJ.MachThreshold);
                        if (CFG.AutoParachutes)
                        {
                            Status("yellow", "Waiting for the right moment to deploy parachutes...");
                        }
                        else
                        {
                            Status("red", "Automatic parachute deployment is disabled.\nActivate parachutes manually when needed.");
                        }
                    }
                }
                if (Body.atmosphere)
                {
                    VSL.BrakesOn();
                }
                if (!VSL.OnPlanetParams.HaveParachutes &&
                    !VSL.Engines.HaveNextStageEngines &&
                    (VSL.Engines.MaxThrustM.Equals(0) || !VSL.Controls.HaveControlAuthority))
                {
                    if (Body.atmosphere && not_too_hot)
                    {
                        brake_with_drag();
                    }
                    Status("red", "Crash is imminent.\nVertical impact speed: {0}", Utils.formatBigValue((float)terminal_velocity, "m/s"));
                }
                break;

            case LandingStage.SoftLanding:
                CFG.BR.Off();
                THR.Throttle = 0;
                set_destination_vector();
                setup_for_deceleration();
                if (vessel_within_range || vessel_after_target ||
                    trajectory.BrakeEndUT - VSL.Physics.UT < LTRJ.ParachutesDeployOffset)
                {
                    do_aerobraking_if_requested(true);
                }
                var turn_time = VSL.Torque.MaxPossible.MinRotationTime(VSL.Controls.AttitudeError);
                if (!Working)
                {
                    correct_landing_site();
                    correct_attitude_with_thrusters(turn_time);
                    VSL.Info.TTB = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                    //VSL.Engines.OnPlanetTTB(VSL.vessel.srf_velocity, VSL.Physics.Up);
                    VSL.Info.Countdown -= VSL.Info.TTB + turn_time;
                    Working             = VSL.Info.Countdown <= 0 || VSL.vessel.srfSpeed < LTRJ.BrakeEndSpeed;        //TODO: is this correct?
                    if (!Working)
                    {
                        if (VSL.Controls.InvAlignmentFactor > 0.5)
                        {
                            Status("white", "Final deceleration: correcting attitude.\nLanding site error: {0}",
                                   Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        }
                        else
                        {
                            Status("white", "Final deceleration: waiting for the burn.\nLanding site error: {0}",
                                   Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        }
                        break;
                    }
                }
                if (Working)
                {
                    ATC.SetThrustDirW(correction_direction());
                    if (!VSL.Controls.HaveControlAuthority)
                    {
                        correct_attitude_with_thrusters(turn_time);
                        if (!VSL.Torque.HavePotentialControlAuthority)
                        {
                            landing_stage = LandingStage.HardLanding;
                        }
                        break;
                    }
                    if (vessel_within_range || VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        var brake_spd  = -VSL.VerticalSpeed.Absolute;
                        var min_thrust = Utils.Clamp(brake_spd / (VSL.Engines.MaxAccel - VSL.Physics.G) /
                                                     Utils.ClampL((float)VSL.Info.Countdown, 0.01f),
                                                     VSL.OnPlanetParams.GeeVSF, 1);
                        THR.Throttle = Utils.Clamp(brake_spd / LTRJ.BrakeThrustThreshod, min_thrust, 1);
                    }
                    else
                    {
                        THR.Throttle = 1;
                    }
                    if (vessel_within_range && VSL.Altitude.Relative > GLB.LND.StopAtH * VSL.Geometry.D ||
                        VSL.Altitude.Relative > GLB.LND.WideCheckAltitude)
                    {
                        VSL.Info.TTB        = VSL.Engines.TTB((float)VSL.vessel.srfSpeed);
                        VSL.Info.Countdown -= VSL.Info.TTB + turn_time;
                        Working             = THR.Throttle > 0.7 || VSL.Info.Countdown < 10;
                        Status("white", "Final deceleration. Landing site error: {0}",
                               Utils.formatBigValue((float)trajectory.DistanceToTarget, "m"));
                        break;
                    }
                }
                THR.Throttle = 0;
                if (LandASAP)
                {
                    landing_stage = LandingStage.LandHere;
                }
                else
                {
                    stop_aerobraking();
                    if (CFG.Target.DistanceTo(VSL.vessel) - VSL.Geometry.R > LTRJ.Dtol)
                    {
                        approach();
                    }
                    else
                    {
                        land();
                    }
                }
                break;

            case LandingStage.LandHere:
                Status("lime", "Landing...");
                CFG.BR.Off();
                CFG.BlockThrottle        = true;
                CFG.AltitudeAboveTerrain = true;
                CFG.VF.On(VFlight.AltitudeControl);
                CFG.HF.OnIfNot(HFlight.Stop);
                if (CFG.DesiredAltitude >= 0 && !VSL.HorizontalSpeed.MoovingFast)
                {
                    CFG.DesiredAltitude = 0;
                }
                else
                {
                    CFG.DesiredAltitude = Utils.ClampL(VSL.Altitude.Relative / 2, VSL.Geometry.H * 2);
                }
                break;

            case LandingStage.Approach:
                Status("Approaching the target...");
                set_destination_vector();
                if (!CFG.Nav[Navigation.GoToTarget])
                {
                    land();
                }
                break;

            case LandingStage.Land:
                set_destination_vector();
                break;
            }
            return(false);
        }