Organised the key binding system and implemented saving/loading of set key binds.
Organised the key binding system and implemented saving/loading of set key binds.

 Binary files a/Assets/CurseLogo.png and b/Assets/CurseLogo.png differ
 Binary files a/Assets/CurseLogo.psd and b/Assets/CurseLogo.psd differ
--- a/Documents/CHANGES.txt
+++ b/Documents/CHANGES.txt
@@ -1,10 +1,104 @@
+1.0.19.0
+    Added: Added current vessel name readout. (antplant)
+    Added: 'Relative Radial Velocity' and 'Time To Rendezvous' readouts. (itwtx)
+    Added: Readout help strings. (harryyoung)
+    Changed: The 'Torque' value in the editor is now precise to two decimal places.
+    Changed: Time formatting reference (Kerbin/Earth) is now based on the in-game setting.
+    Changed: Eccentric Anomaly, Mean Anomaly and Mean Anomaly At Epoc now display in degrees rather than radians.
+    Fixed: Optimised time formatting. (itwtx)
+    Fixed: TimeToAtmosphere checks that the Apoapsis is outside atmosphere. (Kerbas-ad-astra)
+    Fixed: Issue with stage priority flow. Caused Rapier calculations to fail if LF and O are drawn from different tanks. (Padishar)
+    Fixed: Issue with angle to prograde/retrograde calculations on highly inclined orbits.
+    Fixed: Editor input locks not being reset when a scene change is forced (e.g. via Kerbal Construction Time).
+    Fixed: Roll axis readout now shows the correct sign.
+    Removed: Time Formatter readout as it's not required anymore.
+
+1.0.18.0
+    Added: Orbital readouts - "Speed at Periapsis" and "Speed at Apoapsis". (Padishar)
+    Added: Manoeuvre readouts - "Post-burn Apoapsis" and "Post-burn Periapsis". (Padishar)
+    Added: Orbital readout - "Time to Atmosphere".
+    Fixed: Synched the minimum simulation time sliders and stopped them from snapping back after 999ms. (saybur)
+    Fixed: Added workaround for the bug in Vessel.horizontalSrfSpeed (Padishar)
+    Fixed: Physically insignificant part mass was not being correctly cascaded down through multiple parent parts.
+    Fixed: Intake air demand calculation not working.
+    Fixed: Some build engineer settings labels do not scale with UI size.
+
+1.0.17.0
+    Added: 'Mach Number' readout under the 'Surface' category and included it on the default surface HUD.
+    Added: Stock sections in the Flight Engineer can now become HUDs.
+    Added 'Thermal' readouts category including:
+        Internal Flux
+        Convection Flux
+        Radiation Flux
+        Critical Part Name
+        Critical Part Temperature
+        Critical Part Skin Temperature
+        Critical Part Thermal Percentage of Max Temperature
+        Hottest Part Name
+        Hottest Part Temperature
+        Hottest Part Skin Temperature
+        Coldest Part Name
+        Coldest Part Temperature
+        Coldest Part Skin Temperature
+
+    Changed: Mach on the Build Engineer now accurate to 2 decimal places.
+    Changed: Max mach in the Build Engineer defaults to 1.00 even when no jet engines are present.
+    Changed: Increased eccentricity readout to 5 decimal places.
+    Changed: Implemented Sarbian's object pooling.
+    Changed: The default selected body is now assigned via 'Planitarium.Home'.
+    Changed: HUDs to clamp fully inside the screen instead of allowing them to run off the edge by a certain amount.
+    Fixed: Physically insignificant part mass is now associated with the parent part.
+    Fixed: Longitude and Latitude readouts now use a KER formatter instead of Squad's incorrect implementation.
+    Fixed: Possible null reference in the Rendezvous Processor.
+    Fixed: Fairing mass issues introduced with regards to simulation changes.
+    Fixed: Use of per-propellant fuel flow mode override.
+    Fixed: Burn times calculated for jet engines.
+    Fixed: Thrust issues introduced with Sarbian's simulation alterations.
+    Fixed: Issue where HUDs positioned close to the top/bottom of the screen could be pushed out of position.
+
+1.0.16.6, 02-05-15
+    Fixed: Separately staged fairing mass jettisons are now calculated in the editor.
+
+1.0.16.5, 02-05-2015
+    Fixed: Delta-V not being correctly calculated.
+    Changed: Editor locking now uses the InputLockManager.
+
+1.0.16.4, 01-05-2015
+    Fixed: Physically insignificant part mass is now accounted for.
+    Changed: Module mass accounted for as it now makes its way onto the launch pad (e.g. fairings).
+
+    Various optimisations:
+        Object pooling.
+        Removed LINQ expressions.
+        Converted foreach to for loops.
+
+1.0.16.3, 27-04-2015
+    Fixed issue with the toolbar icons not being created.
+    Removed superfluous 'm/s' on the mach slider in the build engineer.
+
+1.0.16.2, 27-04-2015
+    Changed the atmospheric slider on the build engineer to default to 0km when changing bodies.
+
+1.0.16.1, 26-04-2015, KSP Build #828
+    Merged Sarbian's mach adjustments.
+    Fixed bugs relating to thrust and atmosphere/velocity curves.
+    Changed the atmospheric slider on the Build Engineer to work based on altitude.
+    Changed the atmospheric slider to clamp to the maximum altitude for the selected body.
+    Changed the velocity slider to clamp to the maximum usable mach value for the current vessel.
+
+1.0.16.0, 25-04-2015, KSP Build #821
+    Fixed errors relating to KSP 1.0 update.
+    Fixed fuel simulation to account for new thrust system.
+    Fixed atmospheric engines to use the new velocity curve.
+    Fixed atmospheric readouts to work with the new atmospheric model.
+
 1.0.15.2, 13-02-2015
     Padishar's Fixes:
         Fixed: Calculation of per-stage resource mass.
 
 1.0.15.1, 13-02-2015
     Rebuild
-    
+
 1.0.15.0, 08-02-2015
     Padishar's Fixes:
         Added: Support KIDS ISP thrust correction.
@@ -14,7 +108,7 @@
 
 1.0.14.1, 28-12-2014
     Fixed: Missing texture on the ER-7500 model.
-    
+
 1.0.14.0, 28-12-2014
     Added: Career mode that limits the Flight Engineer by:
         - Requiring an Engineer Kerbal of any level, or placement of an Engineer Chip or ER-7500 part.
@@ -134,7 +228,7 @@
     Added: New readout to the surface category:
         - Vertical Acceleration
         - Horizontal Acceleration
-    
+
     Changed: Atmospheric efficiency readout now shows as a percentage.
     Changed: Atmospheric settings (pressure/velocity) in the editor condensed onto a single line.
     Fixed: Bug where the overlays in the editor would stay open outside of parts screen.
@@ -291,6 +385,7 @@
     Added: Stock toolbar support in the Flight Engineer.
     Changed: Orbital Period has higher precision.
     Fixed: Various NullRefs in editor window and overlay.
-    
+
 1.0.0.0, 24-07-2014
     Initial release for public testing.
+

