Fixed issue where physically insignificant part mass was not being correctly cascaded down through parent parts.
Fixed issue where physically insignificant part mass was not being correctly cascaded down through parent parts.

 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,3 +1,150 @@
+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)
+    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 masses were not correctly being cascaded down through its parents.
+
+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.
+        Fixed: Log spam for stage priority mode.
+        Fixed: Locked tanks preventing simulation from staging.
+        Fixed: No flow and all vessel modes to respect flow states.
+
+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.
+        - Tracking station level 3 enables Flight Engineer everywhere.
+
+    Added: New readouts to the orbital category:
+        - Mean Anomaly at Epoc
+
+    Added: New readouts to the miscellaneous category:
+        - System Time
+
+    Added: Editor Overlay Tab's X position is now changable in the BuildOverlay.xml settings file.
+    Changed: Editor Overlay Tabs start position moved over as to not overlap the parts menu.
+    Fixed: Bug where STAGE_PRIORITY_FLOW resources would not be corrently disabled/enabled.
+    Fixed: Issue with the formatting large Mass and Cost values.
+    Fixed: Error when loading the Engineer7500 part model.
+
+1.0.13.1, 16-12-2014
+    Fixed: Issue with manoeuvre node readouts and low tier tracking station.
+
+1.0.13.0, 16-12-2014
+    Updated for KSP version 0.90
+
+    Added: New readouts to the vessel category:
+        - Heading Rate
+        - Pitch Rate
+        - Roll Rate
+
+    Changed: Simulation to look for fuel lines that use CModuleFuelLine module.
+    Fixed: Editor Overlay now loads the saved visibility value properly.
+    Fixed: Altitude (Terrain) will no longer give a reading below sea level.
+    Fixed: Suicide burn now uses radar altitude that clamps to sea level.
+
+1.0.12.0, 01-12-2014
+    Added: Setting in Build Engineer to enable/disable vectored thrust calculations.
+    Added: Thrust torque field in Build Engineer (courtesy of mic_e).
+    Added: New readouts to the vessel category:
+        - Thrust Offset Angle (courtesy of mic_e)
+        - Thrust Torque (courtesy of mic_e)
+        - Part Count:  stage/total
+        - Heading
+        - Pitch
+        - Roll
+
+    Added: New readouts to the surface category:
+        - Situation
+
+    Added: New readouts to the miscellaneous category:
+        - Vectored Thrust Toggle
+
+    Fixed: The category selection within the section editors now do not always reset back to 'Orbital'.
+    Fixed: Issue where the vessel simulation can sometimes permanently freeze.
+    Fixed: Issue where the vessel simulation would not show updates when the delay was set lower than the frame rate.
+
 1.0.11.3, 11-11-2014
     Changed: Gravity measurements for Isp to 9.82.
 
@@ -63,7 +210,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.
@@ -220,6 +367,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,33 +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 ? 101.325 * body.atmosphereMultiplier : 0;
-                    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)
                 {
@@ -142,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;
@@ -188,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
@@ -17,33 +17,29 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-using System.Linq;
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Flight;
-using KerbalEngineer.Helpers;
-using KerbalEngineer.Settings;
-using KerbalEngineer.UIControls;
-using KerbalEngineer.VesselSimulator;
-
-using UnityEngine;
-
-#endregion
-
 namespace KerbalEngineer.Editor
 {
+    #region Using Directives
+    using System;
+    using Extensions;
+    using Flight;
+    using Helpers;
+    using Settings;
+    using UIControls;
+    using UnityEngine;
+    using VesselSimulator;
+
+    #endregion
+
     [KSPAddon(KSPAddon.Startup.EditorAny, false)]
     public class BuildAdvanced : MonoBehaviour
     {
         #region Fields
+        public static float Altitude = 0.0f;
 
         private GUIStyle areaSettingStyle;
         private GUIStyle areaStyle;
-        private float atmosphericPercentage = 1.0f;
-        private float atmosphericVelocity;
+        private float atmosphericMach;
         private GUIStyle bodiesButtonActiveStyle;
         private GUIStyle bodiesButtonStyle;
         private DropDown bodiesList;
@@ -56,6 +52,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;
@@ -67,11 +64,9 @@
         private GUIStyle titleStyle;
         private bool visible = true;
         private GUIStyle windowStyle;
-
         #endregion
 
         #region Properties
-
         /// <summary>
         ///     Gets the current instance if started or returns null.
         /// </summary>
@@ -82,8 +77,14 @@
         /// </summary>
         public bool CompactMode
         {
-            get { return this.compactMode; }
-            set { this.compactMode = value; }
+            get
+            {
+                return compactMode;
+            }
+            set
+            {
+                compactMode = value;
+            }
         }
 
         /// <summary>
@@ -91,8 +92,14 @@
         /// </summary>
         public bool ShowAllStages
         {
-            get { return this.showAllStages; }
-            set { this.showAllStages = value; }
+            get
+            {
+                return showAllStages;
+            }
+            set
+            {
+                showAllStages = value;
+            }
         }
 
         /// <summary>
@@ -100,8 +107,14 @@
         /// </summary>
         public bool ShowAtmosphericDetails
         {
-            get { return this.showAtmosphericDetails; }
-            set { this.showAtmosphericDetails = value; }
+            get
+            {
+                return showAtmosphericDetails;
+            }
+            set
+            {
+                showAtmosphericDetails = value;
+            }
         }
 
         /// <summary>
@@ -109,8 +122,14 @@
         /// </summary>
         public bool ShowSettings
         {
-            get { return this.showSettings; }
-            set { this.showSettings = value; }
+            get
+            {
+                return showSettings;
+            }
+            set
+            {
+                showSettings = value;
+            }
         }
 
         /// <summary>
@@ -118,26 +137,40 @@
         /// </summary>
         public bool Visible
         {
-            get { return this.visible; }
-            set { this.visible = value; }
-        }
-
+            get
+            {
+                return visible;
+            }
+            set
+            {
+                visible = value;
+            }
+        }
         #endregion
 
-        #region Methods: protected
+        #region Methods
+        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;
 
         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 -= GetStageInfo;
+                SimManager.OnReady += GetStageInfo;
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex);
+                Logger.Exception(ex, "BuildAdvanced.Awake()");
             }
         }
 
@@ -148,22 +181,22 @@
         {
             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()");
             }
         }
 
@@ -171,56 +204,65 @@
         {
             try
             {
-                if (!this.visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0 || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts)
+                if (!visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0 || EditorLogic.fetch.editorScreen != EditorScreen.Parts)
                 {
                     return;
                 }
 
-                if (SimManager.ResultsReady())
-                {
-                    this.stages = SimManager.Stages;
-                }
-
-                SimManager.RequestSimulation();
-
-                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()");
             }
         }
 
@@ -228,12 +270,12 @@
         {
             try
             {
-                this.InitialiseStyles();
-                GuiDisplaySize.OnSizeChanged += this.OnSizeChanged;
+                InitialiseStyles();
+                GuiDisplaySize.OnSizeChanged += OnSizeChanged;
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex);
+                Logger.Exception(ex, "BuildAdvanced.Start()");
             }
         }
 
@@ -243,56 +285,54 @@
             {
                 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.Velocity = this.atmosphericVelocity;
+                SimManager.Mach = atmosphericMach;
+
+                SimManager.RequestSimulation();
                 SimManager.TryStartSimulation();
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex, "BuildAdvanced->Update");
-            }
-        }
-
-        #endregion
-
-        #region Methods: private
+                Logger.Exception(ex, "BuildAdvanced.Update()");
+            }
+        }
 
         /// <summary>
         ///     Checks whether the editor should be locked to stop click-through.
         /// </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);
             }
         }
 
@@ -301,36 +341,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("Velocity: " + this.atmosphericVelocity.ToString("F1") + "m/s", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
-            GUI.skin = HighLogic.Skin;
-            this.atmosphericVelocity = GUILayout.HorizontalSlider(this.atmosphericVelocity, 0, 2500f);
-            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);
                 }
             }
         }
@@ -339,18 +386,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);
                 }
             }
         }
@@ -361,12 +409,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();
@@ -378,12 +427,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.Concat(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();
@@ -395,12 +445,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();
@@ -412,12 +463,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();
@@ -429,12 +481,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();
@@ -446,12 +499,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();
@@ -463,39 +517,55 @@
         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("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("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("Flight Engineer activation mode:", this.settingStyle);
-            FlightEngineerPartless.IsPartless = GUILayout.Toggle(FlightEngineerPartless.IsPartless, "PARTLESS", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
-            FlightEngineerPartless.IsPartless = !GUILayout.Toggle(!FlightEngineerPartless.IsPartless, "MODULE", 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("GUI Size: " + GuiDisplaySize.Increment, this.settingStyle);
-            if (GUILayout.Button("<", 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 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("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 + "ms", this.settingStyle);
+            GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.TotalMilliseconds + "ms", settingStyle);
             GUI.skin = HighLogic.Skin;
-            SimManager.minSimTime = (long)GUILayout.HorizontalSlider(SimManager.minSimTime, 0, 2000.0f);
+            SimManager.minSimTime = TimeSpan.FromMilliseconds(GUILayout.HorizontalSlider((float)SimManager.minSimTime.TotalMilliseconds, 0, 2000.0f));
             GUI.skin = null;
         }
 
@@ -505,12 +575,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();
@@ -522,12 +593,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();
@@ -539,12 +611,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();
@@ -556,12 +629,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();
@@ -571,15 +645,24 @@
         {
             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()
+        {
+            stages = SimManager.Stages;
+            if (stages != null && stages.Length > 0)
+            {
+                maxMach = stages[stages.Length - 1].maxMach;
             }
         }
 
@@ -588,22 +671,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 =
                 {
@@ -614,7 +697,7 @@
                 alignment = TextAnchor.MiddleCenter
             };
 
-            this.titleStyle = new GUIStyle(HighLogic.Skin.label)
+            titleStyle = new GUIStyle(HighLogic.Skin.label)
             {
                 normal =
                 {
@@ -626,7 +709,7 @@
                 stretchWidth = true,
             };
 
-            this.infoStyle = new GUIStyle(HighLogic.Skin.label)
+            infoStyle = new GUIStyle(HighLogic.Skin.label)
             {
                 fontSize = (int)(11 * GuiDisplaySize.Offset),
                 fontStyle = FontStyle.Bold,
@@ -634,21 +717,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),
@@ -666,10 +749,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
             };
         }
 
@@ -680,27 +763,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>
@@ -710,77 +793,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();
                 }
 
@@ -788,10 +881,9 @@
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex);
-            }
-        }
-
+                Logger.Exception(ex, "BuildAdvanced.Window()");
+            }
+        }
         #endregion
     }
 }

--- a/KerbalEngineer/Editor/BuildOverlay.cs
+++ b/KerbalEngineer/Editor/BuildOverlay.cs
@@ -19,17 +19,21 @@
 
 #region Using Directives
 
-using System;
-
-using KerbalEngineer.Helpers;
-using KerbalEngineer.Settings;
-
-using UnityEngine;
+
 
 #endregion
 
 namespace KerbalEngineer.Editor
 {
+    #region Using Directives
+
+    using System;
+    using Helpers;
+    using Settings;
+    using UnityEngine;
+
+    #endregion
+
     [KSPAddon(KSPAddon.Startup.EditorAny, false)]
     public class BuildOverlay : MonoBehaviour
     {
@@ -191,16 +195,17 @@
 
         #endregion
 
-        #region Methods: public
+        #region Methods
 
         public static void Load()
         {
             var handler = SettingHandler.Load("BuildOverlay.xml");
-            handler.GetSet("visible", Visible);
+            Visible = handler.GetSet("visible", Visible);
             BuildOverlayPartInfo.NamesOnly = handler.GetSet("namesOnly", BuildOverlayPartInfo.NamesOnly);
             BuildOverlayPartInfo.ClickToOpen = handler.GetSet("clickToOpen", BuildOverlayPartInfo.ClickToOpen);
             buildOverlayVessel.Open = handler.GetSet("vesselOpen", buildOverlayVessel.Open);
             buildOverlayResources.Open = handler.GetSet("resourcesOpen", buildOverlayResources.Open);
+            buildOverlayVessel.WindowX = handler.GetSet("vesselWindowX", buildOverlayVessel.WindowX);
             handler.Save("BuildOverlay.xml");
         }
 
@@ -212,12 +217,9 @@
             handler.Set("clickToOpen", BuildOverlayPartInfo.ClickToOpen);
             handler.Set("vesselOpen", buildOverlayVessel.Open);
             handler.Set("resourcesOpen", buildOverlayResources.Open);
+            handler.Set("vesselWindowX", buildOverlayVessel.WindowX);
             handler.Save("BuildOverlay.xml");
         }
-
-        #endregion
-
-        #region Methods: protected
 
         protected void Awake()
         {

--- 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)
 
@@ -97,67 +115,71 @@
         {
             try
             {
-                if (!Visible || Hidden || EditorLogic.startPod == null || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts)
+                if (!Visible || Hidden || EditorLogic.RootPart == null || EditorLogic.fetch.editorScreen != EditorScreen.Parts)
                 {
                     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.Concat(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.Concat(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.Concat(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.Concat(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 != EditorLogic.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,29 +18,26 @@
 // 
 
 #region Using Directives
-
-using System;
-using System.Collections.Generic;
-
-using KerbalEngineer.Helpers;
-using KerbalEngineer.VesselSimulator;
-
-using UnityEngine;
-
 #endregion
 
 namespace KerbalEngineer.Editor
 {
+    #region Using Directives
+    using System;
+    using System.Collections.Generic;
+    using Helpers;
+    using UnityEngine;
+    using VesselSimulator;
+
+    #endregion
+
     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>();
@@ -51,46 +48,82 @@
         private GUIContent tabContent;
         private Rect tabPosition;
         private Vector2 tabSize;
-        private Rect windowPosition = new Rect(300.0f, 0.0f, Width, 0.0f);
-
+        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; }
-        }
-
-        #endregion
-
-        #region Methods: protected
+            get
+            {
+                return windowPosition;
+            }
+        }
+
+        public float WindowX
+        {
+            get
+            {
+                return windowPosition.x;
+            }
+            set
+            {
+                windowPosition.x = value;
+            }
+        }
+        #endregion
+
+        #region Methods
+        protected void Awake()
+        {
+            try
+            {
+                SimManager.OnReady -= GetStageInfo;
+                SimManager.OnReady += GetStageInfo;
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+            }
+        }
 
         protected void OnGUI()
         {
             try
             {
-                if (!Visible || EditorLogic.startPod == null || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts)
+                if (!Visible || EditorLogic.RootPart == null || 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.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)
@@ -103,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)
             {
@@ -116,48 +149,49 @@
         {
             try
             {
-                if (!Visible || EditorLogic.startPod == null)
+                if (!Visible || EditorLogic.RootPart == null)
                 {
                     return;
                 }
 
-                if (this.openPercent > 0.0)
-                {
-                    this.SetVesselInfo();
-                }
-
-                this.SetSlidePosition();
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex);
-            }
-        }
-
-        #endregion
-
-        #region Methods: private
+                if (openPercent > 0.0)
+                {
+                    SetVesselInfo();
+                }
+
+                SetSlidePosition();
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+            }
+        }
+
+        private void GetStageInfo()
+        {
+            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()
@@ -166,7 +200,7 @@
 
             if (BuildAdvanced.Instance.ShowAtmosphericDetails)
             {
-                SimManager.Atmosphere = CelestialBodies.SelectedBody.Atmosphere * 0.01;
+                SimManager.Atmosphere = CelestialBodies.SelectedBody.GetAtmospheres(BuildAdvanced.Altitude);
             }
             else
             {
@@ -176,18 +210,14 @@
             SimManager.RequestSimulation();
             SimManager.TryStartSimulation();
 
-            if (SimManager.ResultsReady())
-            {
-                this.lastStage = SimManager.LastStage;
-            }
-
-            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));
             }
         }
 
@@ -195,8 +225,8 @@
         {
             try
             {
-                var firstItem = true;
-                foreach (var item in this.infoItems)
+                bool firstItem = true;
+                foreach (PartInfoItem item in infoItems)
                 {
                     if (!firstItem)
                     {
@@ -223,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,31 @@
 //     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.11.3";
-
-        #endregion
-
-        #region Fields
+        public const string ASSEMBLY_VERSION = "1.0.18.0";
 
         private static string assemblyFile;
         private static string assemblyName;
         private static string assemblyPath;
-
-        #endregion
-
-        #region Properties
 
         /// <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 +47,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 +58,10 @@
         /// </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
     }
 }

--- 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/PartExtensions.cs
+++ b/KerbalEngineer/Extensions/PartExtensions.cs
@@ -17,19 +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.
@@ -44,32 +42,43 @@
         /// </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>
         public static double GetCostDry(this Part part)
         {
-            return part.partInfo.cost - GetResourceCostMax(part) + part.GetModuleCosts();
+            return part.partInfo.cost - GetResourceCostMax(part) + part.GetModuleCosts(0.0f);
         }
 
         /// <summary>
@@ -77,7 +86,23 @@
         /// </summary>
         public static double GetCostMax(this Part part)
         {
-            return part.partInfo.cost + part.GetModuleCosts();
+            return part.partInfo.cost + part.GetModuleCosts(0.0f);
+        }
+
+        /// <summary>
+        ///     Gets the cost of the part modules
+        ///     Same as stock but without mem allocation
+        /// </summary>
+        public static double GetModuleCostsNoAlloc(this Part part, float defaultCost)
+        {
+            float cost = 0f;
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                PartModule pm = part.Modules[i];
+                if (pm is IPartCostModifier)
+                    cost += (pm as IPartCostModifier).GetModuleCost(defaultCost);
+            }
+            return cost;
         }
 
         /// <summary>
@@ -85,7 +110,7 @@
         /// </summary>
         public static double GetCostWet(this Part part)
         {
-            return part.partInfo.cost - GetResourceCostInverted(part) + part.GetModuleCosts();
+            return part.partInfo.cost - GetResourceCostInverted(part) + part.GetModuleCostsNoAlloc(0.0f); // part.GetModuleCosts allocate 44B per call. 
         }
 
         /// <summary>
@@ -99,30 +124,37 @@
         /// <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.
         /// </summary>
         public static T GetModule<T>(this Part part) where T : PartModule
         {
-            return part.Modules.OfType<T>().FirstOrDefault();
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                PartModule pm = part.Modules[i];
+                if (pm is T)
+                    return (T)pm;
+            }
+            return null;
         }
 
         /// <summary>
@@ -130,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>
@@ -138,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>
@@ -146,7 +178,7 @@
         /// </summary>
         public static ModuleAlternator GetModuleAlternator(this Part part)
         {
-            return part.GetModule<ModuleAlternator>();
+            return GetModule<ModuleAlternator>(part);
         }
 
         /// <summary>
@@ -154,7 +186,7 @@
         /// </summary>
         public static ModuleDeployableSolarPanel GetModuleDeployableSolarPanel(this Part part)
         {
-            return part.GetModule<ModuleDeployableSolarPanel>();
+            return GetModule<ModuleDeployableSolarPanel>(part);
         }
 
         /// <summary>
@@ -162,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>
@@ -183,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>
@@ -200,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>
@@ -213,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;
         }
 
@@ -234,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;
         }
 
@@ -254,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>
@@ -262,7 +324,13 @@
         /// </summary>
         public static double GetResourceCostInverted(this Part part)
         {
-            return part.Resources.list.Sum(r => (r.maxAmount - r.amount) * r.info.unitCost);
+            double sum = 0;
+            for (int i = 0; i < part.Resources.list.Count; i++)
+            {
+                PartResource r = part.Resources.list[i];
+                sum += (r.maxAmount - r.amount) * r.info.unitCost;
+            }
+            return sum;
         }
 
         /// <summary>
@@ -270,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.
@@ -307,7 +382,12 @@
         /// </summary>
         public static bool HasModule<T>(this Part part) where T : PartModule
         {
-            return part.Modules.OfType<T>().Any();
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                if (part.Modules[i] is T)
+                    return true;
+            }
+            return false;
         }
 
         /// <summary>
