Exemple #1
0
 /// <summary>
 /// Here when the add-on loads upon flight start.
 /// </summary>
 public void Start()
 {
     Logging.Log("Starting");
     userSelection      = AltimeterDisplayState.DEFAULT;
     userClickedTumbler = false;
     parachutes.Clear();
     vesselId        = uint.MaxValue;
     vesselPartCount = -1;
     isGamePaused    = false;
 }
Exemple #2
0
 /// <summary>
 /// Here whenever the altimeter display mode gets toggled (either by the player or by this mod).
 /// </summary>
 /// <param name="data"></param>
 private void OnAltimeterDisplayModeToggle(AltimeterDisplayState mode)
 {
     Logging.Log("Altimeter mode changed to: " + mode);
     earliestAllowableToggleTime = DateTime.Now + MINIMUM_DWELL_TIME;
     if (userClickedTumbler)
     {
         userClickedTumbler = false;
         userSelection      = mode;
     }
 }
Exemple #3
0
        /// <summary>
        /// Based on the current ship situation, determine what state the altimeter should be in.
        /// Returns DEFAULT if "not applicable" and there's no recommendation.
        /// </summary>
        /// <param name="vessel">The vessel for which we're recommending.</param>
        /// <param name="parachutes">The set of parachutes on the vessel.</param>
        /// <param name="previousState">The prior state of the altimeter.</param>
        /// <param name="reason">The reason for the recommendation. May be empty if the recommendation is the same as the previous state.</param>
        /// <returns></returns>
        private static AltimeterDisplayState RecommendAltimeterState(
            Vessel vessel,
            List <ModuleParachute> parachutes,
            AltimeterDisplayState previousState,
            out string reason)
        {
            reason = string.Empty;

            // Are we landed?
            switch (vessel.situation)
            {
            case Vessel.Situations.LANDED:
            case Vessel.Situations.PRELAUNCH:
            case Vessel.Situations.SPLASHED:
                reason = "on surface";
                return(AutoAGLSettings.LandedSplashedPreference);
            }

            // Check for imminent terrain collision.
            double clearance = CurrentGroundClearance(vessel);
            double collisionThresholdSeconds = AutoAGLSettings.TerrainCollisionThresholdSeconds(Atmospheres(vessel));

            if (!double.IsNaN(collisionThresholdSeconds))
            {
                double timeAhead;
                double collisionSeconds = ProjectTimeUntilImpact(vessel, collisionThresholdSeconds, out timeAhead);
                if (collisionSeconds < collisionThresholdSeconds)
                {
                    if (previousState != AltimeterDisplayState.AGL)
                    {
                        if (vessel.verticalSpeed < 0)
                        {
                            if (timeAhead > 0)
                            {
                                reason = string.Format(
                                    "< {0:0.0}s from terrain {1:0.0}s ahead, {2:0}m @ {3:0} m/s",
                                    collisionThresholdSeconds,
                                    timeAhead,
                                    clearance,
                                    -vessel.verticalSpeed);
                            }
                            else
                            {
                                reason = string.Format(
                                    "< {0:0.0}s from terrain, {1:0}m @ {2:0} m/s",
                                    collisionThresholdSeconds,
                                    clearance,
                                    -vessel.verticalSpeed);
                            }
                        }
                        else
                        {
                            if (timeAhead > 0)
                            {
                                reason = string.Format(
                                    "< {0:0.0}s from terrain {1:0.0}s ahead, {2:0}m",
                                    collisionThresholdSeconds,
                                    timeAhead,
                                    clearance);
                            }
                            else
                            {
                                reason = string.Format(
                                    "< {0:0.0}s from terrain, {1:0}m",
                                    collisionThresholdSeconds,
                                    clearance);
                            }
                        }
                    }
                    return(AltimeterDisplayState.AGL);
                }
            }

            // Check for deployed chute
            double parachuteAltitude = double.NaN;

            if (AutoAGLSettings.ParachuteAltitudeMultiplier > 0)
            {
                parachuteAltitude = CalculateParachuteActivationAltitude(parachutes);
                if (clearance < parachuteAltitude * AutoAGLSettings.ParachuteAltitudeMultiplier)
                {
                    if (previousState != AltimeterDisplayState.AGL)
                    {
                        reason = string.Format("< {0:0.0}x parachute's {1}m", AutoAGLSettings.ParachuteAltitudeMultiplier, parachuteAltitude);
                    }
                    return(AltimeterDisplayState.AGL);
                }
            }

            // None of the above apply, so prefer ASL by default.
            if (previousState != AltimeterDisplayState.ASL)
            {
                if (!double.IsNaN(collisionThresholdSeconds))
                {
                    reason = string.Format(
                        "> {0:0.0}s from terrain, {1:0}m",
                        collisionThresholdSeconds,
                        clearance);
                }
                else if (!double.IsNaN(parachuteAltitude))
                {
                    reason = (parachuteAltitude > 0)
                        ? string.Format("> {0:0.0}x parachute's {1}m", AutoAGLSettings.ParachuteAltitudeMultiplier, parachuteAltitude)
                        : "no active chutes";
                }
                else
                {
                    reason = "all checks disabled";
                }
            }
            return(AltimeterDisplayState.ASL);
        }