--- a/KerbalEngineer/CelestialBodies.cs
+++ b/KerbalEngineer/CelestialBodies.cs
@@ -17,16 +17,12 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-#endregion
-
 namespace KerbalEngineer
 {
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
     /*
      * 
      * With thanks to Nathaniel R. Lewis (aka. Teknoman117) (linux.robotdude@gmail.com) for working out
@@ -36,14 +32,13 @@
 
     public static class CelestialBodies
     {
-        #region Constructors
-
         static CelestialBodies()
         {
             try
             {
                 SystemBody = new BodyInfo(PSystemManager.Instance.localBodies.Find(b => b.referenceBody == null || b.referenceBody == b));
-                if (!SetSelectedBody("Kerbin"))
+                String homeCBName = Planetarium.fetch.Home.bodyName;
+                if (!SetSelectedBody(homeCBName))
                 {
                     SelectedBody = SystemBody;
                     SelectedBody.SetSelected(true);
@@ -55,16 +50,8 @@
             }
         }
 
-        #endregion
-
-        #region Properties
-
         public static BodyInfo SelectedBody { get; private set; }
         public static BodyInfo SystemBody { get; private set; }
-
-        #endregion
-
-        #region Public Methods
 
         /// <summary>
         ///     Gets a body given a supplied body name.
@@ -89,7 +76,7 @@
         {
             try
             {
-                var body = GetBodyInfo(bodyName);
+                BodyInfo body = GetBodyInfo(bodyName);
                 if (body != null)
                 {
                     if (SelectedBody != null)
@@ -108,34 +95,26 @@
             return false;
         }
 
-        #endregion
-
-        #region Nested type: BodyInfo
-
         public class BodyInfo
         {
-            #region Constructors
-
             public BodyInfo(CelestialBody body, BodyInfo parent = null)
             {
                 try
                 {
                     // Set the body information.
-                    this.CelestialBody = body;
-                    this.Name = body.bodyName;
-                    this.Gravity = 9.81 * body.GeeASL;
-                    //this.Atmosphere = body.atmosphere ? body.GetPressure(0) : 0;
-                    this.Atmosphere = body.atmosphere ? body.atmospherePressureSeaLevel : 0;   // Check that one because I did not. S
-                    this.Parent = parent; 
+                    CelestialBody = body;
+                    Name = body.bodyName;
+                    Gravity = 9.81 * body.GeeASL;
+                    Parent = parent;
 
                     // Set orbiting bodies information.
-                    this.Children = new List<BodyInfo>();
-                    foreach (var orbitingBody in body.orbitingBodies)
-                    {
-                        this.Children.Add(new BodyInfo(orbitingBody, this));
-                    }
-
-                    this.SelectedDepth = 0;
+                    Children = new List<BodyInfo>();
+                    foreach (CelestialBody orbitingBody in body.orbitingBodies)
+                    {
+                        Children.Add(new BodyInfo(orbitingBody, this));
+                    }
+
+                    SelectedDepth = 0;
                 }
                 catch (Exception ex)
                 {
@@ -143,37 +122,28 @@
                 }
             }
 
-            #endregion
-
-            #region Properties
-
+            public CelestialBody CelestialBody { get; private set; }
+            public List<BodyInfo> Children { get; private set; }
+            public double Gravity { get; private set; }
             public string Name { get; private set; }
-            public double Gravity { get; private set; }
-            public double Atmosphere { get; private set; }
             public BodyInfo Parent { get; private set; }
-            public List<BodyInfo> Children { get; private set; }
-            public CelestialBody CelestialBody { get; private set; }
             public bool Selected { get; private set; }
             public int SelectedDepth { get; private set; }
 
-            #endregion
-
-            #region Public Methods
-
             public BodyInfo GetBodyInfo(string bodyName)
             {
                 try
                 {
                     // This is the searched body.
-                    if (String.Equals(this.Name, bodyName, StringComparison.CurrentCultureIgnoreCase))
+                    if (String.Equals(Name, bodyName, StringComparison.CurrentCultureIgnoreCase))
                     {
                         return this;
                     }
 
                     // Check to see if any of this bodies children are the searched body.
-                    foreach (var child in this.Children)
-                    {
-                        var body = child.GetBodyInfo(bodyName);
+                    foreach (BodyInfo child in Children)
+                    {
+                        BodyInfo body = child.GetBodyInfo(bodyName);
                         if (body != null)
                         {
                             return body;
@@ -189,33 +159,44 @@
                 return null;
             }
 
+            public double GetDensity(double altitude)
+            {
+                return CelestialBody.GetDensity(GetPressure(altitude), GetTemperature(altitude));
+            }
+
+            public double GetPressure(double altitude)
+            {
+                return CelestialBody.GetPressure(altitude);
+            }
+
+            public double GetTemperature(double altitude)
+            {
+                return CelestialBody.GetTemperature(altitude);
+            }
+
+            public double GetAtmospheres(double altitude)
+            {
+                return GetPressure(altitude) * PhysicsGlobals.KpaToAtmospheres;
+            }
+
             public void SetSelected(bool state, int depth = 0)
             {
-                this.Selected = state;
-                this.SelectedDepth = depth;
-                if (this.Parent != null)
-                {
-                    this.Parent.SetSelected(state, depth + 1);
-                }
-            }
-
-            #endregion
-
-            #region Debugging
+                Selected = state;
+                SelectedDepth = depth;
+                if (Parent != null)
+                {
+                    Parent.SetSelected(state, depth + 1);
+                }
+            }
 
             public override string ToString()
             {
-                var log = "\n" + this.Name +
-                          "\n\tGravity: " + this.Gravity +
-                          "\n\tAtmosphere: " + this.Atmosphere +
-                          "\n\tSelected: " + this.Selected;
-
-                return this.Children.Aggregate(log, (current, child) => current + "\n" + child);
-            }
-
-            #endregion
-        }
-
-        #endregion
+                string log = "\n" + Name +
+                             "\n\tGravity: " + Gravity +
+                             "\n\tSelected: " + Selected;
+
+                return Children.Aggregate(log, (current, child) => current + "\n" + child);
+            }
+        }
     }
 }

--- a/KerbalEngineer/Control/ControlCentre.cs
+++ b/KerbalEngineer/Control/ControlCentre.cs
@@ -142,7 +142,7 @@
             try
             {
                 GUI.skin = null;
-                this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion + " - CONTROL CENTRE", HighLogic.Skin.window);
+                this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, "KERBAL ENGINEER REDUX " + EngineerGlobals.ASSEMBLY_VERSION + " - CONTROL CENTRE", HighLogic.Skin.window);
                 this.CentreWindow();
             }
             catch (Exception ex)

--- a/KerbalEngineer/Editor/BuildAdvanced.cs
+++ b/KerbalEngineer/Editor/BuildAdvanced.cs
@@ -1,7 +1,5 @@
 // 
-//     Kerbal Engineer Redux
-// 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -19,28 +17,29 @@
 
 namespace KerbalEngineer.Editor
 {
-    #region Using Directives
-
     using System;
-    using System.Linq;
     using Extensions;
     using Flight;
     using Helpers;
+    using KeyBinding;
     using Settings;
     using UIControls;
     using UnityEngine;
     using VesselSimulator;
 
-    #endregion
-
     [KSPAddon(KSPAddon.Startup.EditorAny, false)]
     public class BuildAdvanced : MonoBehaviour
     {
-        #region Fields
+        public static float Altitude;
+
+        private static Rect compactModeRect = new Rect(0.0f, 5.0f, 0.0f, 20.0f);
+        private static Stage stage;
+        private static int stagesCount;
+        private static int stagesLength;
+        private static string title;
 
         private GUIStyle areaSettingStyle;
         private GUIStyle areaStyle;
-        private float atmosphericPercentage = 1.0f;
         private float atmosphericMach;
         private GUIStyle bodiesButtonActiveStyle;
         private GUIStyle bodiesButtonStyle;
@@ -54,6 +53,7 @@
         private bool hasChanged;
         private GUIStyle infoStyle;
         private bool isEditorLocked;
+        private float maxMach;
         private int numberOfStages;
         private Rect position = new Rect(265.0f, 45.0f, 0, 0);
         private GUIStyle settingAtmoStyle;
@@ -66,10 +66,6 @@
         private bool visible = true;
         private GUIStyle windowStyle;
 
-        #endregion
-
-        #region Properties
-
         /// <summary>
         ///     Gets the current instance if started or returns null.
         /// </summary>
@@ -80,8 +76,14 @@
         /// </summary>
         public bool CompactMode
         {
-            get { return this.compactMode; }
-            set { this.compactMode = value; }
+            get
+            {
+                return compactMode;
+            }
+            set
+            {
+                compactMode = value;
+            }
         }
 
         /// <summary>
@@ -89,8 +91,14 @@
         /// </summary>
         public bool ShowAllStages
         {
-            get { return this.showAllStages; }
-            set { this.showAllStages = value; }
+            get
+            {
+                return showAllStages;
+            }
+            set
+            {
+                showAllStages = value;
+            }
         }
 
         /// <summary>
@@ -98,8 +106,14 @@
         /// </summary>
         public bool ShowAtmosphericDetails
         {
-            get { return this.showAtmosphericDetails; }
-            set { this.showAtmosphericDetails = value; }
+            get
+            {
+                return showAtmosphericDetails;
+            }
+            set
+            {
+                showAtmosphericDetails = value;
+            }
         }
 
         /// <summary>
@@ -107,8 +121,14 @@
         /// </summary>
         public bool ShowSettings
         {
-            get { return this.showSettings; }
-            set { this.showSettings = value; }
+            get
+            {
+                return showSettings;
+            }
+            set
+            {
+                showSettings = value;
+            }
         }
 
         /// <summary>
@@ -116,30 +136,32 @@
         /// </summary>
         public bool Visible
         {
-            get { return this.visible; }
-            set { this.visible = value; }
-        }
-
-        #endregion
-
-        #region Methods
+            get
+            {
+                return visible;
+            }
+            set
+            {
+                visible = value;
+            }
+        }
 
         protected void Awake()
         {
             try
             {
                 Instance = this;
-                this.bodiesList = this.gameObject.AddComponent<DropDown>();
-                this.bodiesList.DrawCallback = this.DrawBodiesList;
-                this.Load();
+                bodiesList = gameObject.AddComponent<DropDown>();
+                bodiesList.DrawCallback = DrawBodiesList;
+                Load();
 
                 SimManager.UpdateModSettings();
-                SimManager.OnReady -= this.GetStageInfo;
-                SimManager.OnReady += this.GetStageInfo;
+                SimManager.OnReady -= GetStageInfo;
+                SimManager.OnReady += GetStageInfo;
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex);
+                Logger.Exception(ex, "BuildAdvanced.Awake()");
             }
         }
 
@@ -148,74 +170,94 @@
         /// </summary>
         protected void OnDestroy()
         {
+            Logger.Log("BuildAdvanced->OnDestroy");
+
             try
             {
-                var handler = new SettingHandler();
-                handler.Set("visible", this.visible);
-                handler.Set("windowPositionX", this.position.x);
-                handler.Set("windowPositionY", this.position.y);
-                handler.Set("compactMode", this.compactMode);
-                handler.Set("compactCollapseRight", this.compactCollapseRight);
-                handler.Set("showAllStages", this.showAllStages);
-                handler.Set("showAtmosphericDetails", this.showAtmosphericDetails);
-                handler.Set("showSettings", this.showSettings);
+                SettingHandler handler = new SettingHandler();
+                handler.Set("visible", visible);
+                handler.Set("windowPositionX", position.x);
+                handler.Set("windowPositionY", position.y);
+                handler.Set("compactMode", compactMode);
+                handler.Set("compactCollapseRight", compactCollapseRight);
+                handler.Set("showAllStages", showAllStages);
+                handler.Set("showAtmosphericDetails", showAtmosphericDetails);
+                handler.Set("showSettings", showSettings);
                 handler.Set("selectedBodyName", CelestialBodies.SelectedBody.Name);
                 handler.Save("BuildAdvanced.xml");
-                GuiDisplaySize.OnSizeChanged -= this.OnSizeChanged;
+                GuiDisplaySize.OnSizeChanged -= OnSizeChanged;
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex);
-            }
+                Logger.Exception(ex, "BuildAdvanced.OnDestroy()");
+            }
+
+            EditorLock(false);
         }
 
         protected void OnGUI()
         {
             try
             {
-                if (!this.visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0 || EditorLogic.fetch.editorScreen != EditorScreen.Parts)
+                if (!visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0 || EditorLogic.fetch.editorScreen != EditorScreen.Parts)
                 {
                     return;
                 }
 
-                if (this.stages == null)
+                if (stages == null)
                 {
                     return;
                 }
 
                 // Change the window title based on whether in compact mode or not.
-                var title = !this.compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion : "K.E.R. " + EngineerGlobals.AssemblyVersion + (this.showAtmosphericDetails ? " (ATMOS.)" : String.Empty);
+                title = !compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.ASSEMBLY_VERSION : "K.E.R. " + EngineerGlobals.ASSEMBLY_VERSION;
 
                 // Reset the window size when the staging or something else has changed.
-                var stageCount = this.stages.Count(stage => this.showAllStages || stage.deltaV > 0);
-                if (this.hasChanged || stageCount != this.numberOfStages)
-                {
-                    this.hasChanged = false;
-                    this.numberOfStages = stageCount;
-
-                    this.position.width = 0;
-                    this.position.height = 0;
+                stagesLength = stages.Length;
+                if (showAllStages)
+                {
+                    stagesCount = stagesLength;
+                }
+                if (showAllStages == false)
+                {
+                    stagesCount = 0;
+                    for (int i = 0; i < stagesLength; ++i)
+                    {
+                        if (stages[i].deltaV > 0.0f)
+                        {
+                            stagesCount = stagesCount + 1;
+                        }
+                    }
+                }
+
+                if (hasChanged || stagesCount != numberOfStages)
+                {
+                    hasChanged = false;
+                    numberOfStages = stagesCount;
+
+                    position.width = 0;
+                    position.height = 0;
                 }
 
                 GUI.skin = null;
-                this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, title, this.windowStyle).ClampToScreen();
-
-                if (this.compactCheck > 0 && this.compactCollapseRight)
-                {
-                    this.position.x = this.compactRight - this.position.width;
-                    this.compactCheck--;
-                }
-                else if (this.compactCheck > 0)
-                {
-                    this.compactCheck = 0;
+                position = GUILayout.Window(GetInstanceID(), position, Window, title, windowStyle).ClampToScreen();
+
+                if (compactCheck > 0 && compactCollapseRight)
+                {
+                    position.x = compactRight - position.width;
+                    compactCheck--;
+                }
+                else if (compactCheck > 0)
+                {
+                    compactCheck = 0;
                 }
 
                 // Check editor lock to manage click-through.
-                this.CheckEditorLock();
+                CheckEditorLock();
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex);
+                Logger.Exception(ex, "BuildAdvanced.OnGUI()");
             }
         }
 
@@ -223,12 +265,12 @@
         {
             try
             {
-                this.InitialiseStyles();
-                GuiDisplaySize.OnSizeChanged += this.OnSizeChanged;
+                InitialiseStyles();
+                GuiDisplaySize.OnSizeChanged += OnSizeChanged;
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex);
+                Logger.Exception(ex, "BuildAdvanced.Start()");
             }
         }
 
@@ -238,39 +280,39 @@
             {
                 if (Input.GetKeyDown(KeyBinder.EditorShowHide))
                 {
-                    this.visible = !this.visible;
-                    if (!this.visible)
+                    visible = !visible;
+                    if (!visible)
                     {
-                        this.EditorLock(false);
+                        EditorLock(false);
                     }
                 }
 
-                if (!this.visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0)
-                {
-                    this.bodiesList.enabled = false;
+                if (!visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0)
+                {
+                    bodiesList.enabled = false;
                     return;
                 }
 
                 // Configure the simulation parameters based on the selected reference body.
                 SimManager.Gravity = CelestialBodies.SelectedBody.Gravity;
 
-                if (this.showAtmosphericDetails)
-                {
-                    SimManager.Atmosphere = CelestialBodies.SelectedBody.Atmosphere * 0.01d * this.atmosphericPercentage;
+                if (showAtmosphericDetails)
+                {
+                    SimManager.Atmosphere = CelestialBodies.SelectedBody.GetAtmospheres(Altitude);
                 }
                 else
                 {
                     SimManager.Atmosphere = 0;
                 }
 
-                SimManager.Mach = this.atmosphericMach;
+                SimManager.Mach = atmosphericMach;
 
                 SimManager.RequestSimulation();
                 SimManager.TryStartSimulation();
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex, "BuildAdvanced->Update");
+                Logger.Exception(ex, "BuildAdvanced.Update()");
             }
         }
 
@@ -279,13 +321,13 @@
         /// </summary>
         private void CheckEditorLock()
         {
-            if ((this.position.MouseIsOver() || this.bodiesList.Position.MouseIsOver()) && !this.isEditorLocked)
-            {
-                this.EditorLock(true);
-            }
-            else if (!this.position.MouseIsOver() && !this.bodiesList.Position.MouseIsOver() && this.isEditorLocked)
-            {
-                this.EditorLock(false);
+            if ((position.MouseIsOver() || bodiesList.Position.MouseIsOver()) && !isEditorLocked)
+            {
+                EditorLock(true);
+            }
+            else if (!position.MouseIsOver() && !bodiesList.Position.MouseIsOver() && isEditorLocked)
+            {
+                EditorLock(false);
             }
         }
 
@@ -294,36 +336,43 @@
         /// </summary>
         private void DrawAtmosphericDetails()
         {
-            GUILayout.BeginHorizontal();
-            GUILayout.BeginVertical();
-            GUILayout.Label("Pressure: " + (this.atmosphericPercentage * 100.0f).ToString("F1") + "%", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
-            GUI.skin = HighLogic.Skin;
-            this.atmosphericPercentage = GUILayout.HorizontalSlider(this.atmosphericPercentage, 0, 1.0f);
-            GUI.skin = null;
-            GUILayout.EndVertical();
-
-            GUILayout.Space(5.0f);
-
-            GUILayout.BeginVertical();
-            GUILayout.Label("Mach: " + this.atmosphericMach.ToString("F1") + "m/s", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
-            GUI.skin = HighLogic.Skin;
-            this.atmosphericMach = GUILayout.HorizontalSlider(this.atmosphericMach, 0, 25f); // the game limits mach to 50 but I did not see curve with more than 25
-            GUI.skin = null;
-            GUILayout.EndVertical();
-            GUILayout.EndHorizontal();
+            try
+            {
+                GUILayout.BeginHorizontal();
+                GUILayout.BeginVertical();
+                GUILayout.Label("Altitude: " + (Altitude * 0.001f).ToString("F1") + "km", settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
+                GUI.skin = HighLogic.Skin;
+                Altitude = GUILayout.HorizontalSlider(Altitude, 0.0f, (float)(CelestialBodies.SelectedBody.CelestialBody.atmosphereDepth));
+                GUI.skin = null;
+                GUILayout.EndVertical();
+
+                GUILayout.Space(5.0f);
+
+                GUILayout.BeginVertical();
+                GUILayout.Label("Mach: " + atmosphericMach.ToString("F2"), settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
+                GUI.skin = HighLogic.Skin;
+                atmosphericMach = GUILayout.HorizontalSlider(Mathf.Clamp(atmosphericMach, 0.0f, maxMach), 0.0f, maxMach);
+                GUI.skin = null;
+                GUILayout.EndVertical();
+                GUILayout.EndHorizontal();
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex, "BuildAdvanced.DrawAtmosphericDetails()");
+            }
         }
 
         private void DrawBodiesList()
         {
             if (CelestialBodies.SystemBody == CelestialBodies.SelectedBody)
             {
-                this.DrawBody(CelestialBodies.SystemBody);
+                DrawBody(CelestialBodies.SystemBody);
             }
             else
             {
-                foreach (var body in CelestialBodies.SystemBody.Children)
-                {
-                    this.DrawBody(body);
+                foreach (CelestialBodies.BodyInfo body in CelestialBodies.SystemBody.Children)
+                {
+                    DrawBody(body);
                 }
             }
         }
@@ -332,18 +381,19 @@
         {
             GUILayout.BeginHorizontal();
             GUILayout.Space(20.0f * depth);
-            if (GUILayout.Button(bodyInfo.Children.Count > 0 ? bodyInfo.Name + " [" + bodyInfo.Children.Count + "]" : bodyInfo.Name, bodyInfo.Selected && bodyInfo.SelectedDepth == 0 ? this.bodiesButtonActiveStyle : this.bodiesButtonStyle))
+            if (GUILayout.Button(bodyInfo.Children.Count > 0 ? bodyInfo.Name + " [" + bodyInfo.Children.Count + "]" : bodyInfo.Name, bodyInfo.Selected && bodyInfo.SelectedDepth == 0 ? bodiesButtonActiveStyle : bodiesButtonStyle))
             {
                 CelestialBodies.SetSelectedBody(bodyInfo.Name);
-                this.bodiesList.Resize = true;
+                Altitude = 0.0f;
+                bodiesList.Resize = true;
             }
             GUILayout.EndHorizontal();
 
             if (bodyInfo.Selected)
             {
-                foreach (var body in bodyInfo.Children)
-                {
-                    this.DrawBody(body, depth + 1);
+                for (int i = 0; i < bodyInfo.Children.Count; ++i)
+                {
+                    DrawBody(bodyInfo.Children[i], depth + 1);
                 }
             }
         }
@@ -354,12 +404,13 @@
         private void DrawBurnTime()
         {
             GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("BURN", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(TimeFormatter.ConvertToString(stage.time), this.infoStyle);
+            GUILayout.Label("BURN", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(TimeFormatter.ConvertToString(stage.time), infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -371,12 +422,13 @@
         private void DrawCost()
         {
             GUILayout.BeginVertical(GUILayout.Width(110.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("COST", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(Units.Cost(stage.cost, stage.totalCost), this.infoStyle);
+            GUILayout.Label("COST", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(Units.Cost(stage.cost, stage.totalCost), infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -388,12 +440,13 @@
         private void DrawDeltaV()
         {
             GUILayout.BeginVertical(GUILayout.Width(100.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("DELTA-V", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(stage.deltaV.ToString("N0") + " / " + stage.inverseTotalDeltaV.ToString("N0") + "m/s", this.infoStyle);
+            GUILayout.Label("DELTA-V", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(stage.deltaV.ToString("N0") + " / " + stage.inverseTotalDeltaV.ToString("N0") + "m/s", infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -405,12 +458,13 @@
         private void DrawIsp()
         {
             GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("ISP", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(stage.isp.ToString("F1") + "s", this.infoStyle);
+            GUILayout.Label("ISP", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(stage.isp.ToString("F1") + "s", infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -422,12 +476,13 @@
         private void DrawMass()
         {
             GUILayout.BeginVertical(GUILayout.Width(110.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("MASS", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(Units.ToMass(stage.mass, stage.totalMass), this.infoStyle);
+            GUILayout.Label("MASS", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(Units.ToMass(stage.mass, stage.totalMass), infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -439,12 +494,13 @@
         private void DrawPartCount()
         {
             GUILayout.BeginVertical(GUILayout.Width(50.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("PARTS", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(stage.partCount + " / " + stage.totalPartCount, this.infoStyle);
+            GUILayout.Label("PARTS", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(stage.partCount + " / " + stage.totalPartCount, infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -456,50 +512,67 @@
         private void DrawSettings()
         {
             GUILayout.BeginHorizontal();
-            GUILayout.Label("Compact mode collapses to the:", this.settingStyle);
-            this.compactCollapseRight = !GUILayout.Toggle(!this.compactCollapseRight, "LEFT", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
-            this.compactCollapseRight = GUILayout.Toggle(this.compactCollapseRight, "RIGHT", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            GUILayout.Label("Compact mode collapses to the:", settingStyle);
+            compactCollapseRight = !GUILayout.Toggle(!compactCollapseRight, "LEFT", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            compactCollapseRight = GUILayout.Toggle(compactCollapseRight, "RIGHT", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
             GUILayout.EndHorizontal();
 
             GUILayout.BeginHorizontal();
-            GUILayout.Label("Simulate using vectored thrust values:");
-            SimManager.vectoredThrust = GUILayout.Toggle(SimManager.vectoredThrust, "ENABLED", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            GUILayout.Label("Simulate using vectored thrust values:", settingStyle);
+            SimManager.vectoredThrust = GUILayout.Toggle(SimManager.vectoredThrust, "ENABLED", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
             GUILayout.EndHorizontal();
 
             GUILayout.BeginHorizontal();
-            GUILayout.Label("Build Engineer Overlay:", this.settingStyle);
-            BuildOverlay.Visible = GUILayout.Toggle(BuildOverlay.Visible, "VISIBLE", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
-            BuildOverlayPartInfo.NamesOnly = GUILayout.Toggle(BuildOverlayPartInfo.NamesOnly, "NAMES ONLY", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
-            BuildOverlayPartInfo.ClickToOpen = GUILayout.Toggle(BuildOverlayPartInfo.ClickToOpen, "CLICK TO OPEN", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            GUILayout.Label("Verbose Simulation Log:", settingStyle);
+            SimManager.logOutput = GUILayout.Toggle(SimManager.logOutput, "ENABLED", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
             GUILayout.EndHorizontal();
 
             GUILayout.BeginHorizontal();
-            GUILayout.Label("Flight Engineer activation mode:", this.settingStyle);
-            FlightEngineerCore.IsCareerMode = GUILayout.Toggle(FlightEngineerCore.IsCareerMode, "CAREER", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
-            FlightEngineerCore.IsCareerMode = !GUILayout.Toggle(!FlightEngineerCore.IsCareerMode, "PARTLESS", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            GUILayout.Label("Build Engineer Overlay:", settingStyle);
+            BuildOverlay.Visible = GUILayout.Toggle(BuildOverlay.Visible, "VISIBLE", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            BuildOverlayPartInfo.NamesOnly = GUILayout.Toggle(BuildOverlayPartInfo.NamesOnly, "NAMES ONLY", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            BuildOverlayPartInfo.ClickToOpen = GUILayout.Toggle(BuildOverlayPartInfo.ClickToOpen, "CLICK TO OPEN", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
             GUILayout.EndHorizontal();
 
             GUILayout.BeginHorizontal();
-            GUILayout.Label("Flight Engineer Career Limitations:", this.settingStyle);
-            FlightEngineerCore.IsKerbalLimited = GUILayout.Toggle(FlightEngineerCore.IsKerbalLimited, "KERBAL", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
-            FlightEngineerCore.IsTrackingStationLimited = GUILayout.Toggle(FlightEngineerCore.IsTrackingStationLimited, "TRACKING", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            GUILayout.Label("Flight Engineer activation mode:", settingStyle);
+            FlightEngineerCore.IsCareerMode = GUILayout.Toggle(FlightEngineerCore.IsCareerMode, "CAREER", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            FlightEngineerCore.IsCareerMode = !GUILayout.Toggle(!FlightEngineerCore.IsCareerMode, "PARTLESS", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
             GUILayout.EndHorizontal();
 
             GUILayout.BeginHorizontal();
-            GUILayout.Label("GUI Size: " + GuiDisplaySize.Increment, this.settingStyle);
-            if (GUILayout.Button("<", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)))
+            GUILayout.Label("Flight Engineer Career Limitations:", settingStyle);
+            FlightEngineerCore.IsKerbalLimited = GUILayout.Toggle(FlightEngineerCore.IsKerbalLimited, "KERBAL", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            FlightEngineerCore.IsTrackingStationLimited = GUILayout.Toggle(FlightEngineerCore.IsTrackingStationLimited, "TRACKING", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
+            GUILayout.EndHorizontal();
+
+            GUILayout.BeginHorizontal();
+            GUILayout.Label("GUI Size: " + GuiDisplaySize.Increment, settingStyle);
+            if (GUILayout.Button("<", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)))
             {
                 GuiDisplaySize.Increment--;
             }
-            if (GUILayout.Button(">", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)))
+            if (GUILayout.Button(">", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)))
             {
                 GuiDisplaySize.Increment++;
             }
             GUILayout.EndHorizontal();
 
-            GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.Milliseconds + "ms", this.settingStyle);
+            GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.TotalMilliseconds + "ms", settingStyle);
             GUI.skin = HighLogic.Skin;
-            SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 2000.0f));
+            SimManager.minSimTime = TimeSpan.FromMilliseconds(GUILayout.HorizontalSlider((float)SimManager.minSimTime.TotalMilliseconds, 0, 2000.0f));
+
+            GUILayout.BeginHorizontal();
+            if (GUILayout.Button("Editor Show/Hide Key: " + KeyBinder.EditorShowHide, buttonStyle, GUILayout.Width(200.0f * GuiDisplaySize.Offset)))
+            {
+                KeyBindPopup.Show("Flight Show/Hide", KeyBinder.EditorShowHide, keyCode => KeyBinder.EditorShowHide = keyCode);
+            }
+            if (GUILayout.Button("Flight Show/Hide Key: " + KeyBinder.FlightShowHide, buttonStyle, GUILayout.Width(200.0f * GuiDisplaySize.Offset)))
+            {
+                KeyBindPopup.Show("Flight Show/Hide", KeyBinder.FlightShowHide, keyCode => KeyBinder.FlightShowHide = keyCode);
+            }
+            GUILayout.EndHorizontal();
+
             GUI.skin = null;
         }
 
@@ -509,12 +582,13 @@
         private void DrawStageNumbers()
         {
             GUILayout.BeginVertical(GUILayout.Width(30.0f * GuiDisplaySize.Offset));
-            GUILayout.Label(string.Empty, this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label("S" + stage.number, this.titleStyle);
+            GUILayout.Label(string.Empty, titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label("S" + stage.number, titleStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -526,12 +600,13 @@
         private void DrawThrust()
         {
             GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("THRUST", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(stage.thrust.ToForce(), this.infoStyle);
+            GUILayout.Label("THRUST", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(stage.thrust.ToForce(), infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -543,12 +618,13 @@
         private void DrawTorque()
         {
             GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("TORQUE", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(stage.maxThrustTorque.ToTorque(), this.infoStyle);
+            GUILayout.Label("TORQUE", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(stage.maxThrustTorque.ToTorque(), infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -560,12 +636,13 @@
         private void DrawTwr()
         {
             GUILayout.BeginVertical(GUILayout.Width(100.0f * GuiDisplaySize.Offset));
-            GUILayout.Label("TWR (MAX)", this.titleStyle);
-            foreach (var stage in this.stages)
-            {
-                if (this.showAllStages || stage.deltaV > 0)
-                {
-                    GUILayout.Label(stage.thrustToWeight.ToString("F2") + " (" + stage.maxThrustToWeight.ToString("F2") + ")", this.infoStyle);
+            GUILayout.Label("TWR (MAX)", titleStyle);
+            for (int i = 0; i < stagesLength; ++i)
+            {
+                stage = stages[i];
+                if (showAllStages || stage.deltaV > 0.0)
+                {
+                    GUILayout.Label(stage.thrustToWeight.ToString("F2") + " (" + stage.maxThrustToWeight.ToString("F2") + ")", infoStyle);
                 }
             }
             GUILayout.EndVertical();
@@ -575,21 +652,25 @@
         {
             if (state)
             {
-                EditorLogic.fetch.Lock(true, true, true, "KER_BuildAdvanced");
+                InputLockManager.SetControlLock(ControlTypes.All, "KER_BuildAdvanced");
                 BuildOverlayPartInfo.Hidden = true;
-                this.isEditorLocked = true;
+                isEditorLocked = true;
             }
             else
             {
-                EditorLogic.fetch.Unlock("KER_BuildAdvanced");
+                InputLockManager.SetControlLock(ControlTypes.None, "KER_BuildAdvanced");
                 BuildOverlayPartInfo.Hidden = false;
-                this.isEditorLocked = false;
+                isEditorLocked = false;
             }
         }
 
         private void GetStageInfo()
         {
-            this.stages = SimManager.Stages;
+            stages = SimManager.Stages;
+            if (stages != null && stages.Length > 0)
+            {
+                maxMach = stages[stages.Length - 1].maxMach;
+            }
         }
 
         /// <summary>
@@ -597,22 +678,22 @@
         /// </summary>
         private void InitialiseStyles()
         {
-            this.windowStyle = new GUIStyle(HighLogic.Skin.window)
+            windowStyle = new GUIStyle(HighLogic.Skin.window)
             {
                 alignment = TextAnchor.UpperLeft
             };
 
-            this.areaStyle = new GUIStyle(HighLogic.Skin.box)
+            areaStyle = new GUIStyle(HighLogic.Skin.box)
             {
                 padding = new RectOffset(0, 0, 9, 0)
             };
 
-            this.areaSettingStyle = new GUIStyle(HighLogic.Skin.box)
+            areaSettingStyle = new GUIStyle(HighLogic.Skin.box)
             {
                 padding = new RectOffset(10, 10, 10, 10)
             };
 
-            this.buttonStyle = new GUIStyle(HighLogic.Skin.button)
+            buttonStyle = new GUIStyle(HighLogic.Skin.button)
             {
                 normal =
                 {
@@ -623,7 +704,7 @@
                 alignment = TextAnchor.MiddleCenter
             };
 
-            this.titleStyle = new GUIStyle(HighLogic.Skin.label)
+            titleStyle = new GUIStyle(HighLogic.Skin.label)
             {
                 normal =
                 {
@@ -632,10 +713,10 @@
                 fontSize = (int)(11 * GuiDisplaySize.Offset),
                 fontStyle = FontStyle.Bold,
                 alignment = TextAnchor.MiddleCenter,
-                stretchWidth = true,
-            };
-
-            this.infoStyle = new GUIStyle(HighLogic.Skin.label)
+                stretchWidth = true
+            };
+
+            infoStyle = new GUIStyle(HighLogic.Skin.label)
             {
                 fontSize = (int)(11 * GuiDisplaySize.Offset),
                 fontStyle = FontStyle.Bold,
@@ -643,21 +724,21 @@
                 stretchWidth = true
             };
 
-            this.settingStyle = new GUIStyle(this.titleStyle)
+            settingStyle = new GUIStyle(titleStyle)
             {
                 alignment = TextAnchor.MiddleLeft,
                 stretchWidth = true,
                 stretchHeight = true
             };
 
-            this.settingAtmoStyle = new GUIStyle(this.titleStyle)
+            settingAtmoStyle = new GUIStyle(titleStyle)
             {
                 margin = new RectOffset(),
                 padding = new RectOffset(),
                 alignment = TextAnchor.UpperLeft
             };
 
-            this.bodiesButtonStyle = new GUIStyle(HighLogic.Skin.button)
+            bodiesButtonStyle = new GUIStyle(HighLogic.Skin.button)
             {
                 margin = new RectOffset(0, 0, 2, 0),
                 padding = new RectOffset(5, 5, 5, 5),
@@ -675,10 +756,10 @@
                 fixedHeight = 20.0f
             };
 
-            this.bodiesButtonActiveStyle = new GUIStyle(this.bodiesButtonStyle)
-            {
-                normal = this.bodiesButtonStyle.onNormal,
-                hover = this.bodiesButtonStyle.onHover
+            bodiesButtonActiveStyle = new GUIStyle(bodiesButtonStyle)
+            {
+                normal = bodiesButtonStyle.onNormal,
+                hover = bodiesButtonStyle.onHover
             };
         }
 
@@ -689,27 +770,27 @@
         {
             try
             {
-                var handler = SettingHandler.Load("BuildAdvanced.xml");
-                handler.Get("visible", ref this.visible);
-                this.position.x = handler.Get("windowPositionX", this.position.x);
-                this.position.y = handler.Get("windowPositionY", this.position.y);
-                handler.Get("compactMode", ref this.compactMode);
-                handler.Get("compactCollapseRight", ref this.compactCollapseRight);
-                handler.Get("showAllStages", ref this.showAllStages);
-                handler.Get("showAtmosphericDetails", ref this.showAtmosphericDetails);
-                handler.Get("showSettings", ref this.showSettings);
+                SettingHandler handler = SettingHandler.Load("BuildAdvanced.xml");
+                handler.Get("visible", ref visible);
+                position.x = handler.Get("windowPositionX", position.x);
+                position.y = handler.Get("windowPositionY", position.y);
+                handler.Get("compactMode", ref compactMode);
+                handler.Get("compactCollapseRight", ref compactCollapseRight);
+                handler.Get("showAllStages", ref showAllStages);
+                handler.Get("showAtmosphericDetails", ref showAtmosphericDetails);
+                handler.Get("showSettings", ref showSettings);
                 CelestialBodies.SetSelectedBody(handler.Get("selectedBodyName", CelestialBodies.SelectedBody.Name));
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex, "BuildAdvanced->Load");
+                Logger.Exception(ex, "BuildAdvanced.Load()");
             }
         }
 
         private void OnSizeChanged()
         {
-            this.InitialiseStyles();
-            this.hasChanged = true;
+            InitialiseStyles();
+            hasChanged = true;
         }
 
         /// <summary>
@@ -719,77 +800,87 @@
         {
             try
             {
+                compactModeRect = new Rect(position.width - 70.0f * GuiDisplaySize.Offset, 5.0f, 65.0f * GuiDisplaySize.Offset, 20.0f);
+
                 // Draw the compact mode toggle.
-                if (GUI.Toggle(new Rect(this.position.width - 70.0f * GuiDisplaySize.Offset, 5.0f, 65.0f * GuiDisplaySize.Offset, 20.0f), this.compactMode, "COMPACT", this.buttonStyle) != this.compactMode)
-                {
-                    this.hasChanged = true;
-                    this.compactCheck = 2;
-                    this.compactRight = this.position.xMax;
-                    this.compactMode = !this.compactMode;
+                if (GUI.Toggle(compactModeRect, compactMode, "COMPACT", buttonStyle) != compactMode)
+                {
+                    hasChanged = true;
+                    compactCheck = 2;
+                    compactRight = position.xMax;
+                    compactMode = !compactMode;
                 }
 
                 // When not in compact mode draw the 'All Stages' and 'Atmospheric' toggles.
-                if (!this.compactMode)
-                {
-                    if (GUI.Toggle(new Rect(this.position.width - 143.0f * GuiDisplaySize.Offset, 5.0f, 70.0f * GuiDisplaySize.Offset, 20.0f), this.showSettings, "SETTINGS", this.buttonStyle) != this.showSettings)
+                if (!compactMode)
+                {
+                    if (GUI.Toggle(new Rect(position.width - 143.0f * GuiDisplaySize.Offset, 5.0f, 70.0f * GuiDisplaySize.Offset, 20.0f), showSettings, "SETTINGS", buttonStyle) != showSettings)
                     {
-                        this.hasChanged = true;
-                        this.showSettings = !this.showSettings;
+                        hasChanged = true;
+                        showSettings = !showSettings;
                     }
 
-                    if (GUI.Toggle(new Rect(this.position.width - 226.0f * GuiDisplaySize.Offset, 5.0f, 80.0f * GuiDisplaySize.Offset, 20.0f), this.showAllStages, "ALL STAGES", this.buttonStyle) != this.showAllStages)
+                    if (GUI.Toggle(new Rect(position.width - 226.0f * GuiDisplaySize.Offset, 5.0f, 80.0f * GuiDisplaySize.Offset, 20.0f), showAllStages, "ALL STAGES", buttonStyle) != showAllStages)
                     {
-                        this.hasChanged = true;
-                        this.showAllStages = !this.showAllStages;
+                        hasChanged = true;
+                        showAllStages = !showAllStages;
                     }
 
-                    if (GUI.Toggle(new Rect(this.position.width - 324.0f * GuiDisplaySize.Offset, 5.0f, 95.0f * GuiDisplaySize.Offset, 20.0f), this.showAtmosphericDetails, "ATMOSPHERIC", this.buttonStyle) != this.showAtmosphericDetails)
+                    if (GUI.Toggle(new Rect(position.width - 324.0f * GuiDisplaySize.Offset, 5.0f, 95.0f * GuiDisplaySize.Offset, 20.0f), showAtmosphericDetails, "ATMOSPHERIC", buttonStyle) != showAtmosphericDetails)
                     {
-                        this.hasChanged = true;
-                        this.showAtmosphericDetails = !this.showAtmosphericDetails;
+                        hasChanged = true;
+                        showAtmosphericDetails = !showAtmosphericDetails;
                     }
 
-                    this.bodiesListPosition = new Rect(this.position.width - 452.0f * GuiDisplaySize.Offset, 5.0f, 125.0f * GuiDisplaySize.Offset, 20.0f);
-                    this.bodiesList.enabled = GUI.Toggle(this.bodiesListPosition, this.bodiesList.enabled, "BODY: " + CelestialBodies.SelectedBody.Name.ToUpper(), this.buttonStyle);
-                    this.bodiesList.SetPosition(this.bodiesListPosition.Translate(this.position));
+                    bodiesListPosition = new Rect(position.width - 452.0f * GuiDisplaySize.Offset, 5.0f, 125.0f * GuiDisplaySize.Offset, 20.0f);
+                    bodiesList.enabled = GUI.Toggle(bodiesListPosition, bodiesList.enabled, "BODY: " + CelestialBodies.SelectedBody.Name.ToUpper(), buttonStyle);
+                    bodiesList.SetPosition(bodiesListPosition.Translate(position));
+                }
+                else
+                {
+                    if (GUI.Toggle(new Rect(position.width - 133.0f * GuiDisplaySize.Offset, 5.0f, 60.0f * GuiDisplaySize.Offset, 20.0f), showAtmosphericDetails, "ATMO", buttonStyle) != showAtmosphericDetails)
+                    {
+                        hasChanged = true;
+                        showAtmosphericDetails = !showAtmosphericDetails;
+                    }
                 }
 
                 // Draw the main informational display box.
-                if (!this.compactMode)
-                {
-                    GUILayout.BeginHorizontal(this.areaStyle);
-                    this.DrawStageNumbers();
-                    this.DrawPartCount();
-                    this.DrawCost();
-                    this.DrawMass();
-                    this.DrawIsp();
-                    this.DrawThrust();
-                    this.DrawTorque();
-                    this.DrawTwr();
-                    this.DrawDeltaV();
-                    this.DrawBurnTime();
+                if (!compactMode)
+                {
+                    GUILayout.BeginHorizontal(areaStyle);
+                    DrawStageNumbers();
+                    DrawPartCount();
+                    DrawCost();
+                    DrawMass();
+                    DrawIsp();
+                    DrawThrust();
+                    DrawTorque();
+                    DrawTwr();
+                    DrawDeltaV();
+                    DrawBurnTime();
                     GUILayout.EndHorizontal();
 
-                    if (this.showAtmosphericDetails)
+                    if (showAtmosphericDetails && !compactMode)
                     {
-                        GUILayout.BeginVertical(this.areaSettingStyle);
-                        this.DrawAtmosphericDetails();
+                        GUILayout.BeginVertical(areaSettingStyle);
+                        DrawAtmosphericDetails();
                         GUILayout.EndVertical();
                     }
 
-                    if (this.showSettings)
+                    if (showSettings)
                     {
-                        GUILayout.BeginVertical(this.areaSettingStyle);
-                        this.DrawSettings();
+                        GUILayout.BeginVertical(areaSettingStyle);
+                        DrawSettings();
                         GUILayout.EndVertical();
                     }
                 }
                 else // Draw only a few details when in compact mode.
                 {
-                    GUILayout.BeginHorizontal(this.areaStyle);
-                    this.DrawStageNumbers();
-                    this.DrawTwr();
-                    this.DrawDeltaV();
+                    GUILayout.BeginHorizontal(areaStyle);
+                    DrawStageNumbers();
+                    DrawTwr();
+                    DrawDeltaV();
                     GUILayout.EndHorizontal();
                 }
 
@@ -797,10 +888,8 @@
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex);
-            }
-        }
-
-        #endregion
+                Logger.Exception(ex, "BuildAdvanced.Window()");
+            }
+        }
     }
 }

--- a/KerbalEngineer/Editor/BuildOverlayPartInfo.cs
+++ b/KerbalEngineer/Editor/BuildOverlayPartInfo.cs
@@ -17,27 +17,35 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Helpers;
-
-using UnityEngine;
-
-#endregion
-
 namespace KerbalEngineer.Editor
 {
+    using System;
+    using System.Collections.Generic;
+    using Extensions;
+    using Helpers;
+    using UnityEngine;
+
     public class BuildOverlayPartInfo : MonoBehaviour
     {
-        #region Fields
-
         private static bool clickToOpen = true;
+        private static ModuleGenerator.GeneratorResource generatorResource;
+        private static ModuleAlternator moduleAlternator;
+        private static ModuleDataTransmitter moduleDataTransmitter;
+        private static ModuleDeployableSolarPanel moduleDeployableSolarPanel;
+        private static ModuleGenerator moduleGenerator;
+        private static ModuleGimbal moduleGimbal;
+        private static ModuleParachute moduleParachute;
+        private static ModuleRCS moduleRcs;
+        private static ModuleReactionWheel moduleReactionWheel;
+        private static ModuleResource moduleResource;
+        private static ModuleScienceExperiment moduleScienceExperiment;
         private static bool namesOnly;
+        private static Part part;
+        private static PartInfoItem partInfoItem;
+        private static PartResource partResource;
+        private static Propellant propellant;
+        private static PartExtensions.ProtoModuleDecoupler protoModuleDecoupler;
+        private static PartExtensions.ProtoModuleEngine protoModuleEngine;
         private static bool visible = true;
 
         private readonly List<PartInfoItem> infoItems = new List<PartInfoItem>();
@@ -47,44 +55,54 @@
         private bool showInfo;
         private bool skipFrame;
 
-        #endregion
-
-        #region Properties
-
         public static bool ClickToOpen
         {
-            get { return clickToOpen; }
-            set { clickToOpen = value; }
+            get
+            {
+                return clickToOpen;
+            }
+            set
+            {
+                clickToOpen = value;
+            }
         }
 
         public static bool Hidden { get; set; }
 
         public static bool NamesOnly
         {
-            get { return namesOnly; }
-            set { namesOnly = value; }
+            get
+            {
+                return namesOnly;
+            }
+            set
+            {
+                namesOnly = value;
+            }
         }
 
         public static bool Visible
         {
-            get { return visible; }
-            set { visible = value; }
-        }
-
-        #endregion
-
-        #region Methods: protected
+            get
+            {
+                return visible;
+            }
+            set
+            {
+                visible = value;
+            }
+        }
 
         protected void OnGUI()
         {
             try
             {
-                if (!Visible || Hidden || this.selectedPart == null)
+                if (!Visible || Hidden || selectedPart == null)
                 {
                     return;
                 }
 
-                this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, String.Empty, BuildOverlay.WindowStyle);
+                position = GUILayout.Window(GetInstanceID(), position, Window, String.Empty, BuildOverlay.WindowStyle);
             }
             catch (Exception ex)
 
@@ -102,62 +120,66 @@
                     return;
                 }
 
-                this.position.x = Mathf.Clamp(Input.mousePosition.x + 16.0f, 0.0f, Screen.width - this.position.width);
-                this.position.y = Mathf.Clamp(Screen.height - Input.mousePosition.y, 0.0f, Screen.height - this.position.height);
-                if (this.position.x < Input.mousePosition.x + 20.0f)
-                {
-                    this.position.y = Mathf.Clamp(this.position.y + 20.0f, 0.0f, Screen.height - this.position.height);
-                }
-                if (this.position.x < Input.mousePosition.x + 16.0f && this.position.y < Screen.height - Input.mousePosition.y)
-                {
-                    this.position.x = Input.mousePosition.x - 3 - this.position.width;
-                }
-
-                this.infoItems.Clear();
-                var part = EditorLogic.fetch.ship.parts.Find(p => p.stackIcon.highlightIcon) ?? EditorLogic.SelectedPart;
+                position.x = Mathf.Clamp(Input.mousePosition.x + 16.0f, 0.0f, Screen.width - position.width);
+                position.y = Mathf.Clamp(Screen.height - Input.mousePosition.y, 0.0f, Screen.height - position.height);
+                if (position.x < Input.mousePosition.x + 20.0f)
+                {
+                    position.y = Mathf.Clamp(position.y + 20.0f, 0.0f, Screen.height - position.height);
+                }
+                if (position.x < Input.mousePosition.x + 16.0f && position.y < Screen.height - Input.mousePosition.y)
+                {
+                    position.x = Input.mousePosition.x - 3 - position.width;
+                }
+
+                part = EditorLogic.fetch.ship.parts.Find(p => p.stackIcon.highlightIcon) ?? EditorLogic.SelectedPart;
                 if (part != null)
                 {
-                    if (!part.Equals(this.selectedPart))
-                    {
-                        this.selectedPart = part;
-                        this.ResetInfo();
-                    }
-                    if (NamesOnly || this.skipFrame)
-                    {
-                        this.skipFrame = false;
+                    if (!part.Equals(selectedPart))
+                    {
+                        selectedPart = part;
+                        ResetInfo();
+                    }
+                    if (NamesOnly || skipFrame)
+                    {
+                        skipFrame = false;
                         return;
                     }
 
-                    this.SetCostInfo();
-                    this.SetMassItems();
-                    this.SetResourceItems();
-                    this.SetEngineInfo();
-                    this.SetAlternatorInfo();
-                    this.SetGimbalInfo();
-                    this.SetRcsInfo();
-                    this.SetParachuteInfo();
-                    this.SetSasInfo();
-                    this.SetReactionWheelInfo();
-                    this.SetSolarPanelInfo();
-                    this.SetGeneratorInfo();
-                    this.SetDecouplerInfo();
-                    this.SetTransmitterInfo();
-                    this.SetScienceExperimentInfo();
-                    this.SetScienceContainerInfo();
-                    this.SetSingleActivationInfo();
-
-                    if (!this.showInfo && Input.GetMouseButtonDown(2))
-                    {
-                        this.showInfo = true;
-                    }
-                    else if (ClickToOpen && this.showInfo && Input.GetMouseButtonDown(2))
-                    {
-                        this.ResetInfo();
+                    if (!showInfo && Input.GetMouseButtonDown(2))
+                    {
+                        showInfo = true;
+                    }
+                    else if (ClickToOpen && showInfo && Input.GetMouseButtonDown(2))
+                    {
+                        ResetInfo();
+                    }
+
+                    if (showInfo)
+                    {
+                        PartInfoItem.Release(infoItems);
+                        infoItems.Clear();
+                        SetCostInfo();
+                        SetMassItems();
+                        SetResourceItems();
+                        SetEngineInfo();
+                        SetAlternatorInfo();
+                        SetGimbalInfo();
+                        SetRcsInfo();
+                        SetParachuteInfo();
+                        SetSasInfo();
+                        SetReactionWheelInfo();
+                        SetSolarPanelInfo();
+                        SetGeneratorInfo();
+                        SetDecouplerInfo();
+                        SetTransmitterInfo();
+                        SetScienceExperimentInfo();
+                        SetScienceContainerInfo();
+                        SetSingleActivationInfo();
                     }
                 }
                 else
                 {
-                    this.selectedPart = null;
+                    selectedPart = null;
                 }
             }
             catch (Exception ex)
@@ -166,277 +188,277 @@
             }
         }
 
-        #endregion
-
-        #region Methods: private
-
         private void ResetInfo()
         {
-            this.showInfo = !clickToOpen;
-            this.skipFrame = true;
-            this.position.width = namesOnly || clickToOpen ? 0.0f : 200.0f;
-            this.position.height = 0.0f;
+            showInfo = !clickToOpen;
+            skipFrame = true;
+            position.width = namesOnly || clickToOpen ? 0.0f : 200.0f;
+            position.height = 0.0f;
         }
 
         private void SetAlternatorInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleAlternator>())
-            {
-                return;
-            }
-
-            var alternator = this.selectedPart.GetModule<ModuleAlternator>();
-            this.infoItems.Add(new PartInfoItem("Alternator"));
-            foreach (var resource in alternator.outputResources)
-            {
-                this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate()));
+            moduleAlternator = selectedPart.GetModule<ModuleAlternator>();
+            if (moduleAlternator != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Alternator"));
+                for (int i = 0; i < moduleAlternator.outputResources.Count; ++i)
+                {
+                    moduleResource = moduleAlternator.outputResources[i];
+                    infoItems.Add(PartInfoItem.Create("\t" + moduleResource.name, moduleResource.rate.ToRate()));
+                }
             }
         }
 
         private void SetCostInfo()
         {
-            this.infoItems.Add(new PartInfoItem("Cost", Units.ConcatF(this.selectedPart.GetCostDry(), this.selectedPart.GetCostWet())));
+            infoItems.Add(PartInfoItem.Create("Cost", Units.ConcatF(selectedPart.GetCostDry(), selectedPart.GetCostWet())));
         }
 
         private void SetDecouplerInfo()
         {
-            if (!this.selectedPart.IsDecoupler())
-            {
-                return;
-            }
-
-            var decoupler = this.selectedPart.GetProtoModuleDecoupler();
-            this.infoItems.Add(new PartInfoItem("Ejection Force", decoupler.EjectionForce.ToForce()));
-            if (decoupler.IsOmniDecoupler)
-            {
-                this.infoItems.Add(new PartInfoItem("Omni-directional"));
+            protoModuleDecoupler = selectedPart.GetProtoModuleDecoupler();
+            if (protoModuleDecoupler != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Ejection Force", protoModuleDecoupler.EjectionForce.ToForce()));
+                if (protoModuleDecoupler.IsOmniDecoupler)
+                {
+                    infoItems.Add(PartInfoItem.Create("Omni-directional"));
+                }
             }
         }
 
         private void SetEngineInfo()
         {
-            if (!this.selectedPart.IsEngine())
-            {
-                return;
-            }
-
-            var engine = this.selectedPart.GetProtoModuleEngine();
-            this.infoItems.Add(new PartInfoItem("Thrust", Units.ToForce(engine.MinimumThrust, engine.MaximumThrust)));
-            this.infoItems.Add(new PartInfoItem("Isp", Units.ConcatF(engine.GetSpecificImpulse(1.0f), engine.GetSpecificImpulse(0.0f)) + "s"));
-            if (engine.Propellants.Count > 0)
-            {
-                this.infoItems.Add(new PartInfoItem("Propellants"));
-                var totalRatio = engine.Propellants.Sum(p => p.ratio);
-                foreach (var propellant in engine.Propellants)
-                {
-                    this.infoItems.Add(new PartInfoItem("\t" + propellant.name, (propellant.ratio / totalRatio).ToPercent()));
+            protoModuleEngine = selectedPart.GetProtoModuleEngine();
+            if (protoModuleEngine != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Thrust", Units.ToForce(protoModuleEngine.MinimumThrust, protoModuleEngine.MaximumThrust)));
+                infoItems.Add(PartInfoItem.Create("Isp", Units.ConcatF(protoModuleEngine.GetSpecificImpulse(1.0f), protoModuleEngine.GetSpecificImpulse(0.0f)) + "s"));
+                if (protoModuleEngine.Propellants.Count > 0)
+                {
+                    infoItems.Add(PartInfoItem.Create("Propellants"));
+
+                    float totalRatio = 0.0f;
+                    for (int i = 0; i < protoModuleEngine.Propellants.Count; ++i)
+                    {
+                        totalRatio = totalRatio + protoModuleEngine.Propellants[i].ratio;
+                    }
+
+                    for (int i = 0; i < protoModuleEngine.Propellants.Count; ++i)
+                    {
+                        propellant = protoModuleEngine.Propellants[i];
+                        infoItems.Add(PartInfoItem.Create("\t" + propellant.name, (propellant.ratio / totalRatio).ToPercent()));
+                    }
                 }
             }
         }
 
         private void SetGeneratorInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleGenerator>())
-            {
-                return;
-            }
-
-            var generator = this.selectedPart.GetModule<ModuleGenerator>();
-            if (generator.inputList.Count > 0)
-            {
-                this.infoItems.Add(new PartInfoItem("Generator Input"));
-                foreach (var resource in generator.inputList)
-                {
-                    this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate()));
-                }
-            }
-            if (generator.outputList.Count > 0)
-            {
-                this.infoItems.Add(new PartInfoItem("Generator Output"));
-                foreach (var resource in generator.outputList)
-                {
-                    this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate()));
-                }
-            }
-            if (generator.isAlwaysActive)
-            {
-                this.infoItems.Add(new PartInfoItem("Generator is Always Active"));
+            moduleGenerator = selectedPart.GetModule<ModuleGenerator>();
+            if (moduleGenerator != null)
+            {
+                if (moduleGenerator.inputList.Count > 0)
+                {
+                    infoItems.Add(PartInfoItem.Create("Generator Input"));
+                    for (int i = 0; i < moduleGenerator.inputList.Count; ++i)
+                    {
+                        generatorResource = moduleGenerator.inputList[i];
+                        infoItems.Add(PartInfoItem.Create("\t" + generatorResource.name, generatorResource.rate.ToRate()));
+                    }
+                }
+                if (moduleGenerator.outputList.Count > 0)
+                {
+                    infoItems.Add(PartInfoItem.Create("Generator Output"));
+                    for (int i = 0; i < moduleGenerator.outputList.Count; ++i)
+                    {
+                        generatorResource = moduleGenerator.outputList[i];
+                        infoItems.Add(PartInfoItem.Create("\t" + generatorResource.name, generatorResource.rate.ToRate()));
+                    }
+                }
+                if (moduleGenerator.isAlwaysActive)
+                {
+                    infoItems.Add(PartInfoItem.Create("Generator is Always Active"));
+                }
             }
         }
 
         private void SetGimbalInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleGimbal>())
-            {
-                return;
-            }
-
-            var gimbal = this.selectedPart.GetModule<ModuleGimbal>();
-            this.infoItems.Add(new PartInfoItem("Thrust Vectoring", gimbal.gimbalRange.ToString("F2")));
+            moduleGimbal = selectedPart.GetModule<ModuleGimbal>();
+            if (moduleGimbal != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Thrust Vectoring", moduleGimbal.gimbalRange.ToString("F2")));
+            }
         }
 
         private void SetMassItems()
         {
-            if (this.selectedPart.physicalSignificance == Part.PhysicalSignificance.FULL)
-            {
-                this.infoItems.Add(new PartInfoItem("Mass", Units.ToMass(this.selectedPart.GetDryMass(), this.selectedPart.GetWetMass())));
+            if (selectedPart.physicalSignificance == Part.PhysicalSignificance.FULL)
+            {
+                infoItems.Add(PartInfoItem.Create("Mass", Units.ToMass(selectedPart.GetDryMass(), selectedPart.GetWetMass())));
             }
         }
 
         private void SetParachuteInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleParachute>())
-            {
-                return;
-            }
-
-            var parachute = this.selectedPart.GetModule<ModuleParachute>();
-            this.infoItems.Add(new PartInfoItem("Deployed Drag", Units.ConcatF(parachute.semiDeployedDrag, parachute.fullyDeployedDrag)));
-            this.infoItems.Add(new PartInfoItem("Deployment Altitude", parachute.deployAltitude.ToDistance()));
-            this.infoItems.Add(new PartInfoItem("Deployment Pressure", parachute.minAirPressureToOpen.ToString("F2")));
+            moduleParachute = selectedPart.GetModule<ModuleParachute>();
+            if (moduleParachute != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Deployed Drag", Units.ConcatF(moduleParachute.semiDeployedDrag, moduleParachute.fullyDeployedDrag)));
+                infoItems.Add(PartInfoItem.Create("Deployment Altitude", moduleParachute.deployAltitude.ToDistance()));
+                infoItems.Add(PartInfoItem.Create("Deployment Pressure", moduleParachute.minAirPressureToOpen.ToString("F2")));
+            }
         }
 
         private void SetRcsInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleRCS>())
-            {
-                return;
-            }
-
-            var rcs = this.selectedPart.GetModule<ModuleRCS>();
-            this.infoItems.Add(new PartInfoItem("Thruster Power", rcs.thrusterPower.ToForce()));
-            this.infoItems.Add(new PartInfoItem("Specific Impulse", Units.ConcatF(rcs.atmosphereCurve.Evaluate(1.0f), rcs.atmosphereCurve.Evaluate(0.0f)) + "s"));
+            moduleRcs = selectedPart.GetModule<ModuleRCS>();
+            if (moduleRcs != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Thruster Power", moduleRcs.thrusterPower.ToForce()));
+                infoItems.Add(PartInfoItem.Create("Specific Impulse", Units.ConcatF(moduleRcs.atmosphereCurve.Evaluate(1.0f), moduleRcs.atmosphereCurve.Evaluate(0.0f)) + "s"));
+            }
         }
 
         private void SetReactionWheelInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleReactionWheel>())
-            {
-                return;
-            }
-
-            var reactionWheel = this.selectedPart.GetModule<ModuleReactionWheel>();
-            this.infoItems.Add(new PartInfoItem("Reaction Wheel Torque"));
-            this.infoItems.Add(new PartInfoItem("\tPitch", reactionWheel.PitchTorque.ToTorque()));
-            this.infoItems.Add(new PartInfoItem("\tRoll", reactionWheel.RollTorque.ToTorque()));
-            this.infoItems.Add(new PartInfoItem("\tYaw", reactionWheel.YawTorque.ToTorque()));
-            foreach (var resource in reactionWheel.inputResources)
-            {
-                this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate()));
+            moduleReactionWheel = selectedPart.GetModule<ModuleReactionWheel>();
+            if (moduleReactionWheel != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Reaction Wheel Torque"));
+                infoItems.Add(PartInfoItem.Create("\tPitch", moduleReactionWheel.PitchTorque.ToTorque()));
+                infoItems.Add(PartInfoItem.Create("\tRoll", moduleReactionWheel.RollTorque.ToTorque()));
+                infoItems.Add(PartInfoItem.Create("\tYaw", moduleReactionWheel.YawTorque.ToTorque()));
+                for (int i = 0; i < moduleReactionWheel.inputResources.Count; ++i)
+                {
+                    moduleResource = moduleReactionWheel.inputResources[i];
+                    infoItems.Add(PartInfoItem.Create("\t" + moduleResource.name, moduleResource.rate.ToRate()));
+                }
             }
         }
 
         private void SetResourceItems()
         {
-            if (this.selectedPart.Resources.list.Any(r => !r.hideFlow))
-            {
-                this.infoItems.Add(new PartInfoItem("Resources"));
-                foreach (var resource in this.selectedPart.Resources.list.Where(r => !r.hideFlow))
-                {
-                    this.infoItems.Add(resource.GetDensity() > 0
-                        ? new PartInfoItem("\t" + resource.info.name, "(" + resource.GetMass().ToMass() + ") " + resource.amount.ToString("F1"))
-                        : new PartInfoItem("\t" + resource.info.name, resource.amount.ToString("F1")));
+            bool visibleResources = false;
+            for (int i = 0; i < selectedPart.Resources.list.Count; ++i)
+            {
+                if (selectedPart.Resources.list[i].hideFlow == false)
+                {
+                    visibleResources = true;
+                    break;
+                }
+            }
+            if (visibleResources)
+            {
+                infoItems.Add(PartInfoItem.Create("Resources"));
+                for (int i = 0; i < selectedPart.Resources.list.Count; ++i)
+                {
+                    partResource = selectedPart.Resources.list[i];
+
+                    if (partResource.hideFlow == false)
+                    {
+                        infoItems.Add(partResource.GetDensity() > 0
+                            ? PartInfoItem.Create("\t" + partResource.info.name, "(" + partResource.GetMass().ToMass() + ") " + partResource.amount.ToString("F1"))
+                            : PartInfoItem.Create("\t" + partResource.info.name, partResource.amount.ToString("F1")));
+                    }
                 }
             }
         }
 
         private void SetSasInfo()
         {
-            if (this.selectedPart.HasModule<ModuleSAS>())
-            {
-                this.infoItems.Add(new PartInfoItem("SAS Equiped"));
+            if (selectedPart.HasModule<ModuleSAS>())
+            {
+                infoItems.Add(PartInfoItem.Create("SAS Equiped"));
             }
         }
 
         private void SetScienceContainerInfo()
         {
-            if (this.selectedPart.HasModule<ModuleScienceContainer>())
-            {
-                this.infoItems.Add(new PartInfoItem("Science Container"));
+            if (selectedPart.HasModule<ModuleScienceContainer>())
+            {
+                infoItems.Add(PartInfoItem.Create("Science Container"));
             }
         }
 
         private void SetScienceExperimentInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleScienceExperiment>())
-            {
-                return;
-            }
-
-            var experiment = this.selectedPart.GetModule<ModuleScienceExperiment>();
-            this.infoItems.Add(new PartInfoItem("Science Experiment", experiment.experimentActionName));
-            this.infoItems.Add(new PartInfoItem("\tTransmit Efficiency", experiment.xmitDataScalar.ToPercent()));
-            if (!experiment.rerunnable)
-            {
-                this.infoItems.Add(new PartInfoItem("\tSingle Usage"));
+            moduleScienceExperiment = selectedPart.GetModule<ModuleScienceExperiment>();
+            if (moduleScienceExperiment != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Science Experiment", moduleScienceExperiment.experimentActionName));
+                infoItems.Add(PartInfoItem.Create("\tTransmit Efficiency", moduleScienceExperiment.xmitDataScalar.ToPercent()));
+                if (moduleScienceExperiment.rerunnable == false)
+                {
+                    infoItems.Add(PartInfoItem.Create("\tSingle Usage"));
+                }
             }
         }
 
         private void SetSingleActivationInfo()
         {
-            if (this.selectedPart.HasModule<ModuleAnimateGeneric>(m => m.isOneShot))
-            {
-                this.infoItems.Add(new PartInfoItem("Single Activation"));
+            if (selectedPart.HasModule<ModuleAnimateGeneric>(m => m.isOneShot))
+            {
+                infoItems.Add(PartInfoItem.Create("Single Activation"));
             }
         }
 
         private void SetSolarPanelInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleDeployableSolarPanel>())
-            {
-                return;
-            }
-
-            var solarPanel = this.selectedPart.GetModule<ModuleDeployableSolarPanel>();
-            this.infoItems.Add(new PartInfoItem("Charge Rate", solarPanel.chargeRate.ToRate()));
-            if (solarPanel.isBreakable)
-            {
-                this.infoItems.Add(new PartInfoItem("Breakable"));
-            }
-            if (solarPanel.sunTracking)
-            {
-                this.infoItems.Add(new PartInfoItem("Sun Tracking"));
+            moduleDeployableSolarPanel = selectedPart.GetModule<ModuleDeployableSolarPanel>();
+            if (moduleDeployableSolarPanel != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Charge Rate", moduleDeployableSolarPanel.chargeRate.ToRate()));
+                if (moduleDeployableSolarPanel.isBreakable)
+                {
+                    infoItems.Add(PartInfoItem.Create("Breakable"));
+                }
+                if (moduleDeployableSolarPanel.sunTracking)
+                {
+                    infoItems.Add(PartInfoItem.Create("Sun Tracking"));
+                }
             }
         }
 
         private void SetTransmitterInfo()
         {
-            if (!this.selectedPart.HasModule<ModuleDataTransmitter>())
-            {
-                return;
-            }
-
-            var transmitter = this.selectedPart.GetModule<ModuleDataTransmitter>();
-            this.infoItems.Add(new PartInfoItem("Packet Size", transmitter.packetSize.ToString("F2") + " Mits"));
-            this.infoItems.Add(new PartInfoItem("Bandwidth", (transmitter.packetInterval * transmitter.packetSize).ToString("F2") + "Mits/sec"));
-            this.infoItems.Add(new PartInfoItem(transmitter.requiredResource, transmitter.packetResourceCost.ToString("F2") + "/Packet"));
+            moduleDataTransmitter = selectedPart.GetModule<ModuleDataTransmitter>();
+            if (moduleDataTransmitter != null)
+            {
+                infoItems.Add(PartInfoItem.Create("Packet Size", moduleDataTransmitter.packetSize.ToString("F2") + " Mits"));
+                infoItems.Add(PartInfoItem.Create("Bandwidth", (moduleDataTransmitter.packetInterval * moduleDataTransmitter.packetSize).ToString("F2") + "Mits/sec"));
+                infoItems.Add(PartInfoItem.Create(moduleDataTransmitter.requiredResource, moduleDataTransmitter.packetResourceCost.ToString("F2") + "/Packet"));
+            }
         }
 
         private void Window(int windowId)
         {
             try
             {
-                GUILayout.Label(this.selectedPart.partInfo.title, BuildOverlay.TitleStyle);
-                if (this.showInfo)
-                {
-                    foreach (var item in this.infoItems)
-                    {
+                GUILayout.Label(selectedPart.partInfo.title, BuildOverlay.TitleStyle);
+                if (showInfo)
+                {
+                    for (int i = 0; i < infoItems.Count; ++i)
+                    {
+                        partInfoItem = infoItems[i];
                         GUILayout.Space(2.0f);
                         GUILayout.BeginHorizontal();
-                        if (item.Value != null)
+                        if (partInfoItem.Value != null)
                         {
-                            GUILayout.Label(item.Name + ":", BuildOverlay.NameStyle);
+                            GUILayout.Label(partInfoItem.Name + ":", BuildOverlay.NameStyle);
                             GUILayout.Space(25.0f);
-                            GUILayout.Label(item.Value, BuildOverlay.ValueStyle);
+                            GUILayout.Label(partInfoItem.Value, BuildOverlay.ValueStyle);
                         }
                         else
                         {
-                            GUILayout.Label(item.Name, BuildOverlay.NameStyle);
+                            GUILayout.Label(partInfoItem.Name, BuildOverlay.NameStyle);
                         }
                         GUILayout.EndHorizontal();
                     }
                 }
-                else if (this.infoItems.Count > 0)
+                else if (clickToOpen && namesOnly == false)
                 {
                     GUILayout.Space(2.0f);
                     GUILayout.Label("Click middle mouse to show more info...", BuildOverlay.NameStyle);
@@ -447,7 +469,5 @@
                 Logger.Exception(ex);
             }
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Editor/BuildOverlayResources.cs
+++ b/KerbalEngineer/Editor/BuildOverlayResources.cs
@@ -19,22 +19,18 @@
 
 #region Using Directives
 
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-using KerbalEngineer.Extensions;
-
-using UnityEngine;
-
 #endregion
 
 namespace KerbalEngineer.Editor
 {
+    using System;
+    using System.Collections.Generic;
+    using Extensions;
+    using UnityEngine;
+
     public class BuildOverlayResources : MonoBehaviour
     {
         #region Fields
-
         private static bool visible = true;
 
         private readonly Dictionary<int, ResourceInfoItem> resources = new Dictionary<int, ResourceInfoItem>();
@@ -45,40 +41,48 @@
         private Rect tabPosition;
         private Vector2 tabSize;
         private Rect windowPosition = new Rect(0.0f, 0.0f, BuildOverlay.MinimumWidth, 0.0f);
-
         #endregion
 
         #region Properties
-
         public static bool Visible
         {
-            get { return visible; }
-            set { visible = value; }
+            get
+            {
+                return visible;
+            }
+            set
+            {
+                visible = value;
+            }
         }
 
         public bool Open
         {
-            get { return this.open; }
-            set { this.open = value; }
-        }
-
+            get
+            {
+                return open;
+            }
+            set
+            {
+                open = value;
+            }
+        }
         #endregion
 
         #region Methods: protected
-
         protected void OnGUI()
         {
             try
             {
-                if (!Visible || this.resources.Count == 0 || EditorLogic.fetch.editorScreen != EditorScreen.Parts)
+                if (!Visible || resources.Count == 0 || EditorLogic.fetch.editorScreen != EditorScreen.Parts)
                 {
                     return;
                 }
 
-                this.open = GUI.Toggle(this.tabPosition, this.open, this.tabContent, BuildOverlay.TabStyle);
-                if (this.openPercent > 0.0)
-                {
-                    this.windowPosition = GUILayout.Window(this.GetInstanceID(), this.windowPosition, this.Window, String.Empty, BuildOverlay.WindowStyle);
+                open = GUI.Toggle(tabPosition, open, tabContent, BuildOverlay.TabStyle);
+                if (openPercent > 0.0)
+                {
+                    windowPosition = GUILayout.Window(GetInstanceID(), windowPosition, Window, String.Empty, BuildOverlay.WindowStyle);
                 }
             }
             catch (Exception ex)
@@ -91,8 +95,8 @@
         {
             try
             {
-                this.tabContent = new GUIContent("RESOURCES");
-                this.tabSize = BuildOverlay.TabStyle.CalcSize(this.tabContent);
+                tabContent = new GUIContent("RESOURCES");
+                tabSize = BuildOverlay.TabStyle.CalcSize(tabContent);
             }
             catch (Exception ex)
             {
@@ -109,66 +113,74 @@
                     return;
                 }
 
-                this.SetResources();
-                this.SetSlidePosition();
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex);
-            }
-        }
-
+                SetResources();
+                SetSlidePosition();
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+            }
+        }
         #endregion
 
         #region Methods: private
+        private static Part part;
+        private static PartResource partResource;
 
         private void SetResources()
         {
-            var previousCount = this.resources.Count;
-            this.resources.Clear();
-            foreach (var resource in EditorLogic.fetch.ship.parts.SelectMany(p => p.Resources.list).Where(r => r.amount > 0.0))
-            {
-                if (this.resources.ContainsKey(resource.info.id))
-                {
-                    this.resources[resource.info.id].Amount += resource.amount;
-                }
-                else
-                {
-                    this.resources.Add(resource.info.id, new ResourceInfoItem(resource));
-                }
-            }
-
-            if (this.resources.Count < previousCount)
-            {
-                this.windowPosition.height = 0;
+            int previousCount = resources.Count;
+            resources.Clear();
+
+            for (int i = 0; i < EditorLogic.fetch.ship.parts.Count; ++i)
+            {
+                part = EditorLogic.fetch.ship.parts[i];
+                for (int j = 0; j < part.Resources.list.Count; ++j)
+                {
+                    partResource = part.Resources.list[j];
+
+                    if (resources.ContainsKey(partResource.info.id))
+                    {
+                        resources[partResource.info.id].Amount += partResource.amount;
+                    }
+                    else
+                    {
+                        resources.Add(partResource.info.id, new ResourceInfoItem(partResource));
+                    }
+                }
+            }
+
+            if (resources.Count < previousCount)
+            {
+                windowPosition.height = 0;
             }
         }
 
         private void SetSlidePosition()
         {
-            if (this.open && this.openPercent < 1.0f)
-            {
-                this.openPercent = Mathf.Clamp(this.openPercent + Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
-            }
-            else if (!this.open && this.openPercent > 0.0f)
-            {
-                this.openPercent = Mathf.Clamp(this.openPercent - Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
-            }
-
-            this.windowPosition.x = BuildOverlay.BuildOverlayVessel.WindowPosition.xMax + 5.0f;
-            this.windowPosition.y = Mathf.Lerp(Screen.height, Screen.height - this.windowPosition.height, this.openPercent);
-            this.tabPosition.width = this.tabSize.x;
-            this.tabPosition.height = this.tabSize.y;
-            this.tabPosition.x = this.windowPosition.x;
-            this.tabPosition.y = this.windowPosition.y - this.tabPosition.height;
+            if (open && openPercent < 1.0f)
+            {
+                openPercent = Mathf.Clamp(openPercent + Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
+            }
+            else if (!open && openPercent > 0.0f)
+            {
+                openPercent = Mathf.Clamp(openPercent - Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
+            }
+
+            windowPosition.x = BuildOverlay.BuildOverlayVessel.WindowPosition.xMax + 5.0f;
+            windowPosition.y = Mathf.Lerp(Screen.height, Screen.height - windowPosition.height, openPercent);
+            tabPosition.width = tabSize.x;
+            tabPosition.height = tabSize.y;
+            tabPosition.x = windowPosition.x;
+            tabPosition.y = windowPosition.y - tabPosition.height;
         }
 
         private void Window(int windowId)
         {
             try
             {
-                var firstItem = true;
-                foreach (var resource in this.resources)
+                bool firstItem = true;
+                foreach (KeyValuePair<int, ResourceInfoItem> resource in resources)
                 {
                     if (!firstItem)
                     {
@@ -197,7 +209,6 @@
                 Logger.Exception(ex);
             }
         }
-
         #endregion
     }
 }

--- a/KerbalEngineer/Editor/BuildOverlayVessel.cs
+++ b/KerbalEngineer/Editor/BuildOverlayVessel.cs
@@ -18,13 +18,11 @@
 // 
 
 #region Using Directives
-
 #endregion
 
 namespace KerbalEngineer.Editor
 {
     #region Using Directives
-
     using System;
     using System.Collections.Generic;
     using Helpers;
@@ -36,13 +34,10 @@
     public class BuildOverlayVessel : MonoBehaviour
     {
         #region Constants
-
         private const float Width = 175.0f;
-
         #endregion
 
         #region Fields
-
         private static bool visible = true;
 
         private readonly List<PartInfoItem> infoItems = new List<PartInfoItem>();
@@ -54,44 +49,61 @@
         private Rect tabPosition;
         private Vector2 tabSize;
         private Rect windowPosition = new Rect(330.0f, 0.0f, Width, 0.0f);
-
         #endregion
 
         #region Properties
-
         public static bool Visible
         {
-            get { return visible; }
-            set { visible = value; }
+            get
+            {
+                return visible;
+            }
+            set
+            {
+                visible = value;
+            }
         }
 
         public bool Open
         {
-            get { return this.open; }
-            set { this.open = value; }
+            get
+            {
+                return open;
+            }
+            set
+            {
+                open = value;
+            }
         }
 
         public Rect WindowPosition
         {
-            get { return this.windowPosition; }
+            get
+            {
+                return windowPosition;
+            }
         }
 
         public float WindowX
         {
-            get { return this.windowPosition.x; }
-            set { this.windowPosition.x = value; }
-        }
-
+            get
+            {
+                return windowPosition.x;
+            }
+            set
+            {
+                windowPosition.x = value;
+            }
+        }
         #endregion
 
         #region Methods
-
         protected void Awake()
         {
             try
             {
-                SimManager.OnReady -= this.GetStageInfo;
-                SimManager.OnReady += this.GetStageInfo;
+                SimManager.OnReady -= GetStageInfo;
+                SimManager.OnReady += GetStageInfo;
             }
             catch (Exception ex)
             {
@@ -108,10 +120,10 @@
                     return;
                 }
 
-                this.open = GUI.Toggle(this.tabPosition, this.open, this.tabContent, BuildOverlay.TabStyle);
-                if (this.openPercent > 0.0)
-                {
-                    this.windowPosition = GUILayout.Window(this.GetInstanceID(), this.windowPosition, this.VesselWindow, String.Empty, BuildOverlay.WindowStyle);
+                open = GUI.Toggle(tabPosition, open, tabContent, BuildOverlay.TabStyle);
+                if (openPercent > 0.0)
+                {
+                    windowPosition = GUILayout.Window(GetInstanceID(), windowPosition, VesselWindow, String.Empty, BuildOverlay.WindowStyle);
                 }
             }
             catch (Exception ex)
@@ -124,8 +136,8 @@
         {
             try
             {
-                this.tabContent = new GUIContent("VESSEL");
-                this.tabSize = BuildOverlay.TabStyle.CalcSize(this.tabContent);
+                tabContent = new GUIContent("VESSEL");
+                tabSize = BuildOverlay.TabStyle.CalcSize(tabContent);
             }
             catch (Exception ex)
             {
@@ -142,12 +154,12 @@
                     return;
                 }
 
-                if (this.openPercent > 0.0)
-                {
-                    this.SetVesselInfo();
-                }
-
-                this.SetSlidePosition();
+                if (openPercent > 0.0)
+                {
+                    SetVesselInfo();
+                }
+
+                SetSlidePosition();
             }
             catch (Exception ex)
             {
@@ -157,29 +169,29 @@
 
         private void GetStageInfo()
         {
-            this.lastStage = SimManager.LastStage;
+            lastStage = SimManager.LastStage;
         }
 
         private void SetSlidePosition()
         {
-            if (this.open && this.openPercent < 1.0f)
-            {
-                this.openPercent = Mathf.Clamp(this.openPercent + Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
-            }
-            else if (!this.open && this.openPercent > 0.0f)
-            {
-                this.openPercent = Mathf.Clamp(this.openPercent - Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
-            }
-
-            this.windowPosition.y = Mathf.Lerp(Screen.height, Screen.height - this.windowPosition.height, this.openPercent);
-            if (this.windowPosition.width < Width)
-            {
-                this.windowPosition.width = Width;
-            }
-            this.tabPosition.width = this.tabSize.x;
-            this.tabPosition.height = this.tabSize.y;
-            this.tabPosition.x = this.windowPosition.x;
-            this.tabPosition.y = this.windowPosition.y - this.tabPosition.height;
+            if (open && openPercent < 1.0f)
+            {
+                openPercent = Mathf.Clamp(openPercent + Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
+            }
+            else if (!open && openPercent > 0.0f)
+            {
+                openPercent = Mathf.Clamp(openPercent - Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
+            }
+
+            windowPosition.y = Mathf.Lerp(Screen.height, Screen.height - windowPosition.height, openPercent);
+            if (windowPosition.width < Width)
+            {
+                windowPosition.width = Width;
+            }
+            tabPosition.width = tabSize.x;
+            tabPosition.height = tabSize.y;
+            tabPosition.x = windowPosition.x;
+            tabPosition.y = windowPosition.y - tabPosition.height;
         }
 
         private void SetVesselInfo()
@@ -188,7 +200,7 @@
 
             if (BuildAdvanced.Instance.ShowAtmosphericDetails)
             {
-                SimManager.Atmosphere = CelestialBodies.SelectedBody.Atmosphere * 0.01;
+                SimManager.Atmosphere = CelestialBodies.SelectedBody.GetAtmospheres(BuildAdvanced.Altitude);
             }
             else
             {
@@ -198,13 +210,14 @@
             SimManager.RequestSimulation();
             SimManager.TryStartSimulation();
 
-            if (this.lastStage != null)
-            {
-                this.infoItems.Clear();
-                this.infoItems.Add(new PartInfoItem("Delta-V", this.lastStage.deltaV.ToString("N0") + " / " + this.lastStage.totalDeltaV.ToString("N0") + "m/s"));
-                this.infoItems.Add(new PartInfoItem("Mass", Units.ToMass(this.lastStage.mass, this.lastStage.totalMass)));
-                this.infoItems.Add(new PartInfoItem("TWR", this.lastStage.thrustToWeight.ToString("F2") + " (" + this.lastStage.maxThrustToWeight.ToString("F2") + ")"));
-                this.infoItems.Add(new PartInfoItem("Parts", this.lastStage.partCount + " / " + this.lastStage.totalPartCount));
+            if (lastStage != null)
+            {
+                PartInfoItem.Release(infoItems);
+                infoItems.Clear();
+                infoItems.Add(PartInfoItem.Create("Delta-V", lastStage.deltaV.ToString("N0") + " / " + lastStage.totalDeltaV.ToString("N0") + "m/s"));
+                infoItems.Add(PartInfoItem.Create("Mass", Units.ToMass(lastStage.mass, lastStage.totalMass)));
+                infoItems.Add(PartInfoItem.Create("TWR", lastStage.thrustToWeight.ToString("F2") + " (" + lastStage.maxThrustToWeight.ToString("F2") + ")"));
+                infoItems.Add(PartInfoItem.Create("Parts", lastStage.partCount + " / " + lastStage.totalPartCount));
             }
         }
 
@@ -212,8 +225,8 @@
         {
             try
             {
-                var firstItem = true;
-                foreach (var item in this.infoItems)
+                bool firstItem = true;
+                foreach (PartInfoItem item in infoItems)
                 {
                     if (!firstItem)
                     {
@@ -240,7 +253,6 @@
                 Logger.Exception(ex);
             }
         }
-
         #endregion
     }
 }

--- a/KerbalEngineer/Editor/BuildToolbar.cs
+++ b/KerbalEngineer/Editor/BuildToolbar.cs
@@ -42,6 +42,14 @@
         {
             GameEvents.onGUIApplicationLauncherReady.Add(this.OnGuiAppLauncherReady);
             Logger.Log("BuildToolbar->Awake");
+        }
+
+        private void Start()
+        {
+            if (button == null)
+            {
+                OnGuiAppLauncherReady();
+            }
         }
 
         private void OnDestroy()

--- a/KerbalEngineer/Editor/PartInfoItem.cs
+++ b/KerbalEngineer/Editor/PartInfoItem.cs
@@ -19,29 +19,69 @@
 
 namespace KerbalEngineer.Editor
 {
+    using System.Collections.Generic;
+    using VesselSimulator;
+
     public class PartInfoItem
     {
-        #region Constructors
-
-        public PartInfoItem(string name)
-        {
-            this.Name = name;
-        }
-
-        public PartInfoItem(string name, string value)
-        {
-            this.Name = name;
-            this.Value = value;
-        }
-
-        #endregion
-
-        #region Properties
+        private static readonly Pool<PartInfoItem> pool = new Pool<PartInfoItem>(Create, Reset);
 
         public string Name { get; set; }
 
         public string Value { get; set; }
 
-        #endregion
+        private static PartInfoItem Create()
+        {
+            return new PartInfoItem();
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+        public static void Release(List<PartInfoItem> objList)
+        {
+            for (int i = 0; i < objList.Count; ++i)
+            {
+                objList[i].Release();
+            }
+        }
+
+        private static void Reset(PartInfoItem obj)
+        {
+            obj.Name = string.Empty;
+            obj.Value = string.Empty;
+        }
+
+        public static PartInfoItem Create(string name)
+        {
+            return New(name);
+        }
+
+        public static PartInfoItem Create(string name, string value)
+        {
+            return New(name, value);
+        }
+
+        public static PartInfoItem New(string name)
+        {
+            PartInfoItem obj = pool.Borrow();
+            
+            obj.Name = name;
+            obj.Value = string.Empty;
+
+            return obj;
+        }
+
+        public static PartInfoItem New(string name, string value)
+        {
+            PartInfoItem obj = pool.Borrow();
+
+            obj.Name = name;
+            obj.Value = value;
+
+            return obj;
+        }
     }
 }

--- a/KerbalEngineer/EngineerGlobals.cs
+++ b/KerbalEngineer/EngineerGlobals.cs
@@ -1,7 +1,5 @@
 // 
-//     Kerbal Engineer Redux
-// 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,42 +15,32 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System.IO;
-using System.Reflection;
-
-#endregion
-
 namespace KerbalEngineer
 {
-    public class EngineerGlobals
+    using System.IO;
+    using System.Reflection;
+
+    public static class EngineerGlobals
     {
-        #region Constants
-
         /// <summary>
         ///     Current version of the Kerbal Engineer assembly.
         /// </summary>
-        public const string AssemblyVersion = "1.0.16.0";
-
-        #endregion
-
-        #region Fields
+        public const string ASSEMBLY_VERSION = "1.0.18.1";
 
         private static string assemblyFile;
         private static string assemblyName;
         private static string assemblyPath;
-
-        #endregion
-
-        #region Properties
+        private static string settingsPath;
 
         /// <summary>
         ///     Gets the Kerbal Engineer assembly's path including the file name.
         /// </summary>
         public static string AssemblyFile
         {
-            get { return assemblyFile ?? (assemblyFile = Assembly.GetExecutingAssembly().Location); }
+            get
+            {
+                return assemblyFile ?? (assemblyFile = Assembly.GetExecutingAssembly().Location);
+            }
         }
 
         /// <summary>
@@ -60,7 +48,10 @@
         /// </summary>
         public static string AssemblyName
         {
-            get { return assemblyName ?? (assemblyName = new FileInfo(AssemblyFile).Name); }
+            get
+            {
+                return assemblyName ?? (assemblyName = new FileInfo(AssemblyFile).Name);
+            }
         }
 
         /// <summary>
@@ -68,9 +59,25 @@
         /// </summary>
         public static string AssemblyPath
         {
-            get { return assemblyPath ?? (assemblyPath = AssemblyFile.Replace(new FileInfo(AssemblyFile).Name, "")); }
+            get
+            {
+                return assemblyPath ?? (assemblyPath = AssemblyFile.Replace(new FileInfo(AssemblyFile).Name, ""));
+            }
         }
 
-        #endregion
+        /// <summary>
+        ///     Gets the settings directory path.
+        /// </summary>
+        public static string SettingsPath
+        {
+            get
+            {
+                if (string.IsNullOrEmpty(settingsPath))
+                {
+                    settingsPath = Path.Combine(AssemblyPath, "Settings");
+                }
+                return settingsPath;
+            }
+        }
     }
 }

--- a/KerbalEngineer/Extensions/DoubleExtensions.cs
+++ b/KerbalEngineer/Extensions/DoubleExtensions.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,18 +17,12 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using KerbalEngineer.Helpers;
-
-#endregion
-
 namespace KerbalEngineer.Extensions
 {
+    using Helpers;
+
     public static class DoubleExtensions
     {
-        #region Methods: public
-
         public static double Clamp(this double value, double lower, double higher)
         {
             return value < lower ? lower : value > higher ? higher : value;
@@ -49,14 +43,19 @@
             return Units.ToDistance(value);
         }
 
-        public static string ToTorque(this double value)
+        public static string ToFlux(this double value)
         {
-            return Units.ToTorque(value);
+            return Units.ToFlux(value);
         }
 
         public static string ToForce(this double value)
         {
             return Units.ToForce(value);
+        }
+
+        public static string ToMach(this double value)
+        {
+            return Units.ToMach(value);
         }
 
         public static string ToMass(this double value)
@@ -79,6 +78,14 @@
             return Units.ToSpeed(value);
         }
 
-        #endregion
+        public static string ToTemperature(this double value)
+        {
+            return Units.ToTemperature(value);
+        }
+
+        public static string ToTorque(this double value)
+        {
+            return Units.ToTorque(value);
+        }
     }
 }

--- a/KerbalEngineer/Extensions/FloatExtensions.cs
+++ b/KerbalEngineer/Extensions/FloatExtensions.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,18 +17,12 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using KerbalEngineer.Helpers;
-
-#endregion
-
 namespace KerbalEngineer.Extensions
 {
+    using Helpers;
+
     public static class FloatExtensions
     {
-        #region Methods: public
-
         public static string ToAcceleration(this float value)
         {
             return Units.ToAcceleration(value);
@@ -44,14 +38,19 @@
             return Units.ToDistance(value);
         }
 
+        public static string ToFlux(this float value)
+        {
+            return Units.ToFlux(value);
+        }
+
         public static string ToForce(this float value)
         {
             return Units.ToForce(value);
         }
 
-        public static string ToTorque(this float value)
+        public static string ToMach(this float value)
         {
-            return Units.ToTorque(value);
+            return Units.ToMach(value);
         }
 
         public static string ToMass(this float value)
@@ -74,6 +73,14 @@
             return Units.ToSpeed(value);
         }
 
-        #endregion
+        public static string ToTemperature(this float value)
+        {
+            return Units.ToTemperature(value);
+        }
+
+        public static string ToTorque(this float value)
+        {
+            return Units.ToTorque(value);
+        }
     }
 }

--- a/KerbalEngineer/Extensions/OrbitExtensions.cs
+++ b/KerbalEngineer/Extensions/OrbitExtensions.cs
@@ -61,12 +61,15 @@
                 return 0.0;
             }
 
-            var angle = AngleHelper.GetAngleBetweenVectors(orbit.getRelativePositionAtUT(universalTime),
-                                                           Vector3d.Exclude(orbit.GetOrbitNormal(), orbit.referenceBody.orbit.getRelativePositionAtUT(universalTime)));
+            Vector3d orbitVector = orbit.getRelativePositionAtUT(universalTime);
+            orbitVector.z = 0.0;
 
-            angle = AngleHelper.Clamp360(angle - 90.0);
+            Vector3d bodyVector = orbit.referenceBody.orbit.getOrbitalVelocityAtUT(universalTime);
+            bodyVector.z = 0.0;
 
-            return orbit.inclination > 90.0 ? angle : 360.0 - angle;
+            double angle = AngleHelper.GetAngleBetweenVectors(bodyVector, orbitVector);
+
+            return AngleHelper.Clamp360(orbit.inclination < 90.0 ? angle : 360.0 - angle);
         }
 
         public static double GetAngleToRetrograde(this Orbit orbit)
@@ -81,12 +84,15 @@
                 return 0.0;
             }
 
-            var angle = AngleHelper.GetAngleBetweenVectors(orbit.getRelativePositionAtUT(universalTime),
-                                                           Vector3d.Exclude(orbit.GetOrbitNormal(), orbit.referenceBody.orbit.getRelativePositionAtUT(universalTime)));
+            Vector3d orbitVector = orbit.getRelativePositionAtUT(universalTime);
+            orbitVector.z = 0.0;
 
-            angle = AngleHelper.Clamp360(angle + 90.0);
+            Vector3d bodyVector = orbit.referenceBody.orbit.getOrbitalVelocityAtUT(universalTime);
+            bodyVector.z = 0.0;
 
-            return orbit.inclination > 90.0 ? angle : 360.0 - angle;
+            double angle = AngleHelper.GetAngleBetweenVectors(-bodyVector, orbitVector);
+
+            return AngleHelper.Clamp360(orbit.inclination < 90.0 ? angle : 360.0 - angle);
         }
 
         public static double GetAngleToTrueAnomaly(this Orbit orbit, double trueAnomaly)

--- a/KerbalEngineer/Extensions/PartExtensions.cs
+++ b/KerbalEngineer/Extensions/PartExtensions.cs
@@ -17,21 +17,17 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-#endregion
-
 namespace KerbalEngineer.Extensions
 {
+    using System;
+    using System.Collections.Generic;
     using CompoundParts;
 
     public static class PartExtensions
     {
-        #region Methods: public
+        //private static Part cachePart;
+        //private static PartModule cachePartModule;
+        //private static PartResource cachePartResource;
 
         /// <summary>
         ///     Gets whether the part contains a specific resource.
@@ -46,26 +42,37 @@
         /// </summary>
         public static bool ContainsResources(this Part part)
         {
-            return part.Resources.list.Count(p => p.amount > 0d) > 0;
+            for (int i = 0; i < part.Resources.list.Count; ++i)
+            {
+                if (part.Resources.list[i].amount > 0.0)
+                {
+                    return true;
+                }
+            }
+            return false;
         }
 
         /// <summary>
         ///     Gets whether the part has fuel.
         /// </summary>
+        /* not used
         public static bool EngineHasFuel(this Part part)
         {
-            if (part.HasModule<ModuleEngines>())
-            {
-                return part.GetModuleEngines().getFlameoutState;
-            }
-            if (part.HasModule<MultiModeEngine>())
-            {
-                return part.GetModuleMultiModeEngine().getFlameoutState;
+            PartModule cachePartModule = GetModule<ModuleEngines>(part);
+            if (cachePartModule != null)
+            {
+                return (cachePartModule as ModuleEngines).getFlameoutState;
+            }
+
+            cachePartModule = GetModuleMultiModeEngine(part);
+            if (cachePartModule != null)
+            {
+                return (cachePartModule as ModuleEnginesFX).getFlameoutState;
             }
 
             return false;
         }
-
+        */
         /// <summary>
         ///     Gets the cost of the part excluding resources.
         /// </summary>
@@ -117,23 +124,24 @@
         /// <summary>
         ///     Gets the maximum thrust of the part if it's an engine.
         /// </summary>
+        /* not used
         public static double GetMaxThrust(this Part part)
         {
-            if (part.HasModule<ModuleEngines>())
-            {
-                return part.GetModuleEngines().maxThrust;
-            }
-            if (part.HasModule<MultiModeEngine>())
-            {
-                return part.GetModuleMultiModeEngine().maxThrust;
-            }
-            if (part.HasModule<ModuleEnginesFX>())
-            {
-                return part.GetModuleEnginesFx().maxThrust;
-            }
-
-            return 0d;
-        }
+            PartModule cachePartModule = GetModule<ModuleEngines>(part);
+            if (cachePartModule != null)
+            {
+                return (cachePartModule as ModuleEngines).maxThrust;
+            }
+
+            cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part);
+            if (cachePartModule != null)
+            {
+                return (cachePartModule as ModuleEnginesFX).maxThrust;
+            }
+
+            return 0.0;
+        }
+        */
 
         /// <summary>
         ///     Gets the first typed PartModule in the part's module list.
@@ -154,7 +162,7 @@
         /// </summary>
         public static T GetModule<T>(this Part part, string className) where T : PartModule
         {
-            return (T)Convert.ChangeType(part.Modules[className], typeof(T));
+            return part.Modules[className] as T;
         }
 
         /// <summary>
@@ -162,7 +170,7 @@
         /// </summary>
         public static T GetModule<T>(this Part part, int classId) where T : PartModule
         {
-            return (T)Convert.ChangeType(part.Modules[classId], typeof(T));
+            return part.Modules[classId] as T;
         }
 
         /// <summary>
@@ -170,7 +178,7 @@
         /// </summary>
         public static ModuleAlternator GetModuleAlternator(this Part part)
         {
-            return part.GetModule<ModuleAlternator>();
+            return GetModule<ModuleAlternator>(part);
         }
 
         /// <summary>
@@ -178,7 +186,7 @@
         /// </summary>
         public static ModuleDeployableSolarPanel GetModuleDeployableSolarPanel(this Part part)
         {
-            return part.GetModule<ModuleDeployableSolarPanel>();
+            return GetModule<ModuleDeployableSolarPanel>(part);
         }
 
         /// <summary>
@@ -186,20 +194,20 @@
         /// </summary>
         public static ModuleEngines GetModuleEngines(this Part part)
         {
-            return part.GetModule<ModuleEngines>();
-        }
-
-        public static ModuleEnginesFX GetModuleEnginesFx(this Part part)
-        {
-            return part.GetModule<ModuleEnginesFX>();
-        }
+            return GetModule<ModuleEngines>(part);
+        }
+
+/*        public static ModuleEnginesFX GetModuleEnginesFx(this Part part)
+        {
+            return GetModule<ModuleEnginesFX>(part);
+        }*/
 
         /// <summary>
         ///     Gets a ModuleGenerator typed PartModule.
         /// </summary>
         public static ModuleGenerator GetModuleGenerator(this Part part)
         {
-            return part.GetModule<ModuleGenerator>();
+            return GetModule<ModuleGenerator>(part);
         }
 
         /// <summary>