@@ -315,7 +395,13 @@
         /// </summary>
         public static bool HasModule<T>(this Part part, Func<T, bool> predicate) where T : PartModule
         {
-            return part.Modules.OfType<T>().Any(predicate);
+            for (int i = 0; i < part.Modules.Count; i++)
+            {
+                PartModule pm = part.Modules[i];
+                if (pm is T && predicate(pm as T))
+                    return true;
+            }
+            return false;
         }
 
         /// <summary>
@@ -339,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>
@@ -347,7 +434,7 @@
         /// </summary>
         public static bool IsCommandModule(this Part part)
         {
-            return part.HasModule<ModuleCommand>();
+            return HasModule<ModuleCommand>(part);
         }
 
         /// <summary>
@@ -355,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;
             }
@@ -363,7 +450,7 @@
             {
                 return false;
             }
-            return part.parent.IsDecoupledInStage(stage);
+            return IsDecoupledInStage(part.parent, stage);
         }
 
         /// <summary>
@@ -371,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>
@@ -379,7 +466,7 @@
         /// </summary>
         public static bool IsEngine(this Part part)
         {
-            return part.HasModule<ModuleEngines>() || part.HasModule<ModuleEnginesFX>();
+            return HasModule<ModuleEngines>(part);
         }
 
         /// <summary>
@@ -387,7 +474,7 @@
         /// </summary>
         public static bool IsFuelLine(this Part part)
         {
-            return (part is FuelLine);
+            return HasModule<CModuleFuelLine>(part);
         }
 
         /// <summary>
@@ -395,7 +482,7 @@
         /// </summary>
         public static bool IsGenerator(this Part part)
         {
-            return part.HasModule<ModuleGenerator>();
+            return HasModule<ModuleGenerator>(part);
         }
 
         /// <summary>
@@ -403,7 +490,7 @@
         /// </summary>
         public static bool IsLaunchClamp(this Part part)
         {
-            return part.HasModule<LaunchClamp>();
+            return HasModule<LaunchClamp>(part);
         }
 
         /// <summary>
@@ -411,7 +498,7 @@
         /// </summary>
         public static bool IsParachute(this Part part)
         {
-            return part.HasModule<ModuleParachute>();
+            return HasModule<ModuleParachute>(part);
         }
 
         /// <summary>
@@ -419,13 +506,13 @@
         /// </summary>
         public static bool IsPrimary(this Part part, List<Part> partsList, PartModule module)
         {
-            foreach (var vesselPart in partsList)
-            {
+            for (int i = 0; i < partsList.Count; i++)
+            {
+                var vesselPart = partsList[i];
                 if (!vesselPart.HasModule(module.ClassID))
                 {
                     continue;
                 }
-
                 if (vesselPart == part)
                 {
                     return true;
@@ -438,7 +525,7 @@
 
         public static bool IsRcsModule(this Part part)
         {
-            return part.HasModule<ModuleRCS>();
+            return HasModule<ModuleRCS>(part);
         }
 
         /// <summary>
@@ -446,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>
@@ -454,7 +541,7 @@
         /// </summary>
         public static bool IsSolarPanel(this Part part)
         {
-            return part.HasModule<ModuleDeployableSolarPanel>();
+            return HasModule<ModuleDeployableSolarPanel>(part);
         }
 
         /// <summary>
@@ -462,160 +549,99 @@
         /// </summary>
         public static bool IsSolidRocket(this Part part)
         {
-            return part.HasModule<ModuleEngines>() && part.GetModuleEngines().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)
             {
@@ -79,11 +90,11 @@
                 {
                     return;
                 }
-                if (FlightEngineerCore.Instance != null && this.button.State == RUIToggleButton.ButtonState.DISABLED)
+                if (FlightEngineerCore.IsDisplayable && this.button.State == RUIToggleButton.ButtonState.DISABLED)
                 {
                     this.button.Enable();
                 }
-                else if (FlightEngineerCore.Instance == null && this.button.State != RUIToggleButton.ButtonState.DISABLED)
+                else if (!FlightEngineerCore.IsDisplayable && this.button.State != RUIToggleButton.ButtonState.DISABLED)
                 {
                     this.button.Disable();
                 }

--- a/KerbalEngineer/Flight/ActionMenuGui.cs
+++ b/KerbalEngineer/Flight/ActionMenuGui.cs
@@ -132,7 +132,7 @@
         {
             try
             {
-                if (this.Hidden)
+                if (this.Hidden || !FlightEngineerCore.IsDisplayable)
                 {
                     return;
                 }

--- a/KerbalEngineer/Flight/DisplayStack.cs
+++ b/KerbalEngineer/Flight/DisplayStack.cs
@@ -33,6 +33,8 @@
 
 namespace KerbalEngineer.Flight
 {
+    using Upgradeables;
+
     /// <summary>
     ///     Graphical controller for displaying stacked sections.
     /// </summary>
@@ -150,7 +152,7 @@
         {
             try
             {
-                if (FlightEngineerCore.Instance == null)
+                if (!FlightEngineerCore.IsDisplayable)
                 {
                     return;
                 }
@@ -177,7 +179,7 @@
         {
             try
             {
-                if (FlightEngineerCore.Instance == null)
+                if (!FlightEngineerCore.IsDisplayable)
                 {
                     return;
                 }
@@ -212,7 +214,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/FlightEngineerCore.cs
+++ b/KerbalEngineer/Flight/FlightEngineerCore.cs
@@ -19,21 +19,28 @@
 
 #region Using Directives
 
-using System;
-using System.Collections.Generic;
-
-using KerbalEngineer.Flight.Readouts;
-using KerbalEngineer.Flight.Sections;
-
-using UnityEngine;
-
 #endregion
 
 namespace KerbalEngineer.Flight
 {
+    #region Using Directives
+
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using Extensions;
+    using Readouts;
+    using Sections;
+    using Settings;
+    using UnityEngine;
+    using VesselSimulator;
+
+    #endregion
+
     /// <summary>
     ///     Core management system for the Flight Engineer.
     /// </summary>
+    [KSPAddon(KSPAddon.Startup.Flight, false)]
     public sealed class FlightEngineerCore : MonoBehaviour
     {
         #region Instance
@@ -45,7 +52,210 @@
 
         #endregion
 
+        #region Fields
+
+        private static bool isCareerMode = true;
+        private static bool isKerbalLimited = true;
+        private static bool isTrackingStationLimited = true;
+
+        #endregion
+
         #region Constructors
+
+        static FlightEngineerCore()
+        {
+            try
+            {
+                var handler = SettingHandler.Load("FlightEngineerCore.xml");
+                handler.Get("isCareerMode", ref isCareerMode);
+                handler.Get("isKerbalLimited", ref isKerbalLimited);
+                handler.Get("isTrackingStationLimited", ref isTrackingStationLimited);
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+            }
+        }
+
+        #endregion
+
+        #region Properties
+
+        /// <summary>
+        ///     Gets and sets whether to the Flight Engineer should be run using career limitations.
+        /// </summary>
+        public static bool IsCareerMode
+        {
+            get { return isCareerMode; }
+            set
+            {
+                try
+                {
+                    if (isCareerMode != value)
+                    {
+                        var handler = SettingHandler.Load("FlightEngineerCore.xml");
+                        handler.Set("isCareerMode", value);
+                        handler.Save("FlightEngineerCore.xml");
+                    }
+                    isCareerMode = value;
+                }
+                catch (Exception ex)
+                {
+                    Logger.Exception(ex);
+                }
+            }
+        }
+
+        /// <summary>
+        ///     Gets whether the FlightEngineer should be displayed.
+        /// </summary>
+        public static bool IsDisplayable
+        {
+            get
+            {
+                if (isCareerMode)
+                {
+                    if (isKerbalLimited && FlightGlobals.ActiveVessel.GetVesselCrew().Exists(c => c.experienceTrait.TypeName == "Engineer"))
+                    {
+                        return true;
+                    }
+                    if (isTrackingStationLimited && ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.TrackingStation) == 1.0f)
+                    {
+                        return true;
+                    }
+                    return FlightGlobals.ActiveVessel.parts.Any(p => p.HasModule<FlightEngineerModule>());
+                }
+
+                return true;
+            }
+        }
+
+        /// <summary>
+        ///     Gets and sets whether to the Flight Engineer should be kerbal limited.
+        /// </summary>
+        public static bool IsKerbalLimited
+        {
+            get { return isKerbalLimited; }
+            set
+            {
+                try
+                {
+                    if (isKerbalLimited != value)
+                    {
+                        var handler = SettingHandler.Load("FlightEngineerCore.xml");
+                        handler.Set("isKerbalLimited", value);
+                        handler.Save("FlightEngineerCore.xml");
+                    }
+                    isKerbalLimited = value;
+                }
+                catch (Exception ex)
+                {
+                    Logger.Exception(ex);
+                }
+            }
+        }
+
+        /// <summary>
+        ///     Gets and sets whether to the Flight Engineer should be tracking station limited.
+        /// </summary>
+        public static bool IsTrackingStationLimited
+        {
+            get { return isTrackingStationLimited; }
+            set
+            {
+                try
+                {
+                    if (isTrackingStationLimited != value)
+                    {
+                        var handler = SettingHandler.Load("FlightEngineerCore.xml");
+                        handler.Set("isTrackingStationLimited", value);
+                        handler.Save("FlightEngineerCore.xml");
+                    }
+                    isTrackingStationLimited = value;
+                }
+                catch (Exception ex)
+                {
+                    Logger.Exception(ex);
+                }
+            }
+        }
+
+        /// <summary>
+        ///     Gets the editor windows for sections with open editors.
+        /// </summary>
+        public List<SectionEditor> SectionEditors { get; private set; }
+
+        /// <summary>
+        ///     Gets the section windows for floating sections.
+        /// </summary>
+        public List<SectionWindow> SectionWindows { get; private set; }
+
+        /// <summary>
+        ///     Gets the list of currently running updatable modules.
+        /// </summary>
+        public List<IUpdatable> UpdatableModules { get; private set; }
+
+        #endregion
+
+        #region Methods
+
+        /// <summary>
+        ///     Creates a section editor, adds it to the FlightEngineerCore and returns a reference to it.
+        /// </summary>
+        public SectionEditor AddSectionEditor(SectionModule section)
+        {
+            try
+            {
+                var editor = this.gameObject.AddComponent<SectionEditor>();
+                editor.ParentSection = section;
+                editor.Position = new Rect(section.EditorPositionX, section.EditorPositionY, SectionEditor.Width, SectionEditor.Height);
+                this.SectionEditors.Add(editor);
+                return editor;
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+                return null;
+            }
+        }
+
+        /// <summary>
+        ///     Creates a section window, adds it to the FlightEngineerCore and returns a reference to it.
+        /// </summary>
+        public SectionWindow AddSectionWindow(SectionModule section)
+        {
+            try
+            {
+                var window = this.gameObject.AddComponent<SectionWindow>();
+                window.ParentSection = section;
+                window.WindowPosition = new Rect(section.FloatingPositionX, section.FloatingPositionY, 0, 0);
+                this.SectionWindows.Add(window);
+                return window;
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+                return null;
+            }
+        }
+
+        /// <summary>
+        ///     Adds an updatable object to be automatically updated every frame and will ignore duplicate objects.
+        /// </summary>
+        public void AddUpdatable(IUpdatable updatable)
+        {
+            try
+            {
+                if (!this.UpdatableModules.Contains(updatable))
+                {
+                    this.UpdatableModules.Add(updatable);
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+            }
+        }
 
         /// <summary>
         ///     Create base Flight Engineer child objects.
@@ -59,11 +269,58 @@
                 this.SectionWindows = new List<SectionWindow>();
                 this.SectionEditors = new List<SectionEditor>();
                 this.UpdatableModules = new List<IUpdatable>();
+
+                SimManager.UpdateModSettings();
+
                 Logger.Log("FlightEngineerCore->Awake");
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex, "FlightEngineerCore->Awake");
+                Logger.Exception(ex);
+            }
+        }
+
+        /// <summary>
+        ///     Fixed update all required Flight Engineer objects.
+        /// </summary>
+        private void FixedUpdate()
+        {
+            try
+            {
+                SectionLibrary.FixedUpdate();
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
+            }
+        }
+
+        /// <summary>
+        ///     Force the destruction of child objects on core destruction.
+        /// </summary>
+        private void OnDestroy()
+        {
+            try
+            {
+                SectionLibrary.Save();
+
+                foreach (var window in this.SectionWindows)
+                {
+                    print("[FlightEngineer]: Destroying Floating Window for " + window.ParentSection.Name);
+                    Destroy(window);
+                }
+
+                foreach (var editor in this.SectionEditors)
+                {
+                    print("[FlightEngineer]: Destroying Editor Window for " + editor.ParentSection.Name);
+                    Destroy(editor);
+                }
+
+                Logger.Log("FlightEngineerCore->OnDestroy");
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex);
             }
         }
 
@@ -80,44 +337,6 @@
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex, "FlightEngineerCore->Start");
-            }
-        }
-
-        #endregion
-
-        #region Properties
-
-        /// <summary>
-        ///     Gets the section windows for floating sections.
-        /// </summary>
-        public List<SectionWindow> SectionWindows { get; private set; }
-
-        /// <summary>
-        ///     Gets the editor windows for sections with open editors.
-        /// </summary>
-        public List<SectionEditor> SectionEditors { get; private set; }
-
-        /// <summary>
-        ///     Gets the list of currently running updatable modules.
-        /// </summary>
-        public List<IUpdatable> UpdatableModules { get; private set; }
-
-        #endregion
-
-        #region Updating
-
-        /// <summary>
-        ///     Fixed update all required Flight Engineer objects.
-        /// </summary>
-        private void FixedUpdate()
-        {
-            try
-            {
-                SectionLibrary.FixedUpdate();
-            }
-            catch (Exception ex)
-            {
                 Logger.Exception(ex);
             }
         }
@@ -134,7 +353,7 @@
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex, "FlightEngineerCore->Update");
+                Logger.Exception(ex);
             }
         }
 
@@ -164,102 +383,7 @@
             }
             catch (Exception ex)
             {
-                Logger.Exception(ex, "FlightEngineerCore->UpdateModules");
-            }
-        }
-
-        #endregion
-
-        #region Destruction
-
-        /// <summary>
-        ///     Force the destruction of child objects on core destruction.
-        /// </summary>
-        private void OnDestroy()
-        {
-            try
-            {
-                SectionLibrary.Save();
-
-                foreach (var window in this.SectionWindows)
-                {
-                    print("[FlightEngineer]: Destroying Floating Window for " + window.ParentSection.Name);
-                    Destroy(window);
-                }
-
-                foreach (var editor in this.SectionEditors)
-                {
-                    print("[FlightEngineer]: Destroying Editor Window for " + editor.ParentSection.Name);
-                    Destroy(editor);
-                }
-
-                Logger.Log("FlightEngineerCore->OnDestroy");
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex, "FlightEngineerCore->OnDestroy");
-            }
-        }
-
-        #endregion
-
-        #region Methods
-
-        /// <summary>
-        ///     Creates a section window, adds it to the FlightEngineerCore and returns a reference to it.
-        /// </summary>
-        public SectionWindow AddSectionWindow(SectionModule section)
-        {
-            try
-            {
-                var window = this.gameObject.AddComponent<SectionWindow>();
-                window.ParentSection = section;
-                window.WindowPosition = new Rect(section.FloatingPositionX, section.FloatingPositionY, 0, 0);
-                this.SectionWindows.Add(window);
-                return window;
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex, "FlightEngineerCore->AddSectionWindow");
-                return null;
-            }
-        }
-
-        /// <summary>
-        ///     Creates a section editor, adds it to the FlightEngineerCore and returns a reference to it.
-        /// </summary>
-        public SectionEditor AddSectionEditor(SectionModule section)
-        {
-            try
-            {
-                var editor = this.gameObject.AddComponent<SectionEditor>();
-                editor.ParentSection = section;
-                editor.Position = new Rect(section.EditorPositionX, section.EditorPositionY, SectionEditor.Width, SectionEditor.Height);
-                this.SectionEditors.Add(editor);
-                return editor;
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex, "FlightEngineerCore->AddSectionEditor");
-                return null;
-            }
-        }
-
-        /// <summary>
-        ///     Adds an updatable object to be automatically updated every frame and will ignore duplicate objects.
-        /// </summary>
-        public void AddUpdatable(IUpdatable updatable)
-        {
-            try
-            {
-                if (!this.UpdatableModules.Contains(updatable))
-                {
-                    this.UpdatableModules.Add(updatable);
-                }
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex, "FlightEngineerCore->AddUpdatable");
+                Logger.Exception(ex);
             }
         }
 