Exemple #4
0
        /// <summary>
        /// Called on each frame.
        /// </summary>
        public void LateUpdate()
        {
            // Make sure we have a vessel.
            Vessel vessel = FlightGlobals.ActiveVessel;

            if (vessel == null)
            {
                return;
            }

            // Keep track of any vessel changes we care about.
            UpdateVessel(vessel);

            // The stuff that comes after here may potentially involve doing
            // a fair amount of CPU work, so return without doing anything unless
            // it's time to check.
            DateTime now = DateTime.Now;

            if (now < nextUpdateTime)
            {
                return;
            }
            nextUpdateTime = now + UPDATE_INTERVAL;

            if (!AutoAGLSettings.ModEnabled)
            {
                return;
            }

            if (isGamePaused)
            {
                return;                // no point in calculating if we're not flying
            }
            // To avoid thrashing, we never tinker with the altimeter unless it's been
            // a reasonable length of time since the last time the altimeter mode changed.
            if (now < earliestAllowableToggleTime)
            {
                return;
            }

            // Now we have to balance two possibly conflicting preferences.
            // On the one hand, this mod's logic will have an idea of what the altimeter setting
            // "should" be (automatically), based on ship altitude and parachutes and such.
            // On the other hand, it's possible that the user recently *manually* selected an
            // altimeter mode, by clicking on the tumbler, and we don't want to override the
            // user's manually expressed preference.
            //
            // Here's how we resolve this conflict:  Whenever the user manually picks an altimeter
            // mode, we remember that in the userSelection variable, which is set either to ASL/AGL
            // (if the user has manually picked one of those) or DEFAULT (if the user hasn't picked
            // anything and we have free license to set it automatically).  Here's how we decide:
            //
            // 1. If userSelection is DEFAULT, just set the altimeter to whatever the auto-decider
            //    code wants it to be, and stop here.
            // 2. Otherwise, figure out what we *would* automatically set it to, if the user's
            //    manual decision didn't constrain us.
            // 3. If the indicated auto-mode is different from the user's preference... do nothing
            //    and leave the altimeter alone.
            // 4. If the indicated auto-mode *equals* the user's preference, then still do nothing
            //    to the altimeter (since they're in agreement)... but reset the userSelection flag
            //    to DEFAULT (meaning "no user preference").
            //
            // Here's an example of how that works in practice.  Let's say you're climbing from the
            // surface in AGL mode, and you *haven't* touched the altimeter toggle manually. At some
            // point you climb high enough that the mod automatically switches you to ASL mode. You then
            // decide you don't like that, and manually toggle it to AGL.  At this point, your preference
            // is stored, so the mod won't override you.  Later on, the ship descends again to the
            // point where it *would* set you to AGL if it were in auto mode.  At that point, your
            // manually-expressed preference would get reset and the mod would revert to full auto,
            // so that if the ship then climbs *again*, it would auto-switch to ASL as needed.

            string reason;
            AltimeterDisplayState currentMode      = AltitudeTumbler.Instance.CurrentMode;
            AltimeterDisplayState recommendedState = RecommendAltimeterState(
                vessel,
                parachutes,
                currentMode,
                out reason);

            if (userSelection == AltimeterDisplayState.DEFAULT)
            {
                // No user selection, so just set it if it needs setting.
                if (recommendedState != currentMode)
                {
                    Logging.Log("Automatically switching altimeter to " + recommendedState + " (" + reason + ")");
                    AltitudeTumbler.Instance.SetModeTumbler(recommendedState);
                }
                return;
            }

            // The user picked something.  Did they pick the same as what we automatically picked, or different?
            if (userSelection == recommendedState)
            {
                // It matches, so clear the user selection if it's time yet.
                Logging.Log("Transitioned to auto-" + recommendedState + " zone, clearing user selection");
                userSelection = AltimeterDisplayState.DEFAULT;
                return;
            }

            // If we get here, it means that there's a user selection and it conflicts with the
            // auto-recommended state, so we should do nothing.
        }