@@ -207,16 +215,29 @@
         /// </summary>
         public static ModuleGimbal GetModuleGimbal(this Part part)
         {
-            return part.GetModule<ModuleGimbal>();
+            return GetModule<ModuleGimbal>(part);
         }
 
         /// <summary>
         ///     Gets the current selected ModuleEnginesFX.
         /// </summary>
-        public static ModuleEnginesFX GetModuleMultiModeEngine(this Part part)
-        {
-            var mode = part.GetModule<MultiModeEngine>().mode;
-            return part.Modules.OfType<ModuleEnginesFX>().FirstOrDefault(engine => engine.engineID == mode);
+        public static ModuleEngines GetModuleMultiModeEngine(this Part part)
+        {
+            ModuleEngines moduleEngines;
+            MultiModeEngine multiMod = GetModule<MultiModeEngine>(part);
+            if (multiMod != null)
+            {
+                string mode = multiMod.mode;
+                for (int i = 0; i < part.Modules.Count; ++i)
+                {
+                    moduleEngines = part.Modules[i] as ModuleEngines;
+                    if (moduleEngines != null && moduleEngines.engineID == mode)
+                    {
+                        return moduleEngines;
+                    }
+                }
+            }
+            return null;
         }
 
         /// <summary>
@@ -224,12 +245,12 @@
         /// </summary>
         public static ModuleParachute GetModuleParachute(this Part part)
         {
-            return part.GetModule<ModuleParachute>();
+            return GetModule<ModuleParachute>(part);
         }
 
         public static ModuleRCS GetModuleRcs(this Part part)
         {
-            return part.GetModule<ModuleRCS>();
+            return GetModule<ModuleRCS>(part);
         }
 
         /// <summary>
@@ -237,19 +258,30 @@
         /// </summary>
         public static List<T> GetModules<T>(this Part part) where T : PartModule
         {
-            return part.Modules.OfType<T>().ToList();
+            List<T> list = new List<T>();
+            for (int i = 0; i < part.Modules.Count; ++i)
+            {
+                T module = part.Modules[i] as T;
+                if (module != null)
+                {
+                    list.Add(module);
+                }
+            }
+            return list;
         }
 
         public static ProtoModuleDecoupler GetProtoModuleDecoupler(this Part part)
         {
-            if (HasModule<ModuleDecouple>(part))
-            {
-                return new ProtoModuleDecoupler(GetModule<ModuleDecouple>(part));
-            }
-            if (HasModule<ModuleAnchoredDecoupler>(part))
-            {
-                return new ProtoModuleDecoupler(GetModule<ModuleAnchoredDecoupler>(part));
-            }
+            PartModule cachePartModule = GetModule<ModuleDecouple>(part);
+            if (cachePartModule == null)
+            {
+                cachePartModule = GetModule<ModuleAnchoredDecoupler>(part);
+            }
+            if (cachePartModule != null)
+            {
+                return new ProtoModuleDecoupler(cachePartModule);
+            }
+
             return null;
         }
 
@@ -258,18 +290,18 @@
         /// </summary>
         public static ProtoModuleEngine GetProtoModuleEngine(this Part part)
         {
-            if (HasModule<ModuleEngines>(part))
-            {
-                return new ProtoModuleEngine(GetModule<ModuleEngines>(part));
-            }
-            if (HasModule<MultiModeEngine>(part))
-            {
-                return new ProtoModuleEngine(GetModuleMultiModeEngine(part));
-            }
-            if (HasModule<ModuleEnginesFX>(part))
-            {
-                return new ProtoModuleEngine(GetModule<ModuleEnginesFX>(part));
-            }
+            PartModule cachePartModule = GetModule<ModuleEngines>(part);
+            if (cachePartModule != null)
+            {
+                return new ProtoModuleEngine(cachePartModule);
+            }
+
+            cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part);
+            if (cachePartModule != null)
+            {
+                return new ProtoModuleEngine(cachePartModule);
+            }
+
             return null;
         }
 
@@ -278,7 +310,13 @@
         /// </summary>
         public static double GetResourceCost(this Part part)
         {
-            return part.Resources.list.Sum(r => r.amount * r.info.unitCost);
+            double cost = 0.0;
+            for (int i = 0; i < part.Resources.list.Count; ++i)
+            {
+                PartResource cachePartResource = part.Resources.list[i];
+                cost = cost + (cachePartResource.amount * cachePartResource.info.unitCost);
+            }
+            return cost;
         }
 
         /// <summary>
@@ -300,29 +338,36 @@
         /// </summary>
         public static double GetResourceCostMax(this Part part)
         {
-            return part.Resources.list.Sum(r => r.maxAmount * r.info.unitCost);
+            double cost = 0.0;
+            for (int i = 0; i < part.Resources.list.Count; ++i)
+            {
+                PartResource cachePartResource = part.Resources.list[i];
+                cost = cost + (cachePartResource.maxAmount * cachePartResource.info.unitCost);
+            }
+            return cost;
         }
 
         /// <summary>
         ///     Gets the current specific impulse for the engine.
         /// </summary>
+        /* not used
         public static double GetSpecificImpulse(this Part part, float atmosphere)
         {
-            if (part.HasModule<ModuleEngines>())
-            {
-                return part.GetModuleEngines().atmosphereCurve.Evaluate(atmosphere);
-            }
-            if (part.HasModule<MultiModeEngine>())
-            {
-                return part.GetModuleMultiModeEngine().atmosphereCurve.Evaluate(atmosphere);
-            }
-            if (part.HasModule<ModuleEnginesFX>())
-            {
-                return part.GetModuleEnginesFx().atmosphereCurve.Evaluate(atmosphere);
-            }
-
-            return 0d;
-        }
+            PartModule cachePartModule = GetModule<ModuleEngines>(part);
+            if (cachePartModule != null)
+            {
+                return (cachePartModule as ModuleEngines).atmosphereCurve.Evaluate(atmosphere);
+            }
+
+            cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part);
+            if (cachePartModule != null)
+            {
+                return (cachePartModule as ModuleEnginesFX).atmosphereCurve.Evaluate(atmosphere);
+            }
+
+            return 0.0;
+        }
+        */
 
         /// <summary>
         ///     Gets the total mass of the part including resources.
@@ -380,7 +425,8 @@
         /// </summary>
         public static bool HasOneShotAnimation(this Part part)
         {
-            return part.HasModule<ModuleAnimateGeneric>() && part.GetModule<ModuleAnimateGeneric>().isOneShot;
+            PartModule cachePartModule = GetModule<ModuleAnimateGeneric>(part);
+            return cachePartModule != null && (cachePartModule as ModuleAnimateGeneric).isOneShot;
         }
 
         /// <summary>
@@ -388,7 +434,7 @@
         /// </summary>
         public static bool IsCommandModule(this Part part)
         {
-            return part.HasModule<ModuleCommand>();
+            return HasModule<ModuleCommand>(part);
         }
 
         /// <summary>
@@ -396,7 +442,7 @@
         /// </summary>
         public static bool IsDecoupledInStage(this Part part, int stage)
         {
-            if ((part.IsDecoupler() || part.IsLaunchClamp()) && part.inverseStage == stage)
+            if ((IsDecoupler(part) || IsLaunchClamp(part)) && part.inverseStage == stage)
             {
                 return true;
             }
@@ -404,7 +450,7 @@
             {
                 return false;
             }
-            return part.parent.IsDecoupledInStage(stage);
+            return IsDecoupledInStage(part.parent, stage);
         }
 
         /// <summary>
