void decelerate(bool collision_detected) { VSL.Controls.StopWarp(); DecelerationTimer.Reset(); landing_stage = LandingStage.Decelerate; Working = collision_detected; }
public override void Init() { base.Init(); Dtol = LTRJ.Dtol; CorrectionTimer.Period = LTRJ.CorrectionTimer; StageTimer.action = () => { VSL.ActivateNextStage(); Message("Have to drop ballast to decelerate..."); }; dP_up_timer.action = () => { dP_threshold = Utils.ClampL(dP_threshold * 0.9, LTRJ.MinDPressure); last_dP = VSL.vessel.dynamicPressurekPa; }; dP_down_timer.action = () => { dP_threshold = Utils.ClampH(dP_threshold * 1.1, LTRJ.MaxDPressure); last_dP = VSL.vessel.dynamicPressurekPa; }; NoEnginesTimer.action = () => { landing_stage = LandingStage.HardLanding; }; sim = new AtmoSim(VSL); Executor = new ManeuverExecutor(TCA); scanner = new PQS_Scanner(VSL); scanner.MaxUnevennes = GLB.LND.MaxUnevenness / 3; dP_threshold = LTRJ.MaxDPressure; last_Err = 0; last_dP = 0; Working = false; }
void decelerate(bool collision_detected) { VSL.Controls.StopWarp(); DecelerationTimer.Reset(); landing_stage = LandingStage.Decelerate; Working = collision_detected; // Log("Current Trajectory:\n{}", trajectory);//debug }
void land() { if (CFG.Target != null && !CFG.Target.IsVessel) { LND.StartFromTarget(); } CFG.AP1.On(Autopilot1.Land); landing_stage = LandingStage.Land; }
protected void start_landing() { Working = false; clear_nodes(); update_trajectory(); VSL.Controls.StopWarp(); VSL.Controls.Aligned = false; CFG.AltitudeAboveTerrain = false; landing_stage = LandingStage.Wait; PressureASL = Body.GetPressure(0); }
protected override void reset() { base.reset(); landing_stage = LandingStage.None; DecelerationTimer.Reset(); dP_up_timer.Reset(); dP_down_timer.Reset(); dP_threshold = LTRJ.MaxDPressure; last_Err = 0; last_dP = 0; Working = false; }
void approach() { CFG.BR.Off(); CFG.BlockThrottle = true; CFG.AltitudeAboveTerrain = true; CFG.VF.On(VFlight.AltitudeControl); CFG.DesiredAltitude = LTRJ.ApproachAlt < VSL.Altitude.Relative / 2? LTRJ.ApproachAlt : Utils.ClampL(VSL.Altitude.Relative / 2, VSL.Geometry.H * 2); SetTarget(CFG.Target); CFG.Nav.On(Navigation.GoToTarget); if (CFG.Target.IsVessel) { CFG.Target.Radius = 7; } landing_stage = LandingStage.Approach; }
void BlastOff() { _landingStage = LandingStage.CantLand; _sr.sprite = RegularSprite; float radius = 0.0f; if (_landingObj == _Earth) radius = 10.0f; else if (IsAsteroid(_landingObj)) { radius = 13.0f; } Vector2 random = (new Vector2 (Random.Range (-1.0f, 1.0f), Random.Range (-1.0f, 1.0f))).normalized; Vector3 delta = radius * random; transform.position = transform.position + delta; _landingObj = null; HideText (); }
void CancelLandingPreparations(GameObject _Earth) { _landingStage = LandingStage.CantLand; _landingObj = null; HideText (); }
void PrepareToLandOn(GameObject target) { _landingStage = LandingStage.CanLand; _landingObj = target; ShowText ("Y to land on " + _landingObj.name); }
void InitiateLandingSequence() { _landingStage = LandingStage.Landing; _sr.sprite = LandingSprite; _landingStartTime = Time.time; }
/// <summary> /// Finalizes the landing. Extracts resources, adds to inventory. /// </summary> void FinalizeLanding() { _landingStage = LandingStage.Landed; _sr.sprite = LandedSprite; if (IsAsteroid (_landingObj)) { // Extract resources from this asteroid and add them to inventory this.GetComponent<Inventory> ().MineralXAmt += _landingObj.GetComponent<AsteroidValue> ().Extract (); ShowText ("Y to blast off"); } else { Inventory i = this.GetComponent<Inventory>(); i.returnedAmt += i.MineralXAmt; i.MineralXAmt = 0; ShowText ("A to upgrade; Y to blast off"); } }
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); }
void land() { CFG.AP1.On(Autopilot1.Land); landing_stage = LandingStage.Land; }
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); }