--- a/KerbalEngineer/Flight/FlightEngineerModule.cs
+++ b/KerbalEngineer/Flight/FlightEngineerModule.cs
@@ -19,9 +19,6 @@
 
 #region Using Directives
 
-using System;
-using System.Linq;
-
 #endregion
 
 namespace KerbalEngineer.Flight
@@ -29,73 +26,5 @@
     /// <summary>
     ///     Module that can be attached to parts, giving them FlightEngineerCore management.
     /// </summary>
-    public sealed class FlightEngineerModule : PartModule
-    {
-        #region Fields
-
-        /// <summary>
-        ///     Contains the current FlightEngineerCore through the lifespan of this part.
-        /// </summary>
-        private FlightEngineerCore flightEngineerCore;
-
-        #endregion
-
-        #region Updating
-
-        /// <summary>
-        ///     Logic to create and destroy the FlightEngineerCore.
-        /// </summary>
-        private void Update()
-        {
-            try
-            {
-                if (!HighLogic.LoadedSceneIsFlight || FlightEngineerPartless.IsPartless)
-                {
-                    return;
-                }
-
-                if (this.vessel == FlightGlobals.ActiveVessel)
-                {
-                    // Checks for an existing instance of FlightEngineerCore, and if this part is the first part containing FlightEngineerModule within the vessel.
-                    if (flightEngineerCore == null && this.part == this.vessel.parts.FirstOrDefault(p => p.Modules.Contains("FlightEngineerModule")))
-                    {
-                        this.flightEngineerCore = this.gameObject.AddComponent<FlightEngineerCore>();
-                    }
-                }
-                else if (flightEngineerCore != null)
-                {
-                    // Using DestroyImmediate to force early destruction and keep saving/loading in synch when switching vessels.
-                    DestroyImmediate(flightEngineerCore);
-                }
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex, "FlightEngineerModule->Update");
-            }
-        }
-
-        #endregion
-
-        #region Destruction
-
-        /// <summary>
-        ///     Force the destruction of the FlightEngineerCore on part destruction.
-        /// </summary>
-        private void OnDestroy()
-        {
-            try
-            {
-                if (flightEngineerCore != null)
-                {
-                    DestroyImmediate(flightEngineerCore);
-                }
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex, "FlightEngineerModule->OnDestroy");
-            }
-        }
-
-        #endregion
-    }
+    public class FlightEngineerModule : PartModule { }
 }

--- a/KerbalEngineer/Flight/FlightEngineerPartless.cs
+++ /dev/null
@@ -1,101 +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.Settings;
-
-using UnityEngine;
-
-#endregion
-
-namespace KerbalEngineer.Flight
-{
-    [KSPAddon(KSPAddon.Startup.Flight, false)]
-    public class FlightEngineerPartless : MonoBehaviour
-    {
-        #region Fields
-
-        private FlightEngineerCore flightEngineerCore;
-
-        #endregion
-
-        #region Initialisation
-
-        static FlightEngineerPartless()
-        {
-            try
-            {
-                var handler = SettingHandler.Load("FlightEngineerPartless.xml");
-                handler.Get("isPartless", ref isPartless);
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex, "FlightEngineerPartless->FlightEngineerPartless");
-            }
-        }
-
-        private void Awake()
-        {
-            try
-            {
-                if (isPartless)
-                {
-                    this.flightEngineerCore = this.gameObject.AddComponent<FlightEngineerCore>();
-                }
-            }
-            catch (Exception ex)
-            {
-                Logger.Exception(ex, "FlightEngineerPartless->Awake");
-            }
-        }
-
-        #endregion
-
-        #region Properties
-
-        private static bool isPartless = true;
-
-        public static bool IsPartless
-        {
-            get { return isPartless; }
-            set
-            {
-                try
-                {
-                    if (isPartless != value)
-                    {
-                        var handler = SettingHandler.Load("FlightEngineerPartless.xml");
-                        handler.Set("isPartless", value);
-                        handler.Save("FlightEngineerPartless.xml");
-                    }
-                    isPartless = value;
-                }
-                catch (Exception ex)
-                {
-                    Logger.Exception(ex, "FlightEngineerPartless->IsPartless");
-                }
-            }
-        }
-
-        #endregion
-    }
-}

--- a/KerbalEngineer/Flight/Readouts/Miscellaneous/SimulationDelay.cs
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/SimulationDelay.cs
@@ -28,6 +28,8 @@
 
 namespace KerbalEngineer.Flight.Readouts.Miscellaneous
 {
+    using System;
+
     public class SimulationDelay : ReadoutModule
     {
         #region Constructors
@@ -49,7 +51,7 @@
             GUILayout.BeginHorizontal();
             GUILayout.Label("Sim Delay", this.NameStyle);
             GUI.skin = HighLogic.Skin;
-            SimManager.minSimTime = (long)GUILayout.HorizontalSlider(SimManager.minSimTime, 0, 1000.0f);
+            SimManager.minSimTime = TimeSpan.FromMilliseconds(GUILayout.HorizontalSlider((float)SimManager.minSimTime.TotalMilliseconds, 0, 2000.0f));
             GUI.skin = null;
             GUILayout.EndHorizontal();
         }

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/SystemTime.cs
@@ -1,1 +1,59 @@
+// 
+//     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 SystemTime : ReadoutModule
+    {
+
+
+        #region Constructors
+
+        public SystemTime()
+        {
+            this.Name = "System Time";
+            this.Category = ReadoutCategory.GetCategory("Miscellaneous");
+            this.HelpString = String.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            this.DrawLine(DateTime.Now.ToLongTimeString(), section.IsHud);
+        }
+
+        #endregion
+
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/VectoredThrustToggle.cs
@@ -1,1 +1,56 @@
+// 
+//     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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Miscellaneous
+{
+    #region Using Directives
+
+    using Sections;
+    using UnityEngine;
+    using VesselSimulator;
+
+    #endregion
+
+    public class VectoredThrustToggle : ReadoutModule
+    {
+        #region Constructors
+
+        public VectoredThrustToggle()
+        {
+            this.Name = "Vectored Thrust";
+            this.Category = ReadoutCategory.GetCategory("Miscellaneous");
+            this.HelpString = "Shows a control that will allow you to adjust whether the vessel simulation should account for vectored thrust.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            GUILayout.BeginHorizontal();
+            GUILayout.Label("Vectored Thrust: ", this.NameStyle);
+            SimManager.vectoredThrust = GUILayout.Toggle(SimManager.vectoredThrust, "ENABLED", this.ButtonStyle);
+            GUILayout.EndHorizontal();
+        }
+
+        #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/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
@@ -61,6 +63,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; }
 
         public static double RadialDeltaV { get; private set; }
@@ -91,7 +97,11 @@
 
         public void Update()
         {
-            if (FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0 || !SimulationProcessor.ShowDetails)
+            // Extra tests for low level tracking station not supporting patched conics and maneuver nodes
+            if (FlightGlobals.ActiveVessel.patchedConicSolver == null ||
+                FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes == null ||
+                FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0 ||
+                !SimulationProcessor.ShowDetails)
             {
                 ShowDetails = false;
                 return;
@@ -104,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);
@@ -159,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);

--- /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 = String.Empty;
+            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 = String.Empty;
+            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
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/MeanAnomalyAtEpoc.cs
@@ -1,1 +1,54 @@
+// 
+//     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
+{
+    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;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            this.DrawLine(FlightGlobals.ship_orbit.meanAnomalyAtEpoch.ToAngle(), section.IsHud);
+        }
+
+        #endregion
+    }
+}

--- /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 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)
+            {
+                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 or pe > atmosphere");
+            }
+
+            //log.Flush();
+            this.DrawLine(str, section.IsHud);
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/ReadoutCategory.cs
+++ b/KerbalEngineer/Flight/Readouts/ReadoutCategory.cs
@@ -56,6 +56,7 @@
         public static ReadoutCategory Selected { get; set; }
 
         public string Description { get; set; }
+
         public string Name { get; set; }
 
         #endregion

--- 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
@@ -17,42 +15,31 @@
 //     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.Flight.Readouts.Miscellaneous;
-using KerbalEngineer.Flight.Readouts.Orbital;
-using KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode;
-using KerbalEngineer.Flight.Readouts.Rendezvous;
-using KerbalEngineer.Flight.Readouts.Surface;
-using KerbalEngineer.Flight.Readouts.Vessel;
-using KerbalEngineer.Settings;
-
-using AltitudeSeaLevel = KerbalEngineer.Flight.Readouts.Surface.AltitudeSeaLevel;
-using ApoapsisHeight = KerbalEngineer.Flight.Readouts.Orbital.ApoapsisHeight;
-using OrbitalPeriod = KerbalEngineer.Flight.Readouts.Orbital.OrbitalPeriod;
-using PeriapsisHeight = KerbalEngineer.Flight.Readouts.Orbital.PeriapsisHeight;
-using SemiMajorAxis = KerbalEngineer.Flight.Readouts.Orbital.SemiMajorAxis;
-using SemiMinorAxis = KerbalEngineer.Flight.Readouts.Orbital.SemiMinorAxis;
-using TimeToApoapsis = KerbalEngineer.Flight.Readouts.Orbital.TimeToApoapsis;
-using TimeToPeriapsis = KerbalEngineer.Flight.Readouts.Orbital.TimeToPeriapsis;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts
 {
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using Miscellaneous;
+    using Orbital;
+    using Orbital.ManoeuvreNode;
+    using Rendezvous;
+    using Settings;
+    using Surface;
+    using Thermal;
+    using Vessel;
+    using AltitudeSeaLevel = Surface.AltitudeSeaLevel;
+    using ApoapsisHeight = Orbital.ApoapsisHeight;
+    using OrbitalPeriod = Orbital.OrbitalPeriod;
+    using PeriapsisHeight = Orbital.PeriapsisHeight;
+    using SemiMajorAxis = Orbital.SemiMajorAxis;
+    using SemiMinorAxis = Orbital.SemiMinorAxis;
+    using TimeToApoapsis = Orbital.TimeToApoapsis;
+    using TimeToPeriapsis = Orbital.TimeToPeriapsis;
+
     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.
@@ -65,7 +52,9 @@
                 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");
 
                 // Orbital
                 readouts.Add(new ApoapsisHeight());
@@ -86,6 +75,7 @@
                 readouts.Add(new ArgumentOfPeriapsis());
                 readouts.Add(new TrueAnomaly());
                 readouts.Add(new MeanAnomaly());
+                readouts.Add(new MeanAnomalyAtEpoc());
                 readouts.Add(new EccentricAnomaly());
                 readouts.Add(new SemiMajorAxis());
                 readouts.Add(new SemiMinorAxis());
@@ -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());
@@ -143,6 +139,13 @@
                 readouts.Add(new IntakeAirDemand());
                 readouts.Add(new IntakeAirSupply());
                 readouts.Add(new IntakeAirDemandSupply());
+                readouts.Add(new PartCount());
+                readouts.Add(new Heading());
+                readouts.Add(new Pitch());
+                readouts.Add(new Roll());
+                readouts.Add(new HeadingRate());
+                readouts.Add(new PitchRate());
+                readouts.Add(new RollRate());
 
                 // Rendezvous
                 readouts.Add(new TargetSelector());
@@ -165,11 +168,28 @@
                 readouts.Add(new Rendezvous.SemiMajorAxis());
                 readouts.Add(new Rendezvous.SemiMinorAxis());
 
+                // 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());
 
                 LoadHelpStrings();
             }
@@ -179,22 +199,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: public
+            get
+            {
+                return readouts;
+            }
+            set
+            {
+                readouts = value;
+            }
+        }
 
         /// <summary>
         ///     Gets a list of readout modules which are associated with the specified category.
@@ -217,16 +235,12 @@
         /// </summary>
         public static void Reset()
         {
-            foreach (var readout in readouts)
+            foreach (ReadoutModule readout in readouts)
             {
                 readout.Reset();
             }
         }
 
-        #endregion
-
-        #region Methods: private
-
         /// <summary>
         ///     Loads the help strings from file.
         /// </summary>
@@ -234,8 +248,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);
                 }
@@ -246,7 +260,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/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>
@@ -149,10 +141,6 @@
         /// </summary>
         public bool UpdateRequested { get; set; }
 
-        #endregion
-
-        #region Methods: public
-
         /// <summary>
         ///     Request and update to calculate the details.
         /// </summary>
@@ -166,7 +154,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 +168,50 @@
 
             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;
+        }
 
         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/Surface/AltitudeTerrain.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/AltitudeTerrain.cs
@@ -19,13 +19,17 @@
 
 #region Using Directives
 
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Flight.Sections;
-
 #endregion
 
 namespace KerbalEngineer.Flight.Readouts.Surface
 {
+    #region Using Directives
+
+    using Extensions;
+    using Sections;
+
+    #endregion
+
     public class AltitudeTerrain : ReadoutModule
     {
         #region Constructors
@@ -40,11 +44,18 @@
 
         #endregion
 
-        #region Methods: public
+        #region Methods
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine((FlightGlobals.ship_altitude - FlightGlobals.ActiveVessel.terrainAltitude).ToDistance(), section.IsHud);
+            if (FlightGlobals.ActiveVessel.terrainAltitude > 0.0)
+            {
+                this.DrawLine((FlightGlobals.ship_altitude - FlightGlobals.ActiveVessel.terrainAltitude).ToDistance(), section.IsHud);
+            }
+            else
+            {
+                this.DrawLine((FlightGlobals.ship_altitude).ToDistance(), section.IsHud);
+            }
         }
 
         #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.DragMultiplier;
-
-                    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/Latitude.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/Latitude.cs
@@ -20,6 +20,7 @@
 #region Using Directives
 
 using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
 
 #endregion
 
@@ -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);
+            }
+        }
+    }
+}

--- /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 = string.Empty;
+            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 = string.Empty;
+            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 = string.Empty;
+            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 = string.Empty;
+            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 = string.Empty;
+            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 = string.Empty;
+            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 = string.Empty;
+            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 = string.Empty;
+            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 = string.Empty;
+            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 = string.Empty;
+            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;
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/AttitudeProcessor.cs
@@ -1,1 +1,133 @@
+// 
+//     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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    #region Using Directives
+
+    using UnityEngine;
+
+    #endregion
+
+    public class AttitudeProcessor : IUpdatable, IUpdateRequest
+    {
+        #region Fields
+
+        private static readonly AttitudeProcessor instance = new AttitudeProcessor();
+
+        private Vector3 centreOfMass = Vector3.zero;
+
+        private double heading;
+        private double headingRate;
+        private Vector3 north = Vector3.zero;
+        private double pitch;
+        private double pitchRate;
+        private double previousHeading;
+        private double previousPitch;
+        private double previousRoll;
+        private double roll;
+        private double rollRate;
+        private Quaternion surfaceRotation;
+        private Vector3 up = Vector3.zero;
+
+        #endregion
+
+        #region Properties
+
+        public static double Heading
+        {
+            get { return instance.heading; }
+        }
+
+        public static double HeadingRate
+        {
+            get { return instance.headingRate; }
+        }
+
+        public static AttitudeProcessor Instance
+        {
+            get { return instance; }
+        }
+
+        public static double Pitch
+        {
+            get { return instance.pitch; }
+        }
+
+        public static double PitchRate
+        {
+            get { return instance.pitchRate; }
+        }
+
+        public static double Roll
+        {
+            get { return instance.roll; }
+        }
+
+        public static double RollRate
+        {
+            get { return instance.rollRate; }
+        }
+
+        public bool UpdateRequested { get; set; }
+
+        #endregion
+
+        #region Methods
+
+        public static void RequestUpdate()
+        {
+            instance.UpdateRequested = true;
+        }
+
+        public void Update()
+        {
+            this.surfaceRotation = this.GetSurfaceRotation();
+
+            this.previousHeading = this.heading;
+            this.previousPitch = this.pitch;
+            this.previousRoll = this.roll;
+
+            // This code was derived from MechJeb2's implementation for getting the vessel's surface relative rotation.
+            this.heading = this.surfaceRotation.eulerAngles.y;
+            this.pitch = this.surfaceRotation.eulerAngles.x > 180.0f
+                ? 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;
+
+            this.headingRate = this.heading - this.previousHeading;
+            this.pitchRate = this.pitch - this.previousPitch;
+            this.rollRate = this.roll - this.previousRoll;
+        }
+
+        private Quaternion GetSurfaceRotation()
+        {
+            // This code was derived from MechJeb2's implementation for getting the vessel's surface relative rotation.
+            this.centreOfMass = FlightGlobals.ActiveVessel.findWorldCenterOfMass();
+            this.up = (this.centreOfMass - FlightGlobals.ActiveVessel.mainBody.position).normalized;
+            this.north = Vector3.ProjectOnPlane((FlightGlobals.ActiveVessel.mainBody.position + FlightGlobals.ActiveVessel.mainBody.transform.up * (float)FlightGlobals.ActiveVessel.mainBody.Radius) - this.centreOfMass, this.up).normalized;
+
+            return Quaternion.Inverse(Quaternion.Euler(90.0f, 0.0f, 0.0f) * Quaternion.Inverse(FlightGlobals.ActiveVessel.transform.rotation) * Quaternion.LookRotation(this.north, this.up));
+        }
+
+        #endregion
+    }
+}