@@ -412,7 +458,7 @@
         /// </summary>
         public static bool IsDecoupler(this Part part)
         {
-            return part.HasModule<ModuleDecouple>() || part.HasModule<ModuleAnchoredDecoupler>();
+            return HasModule<ModuleDecouple>(part) || HasModule<ModuleAnchoredDecoupler>(part);
         }
 
         /// <summary>
@@ -420,7 +466,7 @@
         /// </summary>
         public static bool IsEngine(this Part part)
         {
-            return part.HasModule<ModuleEngines>() || part.HasModule<ModuleEnginesFX>();
+            return HasModule<ModuleEngines>(part);
         }
 
         /// <summary>
@@ -428,7 +474,7 @@
         /// </summary>
         public static bool IsFuelLine(this Part part)
         {
-            return (HasModule<CModuleFuelLine>(part));
+            return HasModule<CModuleFuelLine>(part);
         }
 
         /// <summary>
@@ -436,7 +482,7 @@
         /// </summary>
         public static bool IsGenerator(this Part part)
         {
-            return part.HasModule<ModuleGenerator>();
+            return HasModule<ModuleGenerator>(part);
         }
 
         /// <summary>
@@ -444,7 +490,7 @@
         /// </summary>
         public static bool IsLaunchClamp(this Part part)
         {
-            return part.HasModule<LaunchClamp>();
+            return HasModule<LaunchClamp>(part);
         }
 
         /// <summary>
@@ -452,7 +498,7 @@
         /// </summary>
         public static bool IsParachute(this Part part)
         {
-            return part.HasModule<ModuleParachute>();
+            return HasModule<ModuleParachute>(part);
         }
 
         /// <summary>
@@ -467,7 +513,6 @@
                 {
                     continue;
                 }
-
                 if (vesselPart == part)
                 {
                     return true;
@@ -480,7 +525,7 @@
 
         public static bool IsRcsModule(this Part part)
         {
-            return part.HasModule<ModuleRCS>();
+            return HasModule<ModuleRCS>(part);
         }
 
         /// <summary>
@@ -488,7 +533,7 @@
         /// </summary>
         public static bool IsSepratron(this Part part)
         {
-            return (part.IsSolidRocket() && part.ActivatesEvenIfDisconnected && part.IsDecoupledInStage(part.inverseStage));
+            return IsSolidRocket(part) && part.ActivatesEvenIfDisconnected && IsDecoupledInStage(part, part.inverseStage);
         }
 
         /// <summary>
@@ -496,7 +541,7 @@
         /// </summary>
         public static bool IsSolarPanel(this Part part)
         {
-            return part.HasModule<ModuleDeployableSolarPanel>();
+            return HasModule<ModuleDeployableSolarPanel>(part);
         }
 
         /// <summary>
@@ -504,160 +549,99 @@
         /// </summary>
         public static bool IsSolidRocket(this Part part)
         {
-            return (part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked) || (part.HasModule<ModuleEnginesFX>() && part.GetModuleEnginesFx().throttleLocked);
-        }
-
-        #endregion
-
-        #region Nested Type: ProtoModuleDecoupler
+            return (part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked);
+        }
 
         public class ProtoModuleDecoupler
         {
-            #region Fields
-
             private readonly PartModule module;
 
-            #endregion
-
-            #region Constructors
-
             public ProtoModuleDecoupler(PartModule module)
             {
                 this.module = module;
 
                 if (this.module is ModuleDecouple)
                 {
-                    this.SetModuleDecouple();
+                    SetModuleDecouple();
                 }
                 else if (this.module is ModuleAnchoredDecoupler)
                 {
-                    this.SetModuleAnchoredDecoupler();
-                }
-            }
-
-            #endregion
-
-            #region Properties
+                    SetModuleAnchoredDecoupler();
+                }
+            }
 
             public double EjectionForce { get; private set; }
             public bool IsOmniDecoupler { get; private set; }
 
-            #endregion
-
-            #region Methods: private
-
             private void SetModuleAnchoredDecoupler()
             {
-                var decoupler = this.module as ModuleAnchoredDecoupler;
+                ModuleAnchoredDecoupler decoupler = module as ModuleAnchoredDecoupler;
                 if (decoupler == null)
                 {
                     return;
                 }
 
-                this.EjectionForce = decoupler.ejectionForce;
+                EjectionForce = decoupler.ejectionForce;
             }
 
             private void SetModuleDecouple()
             {
-                var decoupler = this.module as ModuleDecouple;
+                ModuleDecouple decoupler = module as ModuleDecouple;
                 if (decoupler == null)
                 {
                     return;
                 }
 
-                this.EjectionForce = decoupler.ejectionForce;
-                this.IsOmniDecoupler = decoupler.isOmniDecoupler;
-            }
-
-            #endregion
-        }
-
-        #endregion
-
-        #region Nested Type: ProtoModuleEngine
-
+                EjectionForce = decoupler.ejectionForce;
+                IsOmniDecoupler = decoupler.isOmniDecoupler;
+            }
+        }
+
+        // This needs updating to handle multi-mode engines and engines with multiple ModuleEngines correctly.
+        // It currently just shows the stats of the currently active module for multi-mode engines and just 
+        // the first ModuleEngines for engines with multiple modules.
+        // It should really show all the modes for multi-mode engines as separate sections.
+        // For other engines with multiple ModuleEngines it should combine the separate modules into a single set of data
+        // The constructor should be changed to take the Part itself.  It can be called if HasModule<ModuleEngines>() is true.
         public class ProtoModuleEngine
         {
-            #region Fields
-
             private readonly PartModule module;
 
-            #endregion
-
-            #region Constructors
-
             public ProtoModuleEngine(PartModule module)
             {
                 this.module = module;
 
                 if (module is ModuleEngines)
                 {
-                    this.SetModuleEngines();
-                }
-                else if (module is ModuleEnginesFX)
-                {
-                    this.SetModuleEnginesFx();
-                }
-            }
-
-            #endregion
-
-            #region Properties
+                    SetModuleEngines();
+                }
+            }
 
             public double MaximumThrust { get; private set; }
             public double MinimumThrust { get; private set; }
             public List<Propellant> Propellants { get; private set; }
 
-            #endregion
-
-            #region Methods: public
-
             public float GetSpecificImpulse(float atmosphere)
             {
-                if (this.module is ModuleEngines)
-                {
-                    return (this.module as ModuleEngines).atmosphereCurve.Evaluate(atmosphere);
-                }
-                if (this.module is ModuleEnginesFX)
-                {
-                    return (this.module as ModuleEnginesFX).atmosphereCurve.Evaluate(atmosphere);
+                if (module is ModuleEngines)
+                {
+                    return (module as ModuleEngines).atmosphereCurve.Evaluate(atmosphere);
                 }
                 return 0.0f;
             }
 
-            #endregion
-
-            #region Methods: private
-
             private void SetModuleEngines()
             {
-                var engine = this.module as ModuleEngines;
+                ModuleEngines engine = module as ModuleEngines;
                 if (engine == null)
                 {
                     return;
                 }
 
-                this.MaximumThrust = engine.maxThrust * (engine.thrustPercentage * 0.01);
-                this.MinimumThrust = engine.minThrust;
-                this.Propellants = engine.propellants;
-            }
-
-            private void SetModuleEnginesFx()
-            {
-                var engine = this.module as ModuleEnginesFX;
-                if (engine == null)
-                {
-                    return;
-                }
-
-                this.MaximumThrust = engine.maxThrust * (engine.thrustPercentage * 0.01);
-                this.MinimumThrust = engine.minThrust;
-                this.Propellants = engine.propellants;
-            }
-
-            #endregion
-        }
-
-        #endregion
+                MaximumThrust = engine.maxThrust * (engine.thrustPercentage * 0.01);
+                MinimumThrust = engine.minThrust;
+                Propellants = engine.propellants;
+            }
+        }
     }
 }

--- /dev/null
+++ b/KerbalEngineer/Extensions/StringExtensions.cs
@@ -1,1 +1,33 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Extensions
+{
+    public static class StringExtensions
+    {
+        public static string ToLength(this string value, int length)
+        {
+            if (value != null && value.Length > length)
+            {
+                value = value.Substring(0, length) + "...";
+            }
+            return value;
+        }
+    }
+}

--- a/KerbalEngineer/Flight/ActionMenu.cs
+++ b/KerbalEngineer/Flight/ActionMenu.cs
@@ -55,6 +55,14 @@
             Logger.Log("ActionMenu was created.");
         }
 