--- 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()

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Heading.cs
@@ -1,1 +1,62 @@
+// 
+//     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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    #region Using Directives
+
+    using Helpers;
+    using Sections;
+
+    #endregion
+
+    public class Heading : ReadoutModule
+    {
+        #region Constructors
+
+        public Heading()
+        {
+            this.Name = "Heading";
+            this.Category = ReadoutCategory.GetCategory("Vessel");
+            this.HelpString = string.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            this.DrawLine(Units.ToAngle(AttitudeProcessor.Heading), section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            AttitudeProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/HeadingRate.cs
@@ -1,1 +1,62 @@
+// 
+//     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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    #region Using Directives
+
+    using Helpers;
+    using Sections;
+
+    #endregion
+
+    public class HeadingRate : ReadoutModule
+    {
+        #region Constructors
+
+        public HeadingRate()
+        {
+            this.Name = "Heading Rate";
+            this.Category = ReadoutCategory.GetCategory("Vessel");
+            this.HelpString = string.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            this.DrawLine(Units.ToAngle(AttitudeProcessor.HeadingRate) + "/sec", section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            AttitudeProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirDemandSupply.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirDemandSupply.cs
@@ -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/Mass.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Mass.cs
@@ -28,12 +28,6 @@
 {
     public class Mass : ReadoutModule
     {
-        #region Fields
-
-        private bool showing;
-
-        #endregion
-
         #region Constructors
 
         public Mass()

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/PartCount.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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    #region Using Directives
+
+    using Helpers;
+    using Sections;
+
+    #endregion
+
+    public class PartCount : ReadoutModule
+    {
+        #region Constructors
+
+        public PartCount()
+        {
+            this.Name = "Part Count";
+            this.Category = ReadoutCategory.GetCategory("Vessel");
+            this.HelpString = string.Empty;
+            this.IsDefault = true;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            if (SimulationProcessor.ShowDetails)
+            {
+                this.DrawLine(Units.ConcatF(SimulationProcessor.LastStage.partCount, SimulationProcessor.LastStage.totalPartCount, 0), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            SimulationProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Pitch.cs
@@ -1,1 +1,62 @@
+// 
+//     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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    #region Using Directives
+
+    using Helpers;
+    using Sections;
+
+    #endregion
+
+    public class Pitch : ReadoutModule
+    {
+        #region Constructors
+
+        public Pitch()
+        {
+            this.Name = "Pitch";
+            this.Category = ReadoutCategory.GetCategory("Vessel");
+            this.HelpString = string.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            this.DrawLine(Units.ToAngle(AttitudeProcessor.Pitch), section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            AttitudeProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/PitchRate.cs
@@ -1,1 +1,62 @@
+// 
+//     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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    #region Using Directives
+
+    using Helpers;
+    using Sections;
+
+    #endregion
+
+    public class PitchRate : ReadoutModule
+    {
+        #region Constructors
+
+        public PitchRate()
+        {
+            this.Name = "Pitch Rate";
+            this.Category = ReadoutCategory.GetCategory("Vessel");
+            this.HelpString = string.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            this.DrawLine(Units.ToAngle(AttitudeProcessor.PitchRate) + "/sec", section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            AttitudeProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Roll.cs
@@ -1,1 +1,62 @@
+// 
+//     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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    #region Using Directives
+
+    using Helpers;
+    using Sections;
+
+    #endregion
+
+    public class Roll : ReadoutModule
+    {
+        #region Constructors
+
+        public Roll()
+        {
+            this.Name = "Roll";
+            this.Category = ReadoutCategory.GetCategory("Vessel");
+            this.HelpString = string.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            this.DrawLine(Units.ToAngle(AttitudeProcessor.Roll), section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            AttitudeProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Vessel/RollRate.cs
@@ -1,1 +1,62 @@
+// 
+//     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/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    #region Using Directives
+
+    using Helpers;
+    using Sections;
+
+    #endregion
+
+    public class RollRate : ReadoutModule
+    {
+        #region Constructors
+
+        public RollRate()
+        {
+            this.Name = "Roll Rate";
+            this.Category = ReadoutCategory.GetCategory("Vessel");
+            this.HelpString = string.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            this.DrawLine(Units.ToAngle(AttitudeProcessor.RollRate) + "/sec", section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            AttitudeProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Vessel/SimulationProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/SimulationProcessor.cs
@@ -19,14 +19,19 @@
 
 #region Using Directives
 
-using System;
 
-using KerbalEngineer.VesselSimulator;
 
 #endregion
 
 namespace KerbalEngineer.Flight.Readouts.Vessel
 {
+    #region Using Directives
+
+    using System;
+    using VesselSimulator;
+
+    #endregion
+
     public class SimulationProcessor : IUpdatable, IUpdateRequest
     {
         #region Instance
@@ -34,6 +39,15 @@
         #region Fields
 
         private static readonly SimulationProcessor instance = new SimulationProcessor();
+
+        #endregion
+
+        #region Constructors
+
+        static SimulationProcessor()
+        {
+            SimManager.OnReady += GetStageInfo;
+        }
 
         #endregion
 
@@ -72,7 +86,13 @@
 
         #endregion
 
-        #region Methods: public
+        #region Methods
+
+        private static void GetStageInfo()
+        {
+            Stages = SimManager.Stages;
+            LastStage = SimManager.LastStage;
+        }
 
         public static void RequestUpdate()
         {
@@ -89,9 +109,6 @@
                 return;
             }
 
-            Stages = SimManager.Stages;
-            LastStage = SimManager.LastStage;
-
             if (Stages != null && LastStage != null)
             {
                 ShowDetails = true;
@@ -102,11 +119,8 @@
                 SimManager.Gravity = FlightGlobals.ActiveVessel.mainBody.gravParameter /
                                      Math.Pow(FlightGlobals.ActiveVessel.mainBody.Radius +
                                               FlightGlobals.ActiveVessel.mainBody.GetAltitude(FlightGlobals.ActiveVessel.CoM), 2);
-                SimManager.Velocity = FlightGlobals.ActiveVessel.srfSpeed;
+                SimManager.Mach = FlightGlobals.ActiveVessel.mach;
             }
-
-            // Cybutek: We should be allowing this to be set too but not sure where you want to put the control
-            //SimManager.vectoredThrust = vectoredThrust; 
         }
 
         #endregion

--- a/KerbalEngineer/Flight/Readouts/Vessel/SuicideBurnProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/SuicideBurnProcessor.cs
@@ -19,12 +19,18 @@
 
 #region Using Directives
 
-using System;
+
 
 #endregion
 
 namespace KerbalEngineer.Flight.Readouts.Vessel
 {
+    #region Using Directives
+
+    using System;
+
+    #endregion
+
     public class SuicideBurnProcessor : IUpdatable, IUpdateRequest
     {
         #region Fields
@@ -55,7 +61,7 @@
 
         #endregion
 
-        #region Methods: public
+        #region Methods
 
         public static void RequestUpdate()
         {
@@ -79,7 +85,9 @@
 
             this.gravity = FlightGlobals.currentMainBody.gravParameter / Math.Pow(FlightGlobals.currentMainBody.Radius, 2.0);
             this.acceleration = SimulationProcessor.LastStage.thrust / SimulationProcessor.LastStage.totalMass;
-            this.radarAltitude = FlightGlobals.ship_altitude - FlightGlobals.ActiveVessel.terrainAltitude;
+            this.radarAltitude = FlightGlobals.ActiveVessel.terrainAltitude > 0.0
+                ? FlightGlobals.ship_altitude - FlightGlobals.ActiveVessel.terrainAltitude
+                : FlightGlobals.ship_altitude;
 
             DeltaV = Math.Sqrt((2 * this.gravity * this.radarAltitude) + Math.Pow(FlightGlobals.ship_verticalSpeed, 2.0));
             Altitude = Math.Pow(DeltaV, 2.0) / (2.0 * this.acceleration);

--- a/KerbalEngineer/Flight/Sections/SectionEditor.cs
+++ b/KerbalEngineer/Flight/Sections/SectionEditor.cs
@@ -119,7 +119,7 @@
             try
             {
                 this.InitialiseStyles();
-                ReadoutCategory.Selected = ReadoutCategory.GetCategory("Orbital");
+                //ReadoutCategory.Selected = ReadoutCategory.GetCategory("Orbital");
                 RenderingManager.AddToPostDrawQueue(0, this.Draw);
             }
             catch (Exception ex)
@@ -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
@@ -118,7 +118,7 @@
         /// </summary>
         private void Draw()
         {
-            if (this.ParentSection == null || !this.ParentSection.IsVisible || (DisplayStack.Instance.Hidden && !this.ParentSection.IsHud))
+            if (this.ParentSection == null || !this.ParentSection.IsVisible || (DisplayStack.Instance.Hidden && !this.ParentSection.IsHud) || !FlightEngineerCore.IsDisplayable)
             {
                 return;
             }
@@ -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,6 +38,12 @@
                 return Vector3d.zero;
             }
         }
+
+        public void Reset()
+        {
+            sum = Vector3d.zero;
+            count = 0;
+        }
     }
 
     public class WeightedVectorAverager
@@ -61,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
@@ -19,19 +19,39 @@
 
 using System;
 using System.Collections.Generic;
+using KerbalEngineer.VesselSimulator;
 
 namespace KerbalEngineer
 {
     // a (force, application point) tuple
     public class AppliedForce
     {
+        private static readonly Pool<AppliedForce> pool = new Pool<AppliedForce>(Create, Reset);
+
         public Vector3d vector;
         public Vector3d applicationPoint;
 
-        public AppliedForce(Vector3d vector, Vector3d applicationPoint) {
-            this.vector = vector;
-            this.applicationPoint = applicationPoint;
+        static private AppliedForce Create()
+        {
+            return new AppliedForce();
         }
+
+        static private void Reset(AppliedForce appliedForce) { }
+
+        static public AppliedForce New(Vector3d vector, Vector3d applicationPoint)
+        {
+            AppliedForce force = pool.Borrow();
+            force.vector = vector;
+            force.applicationPoint = applicationPoint;
+            return force;
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+
     }
 
 	// This class was mostly adapted from FARCenterQuery, part of FAR, by ferram4, GPLv3
@@ -47,7 +67,7 @@
 	// some amount of residual torque. The line with the least amount of residual torque is chosen.
 	public class ForceAccumulator
 	{
-		// Total force.
+	    // Total force.
 		private Vector3d totalForce = Vector3d.zero;
 		// Torque needed to compensate if force were applied at origin.
 		private Vector3d totalZeroOriginTorque = Vector3d.zero;
@@ -99,5 +119,12 @@
         {
             return GetMinTorqueForceApplicationPoint(avgApplicationPoint.Get());
         }
+
+	    public void Reset()
+	    {
+	        totalForce = Vector3d.zero;
+	        totalZeroOriginTorque = Vector3d.zero;
+            avgApplicationPoint.Reset();
+	    }
 	}
 }

--- /dev/null
+++ b/KerbalEngineer/Helpers/Pool.cs
@@ -1,1 +1,53 @@
+using System.Collections.Generic;
 
+namespace KerbalEngineer
+{
+    /// <summary>
+    ///     Pool of object
+    /// </summary>
+    public class Pool<T> {
+        
+        private readonly Stack<T> values = new Stack<T>();
+
+        private readonly CreateDelegate<T> create;
+        private readonly ResetDelegate<T> reset;
+
+        public delegate R CreateDelegate<out R>();
+        public delegate void ResetDelegate<in T1>(T1 a);
+        
+        /// <summary>
+        ///     Creates an empty pool with the specified object creation and reset delegates.
+        /// </summary>
+        public Pool(CreateDelegate<T> create, ResetDelegate<T> reset) {
+            this.create = create;
+            this.reset = reset;
+        }
+
+        /// <summary>
+        ///     Borrows an object from the pool.
+        /// </summary>
+        public T Borrow() {
+            lock (values) {
+                return values.Count > 0 ? values.Pop() : create();
+            }
+        }
+        
+        /// <summary>
+        ///     Release an object, reset it and returns it to the pool.
+        /// </summary>
+        public void Release(T value) {
+            reset(value);
+            lock (values) {
+                values.Push(value);
+            }
+        }
+        
+        /// <summary>
+        ///     Current size of the pool.
+        /// </summary>
+        public int Count()
+        {
+            return values.Count;
+        }
+    }
+}

--- 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
@@ -17,28 +17,57 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-
-#endregion
-
 namespace KerbalEngineer.Helpers
 {
+    using System;
+
     public static class Units
     {
-        #region Methods: public
-
-        public static string Concat(double value1, double value2, int decimals = 1)
+        public const double GRAVITY = 9.80665;
+
+        public static string Concat(int value1, int value2)
+        {
+            return value1 + " / " + value2;
+        }
+
+        public static string ConcatF(double value1, double value2, int decimals = 1)
         {
             return value1.ToString("F" + decimals) + " / " + value2.ToString("F" + decimals);
         }
 
-        public static string Concat(double value1, double value2, double value3, int decimals = 1)
+        public static string ConcatF(double value1, double value2, double value3, int decimals = 1)
         {
             return value1.ToString("F" + decimals) + " / " + value2.ToString("F" + decimals) + " / " + value3.ToString("F" + decimals);
         }
 
+        public static string ConcatN(double value1, double value2, int decimals = 1)
+        {
+            return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals);
+        }
+
+        public static string ConcatN(double value1, double value2, double value3, int decimals = 1)
+        {
+            return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals) + " / " + value3.ToString("N" + decimals);
+        }
+
+        public static string Cost(double value, int decimals = 1)
+        {
+            if (value >= 1000000.0)
+            {
+                return (value / 1000.0).ToString("N" + decimals) + "K";
+            }
+            return value.ToString("N" + decimals);
+        }
+
+        public static string Cost(double value1, double value2, int decimals = 1)
+        {
+            if (value1 >= 1000000.0 || value2 >= 1000000.0)
+            {
+                return (value1 / 1000.0).ToString("N" + decimals) + " / " + (value2 / 1000.0).ToString("N" + decimals) + "K";
+            }
+            return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals);
+        }
+
         public static string ToAcceleration(double value, int decimals = 2)
         {
             return value.ToString("N" + decimals) + "m/s²";
@@ -52,6 +81,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)
@@ -83,9 +123,9 @@
             return value.ToString("N" + decimals) + "Mm";
         }
 
-        public static string ToTorque(double value)
-        {
-            return value.ToString((value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N1" : "N0") + "kNm";
+        public static string ToFlux(double value)
+        {
+            return value.ToString("#,0.00") + "W";
         }
 
         public static string ToForce(double value)
@@ -95,19 +135,34 @@
 
         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)
         {
+            if (value >= 1000.0)
+            {
+                return value.ToString("N" + decimals + 2) + "t";
+            }
+
             value *= 1000.0;
             return value.ToString("N" + decimals) + "kg";
         }
 
         public static string ToMass(double value1, double value2, int decimals = 0)
         {
+            if (value1 >= 1000.0f || value2 >= 1000.0f)
+            {
+                return value1.ToString("N" + decimals + 2) + " / " + value2.ToString("N" + decimals + 2) + "t";
+            }
+
             value1 *= 1000.0;
             value2 *= 1000.0;
             return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals) + "kg";
@@ -133,11 +188,24 @@
             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);
         }
 
-        #endregion
+        public static string ToTorque(double value)
+        {
+            return value.ToString((value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N1" : "N0") + "kNm";
+        }
     }
 }

--- a/KerbalEngineer/KerbalEngineer.csproj
+++ b/KerbalEngineer/KerbalEngineer.csproj
@@ -48,9 +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\FlightEngineerPartless.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" />
@@ -69,10 +71,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" />
@@ -87,7 +100,30 @@
     <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\AttitudeProcessor.cs" />
     <Compile Include="Flight\Readouts\Vessel\DeltaVCurrentTotal.cs" />
+    <Compile Include="Flight\Readouts\Vessel\PitchRate.cs" />
+    <Compile Include="Flight\Readouts\Vessel\HeadingRate.cs" />
+    <Compile Include="Flight\Readouts\Vessel\RollRate.cs" />
+    <Compile Include="Flight\Readouts\Vessel\Roll.cs" />
+    <Compile Include="Flight\Readouts\Vessel\Pitch.cs" />
+    <Compile Include="Flight\Readouts\Vessel\Heading.cs" />
+    <Compile Include="Flight\Readouts\Vessel\PartCount.cs" />
     <Compile Include="Flight\Readouts\Vessel\SuicideBurnDeltaV.cs" />
     <Compile Include="Flight\Readouts\Vessel\SuicideBurnAltitude.cs" />
     <Compile Include="Flight\Readouts\Vessel\SuicideBurnDistance.cs" />
@@ -135,7 +171,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" />
@@ -189,6 +224,7 @@
     <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" />
@@ -213,6 +249,7 @@
       <Private>False</Private>
     </Reference>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Target Name="PostBuildMacros">
     <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">

--- 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,42 +19,62 @@
 
 #region Using Directives
 
-using System;
-using System.Text;
-
 #endregion
 
 namespace KerbalEngineer.VesselSimulator
 {
+    using System;
+    using System.Text;
+
     internal class AttachNodeSim
     {
+
+        private static readonly Pool<AttachNodeSim> pool = new Pool<AttachNodeSim>(Create, Reset);
+
         public PartSim attachedPartSim;
         public String id;
         public AttachNode.NodeType nodeType;
 
-        public AttachNodeSim(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
+        private static AttachNodeSim Create()
         {
-            this.attachedPartSim = partSim;
-            this.nodeType = newNodeType;
-            this.id = newId;
+            return new AttachNodeSim();
+        }
+
+        public static AttachNodeSim New(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
+        {
+            AttachNodeSim nodeSim = pool.Borrow();
+
+            nodeSim.attachedPartSim = partSim;
+            nodeSim.nodeType = newNodeType;
+            nodeSim.id = newId;
+
+            return nodeSim;
+        }
+
+        static private void Reset(AttachNodeSim attachNodeSim) { }
+
+
+        public void Release()
+        {
+            pool.Release(this);
         }
 
         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,307 +17,354 @@
 //     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;
+        public List<AppliedForce> appliedForces = new List<AppliedForce>();
+        public float maxMach;
 
         public double thrust = 0;
 
         // Add thrust vector to account for directional losses
         public Vector3 thrustVec;
 
-        public EngineSim(PartSim theEngine,
+        private static EngineSim Create()
+        {
+            return new EngineSim();
+        }
+
+        private static void Reset(EngineSim engineSim)
+        {
+            engineSim.resourceConsumptions.Reset();
+            engineSim.resourceFlowModes.Reset();
+            engineSim.actualThrust = 0;
+            engineSim.isActive = false;
+            engineSim.isp = 0;
+            for (int i = 0; i < engineSim.appliedForces.Count; i++)
+            {
+                engineSim.appliedForces[i].Release();
+            }
+            engineSim.appliedForces.Clear();
+            engineSim.thrust = 0;
+            engineSim.maxMach = 0f;
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+        public static EngineSim New(PartSim theEngine,
                          double atmosphere,
-                         double velocity,
-                         float maxThrust,
-                         float minThrust,
+                         float machNumber,
+                         float maxFuelFlow,
+                         float minFuelFlow,
                          float thrustPercentage,
-                         float requestedThrust,
                          Vector3 vecThrust,
-                         float realIsp,
                          FloatCurve atmosphereCurve,
-                         FloatCurve velocityCurve,
+                         bool atmChangeFlow,
+                         FloatCurve atmCurve,
+                         FloatCurve velCurve,
+                         float currentThrottle,
+                         float IspG,
                          bool throttleLocked,
                          List<Propellant> propellants,
                          bool active,
-                         bool correctThrust,
-                         List<Transform> thrustTransforms)
-        {
-            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);
-
-            this.partSim = theEngine;
-
-            this.isActive = active;
-            this.thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust;
-            //MonoBehaviour.print("thrust = " + thrust);
-
-            this.thrustVec = vecThrust;
-
-            double flowRate = 0d;
-            if (this.partSim.hasVessel)
-            {
-                //MonoBehaviour.print("hasVessel is true");
-                this.actualThrust = isActive ? requestedThrust : 0.0;
-                if (velocityCurve != null)
-                {
-                    this.actualThrust *= velocityCurve.Evaluate((float)velocity);
-                    //MonoBehaviour.print("actualThrust at velocity = " + actualThrust);
-                }
-
-                this.isp = atmosphereCurve.Evaluate((float)this.partSim.part.staticPressureAtm);
-                if (this.isp == 0d)
-                {
-                    MonoBehaviour.print("Isp at " + this.partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN");
-                }
-
-                if (correctThrust && realIsp == 0)
-                {
-                    float ispsl = atmosphereCurve.Evaluate(0);
-                    if (ispsl != 0)
+                         float resultingThrust,
+                         List<Transform> thrustTransforms,
+                        LogMsg log)
+        {
+            EngineSim engineSim = pool.Borrow();
+
+            engineSim.isp = 0.0;
+            engineSim.maxMach = 0.0f;
+            engineSim.actualThrust = 0.0;
+            engineSim.partSim = theEngine;
+            engineSim.isActive = active;
+            engineSim.thrustVec = vecThrust;
+            engineSim.resourceConsumptions.Reset();
+            engineSim.resourceFlowModes.Reset();
+            engineSim.appliedForces.Clear();
+
+            double flowRate = 0.0;
+            if (engineSim.partSim.hasVessel)
+            {
+                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);
+                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)
+                {
+                    if (log != null) log.buf.AppendLine("throttleLocked is true, using thrust for flowRate");
+                    flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
+                }
+                else
+                {
+                    if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
                     {
-                        this.thrust = this.thrust * this.isp / ispsl;
+                        if (log != null) log.buf.AppendLine("throttled up and not landed, using actualThrust for flowRate");
+                        flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                     }
                     else
                     {
-                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
+                        if (log != null) log.buf.AppendLine("throttled down or landed, using thrust for flowRate");
+                        flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                     }
-                    //MonoBehaviour.print("corrected thrust = " + thrust);
-                }
-
-                if (velocityCurve != null)
-                {
-                    this.thrust *= velocityCurve.Evaluate((float)velocity);
-                    //MonoBehaviour.print("thrust at velocity = " + thrust);
-                }
-
-                if (throttleLocked)
-                {
-                    //MonoBehaviour.print("throttleLocked is true");
-                    flowRate = this.thrust / (this.isp * 9.82);
-                }
-                else
-                {
-                    if (this.partSim.isLanded)
-                    {
-                        //MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle);
-                        flowRate = Math.Max(0.000001d, this.thrust * FlightInputHandler.state.mainThrottle) / (this.isp * 9.82);
-                    }
-                    else
-                    {
-                        if (requestedThrust > 0)
-                        {
-                            if (velocityCurve != null)
-                            {
-                                requestedThrust *= velocityCurve.Evaluate((float)velocity);
-                                //MonoBehaviour.print("requestedThrust at velocity = " + requestedThrust);
-                            }
-
-                            //MonoBehaviour.print("requestedThrust > 0");
-                            flowRate = requestedThrust / (this.isp * 9.82);
-                        }
-                        else
-                        {
-                            //MonoBehaviour.print("requestedThrust <= 0");
-                            flowRate = this.thrust / (this.isp * 9.82);
-                        }
-                    }
                 }
             }
             else
             {
-                //MonoBehaviour.print("hasVessel is false");
-                this.isp = atmosphereCurve.Evaluate((float)atmosphere);
-                if (this.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);
-                }
-
-                if (velocityCurve != null)
-                {
-                    this.thrust *= velocityCurve.Evaluate((float)velocity);
-                    //MonoBehaviour.print("thrust at velocity = " + thrust);
-                }
-
-                flowRate = this.thrust / (this.isp * 9.82);
-            }
-
-            if (SimManager.logOutput)
-            {
-                buffer = new StringBuilder(1024);
-                buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);
-            }
+                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);
+                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;
-            foreach (Propellant propellant in propellants)
-            {
-                flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
-            }
-
-            if (SimManager.logOutput)
-            {
-                buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);
-            }
-
-            foreach (Propellant propellant in propellants)
-            {
+            for (int i = 0; i < propellants.Count; ++i)
+            {
+                Propellant propellant = propellants[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("Add consumption({0}, {1}:{2:d}) = {3:g6}\n", ResourceContainer.GetResourceName(propellant.id), theEngine.name, theEngine.partId, consumptionRate);
-                }
-                this.resourceConsumptions.Add(propellant.id, consumptionRate);
-            }
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print(buffer);
-            }
-
-            appliedForces = new List<AppliedForce>();
-            double thrustPerThrustTransform = thrust / thrustTransforms.Count;
-            foreach (Transform thrustTransform in thrustTransforms) {
+                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);
+                engineSim.resourceFlowModes.Add(propellant.id, (double)propellant.GetFlowMode());
+            }
+
+            double thrustPerThrustTransform = engineSim.thrust / thrustTransforms.Count;
+            for (int i = 0; i < thrustTransforms.Count; i++)
+            {
+                Transform thrustTransform = thrustTransforms[i];
                 Vector3d direction = thrustTransform.forward.normalized;
                 Vector3d position = thrustTransform.position;
-                appliedForces.Add(new AppliedForce(direction * thrustPerThrustTransform, position));
-            }
+
+                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
+        Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>();
+
+        Dictionary<int, HashSet<PartSim>> stagePartSets = new Dictionary<int, HashSet<PartSim>>();
+
+        HashSet<PartSim> visited = new HashSet<PartSim>();
 
         public bool SetResourceDrains(List<PartSim> allParts, List<PartSim> allFuelLines, HashSet<PartSim> drainingParts)
         {
             LogMsg log = null;
-
-            // A dictionary to hold a set of parts for each resource
-            Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>();
-
-            foreach (int type in this.resourceConsumptions.Types)
-            {
-                HashSet<PartSim> sourcePartSet = null;
-                switch (ResourceContainer.GetResourceFlowMode(type))
+            
+            foreach (HashSet<PartSim> sourcePartSet in sourcePartSets.Values)
+            {
+                sourcePartSet.Clear();
+            }
+
+            for (int index = 0; index < this.resourceConsumptions.Types.Count; index++)
+            {
+                int type = this.resourceConsumptions.Types[index];
+
+                HashSet<PartSim> sourcePartSet;
+                if (!sourcePartSets.TryGetValue(type, out sourcePartSet))
+                {
+                    sourcePartSet = new HashSet<PartSim>();
+                    sourcePartSets.Add(type, sourcePartSet);
+                }
+
+                switch ((ResourceFlowMode)this.resourceFlowModes[type])
                 {
                     case ResourceFlowMode.NO_FLOW:
-                        if (this.partSim.resources[type] > SimManager.RESOURCE_MIN)
-                        {
-                            sourcePartSet = new HashSet<PartSim>();
+                        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;
 
                     case ResourceFlowMode.ALL_VESSEL:
-                        foreach (PartSim aPartSim in allParts)
-                        {
-                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)
+                        for (int i = 0; i < allParts.Count; i++)
+                        {
+                            PartSim aPartSim = allParts[i];
+                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN && aPartSim.resourceFlowStates[type] != 0)
                             {
-                                if (sourcePartSet == null)
-                                {
-                                    sourcePartSet = new HashSet<PartSim>();
-                                }
-
                                 sourcePartSet.Add(aPartSim);
                             }
                         }
                         break;
 
                     case ResourceFlowMode.STAGE_PRIORITY_FLOW:
-                    {
-                        Dictionary<int, HashSet<PartSim>> stagePartSets = new Dictionary<int, HashSet<PartSim>>();
-                        int maxStage = -1;
-                        foreach (PartSim aPartSim in allParts)
-                        {
-                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)
+
+                        foreach (HashSet<PartSim> stagePartSet in stagePartSets.Values)
+                        {
+                            stagePartSet.Clear();
+                        }
+                        var maxStage = -1;
+
+                        //Logger.Log(type);
+                        for (int i = 0; i < allParts.Count; i++)
+                        {
+                            var aPartSim = allParts[i];
+                            if (aPartSim.resources[type] <= SimManager.RESOURCE_MIN || aPartSim.resourceFlowStates[type] == 0)
                             {
-                                //int stage = aPartSim.decoupledInStage;            // Use the number of the stage the tank is decoupled in
-                                int stage = aPartSim.DecouplerCount(); // Use the count of decouplers between tank and root
-                                if (stage > maxStage)
-                                {
-                                    maxStage = stage;
-                                }
-                                if (stagePartSets.ContainsKey(stage))
-                                {
-                                    sourcePartSet = stagePartSets[stage];
-                                }
-                                else
-                                {
-                                    sourcePartSet = new HashSet<PartSim>();
-                                    stagePartSets.Add(stage, sourcePartSet);
-                                }
-
-                                sourcePartSet.Add(aPartSim);
+                                continue;
                             }
-                        }
-
-                        while (maxStage >= 0)
-                        {
-                            if (stagePartSets.ContainsKey(maxStage))
+
+                            int stage = aPartSim.DecouplerCount();
+                            if (stage > maxStage)
                             {
-                                if (stagePartSets[maxStage].Count() > 0)
-                                {
-                                    sourcePartSet = stagePartSets[maxStage];
-                                    break;
-                                }
+                                maxStage = stage;
                             }
-                            maxStage--;
-                        }
-                    }
+
+                            if (!stagePartSets.TryGetValue(stage, out sourcePartSet))
+                            {
+                                sourcePartSet = new HashSet<PartSim>();
+                                stagePartSets.Add(stage, sourcePartSet);
+                            }
+                            sourcePartSet.Add(aPartSim);
+                        }
+
+                        for (int j = 0; j <= maxStage; j++)
+                        {
+                            HashSet<PartSim> stagePartSet;
+                            if (stagePartSets.TryGetValue(j, out stagePartSet) && stagePartSet.Count > 0)
+                            {
+                                sourcePartSet = stagePartSet;
+                            }
+                        }
                         break;
 
                     case ResourceFlowMode.STACK_PRIORITY_SEARCH:
-                        HashSet<PartSim> visited = new HashSet<PartSim>();
+                        visited.Clear();
 
                         if (SimManager.logOutput)
                         {
                             log = new LogMsg();
-                            log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + this.partSim.name + ":" + this.partSim.partId);
-                        }
-                        sourcePartSet = this.partSim.GetSourceSet(type, allParts, visited, 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);
@@ -325,11 +372,12 @@
                         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 != null && sourcePartSet.Count > 0)
+
+                if (sourcePartSet.Count > 0)
                 {
                     sourcePartSets[type] = sourcePartSet;
                     if (SimManager.logOutput)
@@ -344,47 +392,44 @@
                     }
                 }
             }
-
+            
             // If we don't have sources for all the needed resources then return false without setting up any drains
-            foreach (int type in this.resourceConsumptions.Types)
-            {
-                if (!sourcePartSets.ContainsKey(type))
+            for (int i = 0; i < this.resourceConsumptions.Types.Count; i++)
+            {
+                int type = this.resourceConsumptions.Types[i];
+                HashSet<PartSim> sourcePartSet; 
+                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
-            foreach (int type in this.resourceConsumptions.Types)
-            {
+            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)
                     {
-                        MonoBehaviour.print("Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" + partSim.partId);
+                        MonoBehaviour.print(
+                            "Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" +
+                            partSim.partId);
                     }
 
                     partSim.resourceDrains.Add(type, amount);
                     drainingParts.Add(partSim);
                 }
             }
-
             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,32 +17,32 @@
 //     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
     {
+        private static readonly Pool<PartSim> pool = new Pool<PartSim>(Create, Reset);
+
         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;
@@ -55,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;
@@ -68,214 +70,226 @@
         public double startMass = 0d;
         public String vesselName;
         public VesselType vesselType;
-
-        public PartSim(Part thePart, int id, double atmosphere, LogMsg log)
-        {
-            this.part = thePart;
-            this.centerOfMass = thePart.transform.TransformPoint(thePart.CoMOffset);
-            this.partId = id;
-            this.name = this.part.partInfo.name;
+        
+
+        private static PartSim Create()
+        {
+            return new PartSim();
+        }
+
+        private static void Reset(PartSim partSim)
+        {
+            for (int i = 0; i < partSim.attachNodes.Count; i++)
+            {
+                partSim.attachNodes[i].Release();
+            }
+            partSim.attachNodes.Clear();
+            partSim.fuelTargets.Clear();
+            partSim.resourceDrains.Reset();
+            partSim.resourceFlowStates.Reset();
+            partSim.resources.Reset();
+            partSim.baseCost = 0d;
+            partSim.baseMass = 0d;
+            partSim.baseMassForCoM = 0d;
+            partSim.startMass = 0d;
+        }
+
+        public void Release()
+        {
+            pool.Release(this);
+        }
+
+        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);
+
+            partSim.parent = null;
+            partSim.parentAttach = partSim.part.attachMode;
+            partSim.fuelCrossFeed = partSim.part.fuelCrossFeed;
+            partSim.noCrossFeedNodeKey = partSim.part.NoCrossFeedNodeKey;
+            partSim.decoupledInStage = partSim.DecoupledInStage(partSim.part);
+            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.baseCost = partSim.part.GetCostDry();
 
             if (log != null)
             {
-                log.buf.AppendLine("Create PartSim for " + this.name);
-            }
-
-            this.parent = null;
-            this.parentAttach = part.attachMode;
-            this.fuelCrossFeed = this.part.fuelCrossFeed;
-            this.noCrossFeedNodeKey = this.part.NoCrossFeedNodeKey;
-            this.decoupledInStage = this.DecoupledInStage(this.part);
-            this.isFuelLine = this.part is FuelLine;
-            this.isFuelTank = this.part is FuelTank;
-            this.isSepratron = this.IsSepratron();
-            this.inverseStage = this.part.inverseStage;
-            //MonoBehaviour.print("inverseStage = " + inverseStage);
-
-            this.cost = this.part.GetCostWet();
+                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
-            this.isNoPhysics = this.part.HasModule<LaunchClamp>() ||
-                               this.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
-                               this.part.PhysicsSignificance == 1;
-
-            if (!this.isNoPhysics)
-            {
-                this.baseMass = this.part.mass;
-            }
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print((this.isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + this.part.mass);
-            }
-
-            foreach (PartResource resource in this.part.Resources)
-            {
+            // 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++)
+            {
+                PartResource resource = partSim.part.Resources[i];
+
                 // Make sure it isn't NaN as this messes up the part mass and hence most of the values
                 // 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);
-                    }
-
-                    this.resources.Add(resource.info.id, resource.amount);
-                    this.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
+                    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.");
-                }
-            }
-
-            this.startMass = this.GetMass();
-
-            this.hasVessel = (this.part.vessel != null);
-            this.isLanded = this.hasVessel && this.part.vessel.Landed;
-            if (this.hasVessel)
-            {
-                this.vesselName = this.part.vessel.vesselName;
-                this.vesselType = this.part.vesselType;
-            }
-            this.initialVesselName = this.part.initialVesselName;
-
-            this.hasMultiModeEngine = this.part.HasModule<MultiModeEngine>();
-            this.hasModuleEnginesFX = this.part.HasModule<ModuleEnginesFX>();
-            this.hasModuleEngines = this.part.HasModule<ModuleEngines>();
-
-            this.isEngine = this.hasMultiModeEngine || this.hasModuleEnginesFX || this.hasModuleEngines;
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print("Created " + this.name + ". Decoupled in stage " + this.decoupledInStage);
+                    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;
+            if (partSim.hasVessel)
+            {
+                partSim.vesselName = partSim.part.vessel.vesselName;
+                partSim.vesselType = partSim.part.vesselType;
+            }
+            partSim.initialVesselName = partSim.part.initialVesselName;
+
+            partSim.hasMultiModeEngine = partSim.part.HasModule<MultiModeEngine>();
+            partSim.hasModuleEngines = partSim.part.HasModule<ModuleEngines>();
+
+            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; }
-        }
-
-        public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double velocity, bool vectoredThrust, LogMsg log)
-        {
-            bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(this.part);
+            get
+            {
+                return resources;
+            }
+        }
+
+        public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
+        {
             if (log != null)
             {
                 log.buf.AppendLine("CreateEngineSims for " + this.name);
-
-                foreach (PartModule partMod in this.part.Modules)
-                {
+                for (int i = 0; i < this.part.Modules.Count; i++)
+                {
+                    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;
-
-                foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>())
-                {
+            }
+
+            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 = new EngineSim(this,
-                                                            atmosphere,
-                                                            velocity,
-                                                            engine.maxThrust,
-                                                            engine.minThrust,
-                                                            engine.thrustPercentage,
-                                                            engine.requestedThrust,
-                                                            thrustvec,
-                                                            engine.realIsp,
-                                                            engine.atmosphereCurve,
-                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
-                                                            engine.throttleLocked,
-                                                            engine.propellants,
-                                                            engine.isOperational,
-                                                            correctThrust,
-                                                            engine.thrustTransforms);
+                        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);
                     }
                 }
             }
-            else
-            {
-                if (this.hasModuleEnginesFX)
-                {
-                    foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>())
-                    {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Module: " + engine.moduleName);
-                        }
-
-                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
-                        EngineSim engineSim = new EngineSim(this,
-                                                            atmosphere,
-                                                            velocity,
-                                                            engine.maxThrust,
-                                                            engine.minThrust,
-                                                            engine.thrustPercentage,
-                                                            engine.requestedThrust,
-                                                            thrustvec,
-                                                            engine.realIsp,
-                                                            engine.atmosphereCurve,
-                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
-                                                            engine.throttleLocked,
-                                                            engine.propellants,
-                                                            engine.isOperational,
-                                                            correctThrust,
-                                                            engine.thrustTransforms);
-                        allEngines.Add(engineSim);
-                    }
-                }
-
-                if (this.hasModuleEngines)
-                {
-                    foreach (ModuleEngines engine in this.part.GetModules<ModuleEngines>())
-                    {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Module: " + engine.moduleName);
-                        }
-
-                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
-                        EngineSim engineSim = new EngineSim(this,
-                                                            atmosphere,
-                                                            velocity,
-                                                            engine.maxThrust,
-                                                            engine.minThrust,
-                                                            engine.thrustPercentage,
-                                                            engine.requestedThrust,
-                                                            thrustvec,
-                                                            engine.realIsp,
-                                                            engine.atmosphereCurve,
-                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
-                                                            engine.throttleLocked,
-                                                            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);
                 }
             }
 
@@ -285,177 +299,148 @@
             }
         }
 
-        private Vector3 CalculateThrustVector(List<Transform> thrustTransforms, LogMsg log)
-        {
-            if (thrustTransforms == null)
-            {
-                return Vector3.forward;
-            }
-
-            Vector3 thrustvec = Vector3.zero;
-            foreach (Transform trans in thrustTransforms)
-            {
-                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();
-            foreach (AttachNode attachNode in this.part.attachNodes)
-            {
-                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 + "");
-                        }
-
-                        this.attachNodes.Add(new AttachNodeSim(attachedSim, attachNode.id, attachNode.nodeType));
-                    }
-                    else
-                    {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("No PartSim for attached part (" + attachNode.attachedPart.partInfo.name + ")");
-                        }
-                    }
-                }
-            }
-
-            foreach (Part p in this.part.fuelLookupTargets)
-            {
-                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;
-            }
-
-            var modList = this.part.Modules.OfType<ModuleEngines>();
-            if (modList.Count() == 0)
-            {
-                return false;
-            }
-
-            if (modList.First().throttleLocked)
-            {
-                return true;
-            }
-
-            return false;
+        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()
@@ -466,67 +451,55 @@
         // All functions below this point must not rely on the part member (it may be null)
         //
 
-        public HashSet<PartSim> GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, LogMsg log, String indent)
+        public void GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, HashSet<PartSim> allSources, LogMsg log, String indent)
         {
             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 += "  ";
             }
 
-            HashSet<PartSim> allSources = new HashSet<PartSim>();
-            HashSet<PartSim> partSources = null;
-
-            // Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns empty list.
+            // 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 + ")");
-                }
-
-                return allSources;
-            }
-
-            //if (log != null)
-            //    log.buf.AppendLine(indent + "Adding this to visited");
+                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");
 
             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");
-
-            foreach (PartSim partSim in this.fuelTargets)
-            {
-                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 + ")");
-
-                    partSources = partSim.GetSourceSet(type, allParts, visited, log, indent);
-                    if (partSources.Count > 0)
-                    {
-                        allSources.UnionWith(partSources);
-                        partSources.Clear();
-                    }
-                }
-            }
-
-            if (allSources.Count > 0)
-            {
-                if (log != null)
-                {
-                    log.buf.AppendLine(indent + "Returning " + allSources.Count + " fuel target sources (" + this.name + ":" + this.partId + ")");
-                }
-
-                return allSources;
-            }
+            //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 (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 + ")");
+                return;
+            }
+
 
             // Rule 3: This rule has been removed and merged with rules 4 and 7 to fix issue with fuel tanks with disabled crossfeed
 
@@ -535,47 +508,40 @@
             //  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)
-            {
-                //MonoBehaviour.print("foreach attach node");
-                foreach (AttachNodeSim attachSim in this.attachNodes)
-                {
+            if (fuelCrossFeed)
+            {
+                lastCount = allSources.Count;
+                //MonoBehaviour.print("for each attach node");
+                for (int i = 0; i < this.attachNodes.Count; i++)
+                {
+                    AttachNodeSim attachSim = this.attachNodes[i];
                     if (attachSim.attachedPartSim != null)
                     {
                         if (attachSim.nodeType == AttachNode.NodeType.Stack)
                         {
-                            if (!(this.noCrossFeedNodeKey != null && this.noCrossFeedNodeKey.Length > 0 && attachSim.id.Contains(this.noCrossFeedNodeKey)))
+                            if (
+                                !(this.noCrossFeedNodeKey != null && this.noCrossFeedNodeKey.Length > 0 &&
+                                  attachSim.id.Contains(this.noCrossFeedNodeKey)))
                             {
                                 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 + ")");
-
-                                    partSources = attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, log, indent);
-                                    if (partSources.Count > 0)
-                                    {
-                                        allSources.UnionWith(partSources);
-                                        partSources.Clear();
-                                    }
+                                    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);
                                 }
                             }
                         }
                     }
                 }
 
-                if (allSources.Count > 0)
-                {
-                    if (log != null)
-                    {
-                        log.buf.AppendLine(indent + "Returning " + allSources.Count + " attached sources (" + this.name + ":" + this.partId + ")");
-                    }
-
-                    return allSources;
+                if (allSources.Count > lastCount)
+                {
+                    if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " attached sources (" + this.name + ":" + this.partId + ")");
+                    return;
                 }
             }
 
@@ -583,76 +549,143 @@
             // 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 + ")");
-                    }
-                }
-
-                return allSources;
+                    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
                     {
-                        allSources = this.parent.GetSourceSet(type, allParts, visited, log, indent);
-                        if (allSources.Count > 0)
+                        lastCount = allSources.Count;
+                        this.parent.GetSourceSet(type, allParts, visited, allSources, log, indent);
+                        if (allSources.Count > lastCount)
                         {
-                            if (log != null)
-                            {
-                                log.buf.AppendLine(indent + "Returning " + allSources.Count + " parent sources (" + this.name + ":" + this.partId + ")");
-                            }
-
-                            return allSources;
+                            if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count  - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")");
+                            return;
                         }
                     }
                 }
             }
 
             // 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 + ")");
-
-            return allSources;
+            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)
         {
             // Loop through the attached parts
-            foreach (AttachNodeSim attachSim in this.attachNodes)
-            {
+            for (int i = 0; i < this.attachNodes.Count; i++)
+            {
+                AttachNodeSim attachSim = this.attachNodes[i];
                 // If the part is in the set then "remove" it by clearing the PartSim reference
                 if (partSims.Contains(attachSim.attachedPartSim))
                 {
                     attachSim.attachedPartSim = null;
                 }
             }
-        }
-
-        public void DrainResources(double time)
-        {
-            //MonoBehaviour.print("DrainResources(" + name + ":" + partId + ", " + time + ")");
-            foreach (int type in this.resourceDrains.Types)
-            {
-                //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 + ")");
+                }
             }
         }
 
@@ -661,11 +694,13 @@
             //MonoBehaviour.print("TimeToDrainResource(" + name + ":" + partId + ")");
             double time = double.MaxValue;
 
-            foreach (int type in this.resourceDrains.Types)
-            {
-                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);
                 }
             }
@@ -675,98 +710,84 @@
             return time;
         }
 
-        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;
-
-            foreach (int type in this.resources.Types)
-            {
-                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);
-
-            foreach (int type in this.resources.Types)
-            {
-                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 + " ";
-                foreach (PartSim partSim in allParts)
-                {
-                    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
@@ -19,6 +19,7 @@
 
 #region Using Directives
 
+using System;
 using System.Collections;
 using System.Collections.Generic;
 
@@ -30,15 +31,17 @@
 {
     public class ResourceContainer
     {
-        private Hashtable resources = new Hashtable();
+        private Dictionary<int, double> resources = new Dictionary<int, double>();
+        private List<int> types = new List<int>();
 
         public double this[int type]
         {
             get
             {
-                if (this.resources.ContainsKey(type))
+                double value;
+                if (this.resources.TryGetValue(type, out value))
                 {
-                    return (double)this.resources[type];
+                    return value;
                 }
 
                 return 0d;
@@ -52,6 +55,7 @@
                 else
                 {
                     this.resources.Add(type, value);
+                    this.types.Add(type);
                 }
             }
         }
@@ -60,13 +64,6 @@
         {
             get
             {
-                List<int> types = new List<int>();
-
-                foreach (int key in this.resources.Keys)
-                {
-                    types.Add(key);
-                }
-
                 return types;
             }
         }
@@ -92,7 +89,7 @@
             {
                 foreach (int type in this.resources.Keys)
                 {
-                    if ((double)this.resources[type] > SimManager.RESOURCE_MIN)
+                    if (this.resources[type] > SimManager.RESOURCE_MIN)
                     {
                         return false;
                     }
@@ -111,7 +108,7 @@
         {
             foreach (int type in types)
             {
-                if (this.HasType(type) && (double)this.resources[type] > SimManager.RESOURCE_MIN)
+                if (this.HasType(type) && this.resources[type] > SimManager.RESOURCE_MIN)
                 {
                     return false;
                 }
@@ -124,17 +121,19 @@
         {
             if (this.resources.ContainsKey(type))
             {
-                this.resources[type] = (double)this.resources[type] + amount;
+                this.resources[type] = this.resources[type] + amount;
             }
             else
             {
                 this.resources.Add(type, amount);
+                this.types.Add(type);
             }
         }
 
         public void Reset()
         {
-            this.resources = new Hashtable();
+            this.resources.Clear();
+            this.types.Clear();
         }
 
         public void Debug()
@@ -148,7 +147,13 @@
         public double GetResourceMass(int type)
         {
             double density = GetResourceDensity(type);
-            return density == 0d ? 0d : (double)this.resources[type] * density;
+            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)
@@ -170,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
@@ -17,251 +17,192 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
-
-using UnityEngine;
-
-#endregion
-
 namespace KerbalEngineer.VesselSimulator
 {
+    #region Using Directives
+
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.Reflection;
+    using System.Threading;
+    using UnityEngine;
+
+    #endregion
+
     public class SimManager
     {
+        #region Constants
+
         public const double RESOURCE_MIN = 0.0001;
+        public const double RESOURCE_PART_EMPTY_THRESH = 0.01;
+
+        #endregion
+
+        #region Fields
+
+        public static bool dumpTree = false;
+        public static bool logOutput = false;
+        public static TimeSpan minSimTime = new TimeSpan(0, 0, 0, 0, 150);
+        public static bool vectoredThrust = false;
+        private static readonly object locker = new object();
+        private static readonly Stopwatch timer = new Stopwatch();
 
         private static bool bRequested;
         private static bool bRunning;
-        private static readonly Stopwatch timer = new Stopwatch();
-        private static long delayBetweenSims;
-
-        public static bool dumpTree = false;
-        public static bool logOutput = false;
-        public static bool vectoredThrust = false;
-        public static long minSimTime = 150;
+        private static TimeSpan delayBetweenSims;
 
         // Support for RealFuels using reflection to check localCorrectThrust without dependency
-        private static bool hasCheckedForRealFuels;
+
+        private static bool hasCheckedForMods;
         private static bool hasInstalledRealFuels;
-
-        private static FieldInfo RF_ModuleEngineConfigs_locaCorrectThrust;
-        private static FieldInfo RF_ModuleHybridEngine_locaCorrectThrust;
-        private static FieldInfo RF_ModuleHybridEngines_locaCorrectThrust;
+        private static FieldInfo RF_ModuleEngineConfigs_localCorrectThrust;
+        private static FieldInfo RF_ModuleHybridEngine_localCorrectThrust;
+        private static FieldInfo RF_ModuleHybridEngines_localCorrectThrust;
+        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
+
+        public delegate void ReadyEvent();
+
+        #endregion
+
+        #region Events
+
+        public static event ReadyEvent OnReady;
+
+        #endregion
+
+        #region Properties
+
+        public static double Atmosphere { get; set; }
+
+        public static double Gravity { get; set; }
+
+        public static Stage LastStage { get; private set; }
+
         public static Stage[] Stages { get; private set; }
-        public static Stage LastStage { get; private set; }
+
+        public static double Mach { get; set; }
+
         public static String failMessage { get; private set; }
-        public static double Gravity { get; set; }
-        public static double Atmosphere { get; set; }
-        public static double Velocity { get; set; }
-
-        private static void GetRealFuelsTypes()
-        {
-            hasCheckedForRealFuels = true;
-
-            foreach (AssemblyLoader.LoadedAssembly assembly in AssemblyLoader.loadedAssemblies)
+
+        #endregion
+
+        #region Methods
+
+        private static void CheckForMods()
+        {
+            hasCheckedForMods = true;
+
+            foreach (var assembly in AssemblyLoader.loadedAssemblies)
             {
                 MonoBehaviour.print("Assembly:" + assembly.assembly);
 
-                if (assembly.assembly.ToString().Split(',')[0] == "RealFuels")
+                var name = assembly.assembly.ToString().Split(',')[0];
+
+                if (name == "RealFuels")
                 {
                     MonoBehaviour.print("Found RealFuels mod");
 
-                    Type RF_ModuleEngineConfigs_Type = assembly.assembly.GetType("RealFuels.ModuleEngineConfigs");
+                    var RF_ModuleEngineConfigs_Type = assembly.assembly.GetType("RealFuels.ModuleEngineConfigs");
                     if (RF_ModuleEngineConfigs_Type != null)
                     {
-                        RF_ModuleEngineConfigs_locaCorrectThrust = RF_ModuleEngineConfigs_Type.GetField("localCorrectThrust");
-                    }
-
-                    Type RF_ModuleHybridEngine_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngine");
+                        RF_ModuleEngineConfigs_localCorrectThrust = RF_ModuleEngineConfigs_Type.GetField("localCorrectThrust");
+                    }
+
+                    var RF_ModuleHybridEngine_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngine");
                     if (RF_ModuleHybridEngine_Type != null)
                     {
-                        RF_ModuleHybridEngine_locaCorrectThrust = RF_ModuleHybridEngine_Type.GetField("localCorrectThrust");
-                    }
-
-                    Type RF_ModuleHybridEngines_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngines");
+                        RF_ModuleHybridEngine_localCorrectThrust = RF_ModuleHybridEngine_Type.GetField("localCorrectThrust");
+                    }
+
+                    var RF_ModuleHybridEngines_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngines");
                     if (RF_ModuleHybridEngines_Type != null)
                     {
-                        RF_ModuleHybridEngines_locaCorrectThrust = RF_ModuleHybridEngines_Type.GetField("localCorrectThrust");
+                        RF_ModuleHybridEngines_localCorrectThrust = RF_ModuleHybridEngines_Type.GetField("localCorrectThrust");
                     }
 
                     hasInstalledRealFuels = true;
                     break;
                 }
+                else if (name == "KerbalIspDifficultyScaler")
+                {
+                    var KIDS_Utils_Type = assembly.assembly.GetType("KerbalIspDifficultyScaler.KerbalIspDifficultyScalerUtils");
+                    if (KIDS_Utils_Type != null)
+                    {
+                        KIDS_Utils_GetIspMultiplier = KIDS_Utils_Type.GetMethod("GetIspMultiplier");
+                    }
+
+                    hasInstalledKIDS = true;
+                }
             }
         }
 
         public static bool DoesEngineUseCorrectedThrust(Part theEngine)
         {
-            if (!hasInstalledRealFuels /*|| HighLogic.LoadedSceneIsFlight*/)
-            {
-                return false;
-            }
-
-            // Look for any of the Real Fuels engine modules and call the relevant method to find out
-            if (RF_ModuleEngineConfigs_locaCorrectThrust != null && theEngine.Modules.Contains("ModuleEngineConfigs"))
-            {
-                PartModule modEngineConfigs = theEngine.Modules["ModuleEngineConfigs"];
-                if (modEngineConfigs != null)
-                {
-                    // Check the localCorrectThrust
-                    if ((bool)RF_ModuleEngineConfigs_locaCorrectThrust.GetValue(modEngineConfigs))
-                    {
-                        return true;
-                    }
-                }
-            }
-
-            if (RF_ModuleHybridEngine_locaCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngine"))
-            {
-                PartModule modHybridEngine = theEngine.Modules["ModuleHybridEngine"];
-                if (modHybridEngine != null)
-                {
-                    // Check the localCorrectThrust
-                    if ((bool)RF_ModuleHybridEngine_locaCorrectThrust.GetValue(modHybridEngine))
-                    {
-                        return true;
-                    }
-                }
-            }
-
-            if (RF_ModuleHybridEngines_locaCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngines"))
-            {
-                PartModule modHybridEngines = theEngine.Modules["ModuleHybridEngines"];
-                if (modHybridEngines != null)
-                {
-                    // Check the localCorrectThrust
-                    if ((bool)RF_ModuleHybridEngines_locaCorrectThrust.GetValue(modHybridEngines))
-                    {
-                        return true;
-                    }
-                }
+            if (hasInstalledRealFuels)
+            {
+                // Look for any of the Real Fuels engine modules and call the relevant method to find out
+                if (RF_ModuleEngineConfigs_localCorrectThrust != null && theEngine.Modules.Contains("ModuleEngineConfigs"))
+                {
+                    var modEngineConfigs = theEngine.Modules["ModuleEngineConfigs"];
+                    if (modEngineConfigs != null)
+                    {
+                        // Return the localCorrectThrust
+                        return (bool)RF_ModuleEngineConfigs_localCorrectThrust.GetValue(modEngineConfigs);
+                    }
+                }
+
+                if (RF_ModuleHybridEngine_localCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngine"))
+                {
+                    var modHybridEngine = theEngine.Modules["ModuleHybridEngine"];
+                    if (modHybridEngine != null)
+                    {
+                        // Return the localCorrectThrust
+                        return (bool)RF_ModuleHybridEngine_localCorrectThrust.GetValue(modHybridEngine);
+                    }
+                }
+
+                if (RF_ModuleHybridEngines_localCorrectThrust != null && theEngine.Modules.Contains("ModuleHybridEngines"))
+                {
+                    var modHybridEngines = theEngine.Modules["ModuleHybridEngines"];
+                    if (modHybridEngines != null)
+                    {
+                        // Return the localCorrectThrust
+                        return (bool)RF_ModuleHybridEngines_localCorrectThrust.GetValue(modHybridEngines);
+                    }
+                }
+            }
+
+            if (hasInstalledKIDS && HighLogic.LoadedSceneIsEditor)
+            {
+                return bKIDSThrustISP;
             }
 
             return false;
         }
 
-        public static void RequestSimulation()
-        {
-            if (!hasCheckedForRealFuels)
-            {
-                GetRealFuelsTypes();
-            }
-
-            bRequested = true;
-            if (!timer.IsRunning)
-            {
-                timer.Start();
-            }
-        }
-
-        public static void TryStartSimulation()
-        {
-            if (bRequested && !bRunning && (HighLogic.LoadedSceneIsEditor || FlightGlobals.ActiveVessel != null) && timer.ElapsedMilliseconds > delayBetweenSims)
-            {
-                bRequested = false;
-                timer.Reset();
-                StartSimulation();
-            }
-        }
-
-        public static bool ResultsReady()
-        {
-            return !bRunning;
-        }
-
-        private static void ClearResults()
-        {
-            failMessage = "";
-            Stages = null;
-            LastStage = null;
-        }
-
-        private static void StartSimulation()
-        {
-            try
-            {
-                bRunning = true;
-                ClearResults();
-                timer.Start();
-
-                List<Part> parts = HighLogic.LoadedSceneIsEditor ? EditorLogic.SortedShipList : FlightGlobals.ActiveVessel.Parts;
-
-                // Create the Simulation object in this thread
-                Simulation sim = new Simulation();
-
-                // 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, Velocity, dumpTree, vectoredThrust))
-                {
-                    ThreadPool.QueueUserWorkItem(RunSimulation, sim);
-                }
-                else
-                {
-                    failMessage = "PrepareSimulation failed";
-                    bRunning = false;
-                    logOutput = false;
-                }
-            }
-            catch (Exception e)
-            {
-                MonoBehaviour.print("Exception in StartSimulation: " + e);
-                failMessage = e.ToString();
-                bRunning = false;
-                logOutput = false;
-            }
-            dumpTree = false;
-        }
-
-        private static void RunSimulation(object simObject)
-        {
-            try
-            {
-                Stages = (simObject as Simulation).RunSimulation();
-                if (Stages != null)
-                {
-                    if (logOutput)
-                    {
-                        foreach (Stage stage in Stages)
-                        {
-                            stage.Dump();
-                        }
-                    }
-                    LastStage = Stages.Last();
-                }
-            }
-            catch (Exception e)
-            {
-                MonoBehaviour.print("Exception in RunSimulation: " + e);
-                Stages = null;
-                LastStage = null;
-                failMessage = e.ToString();
-            }
-
-            timer.Stop();
-#if TIMERS
-            MonoBehaviour.print("Total simulation time: " + timer.ElapsedMilliseconds + "ms");
-#else
-            if (logOutput)
-            {
-                MonoBehaviour.print("Total simulation time: " + timer.ElapsedMilliseconds + "ms");
-            }
-#endif
-            delayBetweenSims = minSimTime - timer.ElapsedMilliseconds;
-            if (delayBetweenSims < 0)
-            {
-                delayBetweenSims = 0;
-            }
-
-            timer.Reset();
-            timer.Start();
-
-            bRunning = false;
-            logOutput = false;
+        public static void UpdateModSettings()
+        {
+            if (!hasCheckedForMods)
+            {
+                CheckForMods();
+            }
+
+            if (hasInstalledKIDS)
+            {
+                // (out ispMultiplierVac, out ispMultiplierAtm, out extendToZeroIsp, out thrustCorrection, out ispCutoff, out thrustCutoff);
+                object[] parameters = new object[6];
+                KIDS_Utils_GetIspMultiplier.Invoke(null, parameters);
+                bKIDSThrustISP = (bool)parameters[3];
+            }
         }
 
         public static String GetVesselTypeString(VesselType vesselType)
@@ -293,5 +234,166 @@
             }
             return "Undefined";
         }
+
+        public static void RequestSimulation()
+        {
+            if (!hasCheckedForMods)
+            {
+                CheckForMods();
+            }
+
+            lock (locker)
+            {
+                bRequested = true;
+                if (!timer.IsRunning)
+                {
+                    timer.Start();
+                }
+            }
+        }
+
+        public static bool ResultsReady()
+        {
+            lock (locker)
+            {
+                return !bRunning;
+            }
+        }
+
+        public static void TryStartSimulation()
+        {
+            lock (locker)
+            {
+                if (!bRequested || bRunning || (timer.Elapsed < delayBetweenSims && timer.Elapsed >= TimeSpan.Zero) || (!HighLogic.LoadedSceneIsEditor && FlightGlobals.ActiveVessel == null))
+                {
+                    return;
+                }
+
+                bRequested = false;
+                timer.Reset();
+            }
+
+            StartSimulation();
+        }
+
+        private static void ClearResults()
+        {
+            failMessage = "";
+            Stages = null;
+            LastStage = null;
+        }
+
+        private static void RunSimulation(object simObject)
+        {
+            try
+            {
+                Stages = (simObject as Simulation).RunSimulation();
+
+                if (Stages != null && Stages.Length > 0)
+                {
+                    if (logOutput)
+                    {
+                        foreach (var stage in Stages)
+                        {
+                            stage.Dump();
+                        }
+                    }
+                    LastStage = Stages[Stages.Length - 1];
+                }
+            }
+            catch (Exception e)
+            {
+                Logger.Exception(e, "SimManager.RunSimulation()");
+                Stages = null;
+                LastStage = null;
+                failMessage = e.ToString();
+            }
+            lock (locker)
+            {
+                timer.Stop();
+#if TIMERS
+            MonoBehaviour.print("Total simulation time: " + timer.ElapsedMilliseconds + "ms");
+#else
+                if (logOutput)
+                {
+                    MonoBehaviour.print("Total simulation time: " + timer.ElapsedMilliseconds + "ms");
+                }
+#endif
+
+                delayBetweenSims = minSimTime - timer.Elapsed;
+                if (delayBetweenSims < TimeSpan.Zero)
+                {
+                    delayBetweenSims = TimeSpan.Zero;
+                }
+
+                timer.Reset();
+                timer.Start();
+
+                bRunning = false;
+                if (OnReady != null)
+                {
+                    OnReady();
+                }
+            }
+
+            logOutput = false;
+        }
+
+        private static void StartSimulation()
+        {
+            try
+            {
+                lock (locker)
+                {
+                    bRunning = true;
+                }
+
+                ClearResults();
+
+                lock (locker)
+                {
+                    timer.Start();
+                }
+
+                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 (simulation.PrepareSimulation(parts, Gravity, Atmosphere, Mach, dumpTree, vectoredThrust))
+                {
+                    ThreadPool.QueueUserWorkItem(RunSimulation, simulation);
+                    //RunSimulation(simulation);
+                }
+                else
+                {
+                    failMessage = "PrepareSimulation failed";
+                    lock (locker)
+                    {
+                        bRunning = false;
+                    }
+                    logOutput = false;
+                }
+            }
+            catch (Exception e)
+            {
+                Logger.Exception(e, "SimManager.StartSimulation()");
+                failMessage = e.ToString();
+                lock (locker)
+                {
+                    bRunning = false;
+                }
+                logOutput = false;
+            }
+            dumpTree = false;
+        }
+
+        #endregion
     }
 }

--- a/KerbalEngineer/VesselSimulator/Simulation.cs
+++ b/KerbalEngineer/VesselSimulator/Simulation.cs
@@ -30,26 +30,33 @@
 
 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;
+        private HashSet<PartSim> decoupledParts = new HashSet<PartSim>();
         private bool doingCurrent;
         private List<PartSim> dontStageParts;
+        private List<List<PartSim>> dontStagePartsLists = new List<List<PartSim>>();
         private HashSet<PartSim> drainingParts;
         private HashSet<int> drainingResources;
         private double gravity;
+        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;
@@ -60,96 +67,113 @@
         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 velocity;
+        private double mach;
+        private float maxMach;
         public String vesselName;
         public VesselType vesselType;
+        private WeightedVectorAverager vectorAverager = new WeightedVectorAverager();
 
         public Simulation()
         {
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print("Simulation created");
-            }
-        }
-
-        private double ShipMass
-        {
-            get
-            {
-                double mass = 0d;
-
-                foreach (PartSim partSim in this.allParts)
-                {
-                    mass += partSim.GetMass();
-                }
-
-                return mass;
-            }
-        }
-
-        private Vector3d ShipCom
-        {
-            get
-            {
-                WeightedVectorAverager averager = new WeightedVectorAverager();
-
-                foreach (PartSim partSim in this.allParts)
-                {
-                    averager.Add(partSim.centerOfMass, partSim.GetMass());
-                }
-
-                return averager.Get();
-            }
-        }
-
-        // This function prepares the simulation by creating all the necessary data structures it will 
-        // need during the simulation.  All required data is copied from the core game data structures 
-        // so that the simulation itself can be run in a background thread without having issues with 
-        // the core game changing the data while the simulation is running.
-        public bool PrepareSimulation(List<Part> parts, double theGravity, double theAtmosphere = 0, double theVelocity = 0, bool dumpTree = false, bool vectoredThrust = false)
-        {
-            LogMsg log = null;
-            if (SimManager.logOutput)
-            {
-                log = new LogMsg();
-                log.buf.AppendLine("PrepareSimulation started");
-                dumpTree = true;
-            }
-            this._timer.Start();
-
-            // Store the parameters in members for ease of access in other functions
-            this.partList = parts;
-            this.gravity = theGravity;
-            this.atmosphere = theAtmosphere;
-            this.velocity = theVelocity;
-            this.lastStage = Staging.lastStage;
-            //MonoBehaviour.print("lastStage = " + lastStage);
-
-            // Create the lists for our simulation parts
             this.allParts = new List<PartSim>();
             this.allFuelLines = new List<PartSim>();
             this.drainingParts = new HashSet<PartSim>();
             this.allEngines = new List<EngineSim>();
             this.activeEngines = new List<EngineSim>();
             this.drainingResources = new HashSet<int>();
+            this.totalStageThrustForce = new ForceAccumulator();
 
             // A dictionary for fast lookup of Part->PartSim during the preparation phase
-            Dictionary<Part, PartSim> partSimLookup = new Dictionary<Part, PartSim>();
+            partSimLookup = new Dictionary<Part, PartSim>();
+
+            if (SimManager.logOutput)
+            {
+                MonoBehaviour.print("Simulation created");
+            }
+        }
+
+        private double ShipMass
+        {
+            get
+            {
+                double mass = 0d;
+
+                for (int i = 0; i < allParts.Count; ++i) { 
+                    mass += allParts[i].GetMass(currentStage);
+                }
+
+                return mass;
+            }
+        }
+
+        private Vector3d ShipCom
+        {
+            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();
+            }
+        }
+
+        // This function prepares the simulation by creating all the necessary data structures it will 
+        // need during the simulation.  All required data is copied from the core game data structures 
+        // so that the simulation itself can be run in a background thread without having issues with 
+        // the core game changing the data while the simulation is running.
+        public bool PrepareSimulation(List<Part> parts, double theGravity, double theAtmosphere = 0, double theMach = 0, bool dumpTree = false, bool vectoredThrust = false, bool fullThrust = false)
+        {
+            LogMsg log = null;
+            if (SimManager.logOutput)
+            {
+                log = new LogMsg();
+                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
+            this.partList = parts;
+            this.gravity = theGravity;
+            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
+            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();
 
             if (this.partList.Count > 0 && this.partList[0].vessel != null)
             {
                 this.vesselName = this.partList[0].vessel.vesselName;
                 this.vesselType = this.partList[0].vessel.vesselType;
             }
-
+            //MonoBehaviour.print("PrepareSimulation pool size = " + PartSim.pool.Count());
             // First we create a PartSim for each Part (giving each a unique id)
             int partId = 1;
-            foreach (Part part in this.partList)
-            {
+            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))
                 {
@@ -161,7 +185,7 @@
                 }
 
                 // Create the PartSim
-                PartSim partSim = new PartSim(part, partId, this.atmosphere, log);
+                PartSim partSim = PartSim.New(part, partId, this.atmosphere, log);
 
                 // Add it to the Part lookup dictionary and the necessary lists
                 partSimLookup.Add(part, partSim);
@@ -172,30 +196,39 @@
                 }
                 if (partSim.isEngine)
                 {
-                    partSim.CreateEngineSims(this.allEngines, this.atmosphere, this.velocity, vectoredThrust, log);
+                    partSim.CreateEngineSims(this.allEngines, this.atmosphere, this.mach, vectoredThrust, fullThrust, log);
                 }
 
                 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
             // First we set up all the parent links
-            foreach (PartSim partSim in this.allParts)
-            {
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim partSim = this.allParts[i];
                 partSim.SetupParent(partSimLookup, log);
             }
 
             // Then, in the VAB/SPH, we add the parent of each fuel line to the fuelTargets list of their targets
             if (HighLogic.LoadedSceneIsEditor)
             {
-                foreach (PartSim partSim in this.allFuelLines)
-                {
-                    if ((partSim.part as FuelLine).target != null)
+                for (int i = 0; i < allFuelLines.Count; ++i)
+                {
+                    PartSim partSim = allFuelLines[i];
+
+                    CModuleFuelLine fuelLine = partSim.part.GetModule<CModuleFuelLine>();
+                    if (fuelLine.target != null)
                     {
                         PartSim targetSim;
-                        if (partSimLookup.TryGetValue((partSim.part as FuelLine).target, out targetSim))
+                        if (partSimLookup.TryGetValue(fuelLine.target, out targetSim))
                         {
                             if (log != null)
                             {
@@ -223,8 +256,10 @@
             }
 
             //MonoBehaviour.print("SetupAttachNodes and count stages");
-            foreach (PartSim partSim in this.allParts)
-            {
+            for (int i = 0; i < allParts.Count; ++i)
+            {
+                PartSim partSim = allParts[i];
+
                 partSim.SetupAttachNodes(partSimLookup, log);
                 if (partSim.decoupledInStage >= this.lastStage)
                 {
@@ -234,9 +269,9 @@
 
             // And finally release the Part references from all the PartSims
             //MonoBehaviour.print("ReleaseParts");
-            foreach (PartSim partSim in this.allParts)
-            {
-                partSim.ReleasePart();
+            for (int i = 0; i < allParts.Count; ++i)
+            { 
+                allParts[i].ReleasePart();
             }
 
             // And dereference the core's part list
@@ -256,7 +291,7 @@
 
             return true;
         }
-
+        
         // This function runs the simulation and returns a newly created array of Stage objects
         public Stage[] RunSimulation()
         {
@@ -265,6 +300,7 @@
                 MonoBehaviour.print("RunSimulation started");
             }
 
+            this._timer.Reset();
             this._timer.Start();
 
             LogMsg log = null;
@@ -276,13 +312,14 @@
             // Start with the last stage to simulate
             // (this is in a member variable so it can be accessed by AllowedToStage and ActivateStage)
             this.currentStage = this.lastStage;
-
             // Work out which engines would be active if just doing the staging and if this is different to the 
             // currently active engines then generate an extra stage
             // Loop through all the engines
             bool anyActive = false;
-            foreach (EngineSim engine in this.allEngines)
-            {
+            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);
@@ -337,7 +374,7 @@
             }
 
             // Create a list of lists of PartSims that prevent decoupling
-            List<List<PartSim>> dontStagePartsLists = this.BuildDontStageLists(log);
+            BuildDontStageLists(log);
 
             if (log != null)
             {
@@ -347,6 +384,7 @@
             // 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)
@@ -354,7 +392,6 @@
                 if (log != null)
                 {
                     log.buf.AppendLine("Simulating stage " + this.currentStage);
-                    log.buf.AppendLine("ShipMass = " + this.ShipMass);
                     log.Flush();
                     this._timer.Reset();
                     this._timer.Start();
@@ -363,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;
@@ -379,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);
 
@@ -408,15 +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
-                foreach (PartSim partSim in this.allParts)
-                {
-                    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];
@@ -428,8 +486,9 @@
                     if (this.dontStageParts.Count > 0)
                     {
                         log.buf.AppendLine("Parts preventing staging:");
-                        foreach (PartSim partSim in this.dontStageParts)
-                        {
+                        for (int i = 0; i < this.dontStageParts.Count; i++)
+                        {
+                            PartSim partSim = this.dontStageParts[i];
                             partSim.DumpPartToBuffer(log.buf, "");
                         }
                     }
@@ -440,6 +499,7 @@
 
                     log.Flush();
                 }
+
 
                 // Now we will loop until we are allowed to stage
                 int loopCounter = 0;
@@ -447,7 +507,6 @@
                 {
                     loopCounter++;
                     //MonoBehaviour.print("loop = " + loopCounter);
-
                     // Calculate how long each draining tank will take to drain and run for the minimum time
                     double resourceDrainTime = double.MaxValue;
                     PartSim partMinDrain = null;
@@ -465,7 +524,6 @@
                     {
                         MonoBehaviour.print("Drain time = " + resourceDrainTime + " (" + partMinDrain.name + ":" + partMinDrain.partId + ")");
                     }
-
                     foreach (PartSim partSim in this.drainingParts)
                     {
                         partSim.DrainResources(resourceDrainTime);
@@ -489,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
@@ -497,7 +555,7 @@
 
                     // Recalculate the current thrust and isp for the next step
                     this.CalculateThrustAndISP();
-
+                    
                     // Check if we actually changed anything
                     if (this.stepStartMass == this.stepEndMass)
                     {
@@ -512,6 +570,10 @@
                         MonoBehaviour.print("stageStartMass = " + this.stageStartMass);
                         MonoBehaviour.print("stepStartMass = " + this.stepStartMass);
                         MonoBehaviour.print("StepEndMass   = " + this.stepEndMass);
+                        Logger.Log("exceeded loop count");
+                        Logger.Log("stageStartMass = " + this.stageStartMass);
+                        Logger.Log("stepStartMass = " + this.stepStartMass);
+                        Logger.Log("StepEndMass   = " + this.stepEndMass);
                         break;
                     }
 
@@ -519,17 +581,18 @@
                     this.stepStartMass = this.stepEndMass;
                 }
 
+
                 // Store more values in the Stage object and stick it in the array
 
                 // Store the magnitude of the deltaV vector
                 stage.deltaV = this.vecStageDeltaV.magnitude;
-                stage.resourceMass = this.stepStartMass - this.stepEndMass;
+                stage.resourceMass = this.stageStartMass - this.stepEndMass;
 
                 // Recalculate effective stage isp from the stage deltaV (flip the standard deltaV calculation around)
                 // 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
                 {
@@ -540,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
@@ -573,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;
@@ -598,29 +660,105 @@
                 this._timer.Stop();
                 MonoBehaviour.print("RunSimulation: " + this._timer.ElapsedMilliseconds + "ms");
             }
-
+            FreePooledObject();
+            
             return stages;
         }
 
-        private List<List<PartSim>> BuildDontStageLists(LogMsg log)
+        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()
+        {
+            //MonoBehaviour.print("FreePooledObject pool size before = " + PartSim.pool.Count() + " for " + allParts.Count + " parts");
+            foreach (PartSim part in allParts)
+            {
+                part.Release();
+            }
+            //MonoBehaviour.print("FreePooledObject pool size after = " + PartSim.pool.Count());
+
+            //MonoBehaviour.print("FreePooledObject pool size before = " + EngineSim.pool.Count() + " for " + allEngines.Count + " engines");
+            foreach (EngineSim engine in allEngines)
+            {
+                engine.Release();
+            }
+            //MonoBehaviour.print("FreePooledObject pool size after = " + EngineSim.pool.Count());
+        }
+
+        private void BuildDontStageLists(LogMsg log)
         {
             if (log != null)
             {
                 log.buf.AppendLine("Creating list with capacity of " + (this.currentStage + 1));
             }
-            List<List<PartSim>> lists = new List<List<PartSim>>();
+
+            dontStagePartsLists.Clear();
             for (int i = 0; i <= this.currentStage; i++)
             {
-                lists.Add(new List<PartSim>());
-            }
-
-            foreach (PartSim partSim in this.allParts)
-            {
+                if (i < dontStagePartsLists.Count)
+                {
+                    dontStagePartsLists[i].Clear();
+                }
+                else
+                {
+                    dontStagePartsLists.Add(new List<PartSim>());
+                }
+            }
+
+            for (int i = 0; i < allParts.Count; ++i)
+            {
+                PartSim partSim = allParts[i];
+
                 if (partSim.isEngine || !partSim.Resources.Empty)
                 {
                     if (log != null)
                     {
-                        log.buf.AppendLine(partSim.name + ":" + partSim.partId + " is engine or tank, decoupled = " + partSim.decoupledInStage);
+                        log.buf.AppendLine(
+                            partSim.name + ":" + partSim.partId + " is engine or tank, decoupled = " + partSim.decoupledInStage);
                     }
 
                     if (partSim.decoupledInStage < -1 || partSim.decoupledInStage > this.currentStage - 1)
@@ -632,28 +770,27 @@
                     }
                     else
                     {
-                        lists[partSim.decoupledInStage + 1].Add(partSim);
+                        dontStagePartsLists[partSim.decoupledInStage + 1].Add(partSim);
                     }
                 }
             }
 
             for (int i = 1; i <= this.lastStage; i++)
             {
-                if (lists[i].Count == 0)
-                {
-                    lists[i] = lists[i - 1];
-                }
-            }
-
-            return lists;
+                if (dontStagePartsLists[i].Count == 0)
+                {
+                    dontStagePartsLists[i] = dontStagePartsLists[i - 1];
+                }
+            }
         }
 
         // This function simply rebuilds the active engines by testing the isActive flag of all the engines
         private void UpdateActiveEngines()
         {
             this.activeEngines.Clear();
-            foreach (EngineSim engine in this.allEngines)
-            {
+            for (int i = 0; i < allEngines.Count; ++i)
+            {
+                EngineSim engine = allEngines[i];
                 if (engine.isActive)
                 {
                     this.activeEngines.Add(engine);
@@ -671,12 +808,14 @@
             this.totalStageActualThrust = 0d;
             this.totalStageFlowRate = 0d;
             this.totalStageIspFlowRate = 0d;
-            this.totalStageThrustForce = new ForceAccumulator();
+            this.totalStageThrustForce.Reset();
 
             // Loop through all the active engines totalling the thrust, actual thrust and mass flow rates
             // The thrust is totalled as vectors
-            foreach (EngineSim engine in this.activeEngines)
-            {
+            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);
@@ -684,13 +823,12 @@
                 this.totalStageFlowRate += engine.ResourceConsumptions.Mass;
                 this.totalStageIspFlowRate += engine.ResourceConsumptions.Mass * engine.isp;
 
-                foreach (AppliedForce f in engine.appliedForces) {
-                    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);
-
             this.totalStageThrust = this.vecThrust.magnitude;
             this.totalStageActualThrust = this.vecActualThrust.magnitude;
 
@@ -725,15 +863,17 @@
             this.drainingParts.Clear();
 
             // Loop through all the active engine modules
-            foreach (EngineSim engine in this.activeEngines)
-            {
+            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
-                    foreach (int type in engine.ResourceConsumptions.Types)
-                    {
-                        this.drainingResources.Add(type);
+                    for (int j = 0; j < engine.ResourceConsumptions.Types.Count; ++j)
+                    { 
+                        drainingResources.Add(engine.ResourceConsumptions.Types[j]);
                     }
                 }
             }
@@ -746,8 +886,9 @@
                 StringBuilder buffer = new StringBuilder(1024);
                 buffer.AppendFormat("Active engines = {0:d}\n", this.activeEngines.Count);
                 int i = 0;
-                foreach (EngineSim engine in this.activeEngines)
-                {
+                for (int j = 0; j < this.activeEngines.Count; j++)
+                {
+                    EngineSim engine = this.activeEngines[j];
                     engine.DumpEngineToBuffer(buffer, "Engine " + (i++) + ":");
                 }
                 MonoBehaviour.print(buffer);
@@ -767,29 +908,32 @@
 
             if (this.activeEngines.Count > 0)
             {
-                foreach (PartSim partSim in this.dontStageParts)
-                {
+                for (int i = 0; i < dontStageParts.Count; ++i)
+                {
+                    PartSim partSim = dontStageParts[i];
+
                     if (SimManager.logOutput)
                     {
                         partSim.DumpPartToBuffer(buffer, "Testing: ");
                     }
                     //buffer.AppendFormat("isSepratron = {0}\n", partSim.isSepratron ? "true" : "false");
 
-                    if (!partSim.isSepratron && !partSim.Resources.EmptyOf(this.drainingResources))
+                    if (!partSim.isSepratron && !partSim.EmptyOf(this.drainingResources))
                     {
                         if (SimManager.logOutput)
                         {
                             partSim.DumpPartToBuffer(buffer, "Decoupled part not empty => false: ");
                             MonoBehaviour.print(buffer);
                         }
-
                         return false;
                     }
 
                     if (partSim.isEngine)
                     {
-                        foreach (EngineSim engine in this.activeEngines)
-                        {
+                        for (int j = 0; j < activeEngines.Count; ++j)
+                        {
+                            EngineSim engine = activeEngines[j];
+
                             if (engine.partSim == partSim)
                             {
                                 if (SimManager.logOutput)
@@ -827,9 +971,11 @@
         private void ActivateStage()
         {
             // Build a set of all the parts that will be decoupled
-            HashSet<PartSim> decoupledParts = new HashSet<PartSim>();
-            foreach (PartSim partSim in this.allParts)
-            {
+            decoupledParts.Clear();
+            for (int i = 0; i < allParts.Count; ++i)
+            {
+                PartSim partSim = allParts[i];
+
                 if (partSim.decoupledInStage >= this.currentStage)
                 {
                     decoupledParts.Add(partSim);
@@ -840,14 +986,17 @@
             {
                 // Remove it from the all parts list
                 this.allParts.Remove(partSim);
+                partSim.Release();
                 if (partSim.isEngine)
                 {
                     // If it is an engine then loop through all the engine modules and remove all the ones from this engine part
                     for (int i = this.allEngines.Count - 1; i >= 0; i--)
                     {
-                        if (this.allEngines[i].partSim == partSim)
+                        EngineSim engine = this.allEngines[i];
+                        if (engine.partSim == partSim)
                         {
                             this.allEngines.RemoveAt(i);
+                            engine.Release();
                         }
                     }
                 }
@@ -859,15 +1008,16 @@
             }
 
             // Loop through all the (remaining) parts
-            foreach (PartSim partSim in this.allParts)
-            {
+            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
-            foreach (EngineSim engine in this.allEngines)
-            {
+            for (int i = 0; i < allEngines.Count; ++i)
+            {
+                EngineSim engine = allEngines[i];
                 if (engine.partSim.inverseStage == this.currentStage)
                 {
                     engine.isActive = true;
@@ -901,3 +1051,4 @@
         }
     }
 }
+

--- a/KerbalEngineer/VesselSimulator/Stage.cs
+++ b/KerbalEngineer/VesselSimulator/Stage.cs
@@ -29,27 +29,29 @@
 {
     public class Stage
     {
-        public double actualThrust = 0f;
-        public double actualThrustToWeight = 0f;
-        public double cost = 0d;
-        public double deltaV = 0f;
-        public double inverseTotalDeltaV = 0f;
-        public double isp = 0f;
-        public double mass = 0f;
-        public double maxThrustToWeight = 0f;
+        public double actualThrust = 0.0;
+        public double actualThrustToWeight = 0.0;
+        public double cost = 0.0;
+        public double deltaV = 0.0;
+        public double inverseTotalDeltaV = 0.0;
+        public double isp = 0.0;
+        public double mass = 0.0;
+        public double rcsMass = 0.0;
+        public double maxThrustToWeight = 0.0;
         public int number = 0;
-        public double thrust = 0f;
-        public double thrustToWeight = 0f;
-        public double time = 0f;
-        public double totalCost = 0;
-        public double totalDeltaV = 0f;
-        public double totalMass = 0f;
-        public double totalTime = 0f;
+        public double thrust = 0.0;
+        public double thrustToWeight = 0.0;
+        public double time = 0.0;
+        public double totalCost = 0.0;
+        public double totalDeltaV = 0.0;
+        public double totalMass = 0.0;
+        public double totalTime = 0.0;
         public int totalPartCount = 0;
         public int partCount = 0;
         public double resourceMass = 0.0;
-        public double maxThrustTorque = 0f;
-        public double thrustOffsetAngle = 0f;
+        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
@@ -5,13 +5,13 @@
 	{
 		"MAJOR":1,
 		"MINOR":0,
-		"PATCH":11,
-		"BUILD":3
+		"PATCH":17,
+		"BUILD":0
 	},
 	"KSP_VERSION":
 	{
-		"MAJOR":0,
-		"MINOR":25,
-		"PATCH":0
+		"MAJOR":1,
+		"MINOR":0,
+		"PATCH":4
 	}
 }

 Binary files /dev/null and b/Output/KerbalEngineer/Parts/Engineer7500/model000.mbm differ
--- a/Output/KerbalEngineer/Parts/Engineer7500/part.cfg
+++ b/Output/KerbalEngineer/Parts/Engineer7500/part.cfg
@@ -7,7 +7,6 @@
 	
 	// --- asset parameters ---
 	mesh = model.mu
-	texture = model000.mbm
 	rescaleFactor = 0.8
 
 	PhysicsSignificance = 1

 Binary files a/Output/KerbalEngineer/Parts/Engineer7500/textures/model000.mbm and /dev/null differ