+        protected void Start()
+        {
+            if (button == null)
+            {
+                OnGuiAppLauncherReady();
+            }
+        }
+
         protected void OnDestroy()
         {
             try
@@ -62,7 +70,10 @@
                 GameEvents.onGUIApplicationLauncherReady.Remove(this.OnGuiAppLauncherReady);
                 GameEvents.onHideUI.Remove(this.OnHide);
                 GameEvents.onShowUI.Remove(this.OnShow);
-                ApplicationLauncher.Instance.RemoveModApplication(this.button);
+                if (button != null)
+                {
+                    ApplicationLauncher.Instance.RemoveModApplication(this.button);
+                }
             }
             catch (Exception ex)
             {

--- a/KerbalEngineer/Flight/DisplayStack.cs
+++ b/KerbalEngineer/Flight/DisplayStack.cs
@@ -33,6 +33,7 @@
 
 namespace KerbalEngineer.Flight
 {
+    using KeyBinding;
     using Upgradeables;
 
     /// <summary>
@@ -214,7 +215,7 @@
         /// </summary>
         private void DrawControlBar()
         {
-            GUILayout.Label("FLIGHT ENGINEER " + EngineerGlobals.AssemblyVersion, this.titleStyle);
+            GUILayout.Label("FLIGHT ENGINEER " + EngineerGlobals.ASSEMBLY_VERSION, this.titleStyle);
 
             this.DrawControlBarButtons(SectionLibrary.StockSections);
             this.DrawControlBarButtons(SectionLibrary.CustomSections);

--- a/KerbalEngineer/Flight/Readouts/Miscellaneous/Separator.cs
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/Separator.cs
@@ -45,7 +45,7 @@
         {
             this.Name = "Separator";
             this.Category = ReadoutCategory.GetCategory("Miscellaneous");
-            this.HelpString = String.Empty;
+            this.HelpString = "Creats a line to help seperate subsections in a module.";
             this.IsDefault = false;
             this.Cloneable = true;
 

--- a/KerbalEngineer/Flight/Readouts/Miscellaneous/SimulationDelay.cs
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/SimulationDelay.cs
@@ -51,7 +51,7 @@
             GUILayout.BeginHorizontal();
             GUILayout.Label("Sim Delay", this.NameStyle);
             GUI.skin = HighLogic.Skin;
-            SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 1000.0f));
+            SimManager.minSimTime = TimeSpan.FromMilliseconds(GUILayout.HorizontalSlider((float)SimManager.minSimTime.TotalMilliseconds, 0, 2000.0f));
             GUI.skin = null;
             GUILayout.EndHorizontal();
         }

--- a/KerbalEngineer/Flight/Readouts/Miscellaneous/SystemTime.cs
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/SystemTime.cs
@@ -40,7 +40,7 @@
         {
             this.Name = "System Time";
             this.Category = ReadoutCategory.GetCategory("Miscellaneous");
-            this.HelpString = String.Empty;
+            this.HelpString = "Shows the System Time in 12 hour format (AM/PM)";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Miscellaneous/TimeReference.cs
+++ /dev/null
@@ -1,66 +1,1 @@
-// 
-//     Kerbal Engineer Redux
-// 
-//     Copyright (C) 2014 CYBUTEK
-// 
-//     This program is free software: you can redistribute it and/or modify
-//     it under the terms of the GNU General Public License as published by
-//     the Free Software Foundation, either version 3 of the License, or
-//     (at your option) any later version.
-// 
-//     This program is distributed in the hope that it will be useful,
-//     but WITHOUT ANY WARRANTY; without even the implied warranty of
-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//     GNU General Public License for more details.
-// 
-//     You should have received a copy of the GNU General Public License
-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
-// 
 
-#region Using Directives
-
-using System;
-
-using KerbalEngineer.Flight.Sections;
-using KerbalEngineer.Helpers;
-
-using UnityEngine;
-
-#endregion
-
-namespace KerbalEngineer.Flight.Readouts.Miscellaneous
-{
-    public class TimeReference : ReadoutModule
-    {
-        #region Constructors
-
-        public TimeReference()
-        {
-            this.Name = "Time Reference Adjuster";
-            this.Category = ReadoutCategory.GetCategory("Miscellaneous");
-            this.HelpString = String.Empty;
-            this.IsDefault = false;
-        }
-
-        #endregion
-
-        #region Methods: public
-
-        public override void Draw(SectionModule section)
-        {
-            GUILayout.BeginHorizontal();
-            GUILayout.Label("Time Ref.: " + TimeFormatter.Reference, this.NameStyle);
-            if (GUILayout.Button("Earth", this.ButtonStyle))
-            {
-                TimeFormatter.SetReference();
-            }
-            if (GUILayout.Button("Kerbin", this.ButtonStyle))
-            {
-                TimeFormatter.SetReference(PSystemManager.Instance.localBodies.Find(body => body.bodyName.Equals("Kerbin")));
-            }
-            GUILayout.EndHorizontal();
-        }
-
-        #endregion
-    }
-}

--- a/KerbalEngineer/Flight/Readouts/Orbital/AngleToEquatorialAscendingNode.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/AngleToEquatorialAscendingNode.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Angle to Equ. AN";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = string.Empty;
+            this.HelpString = "Angular Distance from the vessel to crossing the Equator of the central body, going north of it.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/AngleToEquatorialDescendingNode.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/AngleToEquatorialDescendingNode.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Angle to Equ. DN";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = string.Empty;
+            this.HelpString = "Angular Distance from the vessel to crossing the Equator of the central body, going south of it.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/AngleToPrograde.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/AngleToPrograde.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Angle to Prograde";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Angular Distance from the vessel to crossing the Orbit of the central body on it's retrograde side.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/AngleToRetrograde.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/AngleToRetrograde.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Angle to Retrograde";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Angular Distance from the vessel to crossing the Orbit of the central body on it's retrograde side.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ApoapsisHeight.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ApoapsisHeight.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Apoapsis Height";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = "Shows the vessel's apoapsis height relative to sea level.  (Apoapsis is the highest point of an orbit.)";
+            this.HelpString = "Shows the vessel's apoapsis height relative to sea level. (Apoapsis is the highest point of an orbit.)";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/EccentricAnomaly.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/EccentricAnomaly.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,38 +17,25 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Flight.Sections;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Orbital
 {
+    using Extensions;
+    using Helpers;
+    using Sections;
+
     public class EccentricAnomaly : ReadoutModule
     {
-        #region Constructors
-
         public EccentricAnomaly()
         {
-            this.Name = "Eccentric Anomaly";
-            this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
-            this.IsDefault = false;
+            Name = "Eccentric Anomaly";
+            Category = ReadoutCategory.GetCategory("Orbital");
+            HelpString = string.Empty;
+            IsDefault = false;
         }
-
-        #endregion
-
-        #region Methods: public
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(FlightGlobals.ship_orbit.eccentricAnomaly.ToAngle(), section.IsHud);
+            DrawLine((FlightGlobals.ship_orbit.eccentricAnomaly * Units.RAD_TO_DEG).ToAngle(), section.IsHud);
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Flight/Readouts/Orbital/Eccentricity.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/Eccentricity.cs
@@ -43,7 +43,7 @@
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(FlightGlobals.ship_orbit.eccentricity.ToString("F3"), section.IsHud);
+            this.DrawLine(FlightGlobals.ship_orbit.eccentricity.ToString("F5"), section.IsHud);
         }
 
         #endregion

--- a/KerbalEngineer/Flight/Readouts/Orbital/Inclination.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/Inclination.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Inclination";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = "Shows the vessel's orbital inclination.";
+            this.HelpString = "Shows the vessel's orbital inclination relative to the Equator.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/ManoeuvreProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/ManoeuvreProcessor.cs
@@ -30,6 +30,8 @@
 
 namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
 {
+    using Helpers;
+
     public class ManoeuvreProcessor : IUpdatable, IUpdateRequest
     {
         #region Fields
@@ -60,6 +62,10 @@
         }
 
         public static double NormalDeltaV { get; private set; }
+
+        public static double PostBurnAp { get; private set; }
+
+        public static double PostBurnPe { get; private set; }
 
         public static double ProgradeDeltaV { get; private set; }
 
@@ -108,6 +114,8 @@
             NormalDeltaV = deltaV.y;
             RadialDeltaV = deltaV.x;
             TotalDeltaV = node.GetBurnVector(FlightGlobals.ship_orbit).magnitude;
+            PostBurnAp = node.nextPatch != null ? node.nextPatch.ApA : 0;
+            PostBurnPe = node.nextPatch != null ? node.nextPatch.PeA : 0;
 
             UniversalTime = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].UT;
             AngleToPrograde = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].patch.GetAngleToPrograde(UniversalTime);
@@ -163,7 +171,7 @@
                     deltaVDrain = deltaV.Clamp(0.0, stageDeltaV);
                 }
 
-                var exhaustVelocity = stage.isp * 9.82;
+                var exhaustVelocity = stage.isp * Units.GRAVITY;
                 var flowRate = stage.thrust / exhaustVelocity;
                 var endMass = Math.Exp(Math.Log(startMass) - deltaVDrain / exhaustVelocity);
                 var deltaMass = (startMass - endMass) * Math.Exp(-(deltaVDrain * 0.001) / exhaustVelocity);

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeAngleToPrograde.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeAngleToPrograde.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Manoeuvre Node Angle to Prograde";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Angular Distance from the Node to crossing the Orbit of the central body on it's prograde side.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeAngleToRetrograde.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeAngleToRetrograde.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Manoeuvre Node Angle to Retrograde";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Angular Distance from the Node to crossing the Orbit of the central body on it's retrograde side.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeBurnTime.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeBurnTime.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Manoeuvre Node Burn Time";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "The burn's total duration.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeHalfBurnTime.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeHalfBurnTime.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Manoeuvre Node Half Burn Time";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Half of the burn's total duration.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeNormalDeltaV.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeNormalDeltaV.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Manoeuvre Node DeltaV (Normal)";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Normal component of the total change in velocity.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeProgradeDeltaV.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeProgradeDeltaV.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Manoeuvre Node DeltaV (Prograde)";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Prograde/Retrograde component of the total change in velocity.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeRadialDeltaV.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeRadialDeltaV.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Manoeuvre Node DeltaV (Radial)";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Radial component of the total change in velocity.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeTimeToHalfBurn.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeTimeToHalfBurn.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Time to Manoeuvre Burn";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Time until the Manoeuvre should be started.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeTimeToManoeuvre.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeTimeToManoeuvre.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Time to Manoeuvre Node";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Time until the vessel reaches the position of the Manoeuvre Node.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeTotalDeltaV.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/NodeTotalDeltaV.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Manoeuvre Node DeltaV (Total)";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
+            this.HelpString = "Total change in velocity during the burn.";
             this.IsDefault = true;
         }
 

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/PostBurnApoapsis.cs
@@ -1,1 +1,69 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+
+using KerbalEngineer.Extensions;
+using KerbalEngineer.Flight.Sections;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
+{
+    public class PostBurnApoapsis : ReadoutModule
+    {
+        #region Constructors
+
+        public PostBurnApoapsis()
+        {
+            this.Name = "Post-burn Apoapsis";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = "Farthest point of the vessel's ofbit after the burn.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            if (!ManoeuvreProcessor.ShowDetails)
+            {
+                return;
+            }
+
+            this.DrawLine("Post-burn Apoapsis", ManoeuvreProcessor.PostBurnAp.ToDistance(), section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            ManoeuvreProcessor.Reset();
+        }
+
+        public override void Update()
+        {
+            ManoeuvreProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/PostBurnPeriapsis.cs
@@ -1,1 +1,69 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+
+using KerbalEngineer.Extensions;
+using KerbalEngineer.Flight.Sections;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
+{
+    public class PostBurnPeriapsis : ReadoutModule
+    {
+        #region Constructors
+
+        public PostBurnPeriapsis()
+        {
+            this.Name = "Post-burn Periapsis";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = "Closest point of the vessel's ofbit after the burn.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            if (!ManoeuvreProcessor.ShowDetails)
+            {
+                return;
+            }
+
+            this.DrawLine("Post-burn Periapsis", ManoeuvreProcessor.PostBurnPe.ToDistance(), section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            ManoeuvreProcessor.Reset();
+        }
+
+        public override void Update()
+        {
+            ManoeuvreProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Orbital/MeanAnomaly.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/MeanAnomaly.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,38 +17,25 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Flight.Sections;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Orbital
 {
+    using Extensions;
+    using Helpers;
+    using Sections;
+
     public class MeanAnomaly : ReadoutModule
     {
-        #region Constructors
-
         public MeanAnomaly()
         {
-            this.Name = "Mean Anomaly";
-            this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
-            this.IsDefault = false;
+            Name = "Mean Anomaly";
+            Category = ReadoutCategory.GetCategory("Orbital");
+            HelpString = string.Empty;
+            IsDefault = false;
         }
-
-        #endregion
-
-        #region Methods: public
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(FlightGlobals.ship_orbit.meanAnomaly.ToAngle(), section.IsHud);
+            DrawLine((FlightGlobals.ship_orbit.meanAnomaly * Units.RAD_TO_DEG).ToAngle(), section.IsHud);
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Flight/Readouts/Orbital/MeanAnomalyAtEpoc.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/MeanAnomalyAtEpoc.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,38 +17,25 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Flight.Sections;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Orbital
 {
+    using Extensions;
+    using Helpers;
+    using Sections;
+
     public class MeanAnomalyAtEpoc : ReadoutModule
     {
-        #region Constructors
-
         public MeanAnomalyAtEpoc()
         {
-            this.Name = "Mean Anomaly at Epoc";
-            this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = String.Empty;
-            this.IsDefault = false;
+            Name = "Mean Anomaly at Epoc";
+            Category = ReadoutCategory.GetCategory("Orbital");
+            HelpString = string.Empty;
+            IsDefault = false;
         }
-
-        #endregion
-
-        #region Methods: public
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(FlightGlobals.ship_orbit.meanAnomalyAtEpoch.ToAngle(), section.IsHud);
+            DrawLine((FlightGlobals.ship_orbit.meanAnomalyAtEpoch * Units.RAD_TO_DEG).ToAngle(), section.IsHud);
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Flight/Readouts/Orbital/PeriapsisHeight.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/PeriapsisHeight.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Periapsis Height";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = "Shows the vessel's periapsis height relative to sea level. (Periapsis is the lowest point of an orbit.";
+            this.HelpString = "Shows the vessel's periapsis height relative to sea level. (Periapsis is the lowest point of an orbit.)";
             this.IsDefault = true;
         }
 

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/SpeedAtApoapsis.cs
@@ -1,1 +1,68 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
+using KerbalEngineer.Extensions;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital
+{
+    public class SpeedAtApoapsis : ReadoutModule
+    {
+        #region Constructors
+
+        public SpeedAtApoapsis()
+        {
+            this.Name = "Speed at Apoapsis";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = "Shows the orbital speed of the vessel when at apoapsis, the highest point of the orbit.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            // Vis-viva: v^2 = GM(2/r - 1/a)
+            // All this is easily got from the ships orbit (and reference body)
+            String str;
+            Orbit orbit = FlightGlobals.ship_orbit;
+            if (orbit.eccentricity > 1.0)
+                str = "---m/s";
+            else
+            {
+                double speedsqr = orbit.referenceBody.gravParameter * ((2 / orbit.ApR) - (1 / orbit.semiMajorAxis));
+                if (Double.IsNaN(speedsqr) || speedsqr < 0)
+                    str = "---m/s";     // Don't think this is possible barring bugs in the Orbit class
+                else
+                    str = Math.Sqrt(speedsqr).ToSpeed();
+            }
+            this.DrawLine(str, section.IsHud);
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/SpeedAtPeriapsis.cs
@@ -1,1 +1,64 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
+using KerbalEngineer.Extensions;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital
+{
+    public class SpeedAtPeriapsis : ReadoutModule
+    {
+        #region Constructors
+
+        public SpeedAtPeriapsis()
+        {
+            this.Name = "Speed at Periapsis";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = "Shows the orbital speed of the vessel when at periapsis, the lowest point of the orbit.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            // Vis-viva: v^2 = GM(2/r - 1/a)
+            // All this is easily got from the ships orbit (and reference body)
+            String str;
+            Orbit orbit = FlightGlobals.ship_orbit;
+            double oneovera = (orbit.eccentricity == 1) ? 0 : (1 / orbit.semiMajorAxis);
+            double speedsqr = orbit.referenceBody.gravParameter * ((2 / orbit.PeR) - oneovera);
+            if (Double.IsNaN(speedsqr) || speedsqr < 0)
+                str = "---m/s";
+            else
+                str = Math.Sqrt(speedsqr).ToSpeed();
+            this.DrawLine(str, section.IsHud);
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/TimeToAtmosphere.cs
@@ -1,1 +1,99 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital
+{
+    public class TimeToAtmosphere : ReadoutModule
+    {
+        //private LogMsg log = new LogMsg();
+        
+        #region Constructors
+
+        public TimeToAtmosphere()
+        {
+            this.Name = "Time to Atmosphere";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = "Shows the time until the vessel enters or leaves the atmosphere.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            String str;
+            Orbit orbit = FlightGlobals.ship_orbit;
+
+			if (orbit.referenceBody.atmosphere && orbit.PeA < orbit.referenceBody.atmosphereDepth && orbit.ApA > orbit.referenceBody.atmosphereDepth)
+            {
+                double tA = orbit.TrueAnomalyAtRadius(orbit.referenceBody.atmosphereDepth + orbit.referenceBody.Radius);
+                //log.buf.AppendFormat("tA = {0}\n", tA);
+                double utTime = Planetarium.GetUniversalTime();
+                //log.buf.AppendFormat("utTime = {0}\n", utTime);
+                double timeAtRad1 = orbit.GetUTforTrueAnomaly(tA, orbit.period * 0.5);
+                //log.buf.AppendFormat("timeAtRad1 = {0}\n", timeAtRad1);
+                if (timeAtRad1 < utTime)
+                {
+                    timeAtRad1 += orbit.period;
+                    //log.buf.AppendFormat("timeAtRad1 = {0}\n", timeAtRad1);
+                }
+                double timeAtRad2 = orbit.GetUTforTrueAnomaly(-tA, orbit.period * 0.5);
+                //log.buf.AppendFormat("timeAtRad2 = {0}\n", timeAtRad2);
+                if (timeAtRad2 < utTime)
+                {
+                    timeAtRad2 += orbit.period;
+                    //log.buf.AppendFormat("timeAtRad2 = {0}\n", timeAtRad2);
+                }
+                double time = Math.Min(timeAtRad1, timeAtRad2) - utTime;
+                //log.buf.AppendFormat("time = {0}\n", time);
+
+                if (Double.IsNaN(time))
+                {
+                    str = "---s";
+                    //log.buf.AppendLine("time is NaN");
+                }
+                else
+                {
+                    str = TimeFormatter.ConvertToString(time);
+                    //log.buf.AppendFormat("str = {0}\n", str);
+                }
+            }
+            else
+            {
+                str = "---s";
+                //log.buf.AppendLine("no atmosphere, pe > atmosphere, or ap < atmosphere");
+            }
+
+            //log.Flush();
+            this.DrawLine(str, section.IsHud);
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Orbital/TimeToEquatorialAscendingNode.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/TimeToEquatorialAscendingNode.cs
@@ -35,7 +35,7 @@
         {
             this.Name = "Time to Equ. AN";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the time until the vessel corsses the Equator, going north of it.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Orbital/TimeToEquatorialDescendingNode.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/TimeToEquatorialDescendingNode.cs
@@ -35,7 +35,7 @@
         {
             this.Name = "Time to Equ. DN";
             this.Category = ReadoutCategory.GetCategory("Orbital");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the time until the vessel corsses the Equator, going south of it.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/ReadoutLibrary.cs
+++ b/KerbalEngineer/Flight/Readouts/ReadoutLibrary.cs
@@ -1,7 +1,5 @@
 // 
-//     Kerbal Engineer Redux
-// 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -19,8 +17,6 @@
 
 namespace KerbalEngineer.Flight.Readouts
 {
-    #region Using Directives
-
     using System;
     using System.Collections.Generic;
     using System.Linq;
@@ -30,6 +26,7 @@
     using Rendezvous;
     using Settings;
     using Surface;
+    using Thermal;
     using Vessel;
     using AltitudeSeaLevel = Surface.AltitudeSeaLevel;
     using ApoapsisHeight = Orbital.ApoapsisHeight;
@@ -40,17 +37,9 @@
     using TimeToApoapsis = Orbital.TimeToApoapsis;
     using TimeToPeriapsis = Orbital.TimeToPeriapsis;
 
-    #endregion
-
     public static class ReadoutLibrary
     {
-        #region Fields
-
         private static List<ReadoutModule> readouts = new List<ReadoutModule>();
-
-        #endregion
-
-        #region Constructors
 
         /// <summary>
         ///     Sets up and populates the readout library with the stock readouts.
@@ -63,6 +52,7 @@
                 ReadoutCategory.SetCategory("Surface", "Surface and atmospheric readouts.");
                 ReadoutCategory.SetCategory("Vessel", "Vessel performance statistics.");
                 ReadoutCategory.SetCategory("Rendezvous", "Readouts for rendezvous manovoeures.");
+                ReadoutCategory.SetCategory("Thermal", "Thermal characteristics readouts.");
                 ReadoutCategory.SetCategory("Miscellaneous", "Miscellaneous readouts.");
                 ReadoutCategory.Selected = ReadoutCategory.GetCategory("Orbital");
 
@@ -101,6 +91,11 @@
                 readouts.Add(new NodeTimeToHalfBurn());
                 readouts.Add(new NodeAngleToPrograde());
                 readouts.Add(new NodeAngleToRetrograde());
+                readouts.Add(new PostBurnApoapsis());
+                readouts.Add(new PostBurnPeriapsis());
+                readouts.Add(new SpeedAtApoapsis());
+                readouts.Add(new SpeedAtPeriapsis());
+                readouts.Add(new TimeToAtmosphere());
 
                 // Surface
                 readouts.Add(new AltitudeSeaLevel());
@@ -109,6 +104,7 @@
                 readouts.Add(new VerticalAcceleration());
                 readouts.Add(new HorizontalSpeed());
                 readouts.Add(new HorizontalAcceleration());
+                readouts.Add(new MachNumber());
                 readouts.Add(new Latitude());
                 readouts.Add(new Longitude());
                 readouts.Add(new GeeForce());
@@ -124,6 +120,7 @@
                 readouts.Add(new ImpactBiome());
 
                 // Vessel
+                readouts.Add(new Name());
                 readouts.Add(new DeltaVStaged());
                 readouts.Add(new DeltaVCurrent());
                 readouts.Add(new DeltaVTotal());
@@ -171,12 +168,28 @@
                 readouts.Add(new Rendezvous.OrbitalPeriod());
                 readouts.Add(new Rendezvous.SemiMajorAxis());
                 readouts.Add(new Rendezvous.SemiMinorAxis());
-                
+                readouts.Add(new Rendezvous.RelativeRadialVelocity());
+                readouts.Add(new Rendezvous.TimeToRendezvous());
+
+                // Thermal
+                readouts.Add(new InternalFlux());
+                readouts.Add(new ConvectionFlux());
+                readouts.Add(new RadiationFlux());
+                readouts.Add(new CriticalPart());
+                readouts.Add(new CriticalTemperature());
+                readouts.Add(new CriticalSkinTemperature());
+                readouts.Add(new CriticalThermalPercentage());
+                readouts.Add(new HottestPart());
+                readouts.Add(new HottestTemperature());
+                readouts.Add(new HottestSkinTemperature());
+                readouts.Add(new CoolestPart());
+                readouts.Add(new CoolestTemperature());
+                readouts.Add(new CoolestSkinTemperature());
+
                 // Misc
                 readouts.Add(new Separator());
                 readouts.Add(new GuiSizeAdjustor());
                 readouts.Add(new SimulationDelay());
-                readouts.Add(new TimeReference());
                 readouts.Add(new VectoredThrustToggle());
                 readouts.Add(new SystemTime());
 
@@ -188,22 +201,20 @@
             }
         }
 
-        #endregion
-
-        #region Properties
-
         /// <summary>
         ///     Gets and sets the available readout modules.
         /// </summary>
         public static List<ReadoutModule> Readouts
         {
-            get { return readouts; }
-            set { readouts = value; }
-        }
-
-        #endregion
-
-        #region Methods
+            get
+            {
+                return readouts;
+            }
+            set
+            {
+                readouts = value;
+            }
+        }
 
         /// <summary>
         ///     Gets a list of readout modules which are associated with the specified category.
@@ -226,7 +237,7 @@
         /// </summary>
         public static void Reset()
         {
-            foreach (var readout in readouts)
+            foreach (ReadoutModule readout in readouts)
             {
                 readout.Reset();
             }
@@ -239,8 +250,8 @@
         {
             try
             {
-                var handler = SettingHandler.Load("HelpStrings.xml");
-                foreach (var readout in readouts)
+                SettingHandler handler = SettingHandler.Load("HelpStrings.xml");
+                foreach (ReadoutModule readout in readouts)
                 {
                     readout.HelpString = handler.GetSet(readout.Category + "." + readout.GetType().Name, readout.HelpString);
                 }
@@ -251,7 +262,5 @@
                 Logger.Exception(ex);
             }
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Flight/Readouts/ReadoutModule.cs
+++ b/KerbalEngineer/Flight/Readouts/ReadoutModule.cs
@@ -29,6 +29,8 @@
 
 namespace KerbalEngineer.Flight.Readouts
 {
+    using Extensions;
+
     public abstract class ReadoutModule
     {
         #region Fields
@@ -178,13 +180,13 @@
             {
                 GUILayout.Label(this.Name, this.NameStyle);
                 GUILayout.FlexibleSpace();
-                GUILayout.Label(value, this.ValueStyle);
+                GUILayout.Label(value.ToLength(20), this.ValueStyle);
             }
             else
             {
                 GUILayout.Label(this.Name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f));
                 GUILayout.FlexibleSpace();
-                GUILayout.Label(value, this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
+                GUILayout.Label(value.ToLength(20), this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
             }
             GUILayout.EndHorizontal();
 
@@ -198,13 +200,13 @@
             {
                 GUILayout.Label(name, this.NameStyle);
                 GUILayout.FlexibleSpace();
-                GUILayout.Label(value, this.ValueStyle);
+                GUILayout.Label(value.ToLength(20), this.ValueStyle);
             }
             else
             {
                 GUILayout.Label(name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f));
                 GUILayout.FlexibleSpace();
-                GUILayout.Label(value, this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
+                GUILayout.Label(value.ToLength(20), this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
             }
             GUILayout.EndHorizontal();
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/AltitudeSeaLevel.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/AltitudeSeaLevel.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Altitude (Sea Level)";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the target's altitude above sea level.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/AngleToRelativeAscendingNode.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/AngleToRelativeAscendingNode.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Angle to Rel. AN";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Angular Distance from the vessel to crossing the orbit of the target object, going north of it.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/AngleToRelativeDescendingNode.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/AngleToRelativeDescendingNode.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Angle to Rel. DN";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Angular Distance from the vessel to crossing the orbit of the target object, going south of it.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/ApoapsisHeight.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/ApoapsisHeight.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Apoapsis Height";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the targets's apoapsis height relative to sea level. (Apoapsis is the highest point of an orbit.)";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/Distance.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/Distance.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Distance";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Current distance between the vessel and the target object.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/OrbitalPeriod.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/OrbitalPeriod.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Orbital Period";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the amount of time it will take the target object to complete a full orbit.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/PeriapsisHeight.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/PeriapsisHeight.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Periapsis Height";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the targets's periapsis height relative to sea level. (Periapsis is the lowest point of an orbit.)";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/PhaseAngle.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/PhaseAngle.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Phase Angle";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Angular distance of the vessel relative to the target object.";
             this.IsDefault = true;
         }
 

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/RelativeRadialVelocity.cs
@@ -1,1 +1,66 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using KerbalEngineer.Extensions;
+using KerbalEngineer.Flight.Sections;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Rendezvous
+{
+    public class RelativeRadialVelocity : ReadoutModule
+    {
+        #region Constructors
+
+        public RelativeRadialVelocity()
+        {
+            this.Name = "Relative Radial Velocity";
+            this.Category = ReadoutCategory.GetCategory("Rendezvous");
+            this.HelpString = "Relative radial velocity between your vessel and the target object";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            if (RendezvousProcessor.ShowDetails)
+            {
+               this.DrawLine(RendezvousProcessor.RelativeRadialVelocity.ToSpeed(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(RendezvousProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            RendezvousProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}
+

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/RendezvousProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/RendezvousProcessor.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,30 +17,19 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Helpers;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Rendezvous
 {
+    using System;
+    using Extensions;
+    using Helpers;
+
     public class RendezvousProcessor : IUpdatable, IUpdateRequest
     {
-        #region Fields
-
         private static readonly RendezvousProcessor instance = new RendezvousProcessor();
 
         private Orbit originOrbit;
         private Orbit targetOrbit;
 
-        #endregion
-
-        #region Properties
-
         /// <summary>
         ///     Gets the target's altitude above its reference body.
         /// </summary>
@@ -71,7 +60,10 @@
         /// </summary>
         public static RendezvousProcessor Instance
         {
-            get { return instance; }
+            get
+            {
+                return instance;
+            }
         }
 
         /// <summary>
@@ -145,14 +137,20 @@
         public static double TimeToPeriapsis { get; private set; }
 
         /// <summary>
+        ///     Gets the relative radial velocity.
+        /// </summary>
+        public static double RelativeRadialVelocity { get; private set; }
+
+        /// <summary>
+        ///     Gets approximate (linearly) time to the minimum distance between objects.
+        /// </summary>
+        public static double TimeToRendezvous { get; private set; }
+
+        /// <summary>
         ///     Gets and sets whether the updatable object should be updated.
         /// </summary>
         public bool UpdateRequested { get; set; }
 
-        #endregion
-
-        #region Methods: public
-
         /// <summary>
         ///     Request and update to calculate the details.
         /// </summary>
@@ -166,7 +164,13 @@
         /// </summary>
         public void Update()
         {
-            if (FlightGlobals.fetch.VesselTarget == null)
+            if (FlightGlobals.fetch == null ||
+                FlightGlobals.fetch.VesselTarget == null ||
+                FlightGlobals.ActiveVessel == null ||
+                FlightGlobals.ActiveVessel.targetObject == null ||
+                FlightGlobals.ActiveVessel.targetObject.GetOrbit() == null ||
+                FlightGlobals.ship_orbit == null ||
+                FlightGlobals.ship_orbit.referenceBody == null)
             {
                 ShowDetails = false;
                 return;
@@ -174,55 +178,58 @@
 
             ShowDetails = true;
 
-            this.targetOrbit = FlightGlobals.fetch.VesselTarget.GetOrbit();
-            this.originOrbit = (FlightGlobals.ship_orbit.referenceBody == Planetarium.fetch.Sun || FlightGlobals.ship_orbit.referenceBody == FlightGlobals.ActiveVessel.targetObject.GetOrbit().referenceBody)
+            targetOrbit = FlightGlobals.fetch.VesselTarget.GetOrbit();
+            originOrbit = (FlightGlobals.ship_orbit.referenceBody == Planetarium.fetch.Sun ||
+                           FlightGlobals.ship_orbit.referenceBody == FlightGlobals.ActiveVessel.targetObject.GetOrbit().referenceBody)
                 ? FlightGlobals.ship_orbit
                 : FlightGlobals.ship_orbit.referenceBody.orbit;
 
-            RelativeInclination = this.originOrbit.GetRelativeInclination(this.targetOrbit);
+            RelativeInclination = originOrbit.GetRelativeInclination(targetOrbit);
             RelativeVelocity = FlightGlobals.ship_tgtSpeed;
-            RelativeSpeed = FlightGlobals.ship_obtSpeed - this.targetOrbit.orbitalSpeed;
-            PhaseAngle = this.originOrbit.GetPhaseAngle(this.targetOrbit);
-            InterceptAngle = this.CalcInterceptAngle();
-            TimeToAscendingNode = this.originOrbit.GetTimeToVector(this.GetAscendingNode());
-            TimeToDescendingNode = this.originOrbit.GetTimeToVector(this.GetDescendingNode());
-            AngleToAscendingNode = this.originOrbit.GetAngleToVector(this.GetAscendingNode());
-            AngleToDescendingNode = this.originOrbit.GetAngleToVector(this.GetDescendingNode());
-            AltitudeSeaLevel = this.targetOrbit.altitude;
-            ApoapsisHeight = this.targetOrbit.ApA;
-            PeriapsisHeight = this.targetOrbit.PeA;
-            TimeToApoapsis = this.targetOrbit.timeToAp;
-            TimeToPeriapsis = this.targetOrbit.timeToPe;
-            SemiMajorAxis = this.targetOrbit.semiMajorAxis;
-            SemiMinorAxis = this.targetOrbit.semiMinorAxis;
-
-            Distance = Vector3d.Distance(this.targetOrbit.pos, this.originOrbit.pos);
-            OrbitalPeriod = this.targetOrbit.period;
-        }
-
-        #endregion
-
-        #region Methods: private
+            RelativeSpeed = FlightGlobals.ship_obtSpeed - targetOrbit.orbitalSpeed;
+            PhaseAngle = originOrbit.GetPhaseAngle(targetOrbit);
+            InterceptAngle = CalcInterceptAngle();
+            TimeToAscendingNode = originOrbit.GetTimeToVector(GetAscendingNode());
+            TimeToDescendingNode = originOrbit.GetTimeToVector(GetDescendingNode());
+            AngleToAscendingNode = originOrbit.GetAngleToVector(GetAscendingNode());
+            AngleToDescendingNode = originOrbit.GetAngleToVector(GetDescendingNode());
+            AltitudeSeaLevel = targetOrbit.altitude;
+            ApoapsisHeight = targetOrbit.ApA;
+            PeriapsisHeight = targetOrbit.PeA;
+            TimeToApoapsis = targetOrbit.timeToAp;
+            TimeToPeriapsis = targetOrbit.timeToPe;
+            SemiMajorAxis = targetOrbit.semiMajorAxis;
+            SemiMinorAxis = targetOrbit.semiMinorAxis;
+
+            Distance = Vector3d.Distance(targetOrbit.pos, originOrbit.pos);
+            OrbitalPeriod = targetOrbit.period;
+
+            // beware that the order/sign of coordinates is inconsistent across different exposed variables
+            // in particular, v below does not equal to FlightGlobals.ship_tgtVelocity
+            Vector3d x = targetOrbit.pos - originOrbit.pos;
+            Vector3d v = targetOrbit.vel - originOrbit.vel;
+            double xv = Vector3d.Dot(x, v);
+            TimeToRendezvous = - xv / Vector3d.SqrMagnitude(v);
+            RelativeRadialVelocity = xv / Vector3d.Magnitude(x);
+        }
 
         private double CalcInterceptAngle()
         {
-            var originRadius = (this.originOrbit.semiMinorAxis + this.originOrbit.semiMajorAxis) * 0.5;
-            var targetRadius = (this.targetOrbit.semiMinorAxis + this.targetOrbit.semiMajorAxis) * 0.5;
-            var angle = 180.0 * (1.0 - Math.Pow((originRadius + targetRadius) / (2.0 * targetRadius), 1.5));
+            double originRadius = (originOrbit.semiMinorAxis + originOrbit.semiMajorAxis) * 0.5;
+            double targetRadius = (targetOrbit.semiMinorAxis + targetOrbit.semiMajorAxis) * 0.5;
+            double angle = 180.0 * (1.0 - Math.Pow((originRadius + targetRadius) / (2.0 * targetRadius), 1.5));
             angle = PhaseAngle - angle;
             return RelativeInclination < 90.0 ? AngleHelper.Clamp360(angle) : AngleHelper.Clamp360(360.0 - (180.0 - angle));
         }
 
         private Vector3d GetAscendingNode()
         {
-            return Vector3d.Cross(this.targetOrbit.GetOrbitNormal(), this.originOrbit.GetOrbitNormal());
+            return Vector3d.Cross(targetOrbit.GetOrbitNormal(), originOrbit.GetOrbitNormal());
         }
 
         private Vector3d GetDescendingNode()
         {
-            return Vector3d.Cross(this.originOrbit.GetOrbitNormal(), this.targetOrbit.GetOrbitNormal());
-        }
-
-        #endregion
+            return Vector3d.Cross(originOrbit.GetOrbitNormal(), targetOrbit.GetOrbitNormal());
+        }
     }
 }

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/SemiMajorAxis.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/SemiMajorAxis.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Semi-major Axis";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = String.Empty;
+            this.HelpString = "Shows the distance from the centre of the target's orbit to the farthest edge.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/SemiMinorAxis.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/SemiMinorAxis.cs
@@ -36,7 +36,7 @@
         {
             this.Name = "Semi-minor Axis";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = String.Empty;
+            this.HelpString = "Shows the distance from the centre of the target's orbit to the nearest edge.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToApoapsis.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToApoapsis.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Time to Apoapsis";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the time until the target reaches apoapsis, the highest point of the orbit.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToPeriapsis.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToPeriapsis.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Time to Periapsis";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the time until the target reaches periapsis, the lowest point of the orbit.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToRelativeAscendingNode.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToRelativeAscendingNode.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Time to Rel. AN";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Time until the vessel crosses the target's orbit, going north.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToRelativeDescendingNode.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToRelativeDescendingNode.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Time to Rel. DN";
             this.Category = ReadoutCategory.GetCategory("Rendezvous");
-            this.HelpString = string.Empty;
+            this.HelpString = "Time until the vessel crosses the target's orbit, going south.";
             this.IsDefault = true;
         }
 

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/TimeToRendezvous.cs
@@ -1,1 +1,65 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Rendezvous
+{
+    public class TimeToRendezvous : ReadoutModule
+    {
+        #region Constructors
+
+        public TimeToRendezvous()
+        {
+            this.Name = "Time to Rendezvous";
+            this.Category = ReadoutCategory.GetCategory("Rendezvous");
+            this.HelpString = "Approximate (linearly) time to the minimum distance between objects.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            if (RendezvousProcessor.ShowDetails)
+            {
+               this.DrawLine(TimeFormatter.ConvertToString(RendezvousProcessor.TimeToRendezvous), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(RendezvousProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            RendezvousProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Surface/AtmosphericEfficiency.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/AtmosphericEfficiency.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,36 +17,26 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Flight.Sections;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Surface
 {
+    using Extensions;
+    using Sections;
+
     public class AtmosphericEfficiency : ReadoutModule
     {
-        #region Constructors
-
         public AtmosphericEfficiency()
         {
-            this.Name = "Atmos. Efficiency";
-            this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = "Shows you vessel's efficiency as a ratio of the current velocity and terminal velocity.  Less than 1 means that you are losing efficiency due to gravity and greater than 1 is due to drag.";
-            this.IsDefault = true;
+            Name = "Atmos. Efficiency";
+            Category = ReadoutCategory.GetCategory("Surface");
+            HelpString = "Shows you vessel's efficiency as a ratio of the current velocity and terminal velocity.  Less than 100% means that you are losing efficiency due to gravity and greater than 100% is due to drag.";
+            IsDefault = false;
         }
-
-        #endregion
-
-        #region Methods: public
 
         public override void Draw(SectionModule section)
         {
             if (AtmosphericProcessor.ShowDetails)
             {
-                this.DrawLine(AtmosphericProcessor.Efficiency.ToPercent(), section.IsHud);
+                DrawLine(AtmosphericProcessor.Efficiency.ToPercent(), section.IsHud);
             }
         }
 
@@ -59,7 +49,5 @@
         {
             AtmosphericProcessor.RequestUpdate();
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Flight/Readouts/Surface/AtmosphericProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/AtmosphericProcessor.cs
@@ -29,6 +29,8 @@
 
 namespace KerbalEngineer.Flight.Readouts.Surface
 {
+    using UnityEngine;
+
     public class AtmosphericProcessor : IUpdatable, IUpdateRequest
     {
         #region Instance
@@ -46,7 +48,10 @@
         /// </summary>
         public static AtmosphericProcessor Instance
         {
-            get { return instance; }
+            get
+            {
+                return instance;
+            }
         }
 
         #endregion
@@ -122,13 +127,13 @@
                 }
                 else
                 {
-                    var mass = FlightGlobals.ActiveVessel.parts.Sum(p => p.GetWetMass());
-                    var drag = FlightGlobals.ActiveVessel.parts.Sum(p => p.GetWetMass() * p.maximum_drag);
-                    var grav = FlightGlobals.getGeeForceAtPosition(FlightGlobals.ship_position).magnitude;
-                    var atmo = FlightGlobals.ActiveVessel.atmDensity;
-                    var coef = FlightGlobals.ActiveVessel.parts.Sum(p => p.DragCubes.DragCoeff);
-
-                    TerminalVelocity = Math.Sqrt((2 * mass * grav) / (atmo * drag * coef));
+                    var m = FlightGlobals.ActiveVessel.parts.Sum(part => part.GetWetMass()) * 1000.0;
+                    var g = FlightGlobals.getGeeForceAtPosition(FlightGlobals.ship_position).magnitude;
+                    var a = FlightGlobals.ActiveVessel.parts.Sum(part => part.DragCubes.AreaDrag) * PhysicsGlobals.DragCubeMultiplier;
+                    var p = FlightGlobals.ActiveVessel.atmDensity;
+                    var c = PhysicsGlobals.DragMultiplier;
+
+                    TerminalVelocity = Math.Sqrt((2.0 * m * g) / (p * a * c));
                 }
 
                 Efficiency = FlightGlobals.ship_srfSpeed / TerminalVelocity;

--- a/KerbalEngineer/Flight/Readouts/Surface/HorizontalSpeed.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/HorizontalSpeed.cs
@@ -21,6 +21,7 @@
 
 using KerbalEngineer.Extensions;
 using KerbalEngineer.Flight.Sections;
+using System;
 
 #endregion
 
@@ -44,7 +45,11 @@
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(FlightGlobals.ActiveVessel.horizontalSrfSpeed.ToSpeed(), section.IsHud);
+            // Used to do this but the bug-fix to horizontalSrfSpeed in KSP 1.0.3 actually made it worse so workaround
+            //this.DrawLine(FlightGlobals.ActiveVessel.horizontalSrfSpeed.ToSpeed(), section.IsHud);
+            var ves = FlightGlobals.ActiveVessel;
+            double horizSpeed = Math.Sqrt(ves.srfSpeed * ves.srfSpeed - ves.verticalSpeed * ves.verticalSpeed);
+            this.DrawLine(horizSpeed.ToSpeed(), section.IsHud);
         }
 
         #endregion

--- a/KerbalEngineer/Flight/Readouts/Surface/ImpactAltitude.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/ImpactAltitude.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Impact Altitude";
             this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = string.Empty;
+            this.HelpString = "Altitude at which the Vessel will impact.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Surface/ImpactBiome.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/ImpactBiome.cs
@@ -33,7 +33,7 @@
         {
             this.Name = "Impact Biome";
             this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = string.Empty;
+            this.HelpString = "Biome the Vessel will impact in.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Surface/ImpactLatitude.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/ImpactLatitude.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Impact Latitude";
             this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = string.Empty;
+            this.HelpString = "Latitude of the impact position.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Surface/ImpactLongitude.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/ImpactLongitude.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Impact Longitude";
             this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = string.Empty;
+            this.HelpString = "Longditude of the impact position.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Surface/ImpactTime.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/ImpactTime.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Impact Time";
             this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows time until the vessel impacts the central object.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Surface/Latitude.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/Latitude.cs
@@ -20,6 +20,7 @@
 #region Using Directives
 
 using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
 
 #endregion
 
@@ -33,7 +34,7 @@
         {
             this.Name = "Latitude";
             this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = "Shows the vessel's latitude position around the celestial body.  Latitude is the angle from the equator to poles.";
+            this.HelpString = "Shows the vessel's latitude position around the celestial body. Latitude is the angle from the equator to poles.";
             this.IsDefault = true;
         }
 
@@ -43,7 +44,7 @@
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(KSPUtil.PrintLatitude(FlightGlobals.ship_latitude), section.IsHud);
+            this.DrawLine(Units.ToAngleDMS(FlightGlobals.ship_latitude) + (FlightGlobals.ship_latitude < 0 ? " S" : " N"), section.IsHud);
         }
 
         #endregion

--- a/KerbalEngineer/Flight/Readouts/Surface/Longitude.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/Longitude.cs
@@ -17,35 +17,25 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using KerbalEngineer.Flight.Sections;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Surface
 {
+    using Helpers;
+    using Sections;
+
     public class Longitude : ReadoutModule
     {
-        #region Constructors
-
         public Longitude()
         {
-            this.Name = "Longitude";
-            this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = "Shows the vessel's longitude around a celestial body.  Longitude is the angle from the bodies prime meridian.";
-            this.IsDefault = true;
+            Name = "Longitude";
+            Category = ReadoutCategory.GetCategory("Surface");
+            HelpString = "Shows the vessel's longitude around a celestial body. Longitude is the angle from the bodies prime meridian.";
+            IsDefault = true;
         }
-
-        #endregion
-
-        #region Methods: public
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(KSPUtil.PrintLongitude(FlightGlobals.ship_longitude), section.IsHud);
+            double angle = AngleHelper.Clamp180(FlightGlobals.ship_longitude);
+            DrawLine(Units.ToAngleDMS(angle) + (angle < 0.0 ? "W" : " E"), section.IsHud);
         }
-
-        #endregion
     }
 }

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Surface/MachNumber.cs
@@ -1,1 +1,43 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Surface
+{
+    using Extensions;
+    using Sections;
+
+    public class MachNumber : ReadoutModule
+    {
+        public MachNumber()
+        {
+            Name = "Mach Number";
+            Category = ReadoutCategory.GetCategory("Surface");
+            HelpString = "Shows the vessel's mach number.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (FlightGlobals.ActiveVessel.atmDensity > 0.0)
+            {
+                DrawLine(FlightGlobals.ActiveVessel.mach.ToMach(), section.IsHud);
+            }
+        }
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Surface/Situation.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/Situation.cs
@@ -33,7 +33,7 @@
         {
             this.Name = "Situation";
             this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the vessel's current scientific situation. (Landed, Splashed, Flying Low/High, In Space Low/High)";
             this.IsDefault = true;
         }
 

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/ConvectionFlux.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Extensions;
+    using Sections;
+
+    public class ConvectionFlux : ReadoutModule
+    {
+        public ConvectionFlux()
+        {
+            Name = "Convection Flux";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails && FlightGlobals.ActiveVessel.atmDensity > 0.0)
+            {
+                DrawLine(ThermalProcessor.ConvectionFlux.ToFlux(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CoolestPart.cs
@@ -1,1 +1,52 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Sections;
+
+    public class CoolestPart : ReadoutModule
+    {
+        public CoolestPart()
+        {
+            Name = "Coolest Part";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "The part of the vessel that is enduring the lowest temperature.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.CoolestPartName, section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CoolestSkinTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class CoolestSkinTemperature : ReadoutModule
+    {
+        public CoolestSkinTemperature()
+        {
+            Name = "Coolest Skin Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "Lowest external Temperature on the Vessel.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.CoolestSkinTemperature, ThermalProcessor.CoolestSkinTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CoolestTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class CoolestTemperature : ReadoutModule
+    {
+        public CoolestTemperature()
+        {
+            Name = "Coolest Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "Lowest internal Temperature on the Vessel.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.CoolestTemperature, ThermalProcessor.CoolestTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CriticalPart.cs
@@ -1,1 +1,52 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Sections;
+
+    public class CriticalPart : ReadoutModule
+    {
+        public CriticalPart()
+        {
+            Name = "Critical Part";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "This part is structually most critical. If it endures too high temperature there is a high chance for major structual failure!";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.CriticalPartName, section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CriticalSkinTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class CriticalSkinTemperature : ReadoutModule
+    {
+        public CriticalSkinTemperature()
+        {
+            Name = "Critical Skin Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "Highest external Temperature on the part of the Vessel that is structually most critical.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.CriticalSkinTemperature, ThermalProcessor.CriticalSkinTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CriticalTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class CriticalTemperature : ReadoutModule
+    {
+        public CriticalTemperature()
+        {
+            Name = "Critical Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "Internal Temperature on the part of the Vessel that is structually most critical.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.CriticalTemperature, ThermalProcessor.CriticalTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CriticalThermalPercentage.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Extensions;
+    using Sections;
+
+    public class CriticalThermalPercentage : ReadoutModule
+    {
+        public CriticalThermalPercentage()
+        {
+            Name = "Critical Thermal Percentage";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "Shows how high a temperature the critical Part is enduring relative to it's maximal temperature.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.CriticalTemperaturePercentage.ToPercent(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/HottestPart.cs
@@ -1,1 +1,52 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Sections;
+
+    public class HottestPart : ReadoutModule
+    {
+        public HottestPart()
+        {
+            Name = "Hottest Part";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "The part of the vessel that is enduring the highest temperature.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.HottestPartName, section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/HottestSkinTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class HottestSkinTemperature : ReadoutModule
+    {
+        public HottestSkinTemperature()
+        {
+            Name = "Hottest Skin Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "Highest external Temperature on the Vessel.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.HottestSkinTemperature, ThermalProcessor.HottestSkinTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/HottestTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class HottestTemperature : ReadoutModule
+    {
+        public HottestTemperature()
+        {
+            Name = "Hottest Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = "Highest internal Temperature on the Vessel.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.HottestTemperature, ThermalProcessor.HottestTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/InternalFlux.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Extensions;
+    using Sections;
+
+    public class InternalFlux : ReadoutModule
+    {
+        public InternalFlux()
+        {
+            Name = "Internal Flux";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.InternalFlux.ToFlux(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/RadiationFlux.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Extensions;
+    using Sections;
+
+    public class RadiationFlux : ReadoutModule
+    {
+        public RadiationFlux()
+        {
+            Name = "Radiation Flux";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.RadiationFlux.ToFlux(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/ThermalProcessor.cs
@@ -1,1 +1,161 @@
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using System;
+
+    public class ThermalProcessor : IUpdatable, IUpdateRequest
+    {
+        private static readonly ThermalProcessor instance = new ThermalProcessor();
+
+        static ThermalProcessor()
+        {
+            HottestTemperature = 0.0;
+            HottestTemperatureMax = 0.0;
+            HottestSkinTemperature = 0.0;
+            HottestSkinTemperatureMax = 0.0;
+            CoolestTemperature = 0.0;
+            CoolestTemperatureMax = 0.0;
+            CoolestSkinTemperature = 0.0;
+            CoolestSkinTemperatureMax = 0.0;
+            CriticalTemperature = 0.0;
+            CriticalTemperatureMax = 0.0;
+            CriticalSkinTemperature = 0.0;
+            CriticalSkinTemperatureMax = 0.0;
+            HottestPartName = string.Empty;
+            CoolestPartName = string.Empty;
+            CriticalPartName = string.Empty;
+        }
+
+        public static double ConvectionFlux { get; private set; }
+
+        public static string CoolestPartName { get; private set; }
+
+        public static double CoolestSkinTemperature { get; private set; }
+
+        public static double CoolestSkinTemperatureMax { get; private set; }
+
+        public static double CoolestTemperature { get; private set; }
+
+        public static double CoolestTemperatureMax { get; private set; }
+
+        public static string CriticalPartName { get; private set; }
+
+        public static double CriticalSkinTemperature { get; private set; }
+
+        public static double CriticalSkinTemperatureMax { get; private set; }
+
+        public static double CriticalTemperature { get; private set; }
+
+        public static double CriticalTemperatureMax { get; private set; }
+
+        public static double CriticalTemperaturePercentage { get; private set; }
+
+        public static string HottestPartName { get; private set; }
+
+        public static double HottestSkinTemperature { get; private set; }
+
+        public static double HottestSkinTemperatureMax { get; private set; }
+
+        public static double HottestTemperature { get; private set; }
+
+        public static double HottestTemperatureMax { get; private set; }
+
+        public static ThermalProcessor Instance
+        {
+            get
+            {
+                return instance;
+            }
+        }
+
+        public static double InternalFlux { get; private set; }
+
+        public static double RadiationFlux { get; private set; }
+
+        public static bool ShowDetails { get; private set; }
+
+        public void Update()
+        {
+            if (FlightGlobals.ActiveVessel.parts.Count == 0)
+            {
+                ShowDetails = false;
+                return;
+            }
+
+            ShowDetails = true;
+
+            ConvectionFlux = 0.0;
+            RadiationFlux = 0.0;
+            InternalFlux = 0.0;
+            HottestTemperature = 0.0;
+            HottestSkinTemperature = 0.0;
+            CoolestTemperature = double.MaxValue;
+            CoolestSkinTemperature = double.MaxValue;
+            CriticalTemperature = double.MaxValue;
+            CriticalSkinTemperature = double.MaxValue;
+            CriticalTemperaturePercentage = 0.0;
+            HottestPartName = string.Empty;
+            CoolestPartName = string.Empty;
+            CriticalPartName = string.Empty;
+
+            for (int i = 0; i < FlightGlobals.ActiveVessel.parts.Count; ++i)
+            {
+                Part part = FlightGlobals.ActiveVessel.parts[i];
+
+                ConvectionFlux = ConvectionFlux + part.thermalConvectionFlux;
+                RadiationFlux = RadiationFlux + part.thermalRadiationFlux;
+                InternalFlux = InternalFlux + part.thermalInternalFluxPrevious;
+
+                if (part.temperature > HottestTemperature || part.skinTemperature > HottestSkinTemperature)
+                {
+                    HottestTemperature = part.temperature;
+                    HottestTemperatureMax = part.maxTemp;
+                    HottestSkinTemperature = part.skinTemperature;
+                    HottestSkinTemperatureMax = part.skinMaxTemp;
+                    HottestPartName = part.partInfo.title;
+                }
+                if (part.temperature < CoolestTemperature || part.skinTemperature < CoolestSkinTemperature)
+                {
+                    CoolestTemperature = part.temperature;
+                    CoolestTemperatureMax = part.maxTemp;
+                    CoolestSkinTemperature = part.skinTemperature;
+                    CoolestSkinTemperatureMax = part.skinMaxTemp;
+                    CoolestPartName = part.partInfo.title;
+                }
+
+                if (part.temperature / part.maxTemp > CriticalTemperaturePercentage || part.skinTemperature / part.skinMaxTemp > CriticalTemperaturePercentage)
+                {
+                    CriticalTemperature = part.temperature;
+                    CriticalTemperatureMax = part.maxTemp;
+                    CriticalSkinTemperature = part.skinTemperature;
+                    CriticalSkinTemperatureMax = part.skinMaxTemp;
+                    CriticalTemperaturePercentage = Math.Max(part.temperature / part.maxTemp, part.skinTemperature / part.skinMaxTemp);
+                    CriticalPartName = part.partInfo.title;
+                }
+            }
+        }
+
+        public bool UpdateRequested { get; set; }
+
+        public static void RequestUpdate()
+        {
+            instance.UpdateRequested = true;
+        }
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Vessel/Acceleration.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Acceleration.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Acceleration";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the current and maximum acceleration of the craft.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/AttitudeProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/AttitudeProcessor.cs
@@ -110,8 +110,8 @@
                 ? 360.0f - this.surfaceRotation.eulerAngles.x
                 : -this.surfaceRotation.eulerAngles.x;
             this.roll = this.surfaceRotation.eulerAngles.z > 180.0f
-                ? this.surfaceRotation.eulerAngles.z - 360.0f
-                : this.surfaceRotation.eulerAngles.z;
+                ? 360.0f - this.surfaceRotation.eulerAngles.z
+                : -this.surfaceRotation.eulerAngles.z;
 
             this.headingRate = this.heading - this.previousHeading;
             this.pitchRate = this.pitch - this.previousPitch;

--- a/KerbalEngineer/Flight/Readouts/Vessel/DeltaVStaged.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/DeltaVStaged.cs
@@ -30,13 +30,6 @@
 {
     public class DeltaVStaged : ReadoutModule
     {
-        #region Fields
-
-        private int numberOfStages;
-        private bool showing;
-
-        #endregion
-
         #region Constructors
 
         public DeltaVStaged()

--- a/KerbalEngineer/Flight/Readouts/Vessel/Heading.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Heading.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Heading";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the current Heading.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/HeadingRate.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/HeadingRate.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Heading Rate";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the current change in Heading.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirDemand.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirDemand.cs
@@ -39,7 +39,7 @@
         {
             this.Name = "Intake Air (Demand)";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Displays the Amount of Intake Air required.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirDemandSupply.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirDemandSupply.cs
@@ -42,7 +42,7 @@
         {
             this.Name = "Intake Air (D/S)";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Displays the Ration between required and available Intake Air.";
             this.IsDefault = false;
         }
 
@@ -55,20 +55,11 @@
             var demand = 0.0;
             foreach (var part in FlightGlobals.ActiveVessel.Parts)
             {
-                if (part.Modules.Contains("ModuleEngines"))
+                for (int i = 0; i < part.Modules.Count; i++)
                 {
-                    var engine = part.Modules["ModuleEngines"] as ModuleEngines;
-                    if (engine.isOperational)
-                    {
-                        demand += engine.propellants
-                            .Where(p => p.name == "IntakeAir")
-                            .Sum(p => p.currentRequirement);
-                    }
-                }
-                if (part.Modules.Contains("ModuleEnginesFX"))
-                {
-                    var engine = part.Modules["ModuleEnginesFX"] as ModuleEnginesFX;
-                    if (engine.isOperational)
+                    PartModule partmod = part.Modules[i];
+                    var engine = partmod as ModuleEngines;
+                    if (engine != null && engine.isOperational)
                     {
                         demand += engine.propellants
                             .Where(p => p.name == "IntakeAir")

--- a/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirSupply.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirSupply.cs
@@ -39,7 +39,7 @@
         {
             this.Name = "Intake Air (Supply)";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Displays the available Intake Air.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirUsage.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirUsage.cs
@@ -42,7 +42,7 @@
         {
             this.Name = "Intake Air (Usage)";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Displays the consumption of Intake Air.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/Mass.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Mass.cs
@@ -28,19 +28,13 @@
 {
     public class Mass : ReadoutModule
     {
-        #region Fields
-
-        private bool showing;
-
-        #endregion
-
         #region Constructors
 
         public Mass()
         {
             this.Name = "Mass";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Displays the total Mass of the Vessel.";
             this.IsDefault = true;
         }
 

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Name.cs
@@ -1,1 +1,55 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    public class Name : ReadoutModule
+    {
+        #region Constructors
+
+        public Name()
+        {
+            Name = "Name";
+            Category = ReadoutCategory.GetCategory("Vessel");
+            HelpString = "Displays the name of the current vessel.";
+            IsDefault = true;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            if (SimulationProcessor.ShowDetails)
+            {
+                DrawLine(FlightGlobals.ActiveVessel.vesselName);
+            }
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Vessel/PartCount.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/PartCount.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Part Count";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the total number of Parts the current and next stage.";
             this.IsDefault = true;
         }
 
@@ -46,7 +46,7 @@
         {
             if (SimulationProcessor.ShowDetails)
             {
-                this.DrawLine(Units.ConcatF(SimulationProcessor.LastStage.partCount, SimulationProcessor.LastStage.totalPartCount), section.IsHud);
+                this.DrawLine(Units.ConcatF(SimulationProcessor.LastStage.partCount, SimulationProcessor.LastStage.totalPartCount, 0), section.IsHud);
             }
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/Pitch.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Pitch.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Pitch";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the current Pitch angle.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/PitchRate.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/PitchRate.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Pitch Rate";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the current Pitch speed.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/Roll.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Roll.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Roll";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the current Roll angle.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/RollRate.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/RollRate.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Roll Rate";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the current Roll speed.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/SpecificImpulse.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/SpecificImpulse.cs
@@ -33,7 +33,7 @@
         {
             this.Name = "Specific Impulse";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the average Specific Impulse of all engines in the current stage.";
             this.IsDefault = false;
         }
 

--- a/KerbalEngineer/Flight/Readouts/Vessel/Thrust.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Thrust.cs
@@ -34,7 +34,7 @@
         {
             this.Name = "Thrust";
             this.Category = ReadoutCategory.GetCategory("Vessel");
-            this.HelpString = string.Empty;
+            this.HelpString = "Shows the current and maximum thrust the vessel can put out.";
             this.IsDefault = true;
         }
 

--- a/KerbalEngineer/Flight/Sections/SectionEditor.cs
+++ b/KerbalEngineer/Flight/Sections/SectionEditor.cs
@@ -215,15 +215,18 @@
             this.ParentSection.Name = GUILayout.TextField(this.ParentSection.Name, this.textStyle);
             var isShowingInControlBar = !string.IsNullOrEmpty(this.ParentSection.Abbreviation);
             this.ParentSection.Abbreviation = GUILayout.TextField(this.ParentSection.Abbreviation, this.textStyle, GUILayout.Width(75.0f));
+
+            ParentSection.IsHud = GUILayout.Toggle(this.ParentSection.IsHud, "HUD", this.readoutButtonStyle, GUILayout.Width(50.0f));
+            if (ParentSection.IsHud)
+            {
+                this.ParentSection.IsHudBackground = GUILayout.Toggle(this.ParentSection.IsHudBackground, "BG", this.readoutButtonStyle, GUILayout.Width(50.0f));
+            }
+
             if (this.ParentSection.IsCustom)
             {
                 if (isShowingInControlBar && string.IsNullOrEmpty(this.ParentSection.Abbreviation))
                 {
                     DisplayStack.Instance.RequestResize();
-                }
-                if (this.ParentSection.IsHud = GUILayout.Toggle(this.ParentSection.IsHud, "HUD", this.readoutButtonStyle, GUILayout.Width(50.0f)))
-                {
-                    this.ParentSection.IsHudBackground = GUILayout.Toggle(this.ParentSection.IsHudBackground, "BG", this.readoutButtonStyle, GUILayout.Width(50.0f));
                 }
 
                 if (GUILayout.Button("DELETE SECTION", this.readoutButtonStyle, GUILayout.Width(150.0f)))

--- a/KerbalEngineer/Flight/Sections/SectionLibrary.cs
+++ b/KerbalEngineer/Flight/Sections/SectionLibrary.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -19,22 +19,19 @@
 
 #region Using Directives
 
-using System.Collections.Generic;
-using System.Linq;
-
-using KerbalEngineer.Flight.Readouts;
-using KerbalEngineer.Settings;
-
-using UnityEngine;
-
 #endregion
 
 namespace KerbalEngineer.Flight.Sections
 {
+    using System.Collections.Generic;
+    using System.Linq;
+    using Readouts;
+    using Settings;
+    using UnityEngine;
+
     public static class SectionLibrary
     {
         #region Constructors
-
         /// <summary>
         ///     Sets up and populates the library with the stock sections on creation.
         /// </summary>
@@ -71,7 +68,15 @@
                 ReadoutModules = ReadoutLibrary.GetCategory(ReadoutCategory.GetCategory("Rendezvous")).Where(r => r.IsDefault).ToList()
             });
 
-            var hud1 = new SectionModule
+            CustomSections.Add(new SectionModule
+            {
+                Name = "THERMAL",
+                Abbreviation = "HEAT",
+                ReadoutModules = ReadoutLibrary.GetCategory(ReadoutCategory.GetCategory("Thermal")).Where(r => r.IsDefault).ToList(),
+                IsCustom = true
+            });
+            
+            SectionModule hud1 = new SectionModule
             {
                 Name = "HUD 1",
                 Abbreviation = "HUD 1",
@@ -90,7 +95,7 @@
             hud1.IsHud = true;
             CustomSections.Add(hud1);
 
-            var hud2 = new SectionModule
+            SectionModule hud2 = new SectionModule
             {
                 Name = "HUD 2",
                 Abbreviation = "HUD 2",
@@ -101,7 +106,8 @@
                     ReadoutLibrary.GetReadout("AltitudeTerrain"),
                     ReadoutLibrary.GetReadout("VerticalSpeed"),
                     ReadoutLibrary.GetReadout("HorizontalSpeed"),
-                    ReadoutLibrary.GetReadout("Biome")
+                    ReadoutLibrary.GetReadout("Biome"),
+                    ReadoutLibrary.GetReadout("MachNumber")
                 },
             };
             hud2.FloatingPositionX = Screen.width * 0.75f - (hud2.ReadoutModules.First().ContentWidth * 0.5f);
@@ -109,11 +115,9 @@
             hud2.IsHud = true;
             CustomSections.Add(hud2);
         }
-
         #endregion
 
         #region Properties
-
         /// <summary>
         ///     Gets and sets a list of custom sections.
         /// </summary>
@@ -133,13 +137,11 @@
         ///     Gets and sets a list of stock sections
         /// </summary>
         public static List<SectionModule> StockSections { get; set; }
-
         #endregion
 
         #region Updating
 
         #region Methods: public
-
         /// <summary>
         ///     Fixed update all of the sections.
         /// </summary>
@@ -160,17 +162,15 @@
             UpdateSections(StockSections);
             UpdateSections(CustomSections);
         }
-
         #endregion
 
         #region Methods: private
-
         /// <summary>
         ///     Fixed updates a list of sections.
         /// </summary>
         private static void FixedUpdateSections(IEnumerable<SectionModule> sections)
         {
-            foreach (var section in sections)
+            foreach (SectionModule section in sections)
             {
                 if (section.IsVisible)
                 {
@@ -184,13 +184,13 @@
         /// </summary>
         private static void UpdateSections(IEnumerable<SectionModule> sections)
         {
-            foreach (var section in sections)
+            foreach (SectionModule section in sections)
             {
                 if (section.IsVisible)
                 {
                     if (!section.IsFloating)
                     {
-                        foreach (var readout in section.ReadoutModules)
+                        foreach (ReadoutModule readout in section.ReadoutModules)
                         {
                             if (readout.ResizeRequested)
                             {
@@ -203,7 +203,7 @@
                     }
                     else
                     {
-                        foreach (var readout in section.ReadoutModules)
+                        foreach (ReadoutModule readout in section.ReadoutModules)
                         {
                             if (readout.ResizeRequested)
                             {
@@ -218,13 +218,11 @@
                 NumberOfSections++;
             }
         }
-
         #endregion
 
         #endregion
 
         #region Saving and Loading
-
         /// <summary>
         ///     Loads the state of all stored sections.
         /// </summary>
@@ -243,11 +241,11 @@
                 }
             });
 
-            var handler = SettingHandler.Load("SectionLibrary.xml", new[] {typeof(List<SectionModule>)});
+            SettingHandler handler = SettingHandler.Load("SectionLibrary.xml", new[] { typeof(List<SectionModule>) });
             StockSections = handler.Get("StockSections", StockSections);
             CustomSections = handler.Get("CustomSections", CustomSections);
 
-            foreach (var section in GetAllSections())
+            foreach (SectionModule section in GetAllSections())
             {
                 section.ClearNullReadouts();
             }
@@ -258,22 +256,20 @@
         /// </summary>
         public static void Save()
         {
-            var handler = new SettingHandler();
+            SettingHandler handler = new SettingHandler();
             handler.Set("StockSections", StockSections);
             handler.Set("CustomSections", CustomSections);
             handler.Save("SectionLibrary.xml");
         }
-
         #endregion
 
         #region Methods
-
         /// <summary>
         ///     Gets a list containing all section modules.
         /// </summary>
         public static List<SectionModule> GetAllSections()
         {
-            var sections = new List<SectionModule>();
+            List<SectionModule> sections = new List<SectionModule>();
             sections.AddRange(StockSections);
             sections.AddRange(CustomSections);
             return sections;
@@ -326,7 +322,6 @@
         {
             return StockSections.Remove(GetStockSection(name));
         }
-
         #endregion
     }
 }

--- a/KerbalEngineer/Flight/Sections/SectionWindow.cs
+++ b/KerbalEngineer/Flight/Sections/SectionWindow.cs
@@ -134,7 +134,11 @@
                                                    (!this.ParentSection.IsHud || this.ParentSection.IsEditorVisible) ? this.windowStyle
                                                        : this.ParentSection.IsHudBackground && this.ParentSection.LineCount > 0
                                                            ? this.hudWindowBgStyle
-                                                           : this.hudWindowStyle).ClampToScreen();
+                                                           : this.hudWindowStyle);
+
+            windowPosition = (ParentSection.IsHud) ? windowPosition.ClampInsideScreen() : windowPosition.ClampToScreen();
+
+
             this.ParentSection.FloatingPositionX = this.windowPosition.x;
             this.ParentSection.FloatingPositionY = this.windowPosition.y;
         }

--- a/KerbalEngineer/Helpers/AngleHelper.cs
+++ b/KerbalEngineer/Helpers/AngleHelper.cs
@@ -17,21 +17,30 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using UnityEngine;
-
-#endregion
-
 namespace KerbalEngineer.Helpers
 {
+    using UnityEngine;
+
     public static class AngleHelper
     {
-        #region Methods: public
+        public static double Clamp180(double angle)
+        {
+            angle = Clamp360(angle);
+            if (angle > 180.0)
+            {
+                angle = angle - 360.0;
+            }
+            return angle;
+        }
 
-        public static double Clamp360(double value)
+        public static double Clamp360(double angle)
         {
-            return ClampBetween(value, 0.0, 360.0);
+            angle = angle % 360.0;
+            if (angle < 0.0)
+            {
+                angle = angle + 360.0;
+            }
+            return angle;
         }
 
         public static double ClampBetween(double value, double minimum, double maximum)
@@ -51,8 +60,8 @@
 
         public static double GetAngleBetweenVectors(Vector3d left, Vector3d right)
         {
-            var angle = Vector3d.Angle(left, right);
-            var rotated = QuaternionD.AngleAxis(90.0, Vector3d.forward) * right;
+            double angle = Vector3d.Angle(left, right);
+            Vector3d rotated = QuaternionD.AngleAxis(90.0, Vector3d.forward) * right;
 
             if (Vector3d.Angle(rotated, left) > 90.0)
             {
@@ -60,7 +69,5 @@
             }
             return angle;
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Helpers/Averager.cs
+++ b/KerbalEngineer/Helpers/Averager.cs
@@ -38,18 +38,18 @@
                 return Vector3d.zero;
             }
         }
+
+        public void Reset()
+        {
+            sum = Vector3d.zero;
+            count = 0;
+        }
     }
 
     public class WeightedVectorAverager
     {
         private Vector3d sum = Vector3d.zero;
         private double totalweight = 0;
-
-        public void Reset()
-        {
-            sum = Vector3d.zero;
-            totalweight = 0;
-        }
 
         public void Add(Vector3d v, double weight) {
             sum += v * weight;
@@ -67,6 +67,12 @@
         public double GetTotalWeight() {
             return totalweight;
         }
+
+        public void Reset()
+        {
+            sum = Vector3d.zero;
+            totalweight = 0.0;
+        }
     }
 }
 

--- a/KerbalEngineer/Helpers/ForceAccumulator.cs
+++ b/KerbalEngineer/Helpers/ForceAccumulator.cs
@@ -120,11 +120,11 @@
             return GetMinTorqueForceApplicationPoint(avgApplicationPoint.Get());
         }
 
-        public void Reset()
-        {
-            totalForce = Vector3d.zero;
-            totalZeroOriginTorque = Vector3d.zero;
+	    public void Reset()
+	    {
+	        totalForce = Vector3d.zero;
+	        totalZeroOriginTorque = Vector3d.zero;
             avgApplicationPoint.Reset();
-        }
+	    }
 	}
 }

--- a/KerbalEngineer/Helpers/Pool.cs
+++ b/KerbalEngineer/Helpers/Pool.cs
@@ -49,6 +49,5 @@
         {
             return values.Count;
         }
-
     }
 }

--- a/KerbalEngineer/Helpers/TimeFormatter.cs
+++ b/KerbalEngineer/Helpers/TimeFormatter.cs
@@ -1,7 +1,5 @@
 // 
-//     Kerbal Engineer Redux
-// 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,147 +15,46 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-
-using KerbalEngineer.Settings;
-
-#endregion
-
 namespace KerbalEngineer.Helpers
 {
     public static class TimeFormatter
     {
-        #region Constructors
-
-        static TimeFormatter()
-        {
-            SetReference(false);
-            Load();
-        }
-
-        #endregion
-
-        #region Properties
-
-        public static string Reference { get; set; }
-
-        public static double SecondsPerDay { get; set; }
-
-        public static double SecondsPerHour { get; set; }
-
-        public static double SecondsPerMinute { get; set; }
-
-        public static double SecondsPerYear { get; set; }
-
-        #endregion
-
-        #region Methods: public
-
         public static string ConvertToString(double seconds, string format = "F1")
         {
-            var years = 0;
-            while (seconds >= SecondsPerYear)
+            int years = 0;
+            int days = 0;
+            int hours = 0;
+            int minutes = 0;
+
+            if (seconds > 0.0)
             {
-                years++;
-                seconds -= SecondsPerYear;
-            }
+                years = (int)(seconds / KSPUtil.Year);
+                seconds -= years * KSPUtil.Year;
 
-            var days = 0;
-            while (seconds >= SecondsPerDay)
-            {
-                days++;
-                seconds -= SecondsPerDay;
-            }
+                days = (int)(seconds / KSPUtil.Day);
+                seconds -= days * KSPUtil.Day;
 
-            var hours = 0;
-            while (seconds >= SecondsPerHour)
-            {
-                hours++;
-                seconds -= SecondsPerHour;
-            }
+                hours = (int)(seconds / 3600.0);
+                seconds -= hours * 3600.0;
 
-            var minutes = 0;
-            while (seconds >= SecondsPerMinute)
-            {
-                minutes++;
-                seconds -= SecondsPerMinute;
+                minutes = (int)(seconds / 60.0);
+                seconds -= minutes * 60.0;
             }
 
             if (years > 0)
             {
-                return String.Format("{0}y {1}d {2}h {3}m {4}s", years, days, hours, minutes, seconds.ToString(format));
+                return string.Format("{0}y {1}d {2}h {3}m {4}s", years, days, hours, minutes, seconds.ToString(format));
             }
             if (days > 0)
             {
-                return String.Format("{0}d {1}h {2}m {3}s", days, hours, minutes, seconds.ToString(format));
+                return string.Format("{0}d {1}h {2}m {3}s", days, hours, minutes, seconds.ToString(format));
             }
             if (hours > 0)
             {
-                return String.Format("{0}h {1}m {2}s", hours, minutes, seconds.ToString(format));
+                return string.Format("{0}h {1}m {2}s", hours, minutes, seconds.ToString(format));
             }
 
-            return minutes > 0 ? String.Format("{0}m {1}s", minutes, seconds.ToString(format)) : String.Format("{0}s", seconds.ToString(format));
+            return minutes > 0 ? string.Format("{0}m {1}s", minutes, seconds.ToString(format)) : string.Format("{0}s", seconds.ToString(format));
         }
-
-        public static void Load()
-        {
-            var handler = SettingHandler.Load("TimeFormatter.xml");
-            SecondsPerMinute = handler.Get("SecondsPerMinute", SecondsPerMinute);
-            SecondsPerHour = handler.Get("SecondsPerHour", SecondsPerHour);
-            SecondsPerDay = handler.Get("SecondsPerDay", SecondsPerDay);
-            SecondsPerYear = handler.Get("SecondsPerYear", SecondsPerYear);
-            Reference = handler.Get("Reference", Reference);
-        }
-
-        public static void Save()
-        {
-            var handler = SettingHandler.Load("TimeFormatter.xml");
-            handler.Set("SecondsPerMinute", SecondsPerMinute);
-            handler.Set("SecondsPerHour", SecondsPerHour);
-            handler.Set("SecondsPerDay", SecondsPerDay);
-            handler.Set("SecondsPerYear", SecondsPerYear);
-            handler.Set("Reference", Reference);
-            handler.Save("TimeFormatter.xml");
-        }
-
-        public static void SetReference(bool save = true)
-        {
-            const double minute = 60.0;
-            const double hour = minute * 60.0;
-            const double day = hour * 24.0;
-            const double year = day * 365.0;
-            SetReference(minute, hour, day, year, "Earth", save);
-        }
-
-        public static void SetReference(CelestialBody body, bool save = true)
-        {
-            SetReference(SecondsPerMinute, SecondsPerHour, body.rotationPeriod, body.orbit.period, body.bodyName, save);
-        }
-
-        public static void SetReference(double minute, double hour, double day, double year, string reference, bool save = true)
-        {
-            SecondsPerMinute = minute;
-            SecondsPerHour = hour;
-            SecondsPerDay = day;
-            SecondsPerYear = year;
-            Reference = reference;
-
-            if (save)
-            {
-                Save();
-            }
-        }
-
-        public new static string ToString()
-        {
-            return String.Format("SecondsPerMinute: {0}", SecondsPerMinute) + Environment.NewLine +
-                   String.Format("SecondsPerHour: {0}", SecondsPerHour) + Environment.NewLine +
-                   String.Format("SecondsPerDay: {0}", SecondsPerDay) + Environment.NewLine +
-                   String.Format("SecondsPerYear: {0}", SecondsPerYear) + Environment.NewLine;
-        }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Helpers/Units.cs
+++ b/KerbalEngineer/Helpers/Units.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -19,15 +19,13 @@
 
 namespace KerbalEngineer.Helpers
 {
-    #region Using Directives
-
     using System;
-
-    #endregion
 
     public static class Units
     {
-        #region Methods
+        public const double GRAVITY = 9.80665;
+        public const double RAD_TO_DEG = 180.0 / Math.PI;
+        public const double DEG_TO_RAD = Math.PI / 180.0;
 
         public static string Concat(int value1, int value2)
         {
@@ -85,6 +83,17 @@
         public static string ToAngle(double value, int decimals = 5)
         {
             return value.ToString("F" + decimals) + "°";
+        }
+
+        public static string ToAngleDMS(double value)
+        {
+            double absAngle = Math.Abs(value);
+            int deg = (int)Math.Floor(absAngle);
+            double rem = absAngle - deg;
+            int min = (int)Math.Floor(rem * 60);
+            rem -= ((double)min / 60);
+            int sec = (int)Math.Floor(rem * 3600);
+            return string.Format("{0:0}° {1:00}' {2:00}\"", deg, min, sec);
         }
 
         public static string ToDistance(double value, int decimals = 1)
@@ -116,16 +125,26 @@
             return value.ToString("N" + decimals) + "Mm";
         }
 
+        public static string ToFlux(double value)
+        {
+            return value.ToString("#,0.00") + "W";
+        }
+
         public static string ToForce(double value)
         {
-            return value.ToString((value < 100000.0) ? (value < 10000.0) ? (value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0") + "kN";
+            return value.ToString((value < 100000.0) ? (value < 10000.0) ? (value < 100.0) ? (Math.Abs(value) < double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0") + "kN";
         }
 
         public static string ToForce(double value1, double value2)
         {
-            var format1 = (value1 < 100000.0) ? (value1 < 10000.0) ? (value1 < 100.0) ? (Math.Abs(value1) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0";
-            var format2 = (value2 < 100000.0) ? (value2 < 10000.0) ? (value2 < 100.0) ? (Math.Abs(value2) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0";
+            string format1 = (value1 < 100000.0) ? (value1 < 10000.0) ? (value1 < 100.0) ? (Math.Abs(value1) < double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0";
+            string format2 = (value2 < 100000.0) ? (value2 < 10000.0) ? (value2 < 100.0) ? (Math.Abs(value2) < double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0";
             return value1.ToString(format1) + " / " + value2.ToString(format2) + "kN";
+        }
+
+        public static string ToMach(double value)
+        {
+            return value.ToString("0.00") + "Ma";
         }
 
         public static string ToMass(double value, int decimals = 0)
@@ -171,6 +190,16 @@
             return value.ToString("N" + decimals) + "m/s";
         }
 
+        public static string ToTemperature(double value)
+        {
+            return value.ToString("#,0") + "K";
+        }
+
+        public static string ToTemperature(double value1, double value2)
+        {
+            return value1.ToString("#,0") + " / " + value2.ToString("#,0") + "K";
+        }
+
         public static string ToTime(double value)
         {
             return TimeFormatter.ConvertToString(value);
@@ -178,9 +207,7 @@
 
         public static string ToTorque(double value)
         {
-            return value.ToString((value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N1" : "N0") + "kNm";
-        }
-
-        #endregion
+            return value.ToString((value < 100.0) ? (Math.Abs(value) < double.Epsilon) ? "N0" : "N2" : "N0") + "kNm";
+        }
     }
 }

--- /dev/null
+++ b/KerbalEngineer/Helpers/XmlHelper.cs
@@ -1,1 +1,67 @@
+namespace KerbalEngineer.Helpers
+{
+    using System;
+    using System.IO;
+    using System.Text;
+    using System.Xml.Serialization;
 
+    public static class XmlHelper
+    {
+        /// <summary>
+        ///     Loads an object from disk.
+        /// </summary>
+        public static T LoadObject<T>(string path)
+        {
+            T obj = default(T);
+
+            if (File.Exists(path))
+            {
+                try
+                {
+                    using (StreamReader stream = new StreamReader(path, Encoding.UTF8))
+                    {
+                        obj = (T)new XmlSerializer(typeof(T)).Deserialize(stream);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Logger.Exception(ex);
+                }
+            }
+
+            return obj;
+        }
+
+        /// <summary>
+        ///     Loads and object from disk.
+        /// </summary>
+        public static bool LoadObject<T>(string path, out T obj)
+        {
+            obj = LoadObject<T>(path);
+            return (obj != null);
+        }
+
+        /// <summary>
+        ///     Saves an object to disk.
+        /// </summary>
+        public static void SaveObject<T>(string path, T obj)
+        {
+            if (obj == null || string.IsNullOrEmpty(path))
+            {
+                return;
+            }
+
+            try
+            {
+                using (StreamWriter stream = new StreamWriter(path, false, Encoding.UTF8))
+                {
+                    new XmlSerializer(typeof(T)).Serialize(stream, obj);
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+            }
+        }
+    }
+}

--- a/KerbalEngineer/KerbalEngineer.csproj
+++ b/KerbalEngineer/KerbalEngineer.csproj
@@ -48,11 +48,11 @@
     <Compile Include="Editor\ResourceInfoItem.cs" />
     <Compile Include="Extensions\FloatExtensions.cs" />
     <Compile Include="Extensions\OrbitExtensions.cs" />
+    <Compile Include="Extensions\StringExtensions.cs" />
     <Compile Include="Flight\ActionMenuGui.cs" />
     <Compile Include="Flight\Presets\Preset.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\SystemTime.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\VectoredThrustToggle.cs" />
-    <Compile Include="Flight\Readouts\Miscellaneous\TimeReference.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\Separator.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\GuiSizeAdjustor.cs" />
     <Compile Include="Flight\Readouts\Orbital\AngleToEquatorialDescendingNode.cs" />
@@ -70,11 +70,21 @@
     <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeAngleToPrograde.cs" />
     <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeTotalDeltaV.cs" />
     <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeProgradeDeltaV.cs" />
+    <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\PostBurnApoapsis.cs" />
+    <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\PostBurnPeriapsis.cs" />
     <Compile Include="Flight\Readouts\Orbital\MeanAnomalyAtEpoc.cs" />
     <Compile Include="Flight\Readouts\Orbital\MeanAnomaly.cs" />
     <Compile Include="Flight\Readouts\Orbital\EccentricAnomaly.cs" />
     <Compile Include="Flight\Readouts\Orbital\ArgumentOfPeriapsis.cs" />
     <Compile Include="Flight\Readouts\Orbital\CurrentSoi.cs" />
+    <Compile Include="Flight\Readouts\Orbital\SemiMajorAxis.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Flight\Readouts\Orbital\SpeedAtApoapsis.cs" />
+    <Compile Include="Flight\Readouts\Orbital\SpeedAtPeriapsis.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Flight\Readouts\Orbital\TimeToAtmosphere.cs" />
     <Compile Include="Flight\Readouts\Orbital\TrueAnomaly.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToEquatorialAscendingNode.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToEquatorialDescendingNode.cs" />
@@ -89,6 +99,22 @@
     <Compile Include="Flight\Readouts\Surface\Biome.cs" />
     <Compile Include="Flight\Readouts\Surface\HorizontalAcceleration.cs" />
     <Compile Include="Flight\Readouts\Surface\VerticalAcceleration.cs" />
+    <Compile Include="Flight\Readouts\Surface\MachNumber.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CoolestSkinTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CriticalPart.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CoolestPart.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CoolestTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CriticalThermalPercentage.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CriticalSkinTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CriticalTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\HottestSkinTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\InternalFlux.cs" />
+    <Compile Include="Flight\Readouts\Thermal\RadiationFlux.cs" />
+    <Compile Include="Flight\Readouts\Thermal\ConvectionFlux.cs" />
+    <Compile Include="Flight\Readouts\Thermal\HottestTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\HottestPart.cs" />
+    <Compile Include="Flight\Readouts\Thermal\ThermalProcessor.cs" />
+    <Compile Include="Flight\Readouts\Vessel\Name.cs" />
     <Compile Include="Flight\Readouts\Vessel\AttitudeProcessor.cs" />
     <Compile Include="Flight\Readouts\Vessel\DeltaVCurrentTotal.cs" />
     <Compile Include="Flight\Readouts\Vessel\PitchRate.cs" />
@@ -119,12 +145,13 @@
     <Compile Include="Helpers\AngleHelper.cs" />
     <Compile Include="Helpers\Averager.cs" />
     <Compile Include="Helpers\ForceAccumulator.cs" />
-    <Compile Include="Helpers\Pool.cs" />
     <Compile Include="Helpers\TextureHelper.cs" />
     <Compile Include="Helpers\Units.cs" />
     <Compile Include="Helpers\TimeFormatter.cs" />
-    <Compile Include="KeyBinder.cs" />
+    <Compile Include="Helpers\XmlHelper.cs" />
+    <Compile Include="KeyBinding\KeyBinder.cs" />
     <Compile Include="Control\ControlCentre.cs" />
+    <Compile Include="KeyBinding\KeyBindingsObject.cs" />
     <Compile Include="UIControls\DropDown.cs" />
     <Compile Include="Logger.cs" />
     <Compile Include="EngineerGlobals.cs" />
@@ -146,7 +173,6 @@
     <Compile Include="Flight\Readouts\Orbital\OrbitalPeriod.cs" />
     <Compile Include="Flight\Readouts\Orbital\OrbitalSpeed.cs" />
     <Compile Include="Flight\Readouts\Orbital\PeriapsisHeight.cs" />
-    <Compile Include="Flight\Readouts\Orbital\SemiMajorAxis.cs" />
     <Compile Include="Flight\Readouts\Orbital\SemiMinorAxis.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToApoapsis.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToPeriapsis.cs" />
@@ -197,18 +223,22 @@
     <Compile Include="Settings\SettingHandler.cs" />
     <Compile Include="Settings\SettingItem.cs" />
     <Compile Include="TapeDriveAnimator.cs" />
+    <Compile Include="KeyBinding\KeyBindPopup.cs" />
     <Compile Include="UIControls\WindowObject.cs" />
     <Compile Include="VesselSimulator\AttachNodeSim.cs" />
     <Compile Include="VesselSimulator\EngineSim.cs" />
+    <Compile Include="Helpers\Pool.cs" />
     <Compile Include="VesselSimulator\PartSim.cs" />
     <Compile Include="VesselSimulator\ResourceContainer.cs" />
     <Compile Include="VesselSimulator\SimManager.cs" />
     <Compile Include="VesselSimulator\Simulation.cs" />
     <Compile Include="VesselSimulator\Stage.cs" />
+    <Compile Include="Flight\Readouts\Rendezvous\RelativeRadialVelocity.cs" />
+    <Compile Include="Flight\Readouts\Rendezvous\TimeToRendezvous.cs" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Assembly-CSharp">
-      <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
+      <HintPath>..\Game\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
       <Private>False</Private>
     </Reference>
     <Reference Include="System">
@@ -220,7 +250,7 @@
       <Private>False</Private>
     </Reference>
     <Reference Include="UnityEngine">
-      <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\UnityEngine.dll</HintPath>
+      <HintPath>..\Game\KSP_Data\Managed\UnityEngine.dll</HintPath>
       <Private>False</Private>
     </Reference>
   </ItemGroup>

--- a/KerbalEngineer/KeyBinder.cs
+++ /dev/null
@@ -1,35 +1,1 @@
-// 
-//     Kerbal Engineer Redux
-// 
-//     Copyright (C) 2014 CYBUTEK
-// 
-//     This program is free software: you can redistribute it and/or modify
-//     it under the terms of the GNU General Public License as published by
-//     the Free Software Foundation, either version 3 of the License, or
-//     (at your option) any later version.
-// 
-//     This program is distributed in the hope that it will be useful,
-//     but WITHOUT ANY WARRANTY; without even the implied warranty of
-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//     GNU General Public License for more details.
-// 
-//     You should have received a copy of the GNU General Public License
-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
-// 
 
-using UnityEngine;
-
-namespace KerbalEngineer
-{
-    public class KeyBinder
-    {
-        public static KeyCode EditorShowHide { get; set; }
-
-        public static KeyCode FlightShowHide { get; set; }
-
-        static KeyBinder()
-        {
-            EditorShowHide = FlightShowHide = KeyCode.Backslash;
-        }
-    }
-}

--- /dev/null
+++ b/KerbalEngineer/KeyBinding/KeyBindPopup.cs
@@ -1,1 +1,189 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.KeyBinding
+{
+    using System;
+    using UnityEngine;
+
+    public class KeyBindPopup : MonoBehaviour
+    {
+        private readonly Array availableBindings = Enum.GetValues(typeof(KeyCode));
+        private bool isCentred;
+        private Rect position = new Rect(0.0f, 0.0f, 250.0f, 0.0f);
+
+        /// <summary>
+        ///     Gets whether a key bind popup is already open.
+        /// </summary>
+        public static bool IsOpen { get; private set; }
+
+        /// <summary>
+        ///     Gets the delegate to be invoked when accepted button is clicked.
+        /// </summary>
+        public Action<KeyCode> AcceptClicked { get; private set; }
+
+        /// <summary>
+        ///     Gets the name of the binding to change.
+        /// </summary>
+        public string Name { get; private set; }
+
+        /// <summary>
+        ///     Gets the selected binding.
+        /// </summary>
+        public KeyCode Binding { get; private set; }
+
+        /// <summary>
+        ///     Shows a key bind popup allowing the user to select a key for binding.
+        /// </summary>
+        public static void Show(string name, KeyCode currentBinding, Action<KeyCode> acceptClicked)
+        {
+            if (IsOpen)
+            {
+                return;
+            }
+
+            KeyBindPopup keyBindPopup = new GameObject("SelectKeyBind").AddComponent<KeyBindPopup>();
+            keyBindPopup.Name = name;
+            keyBindPopup.Binding = currentBinding;
+            keyBindPopup.AcceptClicked = acceptClicked;
+        }
+
+        /// <summary>
+        ///     Handles the accept button click event.
+        /// </summary>
+        public void OnAccept()
+        {
+            if (AcceptClicked != null)
+            {
+                AcceptClicked.Invoke(Binding);
+            }
+            Destroy(gameObject);
+        }
+
+        /// <summary>
+        ///     Handles the cancel button click event.
+        /// </summary>
+        public void OnCancel()
+        {
+            Destroy(gameObject);
+        }
+
+        /// <summary>
+        ///     Called by unity when the component is created.
+        /// </summary>
+        protected virtual void Awake()
+        {
+            if (IsOpen)
+            {
+                OnCancel();
+            }
+            else
+            {
+                IsOpen = true;
+            }
+        }
+
+        /// <summary>
+        ///     Called by unity when the component is destroyed.
+        /// </summary>
+        protected virtual void OnDestroy()
+        {
+            IsOpen = false;
+        }
+
+        /// <summary>
+        ///     Called by unity each frame to render the GUI.
+        /// </summary>
+        protected virtual void OnGUI()
+        {
+            position = GUILayout.Window(GetInstanceID(), position, RenderWindow, "Select Key Bind", HighLogic.Skin.window);
+            CentreWindow();
+        }
+
+        /// <summary>
+        ///     Called by unity every frame.
+        /// </summary>
+        protected virtual void Update()
+        {
+            CentreWindow();
+            UpdateBinding();
+        }
+
+        /// <summary>
+        ///     Centres the window on the screen.
+        /// </summary>
+        private void CentreWindow()
+        {
+            if (isCentred == false && position.width > 0.0f && position.height > 0.0f)
+            {
+                isCentred = true;
+                position.center = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f);
+            }
+        }
+
+        /// <summary>
+        ///     Renders the window content.
+        /// </summary>
+        private void RenderWindow(int id)
+        {
+            // Binding labels.
+            GUILayout.BeginVertical(HighLogic.Skin.textArea);
+            GUILayout.Label("Key Bind: " + Name);
+            GUILayout.Label("Selected: " + Binding);
+            GUILayout.EndVertical();
+
+            // Window buttons.
+            GUILayout.BeginHorizontal();
+            if (GUILayout.Button("Cancel", HighLogic.Skin.button))
+            {
+                OnCancel();
+            }
+
+            if (GUILayout.Button("Accept", HighLogic.Skin.button))
+            {
+                OnAccept();
+            }
+            GUILayout.EndHorizontal();
+
+            // Make the window to be draggable.
+            GUI.DragWindow();
+        }
+
+        /// <summary>
+        ///     Updates the binding selected by the user.
+        /// </summary>
+        private void UpdateBinding()
+        {
+            for (int i = 0; i < availableBindings.Length; ++i)
+            {
+                KeyCode keyCode = (KeyCode)availableBindings.GetValue(i);
+
+                if (keyCode == KeyCode.Mouse0)
+                {
+                    continue;
+                }
+
+                if (Input.GetKeyDown(keyCode))
+                {
+                    Binding = keyCode;
+                }
+            }
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/KeyBinding/KeyBinder.cs
@@ -1,1 +1,106 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.KeyBinding
+{
+    using System.IO;
+    using Helpers;
+    using UnityEngine;
+
+    public class KeyBinder
+    {
+        private static readonly string filePath = Path.Combine(EngineerGlobals.SettingsPath, "KeyBinds.xml");
+        private static KeyBindingsObject bindings;
+
+        static KeyBinder()
+        {
+            Load();
+        }
+
+        /// <summary>
+        ///     Gets and sets the key bindings object.
+        /// </summary>
+        public static KeyBindingsObject Bindings
+        {
+            get
+            {
+                if (bindings == null)
+                {
+                    bindings = new KeyBindingsObject();
+                }
+                return bindings;
+            }
+            private set
+            {
+                if (value != null)
+                {
+                    bindings = value;
+                }
+            }
+        }
+
+        /// <summary>
+        ///     Gets and sets the editor show/hide binding.
+        /// </summary>
+        public static KeyCode EditorShowHide
+        {
+            get
+            {
+                return Bindings.EditorShowHide;
+            }
+            set
+            {
+                Bindings.EditorShowHide = value;
+                Save();
+            }
+        }
+
+        /// <summary>
+        ///     Gets and sets the flight show/hide binding.
+        /// </summary>
+        public static KeyCode FlightShowHide
+        {
+            get
+            {
+                return Bindings.FlightShowHide;
+            }
+            set
+            {
+                Bindings.FlightShowHide = value;
+                Save();
+            }
+        }
+
+        /// <summary>
+        ///     Loads the key bindings from disk.
+        /// </summary>
+        public static void Load()
+        {
+            Bindings = XmlHelper.LoadObject<KeyBindingsObject>(filePath);
+        }
+
+        /// <summary>
+        ///     Saves the key bindings to disk.
+        /// </summary>
+        public static void Save()
+        {
+            XmlHelper.SaveObject(filePath, Bindings);
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/KeyBinding/KeyBindingsObject.cs
@@ -1,1 +1,30 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.KeyBinding
+{
+    using UnityEngine;
+
+    public class KeyBindingsObject
+    {
+        public KeyCode EditorShowHide { get; set; }
+
+        public KeyCode FlightShowHide { get; set; }
+    }
+}

--- a/KerbalEngineer/LogMsg.cs
+++ b/KerbalEngineer/LogMsg.cs
@@ -15,7 +15,8 @@
 
         public void Flush()
         {
-            MonoBehaviour.print(this.buf);
+            if (this.buf.Length > 0)
+                MonoBehaviour.print(this.buf);
             this.buf.Length = 0;
         }
     }

--- a/KerbalEngineer/Properties/AssemblyInfo.cs
+++ b/KerbalEngineer/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion(KerbalEngineer.EngineerGlobals.AssemblyVersion)]
+[assembly: AssemblyVersion(KerbalEngineer.EngineerGlobals.ASSEMBLY_VERSION)]
 

--- a/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
+++ b/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
@@ -19,13 +19,13 @@
 
 #region Using Directives
 
-using System;
-using System.Text;
-
 #endregion
 
 namespace KerbalEngineer.VesselSimulator
 {
+    using System;
+    using System.Text;
+
     internal class AttachNodeSim
     {
 
@@ -61,20 +61,20 @@
 
         public void DumpToBuffer(StringBuilder buffer)
         {
-            if (this.attachedPartSim == null)
+            if (attachedPartSim == null)
             {
                 buffer.Append("<staged>:<n>");
             }
             else
             {
-                buffer.Append(this.attachedPartSim.name);
+                buffer.Append(attachedPartSim.name);
                 buffer.Append(":");
-                buffer.Append(this.attachedPartSim.partId);
+                buffer.Append(attachedPartSim.partId);
             }
             buffer.Append("#");
-            buffer.Append(this.nodeType);
+            buffer.Append(nodeType);
             buffer.Append(":");
-            buffer.Append(this.id);
+            buffer.Append(id);
         }
     }
 }

--- a/KerbalEngineer/VesselSimulator/EngineSim.cs
+++ b/KerbalEngineer/VesselSimulator/EngineSim.cs
@@ -17,29 +17,28 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using UnityEngine;
-
-#endregion
-
 namespace KerbalEngineer.VesselSimulator
 {
+    using System;
+    using System.Collections.Generic;
+    using System.Text;
+    using Editor;
+    using Helpers;
+    using UnityEngine;
+
     public class EngineSim
     {
         private static readonly Pool<EngineSim> pool = new Pool<EngineSim>(Create, Reset);
 
         private readonly ResourceContainer resourceConsumptions = new ResourceContainer();
+        private readonly ResourceContainer resourceFlowModes = new ResourceContainer();
 
         public double actualThrust = 0;
         public bool isActive = false;
         public double isp = 0;
         public PartSim partSim;
         public List<AppliedForce> appliedForces = new List<AppliedForce>();
+        public float maxMach;
 
         public double thrust = 0;
 
@@ -54,6 +53,7 @@
         private static void Reset(EngineSim engineSim)
         {
             engineSim.resourceConsumptions.Reset();
+            engineSim.resourceFlowModes.Reset();
             engineSim.actualThrust = 0;
             engineSim.isActive = false;
             engineSim.isp = 0;
@@ -63,6 +63,7 @@
             }
             engineSim.appliedForces.Clear();
             engineSim.thrust = 0;
+            engineSim.maxMach = 0f;
         }
 
         public void Release()
@@ -72,7 +73,7 @@
 
         public static EngineSim New(PartSim theEngine,
                          double atmosphere,
-                         double machNumber,
+                         float machNumber,
                          float maxFuelFlow,
                          float minFuelFlow,
                          float thrustPercentage,
@@ -86,196 +87,107 @@
                          bool throttleLocked,
                          List<Propellant> propellants,
                          bool active,
-                         bool correctThrust,
-                         List<Transform> thrustTransforms)
+                         float resultingThrust,
+                         List<Transform> thrustTransforms,
+                        LogMsg log)
         {
             EngineSim engineSim = pool.Borrow();
 
-
-            StringBuilder buffer = null;
-            //MonoBehaviour.print("Create EngineSim for " + theEngine.name);
-            //MonoBehaviour.print("maxThrust = " + maxThrust);
-            //MonoBehaviour.print("minThrust = " + minThrust);
-            //MonoBehaviour.print("thrustPercentage = " + thrustPercentage);
-            //MonoBehaviour.print("requestedThrust = " + requestedThrust);
-            //MonoBehaviour.print("velocity = " + velocity);
-
+            engineSim.isp = 0.0;
+            engineSim.maxMach = 0.0f;
+            engineSim.actualThrust = 0.0;
             engineSim.partSim = theEngine;
-
             engineSim.isActive = active;
-            //this.thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust;
-            //MonoBehaviour.print("thrust = " + thrust);
-
             engineSim.thrustVec = vecThrust;
-
-            double flowRate = 0d;
+            engineSim.resourceConsumptions.Reset();
+            engineSim.resourceFlowModes.Reset();
+            engineSim.appliedForces.Clear();
+
+            double flowRate = 0.0;
             if (engineSim.partSim.hasVessel)
             {
-                //MonoBehaviour.print("hasVessel is true");
-
-                //this.actualThrust = this.isActive ? resultingThrust : 0.0;
-
+                if (log != null) log.buf.AppendLine("hasVessel is true"); 
+
+                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, engineSim.partSim.part.atmDensity, velCurve, machNumber, ref engineSim.maxMach);
                 engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere);
-
-                //if (this.isp == 0d)
-                //{
-                //    MonoBehaviour.print("Isp at " + this.partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN");
-                //}
-
-
-                // correctThrust is less usefull now that the stock engines do it. Keep or remove.
-
-                //if (correctThrust && realIsp == 0)
-                //{
-                //    float ispsl = atmosphereCurve.Evaluate(0);
-                //    if (ispsl != 0)
-                //    {
-                //        this.thrust = this.thrust * this.isp / ispsl;
-                //    }
-                //    else
-                //    {
-                //        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
-                //    }
-                //    //MonoBehaviour.print("corrected thrust = " + thrust);
-                //}
-
-                //if (velocityCurve != null)
-                //{
-                //    this.thrust *= velocityCurve.Evaluate((float)velocity);
-                //    //MonoBehaviour.print("thrust at velocity = " + thrust);
-                //}
-                
-                float multiplier = 1;
-                if (atmChangeFlow)
-                {
-                    multiplier = (float)(theEngine.part.atmDensity / 1.225);
-                    if (atmCurve != null)
-                    {
-                        multiplier = atmCurve.Evaluate(multiplier);
-                    }
-                    //MonoBehaviour.print("corrected thrust = " + thrust);
-                }
-                if (velCurve != null)
-                {
-                    multiplier *= velCurve.Evaluate((float)machNumber);
+                engineSim.thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
+                engineSim.actualThrust = engineSim.isActive ? resultingThrust : 0.0;
+                if (log != null)
+                {
+                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
+                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
+                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
+                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
                 }
 
                 if (throttleLocked)
                 {
-                    //MonoBehaviour.print("throttleLocked is true");
-                    //flowRate = this.thrust / (this.isp * 9.82);
-                    flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, (thrustPercentage / 100f)) * multiplier;
+                    if (log != null) log.buf.AppendLine("throttleLocked is true, using thrust for flowRate");
+                    flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                 }
                 else
                 {
-                    if (theEngine.isLanded)
-                    {
-                        //MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle);
-                        flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, FlightInputHandler.state.mainThrottle * (thrustPercentage / 100f)) * multiplier;
+                    if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
+                    {
+                        if (log != null) log.buf.AppendLine("throttled up and not landed, using actualThrust for flowRate");
+                        flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                     }
                     else
                     {
-                        if (currentThrottle > 0)
-                        {
-                            //MonoBehaviour.print("requestedThrust > 0");
-                            //flowRate = requestedThrust / (this.isp * 9.82) * multiplier;
-                            flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, currentThrottle * (thrustPercentage / 100f)) * multiplier;
-                        }
-                        else
-                        {
-                            //MonoBehaviour.print("requestedThrust <= 0");
-                            flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, (thrustPercentage / 100f)) * multiplier;
-                        }
+                        if (log != null) log.buf.AppendLine("throttled down or landed, using thrust for flowRate");
+                        flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                     }
                 }
             }
             else
             {
-                //MonoBehaviour.print("hasVessel is false");
+                if (log != null) log.buf.AppendLine("hasVessel is false");
+                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, CelestialBodies.SelectedBody.GetDensity(BuildAdvanced.Altitude), velCurve, machNumber, ref engineSim.maxMach);
                 engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere);
-                if (engineSim.isp == 0d)
-                {
-                    MonoBehaviour.print("Isp at " + atmosphere + " is zero. Flow rate will be NaN");
-                }
-                //if (correctThrust)
-                //{
-                //    float ispsl = atmosphereCurve.Evaluate(0);
-                //    if (ispsl != 0)
-                //    {
-                //        this.thrust = this.thrust * this.isp / ispsl;
-                //    }
-                //    else
-                //    {
-                //        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
-                //    }
-                //    //MonoBehaviour.print("corrected thrust = " + thrust);
-                //}
-
-                float multiplier = 1;
-                if (atmChangeFlow)
-                {
-                    //multiplier = (float)(this.partSim.part.atmDensity / 1.225);
-                    multiplier = (float)atmosphere;    // technically wrong but the same for my Editor need
-                    if (atmCurve != null)
-                    {
-                        multiplier = atmCurve.Evaluate(multiplier);
-                    }
-                }
-
-                if (velCurve != null)
-                {
-                    multiplier *= velCurve.Evaluate((float)machNumber);
-                }
-
-                flowRate = Mathf.Lerp(minFuelFlow, maxFuelFlow, (thrustPercentage / 100f)) * multiplier;
-            }
-
-            if (SimManager.logOutput)
-            {
-                buffer = new StringBuilder(1024);
-                buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);
-            }
-
-            engineSim.thrust = flowRate * (engineSim.isp * IspG);
-            // I did not look into the diff between those 2 so I made them equal...
-            engineSim.actualThrust = engineSim.thrust;
+                engineSim.thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
+                engineSim.actualThrust = 0d;
+                if (log != null)
+                {
+                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
+                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
+                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
+                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
+                }
+
+                if (log != null) log.buf.AppendLine("no vessel, using thrust for flowRate");
+                flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
+            }
+
+            if (log != null) log.buf.AppendFormat("flowRate = {0:g6}\n", flowRate);
 
             float flowMass = 0f;
-            for (int i = 0; i < propellants.Count; i++)
+            for (int i = 0; i < propellants.Count; ++i)
             {
                 Propellant propellant = propellants[i];
-                flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
-            }
-
-            if (SimManager.logOutput)
-            {
-                buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);
-            }
-
-            for (int i = 0; i < propellants.Count; i++)
+                if (!propellant.ignoreForIsp)
+                    flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
+            }
+
+            if (log != null) log.buf.AppendFormat("flowMass = {0:g6}\n", flowMass);
+
+            for (int i = 0; i < propellants.Count; ++i)
             {
                 Propellant propellant = propellants[i];
+
                 if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
                 {
                     continue;
                 }
 
                 double consumptionRate = propellant.ratio * flowRate / flowMass;
-                if (SimManager.logOutput)
-                {
-                    buffer.AppendFormat(
+                if (log != null) log.buf.AppendFormat(
                         "Add consumption({0}, {1}:{2:d}) = {3:g6}\n",
                         ResourceContainer.GetResourceName(propellant.id),
                         theEngine.name,
                         theEngine.partId,
                         consumptionRate);
-                }
                 engineSim.resourceConsumptions.Add(propellant.id, consumptionRate);
-            }
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print(buffer);
+                engineSim.resourceFlowModes.Add(propellant.id, (double)propellant.GetFlowMode());
             }
 
             double thrustPerThrustTransform = engineSim.thrust / thrustTransforms.Count;
@@ -288,12 +200,70 @@
                 AppliedForce appliedForce = AppliedForce.New(direction * thrustPerThrustTransform, position);
                 engineSim.appliedForces.Add(appliedForce);
             }
+
             return engineSim;
         }
 
         public ResourceContainer ResourceConsumptions
         {
-            get { return this.resourceConsumptions; }
+            get
+            {
+                return resourceConsumptions;
+            }
+        }
+
+        public static double GetExhaustVelocity(double isp)
+        {
+            return isp * Units.GRAVITY;
+        }
+
+        public static float GetFlowModifier(bool atmChangeFlow, FloatCurve atmCurve, double atmDensity, FloatCurve velCurve, float machNumber, ref float maxMach)
+        {
+            float flowModifier = 1.0f;
+            if (atmChangeFlow)
+            {
+                flowModifier = (float)(atmDensity / 1.225);
+                if (atmCurve != null)
+                {
+                    flowModifier = atmCurve.Evaluate(flowModifier);
+                }
+            }
+            if (velCurve != null)
+            {
+                flowModifier = flowModifier * velCurve.Evaluate(machNumber);
+                maxMach = velCurve.maxTime;
+            }
+            if (flowModifier < float.Epsilon)
+            {
+                flowModifier = float.Epsilon;
+            }
+            return flowModifier;
+        }
+
+        public static double GetFlowRate(double thrust, double isp)
+        {
+            return thrust / GetExhaustVelocity(isp);
+        }
+
+        public static float GetThrottlePercent(float currentThrottle, float thrustPercentage)
+        {
+            return currentThrottle * GetThrustPercent(thrustPercentage);
+        }
+
+        public static double GetThrust(double flowRate, double isp)
+        {
+            return flowRate * GetExhaustVelocity(isp);
+        }
+
+        public static float GetThrustPercent(float thrustPercentage)
+        {
+            return thrustPercentage * 0.01f;
+        }
+
+        public void DumpEngineToBuffer(StringBuilder buffer, String prefix)
+        {
+            buffer.Append(prefix);
+            buffer.AppendFormat("[thrust = {0:g6}, actual = {1:g6}, isp = {2:g6}\n", thrust, actualThrust, isp);
         }
 
         // A dictionary to hold a set of parts for each resource
@@ -303,14 +273,36 @@
 
         HashSet<PartSim> visited = new HashSet<PartSim>();
 
+        public void DumpSourcePartSets(String msg)
+        {
+            MonoBehaviour.print("DumpSourcePartSets " + msg);
+            foreach (int type in sourcePartSets.Keys)
+            {
+                MonoBehaviour.print("SourcePartSet for " + ResourceContainer.GetResourceName(type));
+                HashSet<PartSim> sourcePartSet = sourcePartSets[type];
+                if (sourcePartSet.Count > 0)
+                {
+                    foreach (PartSim partSim in sourcePartSet)
+                    {
+                        MonoBehaviour.print("Part " + partSim.name + ":" + partSim.partId);
+                    }
+                }
+                else
+                {
+                    MonoBehaviour.print("No parts");
+                }
+            }
+        }
+
         public bool SetResourceDrains(List<PartSim> allParts, List<PartSim> allFuelLines, HashSet<PartSim> drainingParts)
         {
             LogMsg log = null;
-            
+            //DumpSourcePartSets("before clear");
             foreach (HashSet<PartSim> sourcePartSet in sourcePartSets.Values)
             {
                 sourcePartSet.Clear();
             }
+            //DumpSourcePartSets("after clear");
 
             for (int index = 0; index < this.resourceConsumptions.Types.Count; index++)
             {
@@ -322,14 +314,15 @@
                     sourcePartSet = new HashSet<PartSim>();
                     sourcePartSets.Add(type, sourcePartSet);
                 }
-                switch (ResourceContainer.GetResourceFlowMode(type))
+
+                switch ((ResourceFlowMode)this.resourceFlowModes[type])
                 {
                     case ResourceFlowMode.NO_FLOW:
-                        if (this.partSim.resources[type] > SimManager.RESOURCE_MIN && this.partSim.resourceFlowStates[type] != 0)
+                        if (partSim.resources[type] > SimManager.RESOURCE_MIN && partSim.resourceFlowStates[type] != 0)
                         {
                             //sourcePartSet = new HashSet<PartSim>();
                             //MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this");
-                            sourcePartSet.Add(this.partSim);
+                            sourcePartSet.Add(partSim);
                         }
                         break;
 
@@ -361,26 +354,33 @@
                                 continue;
                             }
 
-                            var stage = aPartSim.DecouplerCount();
+                            int stage = aPartSim.DecouplerCount();
                             if (stage > maxStage)
                             {
                                 maxStage = stage;
                             }
 
-                            if (!stagePartSets.TryGetValue(stage, out sourcePartSet))
+                            HashSet<PartSim> tempPartSet;
+                            if (!stagePartSets.TryGetValue(stage, out tempPartSet))
                             {
-                                sourcePartSet = new HashSet<PartSim>();
-                                stagePartSets.Add(stage, sourcePartSet);
+                                tempPartSet = new HashSet<PartSim>();
+                                stagePartSets.Add(stage, tempPartSet);
                             }
-                            sourcePartSet.Add(aPartSim);
-                        }
-
-                        for (var i = 0; i <= maxStage; i++)
+                            tempPartSet.Add(aPartSim);
+                        }
+
+                        for (int j = maxStage; j >= 0; j--)
                         {
                             HashSet<PartSim> stagePartSet;
-                            if (stagePartSets.TryGetValue(i, out stagePartSet) && stagePartSet.Count > 0)
+                            if (stagePartSets.TryGetValue(j, out stagePartSet) && stagePartSet.Count > 0)
                             {
-                                sourcePartSet = stagePartSet;
+                                // We have to copy the contents of the set here rather than copying the set reference or 
+                                // bad things (tm) happen
+                                foreach (PartSim aPartSim in stagePartSet)
+                                {
+                                    sourcePartSet.Add(aPartSim);
+                                }
+                                break;
                             }
                         }
                         break;
@@ -391,11 +391,9 @@
                         if (SimManager.logOutput)
                         {
                             log = new LogMsg();
-                            log.buf.AppendLine(
-                                "Find " + ResourceContainer.GetResourceName(type) + " sources for " + this.partSim.name + ":" +
-                                this.partSim.partId);
-                        }
-                        this.partSim.GetSourceSet(type, allParts, visited, sourcePartSet, log, "");
+                            log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + partSim.name + ":" + partSim.partId);
+                        }
+                        partSim.GetSourceSet(type, allParts, visited, sourcePartSet, log, "");
                         if (SimManager.logOutput)
                         {
                             MonoBehaviour.print(log.buf);
@@ -403,17 +401,13 @@
                         break;
 
                     default:
-                        MonoBehaviour.print(
-                            "SetResourceDrains(" + this.partSim.name + ":" + this.partSim.partId + ") Unexpected flow type for " +
-                            ResourceContainer.GetResourceName(type) + ")");
+                        MonoBehaviour.print("SetResourceDrains(" + partSim.name + ":" + partSim.partId + ") Unexpected flow type for " + ResourceContainer.GetResourceName(type) + ")");
                         break;
                 }
 
-
-                if (sourcePartSet.Count > 0)
-                {
-                    sourcePartSets[type] = sourcePartSet;
-                    if (SimManager.logOutput)
+                if (SimManager.logOutput)
+                {
+                    if (sourcePartSet.Count > 0)
                     {
                         log = new LogMsg();
                         log.buf.AppendLine("Source parts for " + ResourceContainer.GetResourceName(type) + ":");
@@ -424,6 +418,8 @@
                         MonoBehaviour.print(log.buf);
                     }
                 }
+
+                //DumpSourcePartSets("after " + ResourceContainer.GetResourceName(type));
             }
             
             // If we don't have sources for all the needed resources then return false without setting up any drains
@@ -431,24 +427,25 @@
             {
                 int type = this.resourceConsumptions.Types[i];
                 HashSet<PartSim> sourcePartSet; 
-                if (!sourcePartSets.TryGetValue(type, out sourcePartSet) || sourcePartSet.Count() == 0)
+                if (!sourcePartSets.TryGetValue(type, out sourcePartSet) || sourcePartSet.Count == 0)
                 {
                     if (SimManager.logOutput)
                     {
                         MonoBehaviour.print("No source of " + ResourceContainer.GetResourceName(type));
                     }
 
-                    this.isActive = false;
+                    isActive = false;
                     return false;
                 }
             }
+
             // Now we set the drains on the members of the sets and update the draining parts set
             for (int i = 0; i < this.resourceConsumptions.Types.Count; i++)
             {
                 int type = this.resourceConsumptions.Types[i];
                 HashSet<PartSim> sourcePartSet = sourcePartSets[type];
                 // Loop through the members of the set 
-                double amount = this.resourceConsumptions[type] / sourcePartSet.Count;
+                double amount = resourceConsumptions[type] / sourcePartSet.Count;
                 foreach (PartSim partSim in sourcePartSet)
                 {
                     if (SimManager.logOutput)
@@ -464,11 +461,5 @@
             }
             return true;
         }
-
-        public void DumpEngineToBuffer(StringBuilder buffer, String prefix)
-        {
-            buffer.Append(prefix);
-            buffer.AppendFormat("[thrust = {0:g6}, actual = {1:g6}, isp = {2:g6}\n", this.thrust, this.actualThrust, this.isp);
-        }
     }
 }

--- a/KerbalEngineer/VesselSimulator/PartSim.cs
+++ b/KerbalEngineer/VesselSimulator/PartSim.cs
@@ -17,21 +17,16 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using KerbalEngineer.Extensions;
-using UnityEngine;
-
-#endregion
 
 namespace KerbalEngineer.VesselSimulator
 {
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Text;
     using CompoundParts;
+    using Extensions;
+    using UnityEngine;
 
     public class PartSim
     {
@@ -39,14 +34,15 @@
 
         private readonly List<AttachNodeSim> attachNodes = new List<AttachNodeSim>();
 
+        public double realMass;
+        public double baseMass;
+        public double baseMassForCoM;
         public Vector3d centerOfMass;
-        public double baseMass = 0d;
-        public double cost;
+        public double baseCost;
         public int decoupledInStage;
         public bool fuelCrossFeed;
         public List<PartSim> fuelTargets = new List<PartSim>();
         public bool hasModuleEngines;
-        public bool hasModuleEnginesFX;
         public bool hasMultiModeEngine;
 
         public bool hasVessel;
@@ -59,7 +55,9 @@
         public bool isLanded;
         public bool isNoPhysics;
         public bool isSepratron;
-        public bool localCorrectThrust;
+        public bool isFairing;
+        public float fairingMass;
+        public int stageIndex;
         public String name;
         public String noCrossFeedNodeKey;
         public PartSim parent;
@@ -90,7 +88,9 @@
             partSim.resourceDrains.Reset();
             partSim.resourceFlowStates.Reset();
             partSim.resources.Reset();
+            partSim.baseCost = 0d;
             partSim.baseMass = 0d;
+            partSim.baseMassForCoM = 0d;
             partSim.startMass = 0d;
         }
 
@@ -102,17 +102,13 @@
         public static PartSim New(Part thePart, int id, double atmosphere, LogMsg log)
         {
             PartSim partSim = pool.Borrow();
-
 
             partSim.part = thePart;
             partSim.centerOfMass = thePart.transform.TransformPoint(thePart.CoMOffset);
             partSim.partId = id;
             partSim.name = partSim.part.partInfo.name;
 
-            if (log != null)
-            {
-                log.buf.AppendLine("Create PartSim for " + partSim.name);
-            }
+            if (log != null) log.buf.AppendLine("Create PartSim for " + partSim.name);
 
             partSim.parent = null;
             partSim.parentAttach = partSim.part.attachMode;
@@ -122,24 +118,38 @@
             partSim.isFuelLine = partSim.part.HasModule<CModuleFuelLine>();
             partSim.isFuelTank = partSim.part is FuelTank;
             partSim.isSepratron = partSim.IsSepratron();
+            partSim.isFairing = partSim.IsFairing(partSim.part);
             partSim.inverseStage = partSim.part.inverseStage;
             //MonoBehaviour.print("inverseStage = " + inverseStage);
 
-            partSim.cost = partSim.part.GetCostWet();
+            partSim.baseCost = partSim.part.GetCostDry();
+
+            if (log != null)
+            {
+                log.buf.AppendLine("Parent part = " + (partSim.part.parent == null ? "null" : partSim.part.parent.partInfo.name));
+                log.buf.AppendLine("physicalSignificance = " + partSim.part.physicalSignificance);
+                log.buf.AppendLine("PhysicsSignificance = " + partSim.part.PhysicsSignificance);
+            }
 
             // Work out if the part should have no physical significance
-            partSim.isNoPhysics = partSim.part.HasModule<LaunchClamp>() ||
-                               partSim.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
-                               partSim.part.PhysicsSignificance == 1;
-
-            if (!partSim.isNoPhysics)
-            {
-                partSim.baseMass = partSim.part.mass;
-            }
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print((partSim.isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + partSim.part.mass);
+            // The root part is never "no physics"
+            partSim.isNoPhysics = partSim.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
+                                    partSim.part.PhysicsSignificance == 1;
+
+            if (partSim.part.HasModule<LaunchClamp>())
+            {
+                partSim.realMass = 0d;
+                if (log != null) log.buf.AppendLine("Ignoring mass of launch clamp");
+            }
+            else
+            {
+                partSim.realMass = partSim.part.mass;
+                if (log != null) log.buf.AppendLine("Using part.mass of " + partSim.part.mass);
+            }
+
+            if (partSim.isFairing)
+            {
+                partSim.fairingMass = partSim.part.GetModuleMass((float)partSim.realMass);
             }
 
             for (int i = 0; i < partSim.part.Resources.Count; i++)
@@ -150,21 +160,17 @@
                 // This can happen if a resource capacity is 0 and tweakable
                 if (!Double.IsNaN(resource.amount))
                 {
-                    if (SimManager.logOutput)
-                    {
-                        MonoBehaviour.print(resource.resourceName + " = " + resource.amount);
-                    }
+                    if (log != null)
+                        log.buf.AppendLine(resource.resourceName + " = " + resource.amount);
 
                     partSim.resources.Add(resource.info.id, resource.amount);
                     partSim.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
                 }
                 else
                 {
-                    MonoBehaviour.print(resource.resourceName + " is NaN. Skipping.");
-                }
-            }
-
-            partSim.startMass = partSim.GetMass();
+                    if (log != null) log.buf.AppendLine(resource.resourceName + " is NaN. Skipping.");
+                }
+            }
 
             partSim.hasVessel = (partSim.part.vessel != null);
             partSim.isLanded = partSim.hasVessel && partSim.part.vessel.Landed;
@@ -176,31 +182,33 @@
             partSim.initialVesselName = partSim.part.initialVesselName;
 
             partSim.hasMultiModeEngine = partSim.part.HasModule<MultiModeEngine>();
-            partSim.hasModuleEnginesFX = partSim.part.HasModule<ModuleEnginesFX>();
             partSim.hasModuleEngines = partSim.part.HasModule<ModuleEngines>();
 
-            partSim.isEngine = partSim.hasMultiModeEngine || partSim.hasModuleEnginesFX || partSim.hasModuleEngines;
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print("Created " + partSim.name + ". Decoupled in stage " + partSim.decoupledInStage);
-            }
+            partSim.isEngine = partSim.hasMultiModeEngine || partSim.hasModuleEngines;
+
+            if (log != null) log.buf.AppendLine("Created " + partSim.name + ". Decoupled in stage " + partSim.decoupledInStage);
+
             return partSim;
         }
 
+        public ResourceContainer ResourceDrains
+        {
+            get
+            {
+                return resourceDrains;
+            }
+        }
+
         public ResourceContainer Resources
         {
-            get { return this.resources; }
-        }
-
-        public ResourceContainer ResourceDrains
-        {
-            get { return this.resourceDrains; }
+            get
+            {
+                return resources;
+            }
         }
 
         public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
         {
-            bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(this.part);
             if (log != null)
             {
                 log.buf.AppendLine("CreateEngineSims for " + this.name);
@@ -209,33 +217,28 @@
                     PartModule partMod = this.part.Modules[i];
                     log.buf.AppendLine("Module: " + partMod.moduleName);
                 }
-
-                log.buf.AppendLine("correctThrust = " + correctThrust);
-            }
-
-            if (this.hasMultiModeEngine)
-            {
-                // A multi-mode engine has multiple ModuleEnginesFX but only one is active at any point
-                // The mode of the engine is the engineID of the ModuleEnginesFX that is active
-                string mode = this.part.GetModule<MultiModeEngine>().mode;
-
-                List<ModuleEnginesFX> enginesFx = this.part.GetModules<ModuleEnginesFX>();
-                for (int i = 0; i < enginesFx.Count; i++)
-                {
-                    ModuleEnginesFX engine = enginesFx[i];
+            }
+
+            if (hasMultiModeEngine)
+            {
+                // A multi-mode engine has multiple ModuleEngines but only one is active at any point
+                // The mode of the engine is the engineID of the ModuleEngines that is active
+                string mode = part.GetModule<MultiModeEngine>().mode;
+
+                List<ModuleEngines> engines = part.GetModules<ModuleEngines>();
+                for (int i = 0; i < engines.Count; ++i)
+                {
+                    ModuleEngines engine = engines[i];
                     if (engine.engineID == mode)
                     {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Module: " + engine.moduleName);
-                        }
+                        if (log != null) log.buf.AppendLine("Module: " + engine.moduleName);
 
                         Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
 
                         EngineSim engineSim = EngineSim.New(
                             this,
                             atmosphere,
-                            mach,
+                            (float)mach,
                             engine.maxFuelFlow,
                             engine.minFuelFlow,
                             engine.thrustPercentage,
@@ -249,48 +252,44 @@
                             engine.throttleLocked || fullThrust,
                             engine.propellants,
                             engine.isOperational,
-                            correctThrust,
-                            engine.thrustTransforms);
+                            engine.resultingThrust,
+                            engine.thrustTransforms,
+                            log);
                         allEngines.Add(engineSim);
                     }
                 }
             }
-            else
-            {
-                if (this.hasModuleEngines)
-                {
-                    List<ModuleEngines> engines = this.part.GetModules<ModuleEngines>();  // only place that still allocate some memory
-                    for (int i = 0; i < engines.Count; i++)
-                    {
-                        ModuleEngines engine = engines[i];
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Module: " + engine.moduleName);
-                        }
-
-                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
-                        EngineSim engineSim = EngineSim.New(
-                            this,
-                            atmosphere,
-                            mach,
-                            engine.maxFuelFlow,
-                            engine.minFuelFlow,
-                            engine.thrustPercentage,
-                            thrustvec,
-                            engine.atmosphereCurve,
-                            engine.atmChangeFlow,
-                            engine.useAtmCurve ? engine.atmCurve : null,
-                            engine.useVelCurve ? engine.velCurve : null,
-                            engine.currentThrottle,
-                            engine.g,
-                            engine.throttleLocked || fullThrust,
-                            engine.propellants,
-                            engine.isOperational,
-                            correctThrust,
-                            engine.thrustTransforms);
-                        allEngines.Add(engineSim);
-                    }
+            else if (hasModuleEngines)
+            {
+                List<ModuleEngines> engines = part.GetModules<ModuleEngines>();
+                for (int i = 0; i < engines.Count; ++i)
+                {
+                    ModuleEngines engine = engines[i];
+                    if (log != null) log.buf.AppendLine("Module: " + engine.moduleName);
+
+                    Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
+
+                    EngineSim engineSim = EngineSim.New(
+                        this,
+                        atmosphere,
+                        (float)mach,
+                        engine.maxFuelFlow,
+                        engine.minFuelFlow,
+                        engine.thrustPercentage,
+                        thrustvec,
+                        engine.atmosphereCurve,
+                        engine.atmChangeFlow,
+                        engine.useAtmCurve ? engine.atmCurve : null,
+                        engine.useVelCurve ? engine.velCurve : null,
+                        engine.currentThrottle,
+                        engine.g,
+                        engine.throttleLocked || fullThrust,
+                        engine.propellants,
+                        engine.isOperational,
+                        engine.resultingThrust,
+                        engine.thrustTransforms,
+                        log);
+                    allEngines.Add(engineSim);
                 }
             }
 
@@ -300,183 +299,148 @@
             }
         }
 
-        private Vector3 CalculateThrustVector(List<Transform> thrustTransforms, LogMsg log)
-        {
-            if (thrustTransforms == null)
-            {
-                return Vector3.forward;
-            }
-
-            Vector3 thrustvec = Vector3.zero;
-            for (int i = 0; i < thrustTransforms.Count; i++)
-            {
-                Transform trans = thrustTransforms[i];
-                if (log != null)
-                {
-                    log.buf.AppendFormat(
-                        "Transform = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n",
-                        trans.forward.x,
-                        trans.forward.y,
-                        trans.forward.z,
-                        trans.forward.magnitude);
-                }
-
-                thrustvec -= trans.forward;
-            }
-
-            if (log != null)
-            {
-                log.buf.AppendFormat("ThrustVec  = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
-            }
-
-            thrustvec.Normalize();
-
-            if (log != null)
-            {
-                log.buf.AppendFormat("ThrustVecN = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
-            }
-
-            return thrustvec;
-        }
-
-        public void SetupParent(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
-        {
-            if (this.part.parent != null)
-            {
-                this.parent = null;
-                if (partSimLookup.TryGetValue(this.part.parent, out this.parent))
-                {
-                    if (log != null)
-                    {
-                        log.buf.AppendLine("Parent part is " + this.parent.name + ":" + this.parent.partId);
-                    }
-                }
-                else
-                {
-                    if (log != null)
-                    {
-                        log.buf.AppendLine("No PartSim for parent part (" + this.part.parent.partInfo.name + ")");
-                    }
-                }
-            }
-        }
-
-        public void SetupAttachNodes(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
-        {
-            if (log != null)
-            {
-                log.buf.AppendLine("SetupAttachNodes for " + this.name + ":" + this.partId + "");
-            }
-
-            this.attachNodes.Clear();
-            for (int i = 0; i < this.part.attachNodes.Count; i++)
-            {
-                AttachNode attachNode = this.part.attachNodes[i];
-                if (log != null)
-                {
-                    log.buf.AppendLine(
-                        "AttachNode " + attachNode.id + " = " +
-                        (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null"));
-                }
-
-                if (attachNode.attachedPart != null && attachNode.id != "Strut")
-                {
-                    PartSim attachedSim;
-                    if (partSimLookup.TryGetValue(attachNode.attachedPart, out attachedSim))
-                    {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + "");
-                        }
-
-                        AttachNodeSim attachnode = AttachNodeSim.New(attachedSim, attachNode.id, attachNode.nodeType);
-                        this.attachNodes.Add(attachnode);
-                    }
-                    else
-                    {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("No PartSim for attached part (" + attachNode.attachedPart.partInfo.name + ")");
-                        }
-                    }
-                }
-            }
-
-            for (int i = 0; i < this.part.fuelLookupTargets.Count; i++)
-            {
-                Part p = this.part.fuelLookupTargets[i];
-                if (p != null)
-                {
-                    PartSim targetSim;
-                    if (partSimLookup.TryGetValue(p, out targetSim))
-                    {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Fuel target: " + targetSim.name + ":" + targetSim.partId);
-                        }
-
-                        this.fuelTargets.Add(targetSim);
-                    }
-                    else
-                    {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("No PartSim for fuel target (" + p.name + ")");
-                        }
-                    }
-                }
-            }
-        }
-
-        private int DecoupledInStage(Part thePart, int stage = -1)
-        {
-            if (this.IsDecoupler(thePart))
-            {
-                if (thePart.inverseStage > stage)
-                {
-                    stage = thePart.inverseStage;
-                }
-            }
-
-            if (thePart.parent != null)
-            {
-                stage = this.DecoupledInStage(thePart.parent, stage);
-            }
-
-            return stage;
-        }
-
-        private bool IsDecoupler(Part thePart)
-        {
-            return thePart.HasModule<ModuleDecouple>() ||
-                   thePart.HasModule<ModuleAnchoredDecoupler>();
-        }
-
-        private bool IsActiveDecoupler(Part thePart)
-        {
-            return thePart.FindModulesImplementing<ModuleDecouple>().Any(mod => !mod.isDecoupled) ||
-                   thePart.FindModulesImplementing<ModuleAnchoredDecoupler>().Any(mod => !mod.isDecoupled);
-        }
-
-        private bool IsSepratron()
-        {
-            if (!this.part.ActivatesEvenIfDisconnected)
-            {
-                return false;
-            }
-
-            if (this.part is SolidRocket)
-            {
-                return true;
-            }
-
-            if (!this.part.IsEngine())
-            {
-                return false;
-            }
-
-
-            return this.part.IsSolidRocket();
+        public int DecouplerCount()
+        {
+            int count = 0;
+            PartSim partSim = this;
+            while (partSim != null)
+            {
+                if (partSim.isDecoupler)
+                {
+                    count++;
+                }
+
+                partSim = partSim.parent;
+            }
+            return count;
+        }
+
+        public void DrainResources(double time)
+        {
+            //MonoBehaviour.print("DrainResources(" + name + ":" + partId + ", " + time + ")");
+            for (int i = 0; i < resourceDrains.Types.Count; ++i)
+            {
+                int type = resourceDrains.Types[i];
+
+                //MonoBehaviour.print("draining " + (time * resourceDrains[type]) + " " + ResourceContainer.GetResourceName(type));
+                resources.Add(type, -time * resourceDrains[type]);
+                //MonoBehaviour.print(ResourceContainer.GetResourceName(type) + " left = " + resources[type]);
+            }
+        }
+
+        public String DumpPartAndParentsToBuffer(StringBuilder buffer, String prefix)
+        {
+            if (parent != null)
+            {
+                prefix = parent.DumpPartAndParentsToBuffer(buffer, prefix) + " ";
+            }
+
+            DumpPartToBuffer(buffer, prefix);
+
+            return prefix;
+        }
+
+        public void DumpPartToBuffer(StringBuilder buffer, String prefix, List<PartSim> allParts = null)
+        {
+            buffer.Append(prefix);
+            buffer.Append(name);
+            buffer.AppendFormat(":[id = {0:d}, decouple = {1:d}, invstage = {2:d}", partId, decoupledInStage, inverseStage);
+
+            //buffer.AppendFormat(", vesselName = '{0}'", vesselName);
+            //buffer.AppendFormat(", vesselType = {0}", SimManager.GetVesselTypeString(vesselType));
+            //buffer.AppendFormat(", initialVesselName = '{0}'", initialVesselName);
+
+            buffer.AppendFormat(", isNoPhys = {0}", isNoPhysics);
+            buffer.AppendFormat(", baseMass = {0}", baseMass);
+            buffer.AppendFormat(", baseMassForCoM = {0}", baseMassForCoM);
+
+            buffer.AppendFormat(", fuelCF = {0}", fuelCrossFeed);
+            buffer.AppendFormat(", noCFNKey = '{0}'", noCrossFeedNodeKey);
+
+            buffer.AppendFormat(", isSep = {0}", isSepratron);
+
+            for (int i = 0; i < resources.Types.Count; i++)
+            {
+                int type = resources.Types[i];
+                buffer.AppendFormat(", {0} = {1:g6}", ResourceContainer.GetResourceName(type), resources[type]);
+            }
+
+            if (attachNodes.Count > 0)
+            {
+                buffer.Append(", attached = <");
+                attachNodes[0].DumpToBuffer(buffer);
+                for (int i = 1; i < attachNodes.Count; i++)
+                {
+                    buffer.Append(", ");
+                    attachNodes[i].DumpToBuffer(buffer);
+                }
+                buffer.Append(">");
+            }
+
+            // Add more info here
+
+            buffer.Append("]\n");
+
+            if (allParts != null)
+            {
+                String newPrefix = prefix + " ";
+                for (int i = 0; i < allParts.Count; i++)
+                {
+                    PartSim partSim = allParts[i];
+                    if (partSim.parent == this)
+                        partSim.DumpPartToBuffer(buffer, newPrefix, allParts);
+                }
+            }
+        }
+
+        public bool EmptyOf(HashSet<int> types)
+        {
+            foreach (int type in types)
+            {
+                if (resources.HasType(type) && resourceFlowStates[type] != 0 && resources[type] > SimManager.RESOURCE_PART_EMPTY_THRESH)
+                    return false;
+            }
+
+            return true;
+        }
+
+        public double GetMass(int currentStage, bool forCoM = false)
+        {
+            if (decoupledInStage >= currentStage)
+                return 0d;
+
+            double mass = forCoM ? baseMassForCoM : baseMass;
+
+            for (int i = 0; i < resources.Types.Count; ++i)
+            {
+                mass += resources.GetResourceMass(resources.Types[i]);
+            }
+
+            if (hasVessel == false && isFairing && currentStage > inverseStage)
+            {
+                mass += fairingMass;
+            }
+            else if (hasVessel && isFairing && currentStage <= inverseStage)
+            {
+                mass -= fairingMass;
+            }
+
+            return mass;
+        }
+
+        public double GetCost(int currentStage)
+        {
+            if (decoupledInStage >= currentStage)
+                return 0d;
+
+            double cost = baseCost;
+
+            for (int i = 0; i < resources.Types.Count; ++i)
+            {
+                cost += resources.GetResourceCost(resources.Types[i]);
+            }
+
+            return cost;
         }
 
         public void ReleasePart()
@@ -491,56 +455,48 @@
         {
             if (log != null)
             {
-                log.buf.AppendLine(indent + "GetSourceSet(" + ResourceContainer.GetResourceName(type) + ") for " + this.name + ":" + this.partId);
+                log.buf.AppendLine(indent + "GetSourceSet(" + ResourceContainer.GetResourceName(type) + ") for " + name + ":" + partId);
                 indent += "  ";
             }
 
             // Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns as is.
             if (visited.Contains(this))
             {
-                if (log != null)
-                {
-                    log.buf.AppendLine(indent + "Returning empty set, already visited (" + this.name + ":" + this.partId + ")");
-                }
-
+                if (log != null) log.buf.AppendLine(indent + "Returning empty set, already visited (" + name + ":" + partId + ")");
                 return;
             }
 
-            //if (log != null)
-            //    log.buf.AppendLine(indent + "Adding this to visited");
+            if (log != null) log.buf.AppendLine(indent + "Adding this to visited");
 
             visited.Add(this);
 
             // Rule 2: Part performs scan on start of every fuel pipe ending in it. This scan is done in order in which pipes were installed.
             // Then it makes an union of fuel tank sets each pipe scan returned. If the resulting list is not empty, it is returned as result.
-            //MonoBehaviour.print("foreach fuel line");
+            //MonoBehaviour.print("for each fuel line");
 
             int lastCount = allSources.Count;
 
             for (int i = 0; i < this.fuelTargets.Count; i++)
             {
                 PartSim partSim = this.fuelTargets[i];
-                if (visited.Contains(partSim))
-                {
-                    //if (log != null)
-                    //    log.buf.AppendLine(indent + "Fuel target already visited, skipping (" + partSim.name + ":" + partSim.partId + ")");
-                }
-                else
-                {
-                    //if (log != null)
-                    //    log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
-
-                    partSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
+                if (partSim != null)
+                {
+                    if (visited.Contains(partSim))
+                    {
+                        if (log != null) log.buf.AppendLine(indent + "Fuel target already visited, skipping (" + partSim.name + ":" + partSim.partId + ")");
+                    }
+                    else
+                    {
+                        if (log != null) log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
+
+                        partSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
+                    }
                 }
             }
 
             if (allSources.Count > lastCount)
             {
-                if (log != null)
-                {
-                    log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " fuel target sources (" + this.name + ":" + this.partId + ")");
-                }
-
+                if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " fuel target sources (" + this.name + ":" + this.partId + ")");
                 return;
             }
 
@@ -552,10 +508,10 @@
             //  skip the points on the side where multiple points are. [Experiment]
             //  Again, the part creates union of scan lists from each of its neighbor and if it is not empty, returns this list. 
             //  The order in which mount points of a part are scanned appears to be fixed and defined by the part specification file. [Experiment]
-            if (this.fuelCrossFeed)
+            if (fuelCrossFeed)
             {
                 lastCount = allSources.Count;
-                //MonoBehaviour.print("foreach attach node");
+                //MonoBehaviour.print("for each attach node");
                 for (int i = 0; i < this.attachNodes.Count; i++)
                 {
                     AttachNodeSim attachSim = this.attachNodes[i];
@@ -569,13 +525,11 @@
                             {
                                 if (visited.Contains(attachSim.attachedPartSim))
                                 {
-                                    //if (log != null)
-                                    //    log.buf.AppendLine(indent + "Attached part already visited, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
+                                    if (log != null) log.buf.AppendLine(indent + "Attached part already visited, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
                                 }
                                 else
                                 {
-                                    //if (log != null)
-                                    //    log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
+                                    if (log != null) log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
 
                                     attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
                                 }
@@ -586,11 +540,7 @@
 
                 if (allSources.Count > lastCount)
                 {
-                    if (log != null)
-                    {
-                        log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " attached sources (" + this.name + ":" + this.partId + ")");
-                    }
-
+                    if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " attached sources (" + this.name + ":" + this.partId + ")");
                     return;
                 }
             }
@@ -599,31 +549,31 @@
             // type was not disabled [Experiment]) and it contains fuel, it returns itself.
             // Rule 6: If the part is fuel container for searched type of fuel (i.e. it has capability to contain that type of fuel and the fuel 
             // type was not disabled) but it does not contain the requested fuel, it returns empty list. [Experiment]
-            if (this.resources.HasType(type) && this.resourceFlowStates[type] != 0)
-            {
-                if (this.resources[type] > SimManager.RESOURCE_MIN)
+            if (resources.HasType(type) && resourceFlowStates[type] != 0)
+            {
+                if (resources[type] > SimManager.RESOURCE_MIN)
                 {
                     allSources.Add(this);
 
-                    if (log != null)
-                    {
-                        log.buf.AppendLine(indent + "Returning enabled tank as only source (" + this.name + ":" + this.partId + ")");
-                    }
+                    if (log != null) log.buf.AppendLine(indent + "Returning enabled tank as only source (" + name + ":" + partId + ")");
                 }
 
                 return;
+            }
+            else
+            {
+                if (log != null) log.buf.AppendLine(indent + "Not fuel tank or disabled. HasType = " + resources.HasType(type) + "  FlowState = " + resourceFlowStates[type]);
             }
 
             // Rule 7: If the part is radially attached to another part and it is child of that part in the ship's tree structure, it scans its 
             // parent and returns whatever the parent scan returned. [Experiment] [Experiment]
-            if (this.parent != null && this.parentAttach == AttachModes.SRF_ATTACH)
-            {
-                if (this.fuelCrossFeed)
-                {
-                    if (visited.Contains(this.parent))
-                    {
-                        //if (log != null)
-                        //    log.buf.AppendLine(indent + "Parent part already visited, skipping (" + parent.name + ":" + parent.partId + ")");
+            if (parent != null && parentAttach == AttachModes.SRF_ATTACH)
+            {
+                if (fuelCrossFeed)
+                {
+                    if (visited.Contains(parent))
+                    {
+                        if (log != null) log.buf.AppendLine(indent + "Parent part already visited, skipping (" + parent.name + ":" + parent.partId + ")");
                     }
                     else
                     {
@@ -631,11 +581,7 @@
                         this.parent.GetSourceSet(type, allParts, visited, allSources, log, indent);
                         if (allSources.Count > lastCount)
                         {
-                            if (log != null)
-                            {
-                                log.buf.AppendLine(indent + "Returning " + (allSources.Count  - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")");
-                            }
-
+                            if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count  - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")");
                             return;
                         }
                     }
@@ -643,10 +589,14 @@
             }
 
             // Rule 8: If all preceding rules failed, part returns empty list.
-            //if (log != null)
-            //    log.buf.AppendLine(indent + "Returning empty set, no sources found (" + name + ":" + partId + ")");
+            if (log != null) log.buf.AppendLine(indent + "Returning empty set, no sources found (" + name + ":" + partId + ")");
 
             return;
+        }
+
+        public double GetStartMass()
+        {
+            return startMass;
         }
 
         public void RemoveAttachedParts(HashSet<PartSim> partSims)
@@ -661,17 +611,81 @@
                     attachSim.attachedPartSim = null;
                 }
             }
-        }
-
-        public void DrainResources(double time)
-        {
-            //MonoBehaviour.print("DrainResources(" + name + ":" + partId + ", " + time + ")");
-            for (int i = 0; i < this.resourceDrains.Types.Count; i++)
-            {
-                int type = this.resourceDrains.Types[i];
-                //MonoBehaviour.print("draining " + (time * resourceDrains[type]) + " " + ResourceContainer.GetResourceName(type));
-                this.resources.Add(type, -time * this.resourceDrains[type]);
-                //MonoBehaviour.print(ResourceContainer.GetResourceName(type) + " left = " + resources[type]);
+
+            // Loop through the fuel targets (fuel line sources)
+            for (int i = 0; i < this.fuelTargets.Count; i++)
+            {
+                PartSim fuelTargetSim = this.fuelTargets[i];
+                // If the part is in the set then "remove" it by clearing the PartSim reference
+                if (fuelTargetSim != null && partSims.Contains(fuelTargetSim))
+                {
+                    this.fuelTargets[i] = null;
+                }
+            }
+        }
+
+        public void SetupAttachNodes(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
+        {
+            if (log != null) log.buf.AppendLine("SetupAttachNodes for " + name + ":" + partId + "");
+
+            attachNodes.Clear();
+
+            for (int i = 0; i < part.attachNodes.Count; ++i)
+            {
+                AttachNode attachNode = part.attachNodes[i];
+
+                if (log != null) log.buf.AppendLine("AttachNode " + attachNode.id + " = " + (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null"));
+
+                if (attachNode.attachedPart != null && attachNode.id != "Strut")
+                {
+                    PartSim attachedSim;
+                    if (partSimLookup.TryGetValue(attachNode.attachedPart, out attachedSim))
+                    {
+                        if (log != null) log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + "");
+
+                        attachNodes.Add(AttachNodeSim.New(attachedSim, attachNode.id, attachNode.nodeType));
+                    }
+                    else
+                    {
+                        if (log != null) log.buf.AppendLine("No PartSim for attached part (" + attachNode.attachedPart.partInfo.name + ")");
+                    }
+                }
+            }
+
+            for (int i = 0; i < part.fuelLookupTargets.Count; ++i)
+            {
+                Part p = part.fuelLookupTargets[i];
+
+                if (p != null)
+                {
+                    PartSim targetSim;
+                    if (partSimLookup.TryGetValue(p, out targetSim))
+                    {
+                        if (log != null) log.buf.AppendLine("Fuel target: " + targetSim.name + ":" + targetSim.partId);
+
+                        fuelTargets.Add(targetSim);
+                    }
+                    else
+                    {
+                        if (log != null) log.buf.AppendLine("No PartSim for fuel target (" + p.name + ")");
+                    }
+                }
+            }
+        }
+
+        public void SetupParent(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
+        {
+            if (part.parent != null)
+            {
+                parent = null;
+                if (partSimLookup.TryGetValue(part.parent, out parent))
+                {
+                    if (log != null) log.buf.AppendLine("Parent part is " + parent.name + ":" + parent.partId);
+                }
+                else
+                {
+                    if (log != null) log.buf.AppendLine("No PartSim for parent part (" + part.parent.partInfo.name + ")");
+                }
             }
         }
 
@@ -680,12 +694,13 @@
             //MonoBehaviour.print("TimeToDrainResource(" + name + ":" + partId + ")");
             double time = double.MaxValue;
 
-            for (int i = 0; i < this.resourceDrains.Types.Count; i++)
-            {
-                int type = this.resourceDrains.Types[i];
-                if (this.resourceDrains[type] > 0)
-                {
-                    time = Math.Min(time, this.resources[type] / this.resourceDrains[type]);
+            for (int i = 0; i < resourceDrains.Types.Count; ++i)
+            {
+                int type = resourceDrains.Types[i];
+
+                if (resourceDrains[type] > 0)
+                {
+                    time = Math.Min(time, resources[type] / resourceDrains[type]);
                     //MonoBehaviour.print("type = " + ResourceContainer.GetResourceName(type) + "  amount = " + resources[type] + "  rate = " + resourceDrains[type] + "  time = " + time);
                 }
             }
@@ -695,114 +710,84 @@
             return time;
         }
 
-        public bool EmptyOf(HashSet<int> types)
-        {
-            foreach (int type in types)
-            {
-                if (this.resources.HasType(type) && this.resourceFlowStates[type] != 0 && (double)this.resources[type] > SimManager.RESOURCE_MIN)
-                {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-        public int DecouplerCount()
-        {
-            int count = 0;
-            PartSim partSim = this;
-            while (partSim != null)
-            {
-                if (partSim.isDecoupler)
-                {
-                    count++;
-                }
-
-                partSim = partSim.parent;
-            }
-            return count;
-        }
-
-        public double GetStartMass()
-        {
-            return this.startMass;
-        }
-
-        public double GetMass()
-        {
-            double mass = this.baseMass;
-
-            for (int i = 0; i < this.resources.Types.Count; i++)
-            {
-                int type = this.resources.Types[i];
-                mass += this.resources.GetResourceMass(type);
-            }
-
-            return mass;
-        }
-
-        public String DumpPartAndParentsToBuffer(StringBuilder buffer, String prefix)
-        {
-            if (this.parent != null)
-            {
-                prefix = this.parent.DumpPartAndParentsToBuffer(buffer, prefix) + " ";
-            }
-
-            this.DumpPartToBuffer(buffer, prefix);
-
-            return prefix;
-        }
-
-        public void DumpPartToBuffer(StringBuilder buffer, String prefix, List<PartSim> allParts = null)
-        {
-            buffer.Append(prefix);
-            buffer.Append(this.name);
-            buffer.AppendFormat(":[id = {0:d}, decouple = {1:d}, invstage = {2:d}", this.partId, this.decoupledInStage, this.inverseStage);
-
-            buffer.AppendFormat(", vesselName = '{0}'", this.vesselName);
-            buffer.AppendFormat(", vesselType = {0}", SimManager.GetVesselTypeString(this.vesselType));
-            buffer.AppendFormat(", initialVesselName = '{0}'", this.initialVesselName);
-
-            buffer.AppendFormat(", fuelCF = {0}", this.fuelCrossFeed);
-            buffer.AppendFormat(", noCFNKey = '{0}'", this.noCrossFeedNodeKey);
-
-            buffer.AppendFormat(", isSep = {0}", this.isSepratron);
-
-            for (int i = 0; i < this.resources.Types.Count; i++)
-            {
-                int type = this.resources.Types[i];
-                buffer.AppendFormat(", {0} = {1:g6}", ResourceContainer.GetResourceName(type), this.resources[type]);
-            }
-
-            if (this.attachNodes.Count > 0)
-            {
-                buffer.Append(", attached = <");
-                this.attachNodes[0].DumpToBuffer(buffer);
-                for (int i = 1; i < this.attachNodes.Count; i++)
-                {
-                    buffer.Append(", ");
-                    this.attachNodes[i].DumpToBuffer(buffer);
-                }
-                buffer.Append(">");
-            }
-
-            // Add more info here
-
-            buffer.Append("]\n");
-
-            if (allParts != null)
-            {
-                String newPrefix = prefix + " ";
-                for (int i = 0; i < allParts.Count; i++)
-                {
-                    PartSim partSim = allParts[i];
-                    if (partSim.parent == this)
-                    {
-                        partSim.DumpPartToBuffer(buffer, newPrefix, allParts);
-                    }
-                }
-            }
+        private Vector3 CalculateThrustVector(List<Transform> thrustTransforms, LogMsg log)
+        {
+            if (thrustTransforms == null)
+            {
+                return Vector3.forward;
+            }
+
+            Vector3 thrustvec = Vector3.zero;
+            for (int i = 0; i < thrustTransforms.Count; ++i)
+            {
+                Transform trans = thrustTransforms[i];
+
+                if (log != null) log.buf.AppendFormat("Transform = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", trans.forward.x, trans.forward.y, trans.forward.z, trans.forward.magnitude);
+
+                thrustvec -= trans.forward;
+            }
+
+            if (log != null) log.buf.AppendFormat("ThrustVec  = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
+
+            thrustvec.Normalize();
+
+            if (log != null) log.buf.AppendFormat("ThrustVecN = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
+
+            return thrustvec;
+        }
+
+        private int DecoupledInStage(Part thePart, int stage = -1)
+        {
+            if (IsDecoupler(thePart) && thePart.inverseStage > stage)
+                stage = thePart.inverseStage;
+
+            if (thePart.parent != null)
+                stage = DecoupledInStage(thePart.parent, stage);
+
+            return stage;
+        }
+
+        private bool IsActiveDecoupler(Part thePart)
+        {
+            return thePart.FindModulesImplementing<ModuleDecouple>().Any(mod => !mod.isDecoupled) ||
+                   thePart.FindModulesImplementing<ModuleAnchoredDecoupler>().Any(mod => !mod.isDecoupled);
+        }
+
+        private bool IsDecoupler(Part thePart)
+        {
+            return thePart.HasModule<ModuleDecouple>() ||
+                   thePart.HasModule<ModuleAnchoredDecoupler>();
+        }
+
+        private bool IsFairing(Part thePart)
+        {
+            return thePart.HasModule<ModuleProceduralFairing>();
+        }
+
+        private bool IsSepratron()
+        {
+            if (!part.ActivatesEvenIfDisconnected)
+            {
+                return false;
+            }
+
+            if (part is SolidRocket)
+            {
+                return true;
+            }
+
+            IEnumerable<ModuleEngines> modList = part.Modules.OfType<ModuleEngines>();
+            if (modList.Count() == 0)
+            {
+                return false;
+            }
+
+            if (modList.First().throttleLocked)
+            {
+                return true;
+            }
+
+            return false;
         }
     }
 }

--- a/KerbalEngineer/VesselSimulator/ResourceContainer.cs
+++ b/KerbalEngineer/VesselSimulator/ResourceContainer.cs
@@ -150,6 +150,12 @@
             return density == 0d ? 0d : this.resources[type] * density;
         }
 
+        public double GetResourceCost(int type)
+        {
+            double unitCost = GetResourceUnitCost(type);
+            return unitCost == 0d ? 0d : this.resources[type] * unitCost;
+        }
+
         public static ResourceFlowMode GetResourceFlowMode(int type)
         {
             return PartResourceLibrary.Instance.GetDefinition(type).resourceFlowMode;
@@ -157,7 +163,7 @@
 
         public static ResourceTransferMode GetResourceTransferMode(int type)
         {
-            return PartResourceLibrary.Instance.GetDefinition(type).resourceTransferMode;;
+            return PartResourceLibrary.Instance.GetDefinition(type).resourceTransferMode;
         }
 
         public static float GetResourceDensity(int type)
@@ -169,5 +175,10 @@
         {
             return PartResourceLibrary.Instance.GetDefinition(type).name;
         }
+
+        public static double GetResourceUnitCost(int type)
+        {
+            return PartResourceLibrary.Instance.GetDefinition(type).unitCost;
+        }
     }
 }

--- a/KerbalEngineer/VesselSimulator/SimManager.cs
+++ b/KerbalEngineer/VesselSimulator/SimManager.cs
@@ -22,6 +22,7 @@
     #region Using Directives
 
     using System;
+    using System.Collections.Generic;
     using System.Diagnostics;
     using System.Reflection;
     using System.Threading;
@@ -34,6 +35,7 @@
         #region Constants
 
         public const double RESOURCE_MIN = 0.0001;
+        public const double RESOURCE_PART_EMPTY_THRESH = 0.01;
 
         #endregion
 
@@ -60,6 +62,9 @@
         private static bool hasInstalledKIDS;
         private static MethodInfo KIDS_Utils_GetIspMultiplier;
         private static bool bKIDSThrustISP = false;
+        private static List<Part> parts = new List<Part>(); 
+
+        private static Simulation simulation = new Simulation();
         #endregion
 
         #region Delegates
@@ -283,6 +288,7 @@
             try
             {
                 Stages = (simObject as Simulation).RunSimulation();
+
                 if (Stages != null && Stages.Length > 0)
                 {
                     if (logOutput)
@@ -297,8 +303,7 @@
             }
             catch (Exception e)
             {
-                MonoBehaviour.print("Exception in RunSimulation: " + e);
-                Logger.Exception(e);
+                Logger.Exception(e, "SimManager.RunSimulation()");
                 Stages = null;
                 LastStage = null;
                 failMessage = e.ToString();
@@ -350,15 +355,21 @@
                     timer.Start();
                 }
 
-                var parts = HighLogic.LoadedSceneIsEditor ? EditorLogic.fetch.ship.parts : FlightGlobals.ActiveVessel.Parts;
-
-                // Create the Simulation object in this thread
-                var sim = new Simulation();
+                if (HighLogic.LoadedSceneIsEditor)
+                {
+                    parts = EditorLogic.fetch.ship.parts;
+                }
+                else
+                {
+                    parts = FlightGlobals.ActiveVessel.Parts;
+                    Atmosphere = FlightGlobals.ActiveVessel.staticPressurekPa * PhysicsGlobals.KpaToAtmospheres;
+                }
 
                 // This call doesn't ever fail at the moment but we'll check and return a sensible error for display
-                if (sim.PrepareSimulation(parts, Gravity, Atmosphere, Mach, dumpTree, vectoredThrust))
-                {
-                    ThreadPool.QueueUserWorkItem(RunSimulation, sim);
+                if (simulation.PrepareSimulation(parts, Gravity, Atmosphere, Mach, dumpTree, vectoredThrust))
+                {
+                    ThreadPool.QueueUserWorkItem(RunSimulation, simulation);
+                    //RunSimulation(simulation);
                 }
                 else
                 {
@@ -372,8 +383,7 @@
             }
             catch (Exception e)
             {
-                MonoBehaviour.print("Exception in StartSimulation: " + e);
-                Logger.Exception(e);
+                Logger.Exception(e, "SimManager.StartSimulation()");
                 failMessage = e.ToString();
                 lock (locker)
                 {

--- a/KerbalEngineer/VesselSimulator/Simulation.cs
+++ b/KerbalEngineer/VesselSimulator/Simulation.cs
@@ -30,18 +30,19 @@
 
 namespace KerbalEngineer.VesselSimulator
 {
+    using System.ComponentModel;
     using CompoundParts;
     using Extensions;
+    using Helpers;
 
     public class Simulation
     {
-        private const double STD_GRAVITY = 9.82;
         private const double SECONDS_PER_DAY = 86400;
         private readonly Stopwatch _timer = new Stopwatch();
-        private List<EngineSim> activeEngines;
-        private List<EngineSim> allEngines;
-        private List<PartSim> allFuelLines;
-        private List<PartSim> allParts;
+        private List<EngineSim> activeEngines = new List<EngineSim>();
+        private List<EngineSim> allEngines = new List<EngineSim>();
+        private List<PartSim> allFuelLines = new List<PartSim>();
+        private List<PartSim> allParts = new List<PartSim>();
         private double atmosphere;
         private int currentStage;
         private double currentisp;
@@ -55,7 +56,7 @@
         private Dictionary<Part, PartSim> partSimLookup;
 
         private int lastStage;
-        private List<Part> partList;
+        private List<Part> partList = new List<Part>();
         private double simpleTotalThrust;
         private double stageStartMass;
         private Vector3d stageStartCom;
@@ -66,13 +67,15 @@
         private double totalStageFlowRate;
         private double totalStageIspFlowRate;
         private double totalStageThrust;
-        private ForceAccumulator totalStageThrustForce;
+        private ForceAccumulator totalStageThrustForce = new ForceAccumulator();
         private Vector3 vecActualThrust;
         private Vector3 vecStageDeltaV;
         private Vector3 vecThrust;
         private double mach;
+        private float maxMach;
         public String vesselName;
         public VesselType vesselType;
+        private WeightedVectorAverager vectorAverager = new WeightedVectorAverager();
 
         public Simulation()
         {
@@ -99,10 +102,8 @@
             {
                 double mass = 0d;
 
-                for (int i = 0; i < this.allParts.Count; i++)
-                {
-                    PartSim partSim = this.allParts[i];
-                    mass += partSim.GetMass();
+                for (int i = 0; i < allParts.Count; ++i) { 
+                    mass += allParts[i].GetMass(currentStage);
                 }
 
                 return mass;
@@ -113,15 +114,15 @@
         {
             get
             {
-                WeightedVectorAverager averager = new WeightedVectorAverager();
-
-                for (int i = 0; i < this.allParts.Count; i++)
-                {
-                    PartSim partSim = this.allParts[i];
-                    averager.Add(partSim.centerOfMass, partSim.GetMass());
-                }
-
-                return averager.Get();
+                vectorAverager.Reset();
+
+                for (int i = 0; i < allParts.Count; ++i)
+                {
+                    PartSim partSim = allParts[i];
+                    vectorAverager.Add(partSim.centerOfMass, partSim.GetMass(currentStage, true));
+                }
+
+                return vectorAverager.Get();
             }
         }
 
@@ -138,6 +139,7 @@
                 log.buf.AppendLine("PrepareSimulation started");
                 dumpTree = true;
             }
+            this._timer.Reset();
             this._timer.Start();
 
             // Store the parameters in members for ease of access in other functions
@@ -146,15 +148,16 @@
             this.atmosphere = theAtmosphere;
             this.mach = theMach;
             this.lastStage = Staging.lastStage;
+            this.maxMach = 1.0f;
             //MonoBehaviour.print("lastStage = " + lastStage);
 
             // Clear the lists for our simulation parts
-            this.allParts.Clear();
-            this.allFuelLines.Clear();
-            this.drainingParts.Clear();
-            this.allEngines.Clear();
-            this.activeEngines.Clear();
-            this.drainingResources.Clear();
+            allParts.Clear();
+            allFuelLines.Clear();
+            drainingParts.Clear();
+            allEngines.Clear();
+            activeEngines.Clear();
+            drainingResources.Clear();
 
             // A dictionary for fast lookup of Part->PartSim during the preparation phase
             partSimLookup.Clear();
@@ -167,9 +170,10 @@
             //MonoBehaviour.print("PrepareSimulation pool size = " + PartSim.pool.Count());
             // First we create a PartSim for each Part (giving each a unique id)
             int partId = 1;
-            for (int i = 0; i < this.partList.Count; i++)
-            {
-                Part part = this.partList[i];
+            for (int i = 0; i < partList.Count; ++i)
+            {
+                Part part = partList[i];
+
                 // If the part is already in the lookup dictionary then log it and skip to the next part
                 if (partSimLookup.ContainsKey(part))
                 {
@@ -198,6 +202,11 @@
                 partId++;
             }
 
+            for (int i = 0; i < allEngines.Count; ++i)
+            {
+                maxMach = Mathf.Max(maxMach, allEngines[i].maxMach);
+            }
+
             this.UpdateActiveEngines();
 
             // Now that all the PartSims have been created we can do any set up that needs access to other parts
@@ -211,9 +220,10 @@
             // Then, in the VAB/SPH, we add the parent of each fuel line to the fuelTargets list of their targets
             if (HighLogic.LoadedSceneIsEditor)
             {
-                for (int i = 0; i < this.allFuelLines.Count; i++)
-                {
-                    PartSim partSim = this.allFuelLines[i];
+                for (int i = 0; i < allFuelLines.Count; ++i)
+                {
+                    PartSim partSim = allFuelLines[i];
+
                     CModuleFuelLine fuelLine = partSim.part.GetModule<CModuleFuelLine>();
                     if (fuelLine.target != null)
                     {
@@ -246,9 +256,10 @@
             }
 
             //MonoBehaviour.print("SetupAttachNodes and count stages");
-            for (int i = 0; i < this.allParts.Count; i++)
-            {
-                PartSim partSim = this.allParts[i];
+            for (int i = 0; i < allParts.Count; ++i)
+            {
+                PartSim partSim = allParts[i];
+
                 partSim.SetupAttachNodes(partSimLookup, log);
                 if (partSim.decoupledInStage >= this.lastStage)
                 {
@@ -258,10 +269,9 @@
 
             // And finally release the Part references from all the PartSims
             //MonoBehaviour.print("ReleaseParts");
-            for (int i = 0; i < this.allParts.Count; i++)
-            {
-                PartSim partSim = this.allParts[i];
-                partSim.ReleasePart();
+            for (int i = 0; i < allParts.Count; ++i)
+            { 
+                allParts[i].ReleasePart();
             }
 
             // And dereference the core's part list
@@ -290,6 +300,7 @@
                 MonoBehaviour.print("RunSimulation started");
             }
 
+            this._timer.Reset();
             this._timer.Start();
 
             LogMsg log = null;
@@ -305,9 +316,10 @@
             // currently active engines then generate an extra stage
             // Loop through all the engines
             bool anyActive = false;
-            for (int i = 0; i < this.allEngines.Count; i++)
-            {
-                EngineSim engine = this.allEngines[i];
+            for (int i = 0; i < allEngines.Count; ++i)
+            {
+                EngineSim engine = allEngines[i];
+
                 if (log != null)
                 {
                     log.buf.AppendLine("Testing engine mod of " + engine.partSim.name + ":" + engine.partSim.partId);
@@ -362,7 +374,7 @@
             }
 
             // Create a list of lists of PartSims that prevent decoupling
-            this.BuildDontStageLists(log);
+            BuildDontStageLists(log);
 
             if (log != null)
             {
@@ -372,13 +384,14 @@
             // Create the array of stages that will be returned
             Stage[] stages = new Stage[this.currentStage + 1];
 
+            int startStage = currentStage;
+
             // Loop through the stages
             while (this.currentStage >= 0)
             {
                 if (log != null)
                 {
                     log.buf.AppendLine("Simulating stage " + this.currentStage);
-                    log.buf.AppendLine("ShipMass = " + this.ShipMass);
                     log.Flush();
                     this._timer.Reset();
                     this._timer.Start();
@@ -387,13 +400,18 @@
                 // Update active engines and resource drains
                 this.UpdateResourceDrains();
 
+                // Update the masses of the parts to correctly handle "no physics" parts
+                this.stageStartMass = this.UpdatePartMasses();
+
+                if (log != null)
+                    this.allParts[0].DumpPartToBuffer(log.buf, "", this.allParts);
+
                 // Create the Stage object for this stage
                 Stage stage = new Stage();
 
                 this.stageTime = 0d;
                 this.vecStageDeltaV = Vector3.zero;
 
-                this.stageStartMass = this.ShipMass;
                 this.stageStartCom = this.ShipCom;
 
                 this.stepStartMass = this.stageStartMass;
@@ -403,11 +421,11 @@
 
                 // Store various things in the Stage object
                 stage.thrust = this.totalStageThrust;
-                //MonoBehaviour.print("stage.thrust = " + stage.thrust);
+                if (log != null) log.buf.AppendLine("stage.thrust = " + stage.thrust);
                 stage.thrustToWeight = this.totalStageThrust / (this.stageStartMass * this.gravity);
                 stage.maxThrustToWeight = stage.thrustToWeight;
-                //MonoBehaviour.print("StageMass = " + stageStartMass);
-                //MonoBehaviour.print("Initial maxTWR = " + stage.maxThrustToWeight);
+                if (log != null) log.buf.AppendLine("StageMass = " + stageStartMass);
+                if (log != null) log.buf.AppendLine("Initial maxTWR = " + stage.maxThrustToWeight);
                 stage.actualThrust = this.totalStageActualThrust;
                 stage.actualThrustToWeight = this.totalStageActualThrust / (this.stageStartMass * this.gravity);
 
@@ -432,16 +450,31 @@
 
                 stage.thrustOffsetAngle = Math.Asin(sinThrustOffsetAngle) * 180 / Math.PI;
 
-                // Calculate the cost and mass of this stage and add all engines and tanks that are decoupled
-                // in the next stage to the dontStageParts list
-                for (int i = 0; i < this.allParts.Count; i++)
-                {
-                    PartSim partSim = this.allParts[i];
-                    if (partSim.decoupledInStage == this.currentStage - 1)
-                    {
-                        stage.cost += partSim.cost;
-                        stage.mass += partSim.GetStartMass();
-                    }
+                // Calculate the total cost of the vessel at this point
+                stage.totalCost = 0d;
+                for (int i = 0; i < allParts.Count; ++i)
+                {
+                    if (this.currentStage > allParts[i].decoupledInStage)
+                        stage.totalCost += allParts[i].GetCost(currentStage);
+                }
+
+                // The total mass is simply the mass at the start of the stage
+                stage.totalMass = this.stageStartMass;
+
+                // If we have done a previous stage
+                if (currentStage < startStage)
+                {
+                    // Calculate what the previous stage's mass and cost were by subtraction
+                    Stage prev = stages[currentStage + 1];
+                    prev.cost = prev.totalCost - stage.totalCost;
+                    prev.mass = prev.totalMass - stage.totalMass;
+                }
+
+                // The above code will never run for the last stage so set those directly
+                if (currentStage == 0)
+                {
+                    stage.cost = stage.totalCost;
+                    stage.mass = stage.totalMass;
                 }
 
                 this.dontStageParts = dontStagePartsLists[this.currentStage];
@@ -514,7 +547,7 @@
                     // If we have drained anything and the masses make sense then add this step's deltaV to the stage total
                     if (resourceDrainTime > 0d && this.stepStartMass > this.stepEndMass && this.stepStartMass > 0d && this.stepEndMass > 0d)
                     {
-                        this.vecStageDeltaV += this.vecThrust * (float)((this.currentisp * STD_GRAVITY * Math.Log(this.stepStartMass / this.stepEndMass)) / this.simpleTotalThrust);
+                        this.vecStageDeltaV += this.vecThrust * (float)((this.currentisp * Units.GRAVITY * Math.Log(this.stepStartMass / this.stepEndMass)) / this.simpleTotalThrust);
                     }
 
                     // Update the active engines and resource drains for the next step
@@ -559,7 +592,7 @@
                 // Note: If the mass doesn't change then this is a divide by zero
                 if (this.stageStartMass != this.stepStartMass)
                 {
-                    stage.isp = stage.deltaV / (STD_GRAVITY * Math.Log(this.stageStartMass / this.stepStartMass));
+                    stage.isp = stage.deltaV / (Units.GRAVITY * Math.Log(this.stageStartMass / this.stepStartMass));
                 }
                 else
                 {
@@ -570,6 +603,7 @@
                 stage.time = (this.stageTime < SECONDS_PER_DAY) ? this.stageTime : 0d;
                 stage.number = this.doingCurrent ? -1 : this.currentStage; // Set the stage number to -1 if doing current engines
                 stage.totalPartCount = this.allParts.Count;
+                stage.maxMach = maxMach;
                 stages[this.currentStage] = stage;
 
                 // Now activate the next stage
@@ -603,8 +637,6 @@
                 // For each stage we total up the cost, mass, deltaV and time for this stage and all the stages above
                 for (int j = i; j >= 0; j--)
                 {
-                    stages[i].totalCost += stages[j].cost;
-                    stages[i].totalMass += stages[j].mass;
                     stages[i].totalDeltaV += stages[j].deltaV;
                     stages[i].totalTime += stages[j].time;
                     stages[i].partCount = i > 0 ? stages[i].totalPartCount - stages[i - 1].totalPartCount : stages[i].totalPartCount;
@@ -633,7 +665,52 @@
             return stages;
         }
 
-        
+        public double UpdatePartMasses()
+        {
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                this.allParts[i].baseMass = this.allParts[i].realMass;
+                this.allParts[i].baseMassForCoM = this.allParts[i].realMass;
+            }
+
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim part = this.allParts[i];
+
+                // Check if part should pass it's mass onto its parent.
+                if (part.isNoPhysics && part.parent != null)
+                {
+                    PartSim partParent = part.parent;
+
+                    // Loop through all parents until a physically significant parent is found.
+                    while (partParent != null)
+                    {
+                        // Check if parent is physically significant.
+                        if (partParent.isNoPhysics == false)
+                        {
+                            // Apply the mass to the parent and remove it from the originating part.
+                            partParent.baseMassForCoM += part.baseMassForCoM;
+                            part.baseMassForCoM = 0.0;
+
+                            // Break out of the recursive loop.
+                            break;
+                        }
+
+                        // Recursively loop through the parent parts.
+                        partParent = partParent.parent;
+                    }
+                }
+            }
+
+            double totalMass = 0d;
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                totalMass += this.allParts[i].startMass = this.allParts[i].GetMass(currentStage);
+            }
+
+            return totalMass;
+        }
+
         // Make sure we free them all, even if they should all be free already at this point
         public void FreePooledObject()
         {
@@ -658,18 +735,24 @@
             {
                 log.buf.AppendLine("Creating list with capacity of " + (this.currentStage + 1));
             }
-            
+
+            dontStagePartsLists.Clear();
             for (int i = 0; i <= this.currentStage; i++)
             {
                 if (i < dontStagePartsLists.Count)
+                {
                     dontStagePartsLists[i].Clear();
+                }
                 else
+                {
                     dontStagePartsLists.Add(new List<PartSim>());
-            }
-
-            for (int i = 0; i < this.allParts.Count; i++)
-            {
-                PartSim partSim = this.allParts[i];
+                }
+            }
+
+            for (int i = 0; i < allParts.Count; ++i)
+            {
+                PartSim partSim = allParts[i];
+
                 if (partSim.isEngine || !partSim.Resources.Empty)
                 {
                     if (log != null)
@@ -705,9 +788,9 @@
         private void UpdateActiveEngines()
         {
             this.activeEngines.Clear();
-            for (int i = 0; i < this.allEngines.Count; i++)
-            {
-                EngineSim engine = this.allEngines[i];
+            for (int i = 0; i < allEngines.Count; ++i)
+            {
+                EngineSim engine = allEngines[i];
                 if (engine.isActive)
                 {
                     this.activeEngines.Add(engine);
@@ -726,11 +809,13 @@
             this.totalStageFlowRate = 0d;
             this.totalStageIspFlowRate = 0d;
             this.totalStageThrustForce.Reset();
+
             // Loop through all the active engines totalling the thrust, actual thrust and mass flow rates
             // The thrust is totalled as vectors
-            for (int i = 0; i < this.activeEngines.Count; i++)
-            {
-                EngineSim engine = this.activeEngines[i];
+            for (int i = 0; i < activeEngines.Count; ++i)
+            {
+                EngineSim engine = activeEngines[i];
+
                 this.simpleTotalThrust += engine.thrust;
                 this.vecThrust += ((float)engine.thrust * engine.thrustVec);
                 this.vecActualThrust += ((float)engine.actualThrust * engine.thrustVec);
@@ -738,10 +823,9 @@
                 this.totalStageFlowRate += engine.ResourceConsumptions.Mass;
                 this.totalStageIspFlowRate += engine.ResourceConsumptions.Mass * engine.isp;
 
-                for (int j = 0; j < engine.appliedForces.Count; j++)
-                {
-                    AppliedForce f = engine.appliedForces[j];
-                    this.totalStageThrustForce.AddForce(f);
+                for (int j = 0; j < engine.appliedForces.Count; ++j)
+                {
+                    this.totalStageThrustForce.AddForce(engine.appliedForces[j]);
                 }
             }
             //MonoBehaviour.print("vecThrust = " + vecThrust.ToString() + "   magnitude = " + vecThrust.magnitude);
@@ -779,17 +863,17 @@
             this.drainingParts.Clear();
 
             // Loop through all the active engine modules
-            for (int i = 0; i < this.activeEngines.Count; i++)
-            {
-                EngineSim engine = this.activeEngines[i];
+            for (int i = 0; i < activeEngines.Count; ++i)
+            {
+                EngineSim engine = activeEngines[i];
+
                 // Set the resource drains for this engine
                 if (engine.SetResourceDrains(this.allParts, this.allFuelLines, this.drainingParts))
                 {
                     // If it is active then add the consumed resource types to the set
-                    for (int j = 0; j < engine.ResourceConsumptions.Types.Count; j++)
-                    {
-                        int type = engine.ResourceConsumptions.Types[j];
-                        this.drainingResources.Add(type);
+                    for (int j = 0; j < engine.ResourceConsumptions.Types.Count; ++j)
+                    { 
+                        drainingResources.Add(engine.ResourceConsumptions.Types[j]);
                     }
                 }
             }
@@ -824,9 +908,10 @@
 
             if (this.activeEngines.Count > 0)
             {
-                for (int i = 0; i < this.dontStageParts.Count; i++)
-                {
-                    PartSim partSim = this.dontStageParts[i];
+                for (int i = 0; i < dontStageParts.Count; ++i)
+                {
+                    PartSim partSim = dontStageParts[i];
+
                     if (SimManager.logOutput)
                     {
                         partSim.DumpPartToBuffer(buffer, "Testing: ");
@@ -845,9 +930,10 @@
 
                     if (partSim.isEngine)
                     {
-                        for (int j = 0; j < this.activeEngines.Count; j++)
-                        {
-                            EngineSim engine = this.activeEngines[j];
+                        for (int j = 0; j < activeEngines.Count; ++j)
+                        {
+                            EngineSim engine = activeEngines[j];
+
                             if (engine.partSim == partSim)
                             {
                                 if (SimManager.logOutput)
@@ -886,9 +972,10 @@
         {
             // Build a set of all the parts that will be decoupled
             decoupledParts.Clear();
-            for (int i = 0; i < this.allParts.Count; i++)
-            {
-                PartSim partSim = this.allParts[i];
+            for (int i = 0; i < allParts.Count; ++i)
+            {
+                PartSim partSim = allParts[i];
+
                 if (partSim.decoupledInStage >= this.currentStage)
                 {
                     decoupledParts.Add(partSim);
@@ -921,17 +1008,16 @@
             }
 
             // Loop through all the (remaining) parts
-            for (int i = 0; i < this.allParts.Count; i++)
-            {
-                PartSim partSim = this.allParts[i];
+            for (int i = 0; i < allParts.Count; ++i)
+            { 
                 // Ask the part to remove all the parts that are decoupled
-                partSim.RemoveAttachedParts(decoupledParts);
+                allParts[i].RemoveAttachedParts(decoupledParts);
             }
 
             // Now we loop through all the engines and activate those that are ignited in this stage
-            for (int i = 0; i < this.allEngines.Count; i++)
-            {
-                EngineSim engine = this.allEngines[i];
+            for (int i = 0; i < allEngines.Count; ++i)
+            {
+                EngineSim engine = allEngines[i];
                 if (engine.partSim.inverseStage == this.currentStage)
                 {
                     engine.isActive = true;
@@ -965,3 +1051,4 @@
         }
     }
 }
+

--- a/KerbalEngineer/VesselSimulator/Stage.cs
+++ b/KerbalEngineer/VesselSimulator/Stage.cs
@@ -51,6 +51,7 @@
         public double resourceMass = 0.0;
         public double maxThrustTorque = 0.0;
         public double thrustOffsetAngle = 0.0;
+        public float maxMach = 0.0f;
 
         public void Dump()
         {

 Binary files a/Output/KerbalEngineer/KerbalEngineer.dll and b/Output/KerbalEngineer/KerbalEngineer.dll differ
--- a/Output/KerbalEngineer/KerbalEngineer.version
+++ b/Output/KerbalEngineer/KerbalEngineer.version
@@ -1,17 +1,18 @@
 {
-	"NAME":"Kerbal Engineer Redux 1.0",
+	"NAME":"Kerbal Engineer Redux",
 	"URL":"http://ksp-avc.cybutek.net/version.php?id=6",
 	"VERSION":
 	{
 		"MAJOR":1,
 		"MINOR":0,
-		"PATCH":15,
-		"BUILD":2
+		"PATCH":18,
+		"BUILD":0
 	},
 	"KSP_VERSION":
 	{
-		"MAJOR":0,
-		"MINOR":90,
-		"PATCH":0
+		"MAJOR":1,
+		"MINOR":0,
+		"PATCH":4
 	}
 }
+