Major reworking of the HUD underpinnings to be more modular and require less code duplication. Also made the Editor HUD movable, but for now it's stuck along the left edge.
Major reworking of the HUD underpinnings to be more modular and require less code duplication. Also made the Editor HUD movable, but for now it's stuck along the left edge.

--- a/IVOID_Module.cs
+++ b/IVOID_Module.cs
@@ -51,6 +51,7 @@
 	{
 		void Update();
 		void FixedUpdate();
+		void OnDestroy();
 	}
 
 	public interface IVOID_EditorModule : IVOID_Module {}

--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -39,7 +39,7 @@
 // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
 // The form "{Major}.{Minor}.*" will automatically update the build and revision,
 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion("0.14.2.*")]
+[assembly: AssemblyVersion("0.16.*")]
 // The following attributes are used to specify the signing key for the assembly,
 // if desired. See the Mono documentation for more information about signing.
 //[assembly: AssemblyDelaySign(false)]

--- a/VOID.csproj
+++ b/VOID.csproj
@@ -97,6 +97,10 @@
     <Compile Include="VOID_HUDAdvanced.cs" />
     <Compile Include="VOID_TWR.cs" />
     <Compile Include="VOID_CareerStatus.cs" />
+    <Compile Include="VOID_StageInfo.cs" />
+    <Compile Include="VOID_Styles.cs" />
+    <Compile Include="VOID_Data.cs" />
+    <Compile Include="VOID_HUDModule.cs" />
   </ItemGroup>
   <ProjectExtensions>
     <MonoDevelop>

--- a/VOIDEditorMaster.cs
+++ b/VOIDEditorMaster.cs
@@ -40,7 +40,7 @@
 //
 ///////////////////////////////////////////////////////////////////////////////
 
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using ToadicusTools;
@@ -105,6 +105,26 @@
 
 			this.Core.OnGUI();
 		}
+
+		public void OnDestroy()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnDestroy();
+		}
+
+		public void OnApplicationQuit()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnApplicationQuit();
+		}
 	}
 }
 

--- a/VOIDFlightMaster.cs
+++ b/VOIDFlightMaster.cs
@@ -42,7 +42,7 @@
 
 using System;
 using UnityEngine;
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using ToadicusTools;
 
 namespace VOID
@@ -104,6 +104,26 @@
 
 			this.Core.OnGUI();
 		}
+
+		public void OnDestroy()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnDestroy();
+		}
+
+		public void OnApplicationQuit()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnApplicationQuit();
+		}
     }
 }
 

--- a/VOID_CBInfoBrowser.cs
+++ b/VOID_CBInfoBrowser.cs
@@ -84,7 +84,7 @@
 				selectedBodyIdx1--;
 				if (selectedBodyIdx1 < 0) selectedBodyIdx1 = this.core.allBodies.Count - 1;
 			}
-			GUILayout.Label(this.core.allBodies[selectedBodyIdx1].bodyName, this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(this.core.allBodies[selectedBodyIdx1].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
 			if (GUILayout.Button(">", GUILayout.ExpandWidth(false)))
 			{
 				selectedBodyIdx1++;
@@ -100,7 +100,7 @@
 				selectedBodyIdx2--;
 				if (selectedBodyIdx2 < 0) selectedBodyIdx2 = this.core.allBodies.Count - 1;
 			}
-			GUILayout.Label(this.core.allBodies[selectedBodyIdx2].bodyName, this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(this.core.allBodies[selectedBodyIdx2].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
 			if (GUILayout.Button(">", GUILayout.ExpandWidth(false)))
 			{
 				selectedBodyIdx2++;
@@ -282,82 +282,82 @@
 
 		private void body_OP_show_orbital_info(CelestialBody body)
 		{
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.timeToAp), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.timeToPe), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(VOID_Tools.ConvertInterval(body.orbit.period), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(VOID_Tools.ConvertInterval(body.rotationPeriod), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToAp), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToPe), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.period), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(VOID_Tools.FormatInterval(body.rotationPeriod), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 			// Toadicus edit: convert mean anomaly into degrees.
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 			// Toadicus edit: convert eccentric anomaly into degrees.
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-		    if (body.bodyName == "Sun") GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+		    else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 		    else
 		    {
 		        string body_tidally_locked = "No";
 		        if (body.tidallyLocked) body_tidally_locked = "Yes";
-		        GUILayout.Label(body_tidally_locked, this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+		        GUILayout.Label(body_tidally_locked, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 		    }
 		}
 
 		private void body_OP_show_physical_info(CelestialBody body)
 		{
 
-			GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-			GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+			GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+			GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 			// divide by 1000 to convert m to km
-			GUILayout.Label((((4d / 3) * Math.PI * (body.Radius * body.Radius * body.Radius)) / 1000).ToString("0.00e+00") + "km³", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-			GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+			GUILayout.Label((((4d / 3) * Math.PI * (body.Radius * body.Radius * body.Radius)) / 1000).ToString("0.00e+00") + "km³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+			GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 			double p = body.Mass / ((body.Radius * body.Radius * body.Radius) * (4d / 3) * Math.PI);
 
-			GUILayout.Label(p.ToString("##,#") + "kg/m³", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-			if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-
-			GUILayout.Label(body.orbitingBodies.Count.ToString(), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+			if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+			else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+
+			GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 			//show # artificial satellites
 			int num_art_sats = 0;
@@ -366,31 +366,31 @@
 				if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++;
 			}
 
-			GUILayout.Label(num_art_sats.ToString(), this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(num_art_sats.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 			double g_ASL = (VOID_Core.Constant_G * body.Mass) / (body.Radius * body.Radius);
 
-			GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 
 			if (body.atmosphere)
 			{
 				GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m",
-					this.core.LabelStyles["right"],
+					VOID_Styles.labelRight,
 					GUILayout.ExpandWidth(true));
 
 				string O2 = "No";
 				if (body.atmosphereContainsOxygen == true) O2 = "Yes";
-				GUILayout.Label(O2, this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+				GUILayout.Label(O2, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 			}
 			else
 			{
-				GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
-				GUILayout.Label("N/A", this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+				GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
+				GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 			}
 
 			string ocean = "No";
 			if (body.ocean == true) ocean = "Yes";
-			GUILayout.Label(ocean, this.core.LabelStyles["right"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(ocean, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
 		}
 
 		private void cbColumnScience(CelestialBody body)
@@ -408,44 +408,44 @@
 			var scienceValues = body.scienceValues;
 
 			GUILayout.Label(scienceValues.LandedDataValue.ToString("0.0#"),
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 
 			GUILayout.Label(
 				body.ocean ? scienceValues.SplashedDataValue.ToString("0.0#") : "N/A",
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 
 			GUILayout.Label(
 				body.atmosphere ? scienceValues.FlyingLowDataValue.ToString("0.0#") : "N/A",
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 
 			GUILayout.Label(
 				body.atmosphere ? scienceValues.FlyingHighDataValue.ToString("0.0#") : "N/A",
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 
 			GUILayout.Label(scienceValues.InSpaceLowDataValue.ToString("0.0#"),
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 
 			GUILayout.Label(scienceValues.InSpaceHighDataValue.ToString("0.0#"),
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 
 			GUILayout.Label(
 				body.atmosphere ? scienceValues.flyingAltitudeThreshold.ToString("N0") : "N/A",
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 
 			GUILayout.Label(
 				scienceValues.spaceAltitudeThreshold.ToString("N0"),
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 
 			GUILayout.Label(scienceValues.RecoveryValue.ToString("0.0#"),
-				this.core.LabelStyles["right"],
+				VOID_Styles.labelRight,
 				GUILayout.ExpandWidth(true));
 		}
 	}

--- a/VOID_CareerStatus.cs
+++ b/VOID_CareerStatus.cs
@@ -236,57 +236,6 @@
 			VOID_CareerStatus.Instance = null;
 		}
 	}
-
-	public static partial class VOID_Data
-	{
-		public static readonly VOID_StrValue fundingStatus = new VOID_StrValue(
-			string.Intern("Funds"),
-			delegate()
-		{
-			if (VOID_CareerStatus.Instance == null)
-			{
-				return string.Empty;
-			}
-
-			return string.Format("{0} ({1})",
-				VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"),
-				VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange)
-			);
-		}
-		);
-
-		public static readonly VOID_StrValue reputationStatus = new VOID_StrValue(
-			string.Intern("Reputation"),
-			delegate()
-		{
-			if (VOID_CareerStatus.Instance == null)
-			{
-				return string.Empty;
-			}
-
-			return string.Format("{0} ({1})",
-				VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"),
-				VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange)
-			);
-		}
-		);
-
-		public static readonly VOID_StrValue scienceStatus = new VOID_StrValue(
-			string.Intern("Science"),
-			delegate()
-		{
-			if (VOID_CareerStatus.Instance == null)
-			{
-				return string.Empty;
-			}
-
-			return string.Format("{0} ({1})",
-				VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"),
-				VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange)
-			);
-		}
-		);
-	}
 }
 
 

--- a/VOID_Core.cs
+++ b/VOID_Core.cs
@@ -26,7 +26,7 @@
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -120,9 +120,8 @@
 		protected int _windowID = 0;
 
 		protected bool GUIStylesLoaded = false;
-		protected Dictionary<string, GUIStyle> _LabelStyles = new Dictionary<string, GUIStyle>();
-
-		protected CelestialBody _Kerbin;
+
+		protected CelestialBody _homeBody;
 
 		[AVOID_SaveValue("togglePower")]
 		public VOID_SaveValue<bool> togglePower = true;
@@ -167,7 +166,8 @@
 				"ExpRecoveryDialogSkin",
 				"KSP window 5",
 				"KSP window 6",
-				"PartTooltipSkin"
+				"PartTooltipSkin",
+				"KSCContextMenuSkin"
 			};
 		protected bool skinsLoaded = false;
 
@@ -178,6 +178,12 @@
 		internal IButton ToolbarButton;
 
 		internal ApplicationLauncherButton AppLauncherButton;
+
+		/*
+		 * Events
+		 * */
+		public delegate void VOIDEventHandler(object sender);
+		public event VOIDEventHandler onApplicationQuit;
 
 		/*
 		 * Properties
@@ -229,14 +235,6 @@
 			}
 		}
 
-		public Dictionary<string, GUIStyle> LabelStyles
-		{
-			get
-			{
-				return this._LabelStyles;
-			}
-		}
-
 		public List<CelestialBody> allBodies
 		{
 			get
@@ -245,19 +243,25 @@
 			}
 		}
 
-		public CelestialBody Kerbin
-		{
-			get
-			{
-				if (this._Kerbin == null)
-				{
-					if (FlightGlobals.Bodies != null)
+		public List<CelestialBody> sortedBodyList
+		{
+			get;
+			private set;
+		}
+
+		public CelestialBody HomeBody
+		{
+			get
+			{
+				if (this._homeBody == null)
+				{
+					if (Planetarium.fetch != null)
 					{
-						this._Kerbin = FlightGlobals.Bodies.First(b => b.name == "Kerbin");
+						this._homeBody = Planetarium.fetch.Home;
 					}
 				}
 
-				return this._Kerbin;
+				return this._homeBody;
 			}
 		}
 
@@ -436,7 +440,14 @@
 					GUILayout.Height(50)
 				);
 
-				_mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos);
+				if (HighLogic.LoadedSceneIsEditor)
+				{
+					_mainWindowPos = Tools.ClampRectToEditorPad(_mainWindowPos);
+				}
+				else
+				{
+					_mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos);
+				}
 
 				if (_mainWindowPos != this.mainWindowPos)
 				{
@@ -457,7 +468,14 @@
 					GUILayout.Height(50)
 				);
 
-				_configWindowPos = Tools.ClampRectToScreen(_configWindowPos);
+				if (HighLogic.LoadedSceneIsEditor)
+				{
+					_configWindowPos = Tools.ClampRectToEditorPad(_configWindowPos);
+				}
+				else
+				{
+					_configWindowPos = Tools.ClampRectToScreen(_configWindowPos);
+				}
 
 				if (_configWindowPos != this.configWindowPos)
 				{
@@ -593,11 +611,29 @@
 				}
 			}
 
-			foreach (IVOID_BehaviorModule module in
-			         this._modules.OfType<IVOID_BehaviorModule>().Where(m => !m.GetType().IsAbstract))
-			{
-				module.FixedUpdate();
-			}
+			foreach (IVOID_Module module in this.Modules)
+			{
+				if (module is IVOID_BehaviorModule)
+				{
+					((IVOID_BehaviorModule)module).FixedUpdate();
+				}
+			}
+		}
+
+		public void OnDestroy()
+		{
+			foreach (IVOID_Module module in this.Modules)
+			{
+				if (module is IVOID_BehaviorModule)
+				{
+					((IVOID_BehaviorModule)module).OnDestroy();
+				}
+			}
+		}
+
+		public void OnApplicationQuit()
+		{
+			this.onApplicationQuit(this);
 		}
 
 		public void ResetGUI()
@@ -641,7 +677,7 @@
 			}
 			else
 			{
-				GUILayout.Label("-- POWER LOST --", this.LabelStyles["red"]);
+				GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed);
 			}
 
 			this.configWindowMinimized.value = !GUILayout.Toggle(!this.configWindowMinimized, "Configuration");
@@ -686,7 +722,6 @@
 			_content.tooltip = "Select previous skin";
 			if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
 			{
-				this.GUIStylesLoaded = false;
 				this._skinIdx--;
 				Tools.PostDebugMessage(string.Format(
 					"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
@@ -698,13 +733,12 @@
 
 			_content.text = this.Skin.name;
 			_content.tooltip = "Current skin";
-			GUILayout.Label(_content, this.LabelStyles["center"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(_content, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true));
 
 			_content.text = "►";
 			_content.tooltip = "Select next skin";
 			if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
 			{
-				this.GUIStylesLoaded = false;
 				this._skinIdx++;
 				Tools.PostDebugMessage(string.Format(
 					"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
@@ -723,6 +757,7 @@
 			if (this._skinName != skinNames[this._skinIdx])
 			{
 				this._skinName.value = skinNames[this._skinIdx];
+				this.GUIStylesLoaded = false;
 			}
 
 			GUILayout.EndHorizontal();
@@ -774,7 +809,7 @@
 					SimManager.Gravity = this.vessel.mainBody.gravParameter / (radius * radius);
 				}
 
-				SimManager.minSimTime = (long)(this.updatePeriod * 1000);
+				SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)(this.updatePeriod * 1000d));
 
 				SimManager.TryStartSimulation();
 			}
@@ -919,29 +954,7 @@
 
 		protected void LoadGUIStyles()
 		{
-			this.LabelStyles["link"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["link"].fontStyle = FontStyle.Bold;
-
-			this.LabelStyles["center"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["center"].normal.textColor = Color.white;
-			this.LabelStyles["center"].alignment = TextAnchor.UpperCenter;
-
-			this.LabelStyles["center_bold"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["center_bold"].normal.textColor = Color.white;
-			this.LabelStyles["center_bold"].alignment = TextAnchor.UpperCenter;
-			this.LabelStyles["center_bold"].fontStyle = FontStyle.Bold;
-
-			this.LabelStyles["right"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["right"].normal.textColor = Color.white;
-			this.LabelStyles["right"].alignment = TextAnchor.UpperRight;
-
-			this.LabelStyles["red"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["red"].normal.textColor = Color.red;
-			this.LabelStyles["red"].alignment = TextAnchor.MiddleCenter;
-
-			this.iconStyle = new GUIStyle(GUI.skin.button);
-			this.iconStyle.padding = new RectOffset(0, 0, 0, 0);
-			this.iconStyle.overflow = new RectOffset(0, 0, 0, 0);
+			VOID_Styles.OnSkinChanged();
 
 			this.GUIStylesLoaded = true;
 		}
@@ -958,6 +971,16 @@
 			{
 				this.LoadVesselTypes();
 			}
+
+			if (this.sortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
+			{
+				this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
+				this.sortedBodyList.Sort(new CBListComparer());
+				this.sortedBodyList.Reverse();
+
+				Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray())));
+			}
+
 		}
 
 		protected void InitializeToolbarButton()
@@ -973,7 +996,7 @@
 			this.ToolbarButton.Text = this.VoidName;
 			this.SetIconTexture(this.powerState | this.activeState);
 
-			this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT, GameScenes.SPH);
+			this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT);
 
 			this.ToolbarButton.OnClick += 
 				(e) =>
@@ -1145,39 +1168,6 @@
 			Active = 8
 		}
 	}
-
-	public static partial class VOID_Data
-	{
-		public static VOID_Core core
-		{
-			get
-			{
-				if (HighLogic.LoadedSceneIsEditor)
-				{
-					return VOID_EditorCore.Instance;
-				}
-				else
-				{
-					return VOID_Core.Instance;
-				}
-			}
-		}
-
-		public static double KerbinGee
-		{
-			get
-			{
-				if (kerbinGee == default(double))
-				{
-					kerbinGee = core.Kerbin.gravParameter / (core.Kerbin.Radius * core.Kerbin.Radius);
-				}
-
-				return kerbinGee;
-			}
-		}
-
-		private static double kerbinGee;
-	}
 }
 
 

file:b/VOID_Data.cs (new)
--- /dev/null
+++ b/VOID_Data.cs
@@ -1,1 +1,1181 @@
-
+// VOID
+//
+// VOID_Data.cs
+//
+// Copyright © 2014, toadicus
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+//    this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be used
+//    to endorse or promote products derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using KerbalEngineer.VesselSimulator;
+using KSP;
+using System;
+using System.Collections.Generic;
+using ToadicusTools;
+using UnityEngine;
+
+namespace VOID
+{
+	public static class VOID_Data
+	{
+		private static Dictionary<int, IVOID_DataValue> dataValues = new Dictionary<int, IVOID_DataValue>();
+		public static Dictionary<int, IVOID_DataValue> DataValues
+		{
+			get
+			{
+				return dataValues;
+			}
+		}
+
+		#region Constants
+
+		private static double kerbinGee;
+
+		public static double KerbinGee
+		{
+			get
+			{
+				if (kerbinGee == default(double))
+				{
+					kerbinGee = core.HomeBody.gravParameter / (core.HomeBody.Radius * core.HomeBody.Radius);
+				}
+
+				return kerbinGee;
+			}
+		}
+
+		#endregion
+
+		#region Core Data
+
+		public static VOID_Core core
+		{
+			get
+			{
+				if (HighLogic.LoadedSceneIsEditor)
+				{
+					return VOID_EditorCore.Instance;
+				}
+				else
+				{
+					return VOID_Core.Instance;
+				}
+			}
+		}
+
+		#endregion
+
+		#region Atmosphere
+
+		public static readonly VOID_DoubleValue atmDensity =
+			new VOID_DoubleValue(
+				"Atmosphere Density",
+				new Func<double>(() => core.vessel.atmDensity * 1000f),
+				"g/m³"
+			);
+
+		public static readonly VOID_FloatValue atmLimit =
+			new VOID_FloatValue(
+				"Atmosphere Limit",
+				new Func<float>(() => core.vessel.mainBody.maxAtmosphereAltitude),
+				"m"
+			);
+
+		public static readonly VOID_DoubleValue atmPressure =
+			new VOID_DoubleValue(
+				"Pressure",
+				new Func<double>(() => core.vessel.staticPressure),
+				"atm"
+			);
+
+		public static readonly VOID_FloatValue temperature =
+			new VOID_FloatValue(
+				"Temperature",
+				new Func<float>(() => core.vessel.flightIntegrator.getExternalTemperature()),
+				"°C"
+			);
+
+		#endregion
+
+		#region Attitude
+
+		public static readonly VOID_StrValue vesselHeading =
+			new VOID_StrValue(
+				"Heading",
+				delegate()
+				{
+					double heading = core.vessel.getSurfaceHeading();
+					string cardinal = VOID_Tools.get_heading_text(heading);
+
+					return string.Format(
+						"{0}° {1}",
+						heading.ToString("F2"),
+						cardinal
+					);
+				}
+			);
+
+		public static readonly VOID_DoubleValue vesselPitch =
+			new VOID_DoubleValue(
+				"Pitch",
+				() => core.vessel.getSurfacePitch(),
+				"°"
+			);
+
+		#endregion
+
+		#region Career
+
+		public static readonly VOID_StrValue fundingStatus =
+			new VOID_StrValue(
+				string.Intern("Funds"),
+				delegate()
+				{
+					if (VOID_CareerStatus.Instance == null)
+					{
+						return string.Empty;
+					}
+
+					return string.Format("{0} ({1})",
+						VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"),
+						VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange)
+					);
+				}
+			);
+
+		public static readonly VOID_StrValue reputationStatus =
+			new VOID_StrValue(
+				string.Intern("Reputation"),
+				delegate()
+				{
+					if (VOID_CareerStatus.Instance == null)
+					{
+						return string.Empty;
+					}
+
+					return string.Format("{0} ({1})",
+						VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"),
+						VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange)
+					);
+				}
+			);
+
+		public static readonly VOID_StrValue scienceStatus =
+			new VOID_StrValue(
+				string.Intern("Science"),
+				delegate()
+				{
+					if (VOID_CareerStatus.Instance == null)
+					{
+						return string.Empty;
+					}
+
+					return string.Format("{0} ({1})",
+						VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"),
+						VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange)
+					);
+				}
+			);
+
+		#endregion
+
+		#region Control
+
+		public static readonly VOID_FloatValue mainThrottle =
+			new VOID_FloatValue(
+				"Throttle",
+				new Func<float>(() => core.vessel.ctrlState.mainThrottle * 100f),
+				"%"
+			);
+
+		#endregion
+
+		#region Engineering
+
+		public static readonly VOID_IntValue partCount =
+			new VOID_IntValue(
+				"Parts",
+				new Func<int>(() => core.vessel.Parts.Count),
+				""
+			);
+
+		#region Mass
+
+		public static readonly VOID_StrValue comboResourceMass =
+			new VOID_StrValue(
+				"Resource Mass (curr / total)",
+				delegate()
+				{
+					return string.Format("{0} / {1}",
+						stageResourceMass.ValueUnitString("F3"),
+						resourceMass.ValueUnitString("F3")
+					);
+				}
+			);
+
+		public static readonly VOID_DoubleValue resourceMass =
+			new VOID_DoubleValue(
+				"Resource Mass",
+				delegate()
+				{
+					if (core.Stages == null || core.LastStage == null)
+					{
+						return double.NaN;
+					}
+
+					return core.LastStage.resourceMass;
+				},
+				"tons"
+			);
+
+		public static readonly VOID_DoubleValue stageResourceMass =
+			new VOID_DoubleValue(
+				"Resource Mass (Stage)",
+				delegate()
+				{
+					if (core.LastStage == null)
+					{
+						return double.NaN;
+					}
+
+					return core.LastStage.resourceMass;
+				},
+				"tons"
+			);
+
+		public static readonly VOID_DoubleValue totalMass =
+			new VOID_DoubleValue(
+				"Total Mass",
+				delegate()
+				{
+					if (core.Stages == null || core.LastStage == null)
+					{
+						return double.NaN;
+					}
+
+					return core.LastStage.totalMass;
+				},
+				"tons"
+			);
+
+		#endregion
+
+		#region DeltaV
+
+		public static readonly VOID_DoubleValue stageDeltaV =
+			new VOID_DoubleValue(
+				"DeltaV (Current Stage)",
+				delegate()
+				{
+					if (core.Stages == null || core.LastStage == null)
+						return double.NaN;
+					return core.LastStage.deltaV;
+				},
+				"m/s"
+			);
+
+		public static readonly VOID_DoubleValue totalDeltaV =
+			new VOID_DoubleValue(
+				"DeltaV (Total)",
+				delegate()
+				{
+					if (core.Stages == null || core.LastStage == null)
+						return double.NaN;
+					return core.LastStage.totalDeltaV;
+				},
+				"m/s"
+			);
+
+		#endregion
+
+		#region Propulsion
+
+		public static readonly VOID_StrValue currmaxThrustWeight =
+			new VOID_StrValue(
+				"T:W (curr/max)",
+				delegate()
+				{
+					if (core.Stages == null || core.LastStage == null)
+						return "N/A";
+
+					return string.Format(
+						"{0} / {1}",
+						(VOID_Data.currThrustWeight.Value).ToString("F2"),
+						(VOID_Data.maxThrustWeight.Value).ToString("F2")
+					);
+				}
+			);
+
+		public static readonly VOID_StrValue currmaxThrust =
+			new VOID_StrValue(
+				"Thrust (curr/max)",
+				delegate()
+				{
+					if (core.Stages == null || core.LastStage == null)
+						return "N/A";
+
+					double currThrust = core.LastStage.actualThrust;
+					double maxThrust = core.LastStage.thrust;
+
+					return string.Format(
+						"{0} / {1}",
+						currThrust.ToString("F1"),
+						maxThrust.ToString("F1")
+					);
+				}
+			);
+
+		public static readonly VOID_DoubleValue stageMassFlow =
+			new VOID_DoubleValue(
+				"Stage Mass Flow",
+				delegate()
+				{
+					if (core.LastStage == null)
+					{
+						return double.NaN;
+					}
+
+					double stageIsp = core.LastStage.isp;
+					double stageThrust = stageNominalThrust;
+
+					Tools.PostDebugMessage(typeof(VOID_Data), "calculating stageMassFlow from:\n" +
+						"\tstageIsp: {0}\n" +
+						"\tstageThrust: {1}\n" +
+						"\tKerbinGee: {2}\n",
+						stageIsp,
+						stageThrust,
+						KerbinGee
+					);
+
+					return stageThrust / (stageIsp * KerbinGee);
+				},
+				"Mg/s"
+			);
+
+		public static readonly VOID_DoubleValue stageNominalThrust =
+			new VOID_DoubleValue(
+				"Nominal Stage Thrust",
+				delegate()
+				{
+					if (core.LastStage == null)
+					{
+						return double.NaN;
+					}
+
+					if (core.LastStage.actualThrust == 0d)
+					{
+						return core.LastStage.thrust;
+					}
+					else
+					{
+						return core.LastStage.actualThrust;
+					}
+				},
+				"kN"
+			);
+
+		#endregion
+
+		#region Kinetics
+
+		public static readonly VOID_DoubleValue currThrustWeight =
+			new VOID_DoubleValue(
+				"T:W Ratio",
+				delegate()
+				{
+					if (core.LastStage == null)
+					{
+						return double.NaN;
+					}
+
+					return core.LastStage.actualThrustToWeight;
+				},
+				""
+			);
+
+
+
+		public static readonly VOID_DoubleValue maxThrustWeight =
+			new VOID_DoubleValue(
+				"T:W Ratio",
+				delegate()
+				{
+					if (core.LastStage == null)
+					{
+						return double.NaN;
+					}
+
+					return core.LastStage.thrustToWeight;
+				},
+				""
+			);
+
+		public static readonly VOID_DoubleValue nominalThrustWeight =
+			new VOID_DoubleValue(
+				"Thrust-to-Weight Ratio",
+				delegate()
+				{
+					if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d)
+					{
+						return maxThrustWeight.Value;
+					}
+
+					return currThrustWeight.Value;
+				},
+				""
+			);
+
+		public static readonly VOID_DoubleValue surfaceThrustWeight =
+			new VOID_DoubleValue(
+				"Max T:W @ surface",
+				delegate()
+				{
+					if (core.Stages == null || core.LastStage == null)
+						return double.NaN;
+
+					double maxThrust = core.LastStage.thrust;
+					double mass = core.LastStage.totalMass;
+					double gravity = (VOID_Core.Constant_G * core.vessel.mainBody.Mass) /
+					               (core.vessel.mainBody.Radius * core.vessel.mainBody.Radius);
+					double weight = mass * gravity;
+
+					return maxThrust / weight;
+				},
+				""
+			);
+
+		public static readonly VOID_Vector3dValue vesselThrustOffset =
+			new VOID_Vector3dValue(
+				"Thrust Offset",
+				delegate()
+				{
+					if (core.vessel == null)
+					{
+						return Vector3d.zero;
+					}
+
+					List<PartModule> engineModules = core.vessel.getModulesOfType<PartModule>();
+
+					Vector3d thrustPos = Vector3d.zero;
+					Vector3d thrustDir = Vector3d.zero;
+					float thrust = 0;
+
+					foreach (PartModule engine in engineModules)
+					{
+						float moduleThrust = 0;
+
+						switch (engine.moduleName)
+						{
+							case "ModuleEngines":
+							case "ModuleEnginesFX":
+								break;
+							default:
+								continue;
+						}
+
+						if (!engine.isEnabled)
+						{
+							continue;
+						}
+
+						CenterOfThrustQuery cotQuery = new CenterOfThrustQuery();
+
+						if (engine is ModuleEngines)
+						{
+							ModuleEngines engineModule = engine as ModuleEngines;
+
+							moduleThrust = engineModule.finalThrust;
+
+							engineModule.OnCenterOfThrustQuery(cotQuery);
+						}
+						else // engine is ModuleEnginesFX
+						{
+							ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX;
+
+							moduleThrust = engineFXModule.finalThrust;
+
+							engineFXModule.OnCenterOfThrustQuery(cotQuery);
+						}
+
+						if (moduleThrust != 0d)
+						{
+							cotQuery.thrust = moduleThrust;
+						}
+
+						thrustPos += cotQuery.pos * cotQuery.thrust;
+						thrustDir += cotQuery.dir * cotQuery.thrust;
+						thrust += cotQuery.thrust;
+					}
+
+					if (thrust != 0)
+					{
+						thrustPos /= thrust;
+						thrustDir /= thrust;
+					}
+
+					Transform vesselTransform = core.vessel.transform;
+
+					thrustPos = vesselTransform.InverseTransformPoint(thrustPos);
+					thrustDir = vesselTransform.InverseTransformDirection(thrustDir);
+
+					Vector3d thrustOffset = VectorTools.PointDistanceToLine(
+						                      thrustPos, thrustDir.normalized, core.vessel.findLocalCenterOfMass());
+
+					Tools.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" +
+						"\tthrustPos: {0}\n" +
+						"\tthrustDir: {1}\n" +
+						"\tthrustOffset: {2}\n" +
+						"\tvessel.CoM: {3}",
+						thrustPos,
+						thrustDir.normalized,
+						thrustOffset,
+						core.vessel.findWorldCenterOfMass()
+					);
+
+					return thrustOffset;
+				},
+				"m"
+			);
+
+		#endregion
+
+		#region Air Breathing
+
+		public static readonly VOID_StrValue intakeAirStatus =
+			new VOID_StrValue(
+				"Intake Air (Curr / Req)",
+				delegate()
+				{
+					double currentAmount;
+					double currentRequirement;
+
+					currentAmount = 0d;
+					currentRequirement = 0d;
+
+					foreach (Part part in core.vessel.Parts)
+					{
+						if (part.enabled)
+						{
+							ModuleEngines engineModule;
+							ModuleEnginesFX enginesFXModule;
+							List<Propellant> propellantList = null;
+
+							if (part.tryGetFirstModuleOfType<ModuleEngines>(out engineModule))
+							{
+								propellantList = engineModule.propellants;
+							}
+							else if (part.tryGetFirstModuleOfType<ModuleEnginesFX>(out enginesFXModule))
+								{
+									propellantList = enginesFXModule.propellants;
+								}
+
+							if (propellantList != null)
+							{
+								foreach (Propellant propellant in propellantList)
+								{
+									if (propellant.name == "IntakeAir")
+									{
+										currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime;
+										break;
+									}
+								}
+							}
+						}
+
+						ModuleResourceIntake intakeModule;
+
+						if (part.enabled && part.tryGetFirstModuleOfType<ModuleResourceIntake>(out intakeModule))
+						{
+							if (intakeModule.resourceName == "IntakeAir")
+							{
+								currentAmount += intakeModule.airFlow;
+							}
+						}
+					}
+
+					if (currentAmount == 0 && currentRequirement == 0)
+					{
+						return "N/A";
+					}
+
+					return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement);
+				}
+			);
+
+		#endregion
+
+		#region Crew
+
+		public static readonly VOID_IntValue vesselCrewCount =
+			new VOID_IntValue(
+				"Crew Onboard",
+				delegate()
+				{
+					if (core.vessel != null)
+					{
+						return core.vessel.GetCrewCount();
+					}
+					else
+					{
+						return 0;
+					}
+				},
+				""
+			);
+
+		public static readonly VOID_IntValue vesselCrewCapacity =
+			new VOID_IntValue(
+				"Crew Capacity",
+				delegate()
+				{
+					if (core.vessel != null)
+					{
+						return core.vessel.GetCrewCapacity();
+					}
+					else
+					{
+						return 0;
+					}
+				},
+				""
+			);
+
+		#endregion
+
+		#endregion
+
+		#region Location
+
+		public static readonly VOID_DoubleValue downrangeDistance =
+			new VOID_DoubleValue(
+				"Downrange Distance",
+				delegate()
+				{
+
+					if (core.vessel == null ||
+					  Planetarium.fetch == null ||
+					  core.vessel.mainBody != Planetarium.fetch.Home)
+					{
+						return double.NaN;
+					}
+
+					double vesselLongitude = core.vessel.longitude * Math.PI / 180d;
+					double vesselLatitude = core.vessel.latitude * Math.PI / 180d;
+
+					const double kscLongitude = 285.442323427289 * Math.PI / 180d;
+					const double kscLatitude = -0.0972112860655246 * Math.PI / 180d;
+
+					double diffLon = vesselLongitude - kscLongitude;
+					double diffLat = vesselLatitude - kscLatitude;
+
+					double sinHalfDiffLat = Math.Sin(diffLat / 2d);
+					double sinHalfDiffLon = Math.Sin(diffLon / 2d);
+
+					double cosVesselLon = Math.Cos(vesselLongitude);
+					double cosKSCLon = Math.Cos(kscLongitude);
+
+					double haversine =
+						sinHalfDiffLat * sinHalfDiffLat +
+						cosVesselLon * cosKSCLon * sinHalfDiffLon * sinHalfDiffLon;
+
+					double arc = 2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1d - haversine));
+
+					return core.vessel.mainBody.Radius * arc;
+				},
+				"m"
+			);
+
+		public static readonly VOID_StrValue surfLatitude =
+			new VOID_StrValue(
+				"Latitude",
+				new Func<string>(() => VOID_Tools.GetLatitudeString(core.vessel))
+			);
+
+		public static readonly VOID_StrValue surfLongitude =
+			new VOID_StrValue(
+				"Longitude",
+				new Func<string>(() => VOID_Tools.GetLongitudeString(core.vessel))
+			);
+
+		public static readonly VOID_DoubleValue trueAltitude =
+			new VOID_DoubleValue(
+				"Altitude (true)",
+				delegate()
+				{
+					double alt_true = core.vessel.orbit.altitude - core.vessel.terrainAltitude;
+					// HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,
+					// and water covers the whole surface at 0 m.
+					if (core.vessel.terrainAltitude < 0 && core.vessel.mainBody.ocean)
+						alt_true = core.vessel.orbit.altitude;
+					return alt_true;
+				},
+				"m"
+			);
+
+		#endregion
+
+		#region Kinematics
+
+		public static readonly VOID_DoubleValue geeForce =
+			new VOID_DoubleValue(
+				"G-force",
+				new Func<double>(() => core.vessel.geeForce),
+				"gees"
+			);
+
+		public static readonly VOID_DoubleValue horzVelocity =
+			new VOID_DoubleValue(
+				"Horizontal speed",
+				new Func<double>(() => core.vessel.horizontalSrfSpeed),
+				"m/s"
+			);
+
+		public static readonly VOID_DoubleValue surfVelocity =
+			new VOID_DoubleValue(
+				"Surface velocity",
+				new Func<double>(() => core.vessel.srf_velocity.magnitude),
+				"m/s"
+			);
+
+		public static readonly VOID_DoubleValue vertVelocity =
+			new VOID_DoubleValue(
+				"Vertical speed",
+				new Func<double>(() => core.vessel.verticalSpeed),
+				"m/s"
+			);
+
+		public static readonly VOID_DoubleValue vesselAccel =
+			new VOID_DoubleValue(
+				"Acceleration",
+				() => geeForce * KerbinGee,
+				"m/s²"
+			);
+
+		public static readonly VOID_DoubleValue vesselAngularVelocity =
+			new VOID_DoubleValue(
+				"Angular Velocity",
+				delegate()
+				{
+					if (core.vessel != null)
+					{
+						return core.vessel.angularVelocity.magnitude;
+					}
+					else
+					{
+						return double.NaN;
+					}
+				},
+				"rad/s"
+			);
+
+		#endregion
+
+		#region Navigation
+
+		public static int upcomingManeuverNodes
+		{
+			get
+			{
+				if (core.vessel == null ||
+				    core.vessel.patchedConicSolver == null ||
+				    core.vessel.patchedConicSolver.maneuverNodes == null)
+				{
+					return 0;
+				}
+
+				return core.vessel.patchedConicSolver.maneuverNodes.Count;
+			}
+		}
+
+		public static readonly VOID_StrValue burnTimeDoneAtNode =
+			new VOID_StrValue(
+				"Full burn time to be half done at node",
+				delegate()
+				{
+					if (core.LastStage == null && upcomingManeuverNodes < 1)
+					{
+						return "N/A";
+					}
+
+					ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0];
+
+					if ((node.UT - Planetarium.GetUniversalTime()) < 0)
+					{
+						return string.Empty;
+					}
+
+					double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime();
+
+					if (double.IsNaN(interval))
+					{
+						return string.Intern("NaN");
+					}
+
+					int sign = Math.Sign(interval);
+					interval = Math.Abs(interval);
+
+					string format;
+
+					if (sign >= 0)
+					{
+						format = string.Intern("T - {0}");
+					}
+					else
+					{
+						format = string.Intern("T + {0}");
+					}
+
+					return string.Format(format, VOID_Tools.FormatInterval(interval));
+				}
+			);
+
+		public static readonly VOID_StrValue burnTimeHalfDoneAtNode =
+			new VOID_StrValue(
+				"Full burn time to be half done at node",
+				delegate()
+				{
+					if (core.LastStage == null && upcomingManeuverNodes < 1)
+					{
+						return "N/A";
+					}
+
+					ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0];
+
+					if ((node.UT - Planetarium.GetUniversalTime()) < 0)
+					{
+						return string.Empty;
+					}
+
+					double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime();
+
+					if (double.IsNaN(interval))
+					{
+						return string.Intern("NaN");
+					}
+
+					int sign = Math.Sign(interval);
+					interval = Math.Abs(interval);
+
+					string format;
+
+					if (sign >= 0)
+					{
+						format = string.Intern("T - {0}");
+					}
+					else
+					{
+						format = string.Intern("T + {0}");
+					}
+
+					return string.Format(format, VOID_Tools.FormatInterval(interval));
+				}
+			);
+
+		public static readonly VOID_DoubleValue currManeuverDeltaV =
+			new VOID_DoubleValue(
+				"Current Maneuver Delta-V",
+				delegate()
+				{
+					if (upcomingManeuverNodes > 0)
+					{
+						return core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude;
+					}
+					else
+					{
+						return double.NaN;
+					}
+				},
+				"m/s"
+			);
+
+		public static readonly VOID_DoubleValue currManeuverDVRemaining =
+			new VOID_DoubleValue(
+				"Remaining Maneuver Delta-V",
+				delegate()
+				{
+					if (upcomingManeuverNodes > 0)
+					{
+						return core.vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(core.vessel.orbit).magnitude;
+					}
+					else
+					{
+						return double.NaN;
+					}
+				},
+				"m/s"
+			);
+
+		public static readonly VOID_DoubleValue currentNodeBurnDuration =
+			new VOID_DoubleValue(
+				"Total Burn Time",
+				delegate()
+				{
+					if (core.LastStage == null || currManeuverDeltaV.Value == double.NaN)
+					{
+						return double.NaN;
+					}
+
+					double stageThrust = stageNominalThrust;
+
+					return burnTime(currManeuverDeltaV.Value, totalMass, stageMassFlow, stageThrust);
+				},
+				"s"
+			);
+
+		public static readonly VOID_DoubleValue currentNodeBurnRemaining =
+			new VOID_DoubleValue(
+				"Burn Time Remaining",
+				delegate()
+				{
+					if (core.LastStage == null || currManeuverDVRemaining == double.NaN)
+					{
+						return double.NaN;
+					}
+
+					double stageThrust = stageNominalThrust;
+
+					return burnTime(currManeuverDVRemaining, totalMass, stageMassFlow, stageThrust);
+				},
+				"s"
+			);
+
+		public static readonly VOID_DoubleValue currentNodeHalfBurnDuration =
+			new VOID_DoubleValue(
+				"Half Burn Time",
+				delegate()
+				{
+					if (core.LastStage == null || currManeuverDeltaV.Value == double.NaN)
+					{
+						return double.NaN;
+					}
+
+					double stageThrust = stageNominalThrust;
+
+					return burnTime(currManeuverDeltaV.Value / 2d, totalMass, stageMassFlow, stageThrust);
+				},
+				"s"
+			);
+
+		public static readonly VOID_DoubleValue nextManeuverDeltaV =
+			new VOID_DoubleValue(
+				"Current Maneuver Delta-V",
+				delegate()
+				{
+					if (upcomingManeuverNodes > 1)
+					{
+						return core.vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude;
+					}
+					else
+					{
+						return double.NaN;
+					}
+				},
+				"m/s"
+			);
+
+		#endregion
+
+		#region Orbits
+
+		public static readonly VOID_StrValue primaryName =
+			new VOID_StrValue(
+				VOID_Localization.void_primary,
+				delegate()
+				{
+					if (core.vessel == null)
+					{
+						return string.Empty;
+					}
+					return core.vessel.mainBody.name;
+				}
+			);
+
+		public static readonly VOID_DoubleValue orbitAltitude =
+			new VOID_DoubleValue(
+				"Altitude (ASL)",
+				new Func<double>(() => core.vessel.orbit.altitude),
+				"m"
+			);
+
+		public static readonly VOID_DoubleValue orbitVelocity =
+			new VOID_DoubleValue(
+				VOID_Localization.void_velocity,
+				new Func<double>(() => core.vessel.orbit.vel.magnitude),
+				"m/s"
+			);
+
+		public static readonly VOID_DoubleValue orbitApoAlt =
+			new VOID_DoubleValue(
+				VOID_Localization.void_apoapsis,
+				new Func<double>(() => core.vessel.orbit.ApA),
+				"m"
+			);
+
+		public static readonly VOID_DoubleValue oribtPeriAlt =
+			new VOID_DoubleValue(
+				VOID_Localization.void_periapsis,
+				new Func<double>(() => core.vessel.orbit.PeA),
+				"m"
+			);
+
+		public static readonly VOID_StrValue timeToApo =
+			new VOID_StrValue(
+				"Time to Apoapsis",
+				new Func<string>(() => VOID_Tools.FormatInterval(core.vessel.orbit.timeToAp))
+			);
+
+		public static readonly VOID_StrValue timeToPeri =
+			new VOID_StrValue(
+				"Time to Periapsis",
+				new Func<string>(() => VOID_Tools.FormatInterval(core.vessel.orbit.timeToPe))
+			);
+
+		public static readonly VOID_DoubleValue orbitInclination =
+			new VOID_DoubleValue(
+				"Inclination",
+				new Func<double>(() => core.vessel.orbit.inclination),
+				"°"
+			);
+
+		public static readonly VOID_DoubleValue gravityAccel =
+			new VOID_DoubleValue(
+				"Gravity",
+				delegate()
+				{
+					double orbitRadius = core.vessel.mainBody.Radius +
+					                   core.vessel.mainBody.GetAltitude(core.vessel.findWorldCenterOfMass());
+					return (VOID_Core.Constant_G * core.vessel.mainBody.Mass) /
+					(orbitRadius * orbitRadius);
+				},
+				"m/s²"
+			);
+
+		public static readonly VOID_StrValue orbitPeriod =
+			new VOID_StrValue(
+				"Period",
+				new Func<string>(() => VOID_Tools.FormatInterval(core.vessel.orbit.period))
+			);
+
+		public static readonly VOID_DoubleValue semiMajorAxis =
+			new VOID_DoubleValue(
+				"Semi-Major Axis",
+				new Func<double>(() => core.vessel.orbit.semiMajorAxis),
+				"m"
+			);
+
+		public static readonly VOID_DoubleValue eccentricity =
+			new VOID_DoubleValue(
+				"Eccentricity",
+				new Func<double>(() => core.vessel.orbit.eccentricity),
+				""
+			);
+
+		public static readonly VOID_DoubleValue meanAnomaly =
+			new VOID_DoubleValue(
+				"Mean Anomaly",
+				new Func<double>(() => core.vessel.orbit.meanAnomaly * 180d / Math.PI),
+				"°"
+			);
+
+		public static readonly VOID_DoubleValue trueAnomaly = 
+			new VOID_DoubleValue(
+				"True Anomaly",
+				new Func<double>(() => core.vessel.orbit.trueAnomaly),
+				"°"
+			);
+
+		public static readonly VOID_DoubleValue eccAnomaly =
+			new VOID_DoubleValue(
+				"Eccentric Anomaly",
+				new Func<double>(() => core.vessel.orbit.eccentricAnomaly * 180d / Math.PI),
+				"°"
+			);
+
+		public static readonly VOID_DoubleValue longitudeAscNode =
+			new VOID_DoubleValue(
+				"Long. Ascending Node",
+				new Func<double>(() => core.vessel.orbit.LAN),
+				"°"
+			);
+
+		public static readonly VOID_DoubleValue argumentPeriapsis =
+			new VOID_DoubleValue(
+				"Argument of Periapsis",
+				new Func<double>(() => core.vessel.orbit.argumentOfPeriapsis),
+				"°"
+			);
+
+		public static readonly VOID_DoubleValue localSiderealLongitude =
+			new VOID_DoubleValue(
+				"Local Sidereal Longitude",
+				new Func<double>(() => VOID_Tools.FixDegreeDomain(
+						core.vessel.longitude + core.vessel.orbit.referenceBody.rotationAngle)),
+				"°"
+			);
+
+		#endregion
+
+		#region Science
+
+		public static readonly VOID_StrValue expSituation =
+			new VOID_StrValue(
+				"Situation",
+				new Func<string>(() => core.vessel.GetExperimentSituation().HumanString())
+			);
+
+		public static readonly VOID_StrValue currBiome =
+			new VOID_StrValue(
+				"Biome",
+				new Func<string>(() => VOID_Tools.GetBiome(core.vessel).name)
+			);
+
+		#endregion
+
+		#region Surface
+
+		public static readonly VOID_DoubleValue terrainElevation =
+			new VOID_DoubleValue(
+				"Terrain elevation",
+				new Func<double>(() => core.vessel.terrainAltitude),
+				"m"
+			);
+
+		#endregion
+
+		private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust)
+		{
+			Tools.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" +
+				"\tdeltaV: {0}\n" +
+				"\tinitialMass: {1}\n" +
+				"\tmassFlow: {2}\n" +
+				"\tthrust: {3}\n",
+				deltaV,
+				initialMass,
+				massFlow,
+				thrust
+			);
+			return initialMass / massFlow * (1d - Math.Exp(-deltaV * massFlow / thrust));
+		}
+	}
+}
+
+

--- a/VOID_DataLogger.cs
+++ b/VOID_DataLogger.cs
@@ -29,6 +29,7 @@
 using KSP;
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Text;
 using ToadicusTools;
 using UnityEngine;
@@ -40,261 +41,454 @@
 		/*
 		 * Fields
 		 * */
-		protected bool stopwatch1_running;
-
-		protected bool csv_logging;
-		protected bool first_write;
-
-		protected double stopwatch1;
-
-		protected string csv_log_interval_str;
-
-		protected float csv_log_interval;
-
-		protected double csvWriteTimer;
-		protected double csvCollectTimer;
-
-		protected List<string> csvList = new List<string>();
+		#region Fields
+
+		protected bool _loggingActive;
+		protected bool firstWrite;
+
+		[AVOID_SaveValue("logInterval")]
+		protected VOID_SaveValue<float> logInterval;
+		protected string logIntervalStr;
+
+		protected float csvCollectTimer;
+
+		protected List<byte> csvBytes;
+
+		protected string _fileName;
+		protected FileStream _outputFile;
+
+		protected uint outstandingWrites;
+
+		protected System.Text.UTF8Encoding _utf8Encoding;
+
+		#endregion
 
 		/*
 		 * Properties
 		 * */
 
+		#region Properties
+
+		// TODO: Add configurable or incremental file names.
+		protected bool loggingActive
+		{
+			get
+			{
+				return this._loggingActive;
+			}
+			set
+			{
+				if (value != this._loggingActive)
+				{
+					if (value)
+					{
+						this.csvCollectTimer = 0f;
+					}
+					else
+					{
+						this.CloseFileIfOpen();
+					}
+
+					this._loggingActive = value;
+				}
+			}
+		}
+
+		protected string fileName
+		{
+			get
+			{
+				if (this._fileName == null || this._fileName == string.Empty)
+				{
+					this._fileName = KSP.IO.IOUtils.GetFilePathFor(
+						typeof(VOID_Core),
+						string.Format(
+							"{0}_{1}",
+							this.vessel.vesselName,
+							"data.csv"
+						),
+						null
+					);
+				}
+
+				return this._fileName;
+			}
+		}
+
+		protected FileStream outputFile
+		{
+			get
+			{
+				if (this._outputFile == null)
+				{
+					Tools.DebugLogger logger = Tools.DebugLogger.New(this);
+					logger.AppendFormat("Initializing output file '{0}' with mode ", this.fileName);
+
+					if (File.Exists(this.fileName))
+					{
+						logger.Append("append");
+						this._outputFile = new FileStream(
+							this.fileName,
+							FileMode.Append,
+							FileAccess.Write,
+							FileShare.Read,
+							512,
+							true
+						);
+					}
+					else
+					{
+						logger.Append("create");
+						this._outputFile = new FileStream(
+							this.fileName,
+							FileMode.Create,
+							FileAccess.Write,
+							FileShare.Read,
+							512,
+							true
+						);
+
+						byte[] byteOrderMark = utf8Encoding.GetPreamble();
+
+						logger.Append(" and writing preamble");
+						this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length);
+					}
+
+					logger.Append('.');
+
+					logger.AppendFormat("  File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not ");
+
+					logger.Print();
+				}
+
+				return this._outputFile;
+			}
+		}
+
+		public UTF8Encoding utf8Encoding
+		{
+			get
+			{
+				if (this._utf8Encoding == null)
+				{
+					this._utf8Encoding = new UTF8Encoding(true);
+				}
+
+				return this._utf8Encoding;
+			}
+		}
+
+		#endregion
 
 		/*
 		 * Methods
 		 * */
-		public VOID_DataLogger()
-		{
-			this._Name = "CSV Data Logger";
-
-			this.stopwatch1_running = false;
-
-			this.csv_logging = false;
-			this.first_write = true;
-
-			this.stopwatch1 = 0;
-			this.csv_log_interval_str = "0.5";
-
-			this.csvWriteTimer = 0;
-			this.csvCollectTimer = 0;
-
-			this.WindowPos.x = Screen.width - 520;
-			this.WindowPos.y = 85;
-		}
-
-		public override void ModuleWindow(int _)
-		{
-			GUIStyle txt_white = new GUIStyle(GUI.skin.label);
-			txt_white.normal.textColor = txt_white.focused.textColor = Color.white;
-			txt_white.alignment = TextAnchor.UpperRight;
-			GUIStyle txt_green = new GUIStyle(GUI.skin.label);
-			txt_green.normal.textColor = txt_green.focused.textColor = Color.green;
-			txt_green.alignment = TextAnchor.UpperRight;
-			GUIStyle txt_yellow = new GUIStyle(GUI.skin.label);
-			txt_yellow.normal.textColor = txt_yellow.focused.textColor = Color.yellow;
-			txt_yellow.alignment = TextAnchor.UpperRight;
-
-			GUILayout.BeginVertical();
-
-			GUILayout.Label("System time: " + DateTime.Now.ToString("HH:mm:ss"));
-			GUILayout.Label(VOID_Tools.ConvertInterval(stopwatch1));
-
-			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			if (GUILayout.Button("Start"))
-			{
-				if (stopwatch1_running == false) stopwatch1_running = true;
-			}
-			if (GUILayout.Button("Stop"))
-			{
-				if (stopwatch1_running == true) stopwatch1_running = false;
-			}
-			if (GUILayout.Button("Reset"))
-			{
-				if (stopwatch1_running == true) stopwatch1_running = false;
-				stopwatch1 = 0;
-			}
-			GUILayout.EndHorizontal();
-
-			GUIStyle label_style = txt_white;
-			string log_label = "Inactive";
-			if (csv_logging && vessel.situation.ToString() == "PRELAUNCH")
-			{
-				log_label = "Awaiting launch";
-				label_style = txt_yellow;
-			}
-			if (csv_logging && vessel.situation.ToString() != "PRELAUNCH")
-			{
-				log_label = "Active";
-				label_style = txt_green;
-			}
-			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			csv_logging = GUILayout.Toggle(csv_logging, "Data logging: ", GUILayout.ExpandWidth(false));
-			GUILayout.Label(log_label, label_style, GUILayout.ExpandWidth(true));
-			GUILayout.EndHorizontal();
-
-			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false));
-			csv_log_interval_str = GUILayout.TextField(csv_log_interval_str, GUILayout.ExpandWidth(true));
-			GUILayout.Label("s", GUILayout.ExpandWidth(false));
-			GUILayout.EndHorizontal();
-
-			float new_log_interval;
-			if (float.TryParse(csv_log_interval_str, out new_log_interval))
-			{
-				csv_log_interval = new_log_interval;
-			}
-
-			GUILayout.EndVertical();
-			GUI.DragWindow();
-		}
-
+		#region Monobehaviour Lifecycle
 		public void Update()
 		{
+			if (this.csvBytes != null && this.csvBytes.Count > 0)
+			{
+				// csvList is not empty, write it
+				this.AsyncWriteData();
+			}
+
 			// CSV Logging
 			// from ISA MapSat
-			if (csv_logging)
+			if (loggingActive)
 			{
 				//data logging is on
 				//increment timers
-				csvWriteTimer += Time.deltaTime;
-				csvCollectTimer += Time.deltaTime;
-
-				if (csvCollectTimer >= csv_log_interval && vessel.situation != Vessel.Situations.PRELAUNCH)
+				this.csvCollectTimer += Time.deltaTime;
+
+				if (this.csvCollectTimer >= this.logInterval)
 				{
 					//data logging is on, vessel is not prelaunch, and interval has passed
 					//write a line to the list
-					line_to_csvList();  //write to the csv
+					this.CollectLogData();
 				}
-
-				if (csvList.Count != 0 && csvWriteTimer >= 15f)
-				{
-					// csvList is not empty and interval between writings to file has elapsed
-					//write it
-					string[] csvData;
-					csvData = (string[])csvList.ToArray();
-					Innsewerants_writeData(csvData);
-					csvList.Clear();
-					csvWriteTimer = 0f;
-				}
-			}
-			else
-			{
-				//data logging is off
-				//reset any timers and clear anything from csvList
-				csvWriteTimer = 0f;
-				csvCollectTimer = 0f;
-				if (csvList.Count > 0) csvList.Clear();
-			}
-
-			if (stopwatch1_running)
-			{
-				stopwatch1 += Time.deltaTime;
 			}
 		}
 
 		public void FixedUpdate() {}
 
-		private void Innsewerants_writeData(string[] csvArray)
-		{
-			var efile = KSP.IO.File.AppendText<VOID_Core>(vessel.vesselName + "_data.csv", null);
-			foreach (string line in csvArray)
-			{
-				efile.Write(line);
-			}
-			efile.Close();
-		}
-
-		private void line_to_csvList()
-		{
+		public void OnDestroy()
+		{
+			Tools.DebugLogger logger = Tools.DebugLogger.New(this);
+
+			logger.Append("Destroying...");
+
+			this.CloseFileIfOpen();
+
+			logger.Append(" Done.");
+			logger.Print(false);
+		}
+
+		#endregion
+
+		#region VOID_Module Overrides
+
+		public override void LoadConfig()
+		{
+			base.LoadConfig();
+
+			this.logIntervalStr = this.logInterval.value.ToString("#.0##");
+		}
+
+		public override void ModuleWindow(int _)
+		{
+			GUILayout.BeginVertical();
+
+			GUILayout.Label(
+				string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")),
+				GUILayout.ExpandWidth(true)
+			);
+			GUILayout.Label(
+				string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())),
+				GUILayout.ExpandWidth(true)
+			);
+
+			GUIStyle activeLabelStyle = VOID_Styles.labelRed;
+			string activeLabelText = "Inactive";
+			if (loggingActive)
+			{
+				activeLabelText = "Active";
+				activeLabelStyle = VOID_Styles.labelGreen;
+			}
+
+			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
+			this.loggingActive = GUILayout.Toggle(loggingActive, "Data logging: ", GUILayout.ExpandWidth(false));
+			GUILayout.Label(activeLabelText, activeLabelStyle, GUILayout.ExpandWidth(true));
+
+			GUILayout.EndHorizontal();
+
+			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
+			GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false));
+
+			logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true));
+			GUILayout.Label("s", GUILayout.ExpandWidth(false));
+
+			GUILayout.EndHorizontal();
+
+			float newLogInterval;
+			if (float.TryParse(logIntervalStr, out newLogInterval))
+			{
+				logInterval.value = newLogInterval;
+				this.logIntervalStr = this.logInterval.value.ToString("#.0##");
+			}
+
+			GUILayout.EndVertical();
+
+			GUI.DragWindow();
+		}
+
+		#endregion
+
+		#region Data Collection
+
+		private void CollectLogData()
+		{
+			if (this.csvBytes == null)
+			{
+				this.csvBytes = new List<byte>();
+			}
+
 			//called if logging is on and interval has passed
 			//writes one line to the csvList
 
 			StringBuilder line = new StringBuilder();
 
-			if (first_write && !KSP.IO.File.Exists<VOID_Core>(vessel.vesselName + "_data.csv", null))
-			{
-				first_write = false;
+			if (firstWrite)
+			{
+				firstWrite = false;
 				line.Append(
-					"Mission Elapsed Time (s);" +
-					"Altitude ASL (m);" +
-					"Altitude above terrain (m);" +
-					"Surface Latitude (°);" +
-					"Surface Longitude (°);" +
-					"Orbital Velocity (m/s);" +
-					"Surface Velocity (m/s);" +
-					"Vertical Speed (m/s);" +
-					"Horizontal Speed (m/s);" +
-					"Gee Force (gees);" +
-					"Temperature (°C);" +
-					"Gravity (m/s²);" +
-					"Atmosphere Density (g/m³);" +
+					"\"Kerbin Universal Time (s)\"," +
+					"\"Mission Elapsed Time (s)\t\"," +
+					"\"Altitude ASL (m)\"," +
+					"\"Altitude above terrain (m)\"," +
+					"\"Surface Latitude (°)\"," +
+					"\"Surface Longitude (°)\"," +
+					"\"Orbital Velocity (m/s)\"," +
+					"\"Surface Velocity (m/s)\"," +
+					"\"Vertical Speed (m/s)\"," +
+					"\"Horizontal Speed (m/s)\"," +
+					"\"Gee Force (gees)\"," +
+					"\"Temperature (°C)\"," +
+					"\"Gravity (m/s²)\"," +
+					"\"Atmosphere Density (g/m³)\"," +
+					"\"Downrange Distance  (m)\"," +
 					"\n"
 				);
 			}
 
+			// Universal time
+			line.Append(Planetarium.GetUniversalTime().ToString("F2"));
+			line.Append(',');
+
 			//Mission time
 			line.Append(vessel.missionTime.ToString("F3"));
-			line.Append(';');
+			line.Append(',');
 
 			//Altitude ASL
-			line.Append(vessel.orbit.altitude.ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.orbitAltitude.Value.ToString("F3"));
+			line.Append(',');
 
 			//Altitude (true)
-			double alt_true = vessel.orbit.altitude - vessel.terrainAltitude;
-			if (vessel.terrainAltitude < 0) alt_true = vessel.orbit.altitude;
-			line.Append(alt_true.ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.trueAltitude.Value.ToString("F3"));
+			line.Append(',');
 
 			// Surface Latitude
+			line.Append('"');
 			line.Append(VOID_Data.surfLatitude.Value);
-			line.Append(';');
+			line.Append('"');
+			line.Append(',');
 
 			// Surface Longitude
+			line.Append('"');
 			line.Append(VOID_Data.surfLongitude.Value);
-			line.Append(';');
+			line.Append('"');
+			line.Append(',');
 
 			//Orbital velocity
-			line.Append(vessel.orbit.vel.magnitude.ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.orbitVelocity.Value.ToString("F3"));
+			line.Append(',');
 
 			//surface velocity
-			line.Append(vessel.srf_velocity.magnitude.ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.surfVelocity.Value.ToString("F3"));
+			line.Append(',');
 
 			//vertical speed
-			line.Append(vessel.verticalSpeed.ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.vertVelocity.Value.ToString("F3"));
+			line.Append(',');
 
 			//horizontal speed
-			line.Append(vessel.horizontalSrfSpeed.ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.horzVelocity.Value.ToString("F3"));
+			line.Append(',');
 
 			//gee force
-			line.Append(vessel.geeForce.ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.geeForce.Value.ToString("F3"));
+			line.Append(',');
 
 			//temperature
-			line.Append(vessel.flightIntegrator.getExternalTemperature().ToString("F2"));
-			line.Append(';');
+			line.Append(VOID_Data.temperature.Value.ToString("F2"));
+			line.Append(',');
 
 			//gravity
-			double r_vessel = vessel.mainBody.Radius + vessel.mainBody.GetAltitude(vessel.findWorldCenterOfMass());
-			double g_vessel = (VOID_Core.Constant_G * vessel.mainBody.Mass) / (r_vessel * r_vessel);
-			line.Append(g_vessel.ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.gravityAccel.Value.ToString("F3"));
+			line.Append(',');
 
 			//atm density
-			line.Append((vessel.atmDensity * 1000).ToString("F3"));
-			line.Append(';');
+			line.Append(VOID_Data.atmDensity.Value.ToString("G3"));
+			line.Append(',');
+
+			// Downrange Distance
+			line.Append((VOID_Data.downrangeDistance.Value.ToString("G3")));
 
 			line.Append('\n');
 
-			csvList.Add(line.ToString());
-
-			csvCollectTimer = 0f;
-		}
+			csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString()));
+
+			this.csvCollectTimer = 0f;
+		}
+
+		#endregion
+
+		#region File IO Methods
+
+		protected void AsyncWriteCallback(IAsyncResult result)
+		{
+			Tools.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted);
+
+			this.outputFile.EndWrite(result);
+			this.outstandingWrites--;
+		}
+
+		private void AsyncWriteData()
+		{
+			WriteState state = new WriteState();
+
+			state.bytes = this.csvBytes.ToArray();
+			state.stream = this.outputFile;
+
+			this.outstandingWrites++;
+			var writeCallback = new AsyncCallback(this.AsyncWriteCallback);
+
+			this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state);
+
+			this.csvBytes.Clear();
+		}
+
+		private void CloseFileIfOpen()
+		{
+			Tools.DebugLogger logger = Tools.DebugLogger.New(this);
+
+			logger.AppendFormat("Cleaning up file {0}...", this.fileName);
+
+			if (this.csvBytes != null && this.csvBytes.Count > 0)
+			{
+				logger.Append(" Writing remaining data...");
+				this.AsyncWriteData();
+			}
+
+			logger.Append(" Waiting for writes to finish.");
+			while (this.outstandingWrites > 0)
+			{
+				logger.Append('.');
+				System.Threading.Thread.Sleep(10);
+			}
+
+			if (this._outputFile != null)
+			{
+				this._outputFile.Close();
+				this._outputFile = null;
+				logger.Append(" File closed.");
+			}
+
+			logger.Print(false);
+		}
+
+		#endregion
+
+		#region Constructors & Destructors
+
+		public VOID_DataLogger()
+		{
+			this._Name = "CSV Data Logger";
+
+			this.loggingActive = false;
+			this.firstWrite = true;
+
+			this.logInterval = 0.5f;
+			this.csvCollectTimer = 0f;
+
+			this.outstandingWrites = 0;
+
+			this.WindowPos.x = Screen.width - 520f;
+			this.WindowPos.y = 85f;
+
+			this.core.onApplicationQuit += delegate(object sender)
+			{
+				this.CloseFileIfOpen();
+			};
+		}
+
+		~VOID_DataLogger()
+		{
+			this.OnDestroy();
+		}
+
+		#endregion
+
+		#region Subclasses
+
+		private class WriteState
+		{
+			public byte[] bytes;
+			public FileStream stream;
+		}
+
+		#endregion
 	}
 }
 

--- a/VOID_DataValue.cs
+++ b/VOID_DataValue.cs
@@ -34,6 +34,10 @@
 {
 	public interface IVOID_DataValue
 	{
+		string Label { get; }
+		string Units { get; }
+		object Value { get; }
+
 		void Refresh();
 		string ValueUnitString();
 		void DoGUIHorizontal();
@@ -64,6 +68,14 @@
 		 * */
 		public string Label { get; protected set; }
 		public string Units { get; protected set; }
+
+		object IVOID_DataValue.Value
+		{
+			get
+			{
+				return (object)this.Value;
+			}
+		}
 
 		public T Value
 		{
@@ -90,6 +102,8 @@
 			this.Units = Units;
 			this.ValueFunc = ValueFunc;
 			this.lastUpdate = 0;
+
+			VOID_Data.DataValues[this.GetHashCode()] = this;
 		}
 
 		public void Refresh()
@@ -115,6 +129,21 @@
 			GUILayout.FlexibleSpace ();
 			GUILayout.Label (this.ValueUnitString(), GUILayout.ExpandWidth (false));
 			GUILayout.EndHorizontal ();
+		}
+
+		public override int GetHashCode()
+		{
+			int hash;
+			unchecked
+			{
+				hash = 79999;
+
+				hash = hash * 104399 + this.Label.GetHashCode();
+				hash = hash * 104399 + this.ValueFunc.GetHashCode();
+				hash = hash * 104399 + this.Units.GetHashCode();
+			}
+
+			return hash;
 		}
 
 		public override string ToString()

--- a/VOID_EditorCore.cs
+++ b/VOID_EditorCore.cs
@@ -26,7 +26,7 @@
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -99,7 +99,7 @@
 
 			Rect _iconPos = Tools.DockToWindow (this.VOIDIconPos, this.mainWindowPos);
 
-			_iconPos = Tools.ClampRectToScreen (_iconPos, (int)_iconPos.width, (int)_iconPos.height);
+			_iconPos = Tools.ClampRectToEditorPad (_iconPos);
 
 			if (_iconPos != this.VOIDIconPos)
 			{
@@ -111,9 +111,11 @@
 
 		public override void Update()
 		{
+			this.LoadBeforeUpdate();
+
 			foreach (IVOID_EditorModule module in this.Modules)
 			{
-				if (EditorLogic.startPod == null)
+				if (EditorLogic.RootPart == null)
 				{
 					module.StopGUI();
 					continue;
@@ -128,7 +130,7 @@
 				}
 			}
 
-			if (EditorLogic.startPod == null || !HighLogic.LoadedSceneIsEditor)
+			if (EditorLogic.RootPart == null || !HighLogic.LoadedSceneIsEditor)
 			{
 				this.StopGUI();
 				return;

--- a/VOID_EditorHUD.cs
+++ b/VOID_EditorHUD.cs
@@ -26,7 +26,7 @@
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -37,41 +37,20 @@
 
 namespace VOID
 {
-	public class VOID_EditorHUD : VOID_Module, IVOID_EditorModule
+	public class VOID_EditorHUD : VOID_HUDModule, IVOID_EditorModule
 	{
 		/*
 		 * Fields
 		 * */
-		[AVOID_SaveValue("colorIndex")]
-		protected VOID_SaveValue<int> _colorIndex = 0;
-
-		protected List<Color> textColors = new List<Color>();
-
-		protected GUIStyle labelStyle;
-
+		[AVOID_SaveValue("ehudWindowPos")]
+		protected VOID_SaveValue<Rect> ehudWindowPos;
+
+		protected HUDWindow ehudWindow;
 		protected EditorVesselOverlays _vesselOverlays;
 
 		/*
 		 * Properties
 		 * */
-		public int ColorIndex
-		{
-			get
-			{
-				return this._colorIndex;
-			}
-			set
-			{
-				if (this._colorIndex >= this.textColors.Count - 1)
-				{
-					this._colorIndex = 0;
-					return;
-				}
-
-				this._colorIndex = value;
-			}
-		}
-
 		protected EditorVesselOverlays vesselOverlays
 		{
 			get
@@ -122,57 +101,26 @@
 
 			this.toggleActive = true;
 
-			this.textColors.Add(Color.green);
-			this.textColors.Add(Color.black);
-			this.textColors.Add(Color.white);
-			this.textColors.Add(Color.red);
-			this.textColors.Add(Color.blue);
-			this.textColors.Add(Color.yellow);
-			this.textColors.Add(Color.gray);
-			this.textColors.Add(Color.cyan);
-			this.textColors.Add(Color.magenta);
-
-			this.labelStyle = new GUIStyle ();
-			// this.labelStyle.alignment = TextAnchor.UpperRight;
-			this.labelStyle.normal.textColor = this.textColors [this.ColorIndex];
+			this.ehudWindow = new HUDWindow(
+				this.ehudWindowFunc,
+				new Rect(EditorPanels.Instance.partsPanelWidth + 10f, 125f, 300f, 64f)
+			);
+			this.Windows.Add(this.ehudWindow);
+			this.ehudWindowPos = this.ehudWindow.WindowPos;
 
 			Tools.PostDebugMessage (this.GetType().Name + ": Constructed.");
 		}
 
-		public override void DrawGUI()
-		{
-			SimManager.RequestSimulation();
+		public void ehudWindowFunc(int id)
+		{
+			StringBuilder hudString = new StringBuilder();
 
 			if (this.core.LastStage == null)
 			{
 				return;
 			}
 
-			float hudLeft;
-			StringBuilder hudString;
-
-			if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Parts)
-			{
-				hudLeft = EditorPanels.Instance.partsPanelWidth + 10;
-			}
-			else if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Actions)
-			{
-				hudLeft = EditorPanels.Instance.actionsPanelWidth + 10;
-			}
-			else
-			{
-				return;
-			}
-
-			GUI.skin = this.core.Skin;
-
-			Rect hudPos = new Rect (hudLeft, 48, 300, 32);
-
-			hudString = new StringBuilder();
-
 			// GUI.skin = AssetBase.GetGUISkin("KSP window 2");
-
-			labelStyle.normal.textColor = textColors [ColorIndex];
 
 			hudString.Append("Total Mass: ");
 			hudString.Append(this.core.LastStage.totalMass.ToString("F3"));
@@ -212,18 +160,60 @@
 					).ToString("F3"));
 			}
 
-			GUI.Label (
-				hudPos,
-				hudString.ToString(),
-				labelStyle);
-		}
-
-		public override void DrawConfigurables()
-		{
-			if (GUILayout.Button ("Change HUD color", GUILayout.ExpandWidth (false)))
-			{
-				++this.ColorIndex;
-			}
+			GUILayout.Label(hudString.ToString(), VOID_Styles.labelHud, GUILayout.ExpandWidth(true));
+
+			if (!this.positionsLocked)
+			{
+				GUI.DragWindow();
+			}
+
+			GUI.BringWindowToBack(id);
+		}
+
+		public override void DrawGUI()
+		{
+			float hudLeft;
+
+			if (EditorLogic.fetch.editorScreen == EditorScreen.Parts)
+			{
+				hudLeft = EditorPanels.Instance.partsPanelWidth + 10f;
+				hudLeft += EditorPartList.Instance.transformTopLeft.position.x -
+					EditorPartList.Instance.transformTopLeft.parent.parent.position.x -
+					72f;
+			}
+			else if (EditorLogic.fetch.editorScreen == EditorScreen.Actions)
+			{
+				hudLeft = EditorPanels.Instance.actionsPanelWidth + 10f;
+			}
+			else
+			{
+				return;
+			}
+
+			bool snapToEdge = Mathf.Abs(this.ehudWindowPos.value.xMin - hudLeft) < 15f;
+
+			Tools.PostDebugMessage(this,
+				"EditorPartList topLeft.parent.parent.position: {0}\n" +
+				"EditorPartList topLeft.parent.position: {1}\n" +
+				"EditorPartList topLeft.position: {2}\n" +
+				"snapToEdge: {3} (pos.Xmin: {4}; hudLeft: {5})",
+				EditorPartList.Instance.transformTopLeft.parent.parent.position,
+				EditorPartList.Instance.transformTopLeft.parent.position,
+				EditorPartList.Instance.transformTopLeft.position,
+				snapToEdge, this.ehudWindowPos.value.xMin, hudLeft
+			);
+
+			base.DrawGUI();
+
+			Rect hudPos = this.ehudWindow.WindowPos;
+
+			hudPos.xMin = hudLeft;
+			hudPos.width = this.ehudWindow.defaultWindowPos.width;
+
+			this.ehudWindowPos.value = hudPos;
+
+			this.ehudWindow.WindowPos = this.ehudWindowPos;
+
 		}
 	}
 }

--- a/VOID_HUD.cs
+++ b/VOID_HUD.cs
@@ -26,7 +26,7 @@
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -36,47 +36,22 @@
 
 namespace VOID
 {
-	public class VOID_HUD : VOID_Module, IVOID_Module
+	public class VOID_HUD : VOID_HUDModule, IVOID_Module
 	{
 		/*
 		 * Fields
 		 * */
-		[AVOID_SaveValue("colorIndex")]
-		protected VOID_SaveValue<int> _colorIndex;
-
-		protected List<Color> textColors;
-
-		protected Rect leftHUDdefaultPos;
-		protected Rect rightHUDdefaultPos;
-
 		[AVOID_SaveValue("leftHUDPos")]
 		protected VOID_SaveValue<Rect> leftHUDPos;
 		[AVOID_SaveValue("rightHUDPos")]
 		protected VOID_SaveValue<Rect> rightHUDPos;
 
-		[AVOID_SaveValue("positionsLocked")]
-		protected VOID_SaveValue<bool> positionsLocked;
+		protected HUDWindow leftWindow;
+		protected HUDWindow rightWindow;
 
 		/*
 		 * Properties
 		 * */
-		public int ColorIndex
-		{
-			get
-			{
-				return this._colorIndex;
-			}
-			set
-			{
-				if (this._colorIndex >= this.textColors.Count - 1)
-				{
-					this._colorIndex = 0;
-					return;
-				}
-
-				this._colorIndex = value;
-			}
-		}
 
 		/* 
 		 * Methods
@@ -87,29 +62,25 @@
 
 			this.toggleActive = true;
 
-			this._colorIndex = 0;
+			this.leftWindow = new HUDWindow(this.leftHUDWindow, new Rect(Screen.width * .375f - 300f, 0f, 300f, 90f));
+			this.Windows.Add(this.leftWindow);
 
-			this.textColors = new List<Color>();
+			this.leftHUDPos = this.leftWindow.WindowPos;
 
-			this.textColors.Add(Color.green);
-			this.textColors.Add(Color.black);
-			this.textColors.Add(Color.white);
-			this.textColors.Add(Color.red);
-			this.textColors.Add(Color.blue);
-			this.textColors.Add(Color.yellow);
-			this.textColors.Add(Color.gray);
-			this.textColors.Add(Color.cyan);
-			this.textColors.Add(Color.magenta);
+			this.rightWindow = new HUDWindow(this.rightHUDWindow, new Rect(Screen.width * .625f, 0f, 300f, 90f));
+			this.Windows.Add(this.rightWindow);
 
-			this.leftHUDdefaultPos = new Rect(Screen.width * .375f - 300f, 0f, 300f, 90f);
-			this.leftHUDPos = new Rect(this.leftHUDdefaultPos);
-
-			this.rightHUDdefaultPos = new Rect(Screen.width * .625f, 0f, 300f, 90f);
-			this.rightHUDPos = new Rect(this.rightHUDdefaultPos);
-
-			this.positionsLocked = true;
+			this.rightHUDPos = this.rightWindow.WindowPos;
 
 			Tools.PostDebugMessage ("VOID_HUD: Constructed.");
+		}
+
+		public override void DrawGUI()
+		{
+			base.DrawGUI();
+
+			this.leftHUDPos.value = this.leftWindow.WindowPos;
+			this.rightHUDPos.value = this.rightWindow.WindowPos;
 		}
 
 		protected void leftHUDWindow(int id)
@@ -118,7 +89,7 @@
 
 			leftHUD = new StringBuilder();
 
-			this.core.LabelStyles["hud"].alignment = TextAnchor.UpperRight;
+			VOID_Styles.labelHud.alignment = TextAnchor.UpperRight;
 
 			if (this.core.powerAvailable)
 			{
@@ -145,11 +116,11 @@
 			}
 			else
 			{
-				this.core.LabelStyles["hud"].normal.textColor = Color.red;
+				VOID_Styles.labelHud.normal.textColor = Color.red;
 				leftHUD.Append(string.Intern("-- POWER LOST --"));
 			}
 
-			GUILayout.Label(leftHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(leftHUD.ToString(), VOID_Styles.labelHud, GUILayout.ExpandWidth(true));
 
 			if (!this.positionsLocked)
 			{
@@ -165,7 +136,7 @@
 
 			rightHUD = new StringBuilder();
 
-			this.core.LabelStyles["hud"].alignment = TextAnchor.UpperLeft;
+			VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft;
 
 			if (this.core.powerAvailable)
 			{
@@ -191,7 +162,7 @@
 				);
 
 				if (
-					this.core.vessel.mainBody == this.core.Kerbin &&
+					this.core.vessel.mainBody == this.core.HomeBody &&
 					(
 						this.core.vessel.situation == Vessel.Situations.FLYING ||
 						this.core.vessel.situation == Vessel.Situations.SUB_ORBITAL ||
@@ -205,12 +176,12 @@
 			}
 			else
 			{
-				this.core.LabelStyles["hud"].normal.textColor = Color.red;
+				VOID_Styles.labelHud.normal.textColor = Color.red;
 				rightHUD.Append(string.Intern("-- POWER LOST --"));
 			}
 
 
-			GUILayout.Label(rightHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(rightHUD.ToString(), VOID_Styles.labelHud, GUILayout.ExpandWidth(true));
 
 			if (!this.positionsLocked)
 			{
@@ -219,109 +190,6 @@
 
 			GUI.BringWindowToBack(id);
 		}
-
-		public override void DrawGUI()
-		{
-			if (!this.core.LabelStyles.ContainsKey("hud"))
-			{
-				this.core.LabelStyles["hud"] = new GUIStyle(GUI.skin.label);
-			}
-
-			this.core.LabelStyles["hud"].normal.textColor = textColors [ColorIndex];
-
-			GUI.skin = this.core.Skin;
-
-			if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate))
-			{
-				SimManager.RequestSimulation();
-			}
-
-			this.leftHUDPos.value = GUI.Window(
-				this.core.windowID,
-				this.leftHUDPos,
-				VOID_Tools.GetWindowHandler(this.leftHUDWindow),
-				GUIContent.none,
-				GUIStyle.none
-			);
-
-			this.rightHUDPos.value = GUI.Window(
-				this.core.windowID,
-				this.rightHUDPos,
-				VOID_Tools.GetWindowHandler(this.rightHUDWindow),
-				GUIContent.none,
-				GUIStyle.none
-			);
-		}
-
-		public override void DrawConfigurables()
-		{
-			if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false)))
-			{
-				++this.ColorIndex;
-			}
-
-			if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false)))
-			{
-				this.leftHUDPos = new Rect(this.leftHUDdefaultPos);
-				this.rightHUDPos = new Rect(this.rightHUDdefaultPos);
-			}
-
-			this.positionsLocked = GUILayout.Toggle(this.positionsLocked,
-				string.Intern("Lock HUD Positions"),
-				GUILayout.ExpandWidth(false));
-		}
-	}
-
-	public static partial class VOID_Data
-	{
-		public static readonly VOID_StrValue expSituation = new VOID_StrValue(
-			"Situation",
-			new Func<string> (() => core.vessel.GetExperimentSituation().HumanString())
-		);
-
-		public static readonly VOID_DoubleValue vesselPitch = new VOID_DoubleValue(
-			"Pitch",
-			() => core.vessel.getSurfacePitch(),
-			"°"
-		);
-
-		public static readonly VOID_DoubleValue downrangeDistance = new VOID_DoubleValue(
-			"Downrange Distance",
-			delegate() {
-
-			if (core.vessel == null ||
-				Planetarium.fetch == null ||
-				core.vessel.mainBody != Planetarium.fetch.Home
-			)
-			{
-				return double.NaN;
-			}
-
-			double vesselLongitude = core.vessel.longitude * Math.PI / 180d;
-			double vesselLatitude = core.vessel.latitude * Math.PI / 180d;
-
-			const double kscLongitude = 285.442323427289 * Math.PI / 180d;
-			const double kscLatitude = -0.0972112860655246 * Math.PI / 180d;
-
-			double diffLon = vesselLongitude - kscLongitude;
-			double diffLat = vesselLatitude - kscLatitude;
-
-			double sinHalfDiffLat = Math.Sin(diffLat / 2d);
-			double sinHalfDiffLon = Math.Sin(diffLon / 2d);
-
-			double cosVesselLon = Math.Cos(vesselLongitude);
-			double cosKSCLon = Math.Cos(kscLongitude);
-
-			double haversine =
-				sinHalfDiffLat * sinHalfDiffLat +
-				cosVesselLon * cosKSCLon * sinHalfDiffLon * sinHalfDiffLon;
-
-			double arc = 2d * Math.Atan2(Math.Sqrt(haversine), Math.Sqrt(1d - haversine));
-
-			return core.vessel.mainBody.Radius * arc;
-		},
-			"m"
-		);
 	}
 }
 

--- a/VOID_HUDAdvanced.cs
+++ b/VOID_HUDAdvanced.cs
@@ -26,7 +26,7 @@
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-using Engineer.VesselSimulator;
+using KerbalEngineer.VesselSimulator;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -37,37 +37,38 @@
 
 namespace VOID
 {
-	public class VOID_HUDAdvanced : VOID_Module, IVOID_Module
+	public class VOID_HUDAdvanced : VOID_HUDModule, IVOID_Module
 	{
 		/*
 		 * Fields
 		 * */
 		protected VOID_HUD primaryHUD;
 
-		protected Rect leftHUDdefaultPos;
-		protected Rect rightHUDdefaultPos;
+		protected HUDWindow leftHUD;
+		protected HUDWindow rightHUD;
 
 		[AVOID_SaveValue("leftHUDPos")]
 		protected VOID_SaveValue<Rect> leftHUDPos;
 		[AVOID_SaveValue("rightHUDPos")]
 		protected VOID_SaveValue<Rect> rightHUDPos;
 
-		[AVOID_SaveValue("positionsLocked")]
-		protected VOID_SaveValue<bool> positionsLocked;
-
 		/*
 		 * Properties
 		 * */
-		public int ColorIndex
+		public override int ColorIndex
 		{
 			get
 			{
-				if (this.primaryHUD == null)
-				{
-					return 0;
-				}
-
-				return this.primaryHUD.ColorIndex;
+				if (this.primaryHUD != null)
+				{
+					return this.primaryHUD.ColorIndex;
+				}
+
+				return base.ColorIndex;
+			}
+			set
+			{
+				base.ColorIndex = value;
 			}
 		}
 
@@ -80,19 +81,23 @@
 
 			this.toggleActive = true;
 
-			this.leftHUDdefaultPos = new Rect(
+			this.leftHUD = new HUDWindow(this.leftHUDWindow, new Rect(
 				Screen.width * .5f - (float)GameSettings.UI_SIZE * .25f - 300f,
 				Screen.height - 200f,
-				300f, 90f
+				300f, 90f)
 			);
-			this.leftHUDPos = new Rect(this.leftHUDdefaultPos);
-
-			this.rightHUDdefaultPos = new Rect(
+			this.Windows.Add(this.leftHUD);
+
+			this.leftHUDPos = this.leftHUD.WindowPos;
+
+			this.rightHUD = new HUDWindow(this.rightHUDWindow, new Rect(
 				Screen.width * .5f + (float)GameSettings.UI_SIZE * .25f,
 				Screen.height - 200f,
-				300f, 90f
+				300f, 90f)
 			);
-			this.rightHUDPos = new Rect(this.rightHUDdefaultPos);
+			this.Windows.Add(this.rightHUD);
+
+			this.rightHUDPos = this.rightHUD.WindowPos;
 
 			this.positionsLocked = true;
 
@@ -105,7 +110,7 @@
 
 			leftHUD = new StringBuilder();
 
-			this.core.LabelStyles["hud"].alignment = TextAnchor.UpperRight;
+			VOID_Styles.labelHud.alignment = TextAnchor.UpperRight;
 
 			if (this.core.powerAvailable)
 			{
@@ -144,11 +149,11 @@
 			}
 			else
 			{
-				this.core.LabelStyles["hud"].normal.textColor = Color.red;
+				VOID_Styles.labelHud.normal.textColor = Color.red;
 				leftHUD.Append(string.Intern("-- POWER LOST --"));
 			}
 
-			GUILayout.Label(leftHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(leftHUD.ToString(), VOID_Styles.labelHud, GUILayout.ExpandWidth(true));
 
 			if (!this.positionsLocked)
 			{
@@ -164,7 +169,7 @@
 
 			rightHUD = new StringBuilder();
 
-			this.core.LabelStyles["hud"].alignment = TextAnchor.UpperLeft;
+			VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft;
 
 			if (this.core.powerAvailable)
 			{
@@ -182,8 +187,8 @@
 				}
 
 				rightHUD.AppendFormat("Burn Time (Rem/Total): {0} / {1}\n",
-					VOID_Tools.ConvertInterval(VOID_Data.currentNodeBurnRemaining.Value),
-					VOID_Tools.ConvertInterval(VOID_Data.currentNodeBurnDuration.Value)
+					VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnRemaining.Value),
+					VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnDuration.Value)
 				);
 
 				if (VOID_Data.burnTimeDoneAtNode.Value != string.Empty)
@@ -203,11 +208,11 @@
 			}
 			else
 			{
-				this.core.LabelStyles["hud"].normal.textColor = Color.red;
+				VOID_Styles.labelHud.normal.textColor = Color.red;
 				rightHUD.Append(string.Intern("-- POWER LOST --"));
 			}
 
-			GUILayout.Label(rightHUD.ToString(), this.core.LabelStyles["hud"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(rightHUD.ToString(), VOID_Styles.labelHud, GUILayout.ExpandWidth(true));
 
 			if (!this.positionsLocked)
 			{
@@ -229,32 +234,11 @@
 					}
 				}
 			}
-			else
-			{
-				if ((TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate))
-				{
-					SimManager.RequestSimulation();
-				}
-
-				this.leftHUDPos.value = GUI.Window(
-					this.core.windowID,
-					this.leftHUDPos,
-					VOID_Tools.GetWindowHandler(this.leftHUDWindow),
-					GUIContent.none,
-					GUIStyle.none
-				);
-
-				if (VOID_Data.upcomingManeuverNodes > 0)
-				{
-					this.rightHUDPos.value = GUI.Window(
-						this.core.windowID,
-						this.rightHUDPos,
-						VOID_Tools.GetWindowHandler(this.rightHUDWindow),
-						GUIContent.none,
-						GUIStyle.none
-					);
-				}
-			}
+
+			base.DrawGUI();
+
+			this.leftHUDPos.value = this.leftHUD.WindowPos;
+			this.rightHUDPos.value = this.rightHUD.WindowPos;
 		}
 
 		public override void DrawConfigurables()
@@ -264,410 +248,5 @@
 				GUILayout.ExpandWidth(false));
 		}
 	}
-
-	public static partial class VOID_Data
-	{
-		public static int upcomingManeuverNodes
-		{
-			get
-			{
-				if (core.vessel == null ||
-					core.vessel.patchedConicSolver == null ||
-					core.vessel.patchedConicSolver.maneuverNodes == null
-				)
-				{
-					return 0;
-				}
-
-				return core.vessel.patchedConicSolver.maneuverNodes.Count;
-			}
-		}
-
-		public static readonly VOID_Vector3dValue vesselThrustOffset = new VOID_Vector3dValue(
-			"Thrust Offset",
-			delegate()
-		{
-			if (core.vessel == null)
-			{
-				return Vector3d.zero;
-			}
-
-			List<PartModule> engineModules = core.vessel.getModulesOfType<PartModule>();
-
-			Vector3d thrustPos = Vector3d.zero;
-			Vector3d thrustDir = Vector3d.zero;
-			float thrust = 0;
-
-			foreach (PartModule engine in engineModules)
-			{
-				float moduleThrust = 0;
-
-				switch (engine.moduleName)
-				{
-					case "ModuleEngines":
-					case "ModuleEnginesFX":
-						break;
-					default:
-						continue;
-				}
-
-				if (!engine.isEnabled)
-				{
-					continue;
-				}
-
-				CenterOfThrustQuery cotQuery = new CenterOfThrustQuery();
-
-				if (engine is ModuleEngines)
-				{
-					ModuleEngines engineModule = engine as ModuleEngines;
-
-					moduleThrust = engineModule.finalThrust;
-
-					engineModule.OnCenterOfThrustQuery(cotQuery);
-				}
-				else // engine is ModuleEnginesFX
-				{
-					ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX;
-
-					moduleThrust = engineFXModule.finalThrust;
-
-					engineFXModule.OnCenterOfThrustQuery(cotQuery);
-				}
-
-				if (moduleThrust != 0d)
-				{
-					cotQuery.thrust = moduleThrust;
-				}
-
-				thrustPos += cotQuery.pos * cotQuery.thrust;
-				thrustDir += cotQuery.dir * cotQuery.thrust;
-				thrust += cotQuery.thrust;
-			}
-
-			if (thrust != 0)
-			{
-				thrustPos /= thrust;
-				thrustDir /= thrust;
-			}
-
-			Transform vesselTransform = core.vessel.transform;
-
-			thrustPos = vesselTransform.InverseTransformPoint(thrustPos);
-			thrustDir = vesselTransform.InverseTransformDirection(thrustDir);
-
-			Vector3d thrustOffset = VectorTools.PointDistanceToLine(
-				thrustPos, thrustDir.normalized, core.vessel.findLocalCenterOfMass());
-
-			Tools.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" +
-				"\tthrustPos: {0}\n" +
-				"\tthrustDir: {1}\n" +
-				"\tthrustOffset: {2}\n" +
-				"\tvessel.CoM: {3}",
-				thrustPos,
-				thrustDir.normalized,
-				thrustOffset,
-				core.vessel.findWorldCenterOfMass()
-			);
-
-			return thrustOffset;
-		},
-			"m"
-		);
-
-		public static readonly VOID_DoubleValue vesselAccel = new VOID_DoubleValue(
-			"Acceleration",
-			() => geeForce * KerbinGee,
-			"m/s²"
-		);
-
-		public static readonly VOID_IntValue vesselCrewCount = new VOID_IntValue(
-			"Crew Onboard",
-			delegate()
-			{
-				if (core.vessel != null)
-				{
-					return core.vessel.GetCrewCount();
-				}
-				else
-				{
-					return 0;
-				}
-			},
-			""
-		);
-
-		public static readonly VOID_IntValue vesselCrewCapacity = new VOID_IntValue(
-			"Crew Capacity",
-			delegate()
-		{
-			if (core.vessel != null)
-			{
-				return core.vessel.GetCrewCapacity();
-			}
-			else
-			{
-				return 0;
-			}
-		},
-			""
-		);
-
-		public static readonly VOID_DoubleValue vesselAngularVelocity = new VOID_DoubleValue(
-			"Angular Velocity",
-			delegate()
-		{
-			if (core.vessel != null)
-			{
-				return core.vessel.angularVelocity.magnitude;
-			}
-			else
-			{
-				return double.NaN;
-			}
-		},
-			"rad/s"
-		);
-
-		public static readonly VOID_DoubleValue stageNominalThrust = new VOID_DoubleValue(
-			"Nominal Stage Thrust",
-			delegate()
-		{
-			if (core.LastStage == null)
-			{
-				return double.NaN;
-			}
-
-			if (core.LastStage.actualThrust == 0d)
-			{
-				return core.LastStage.thrust;
-			}
-			else
-			{
-				return core.LastStage.actualThrust;
-			}
-		},
-			"kN"
-		);
-
-		public static readonly VOID_DoubleValue stageMassFlow = new VOID_DoubleValue(
-			"Stage Mass Flow",
-			delegate()
-			{
-				if (core.LastStage == null)
-				{
-					return double.NaN;
-				}
-
-			double stageIsp = core.LastStage.isp;
-			double stageThrust = stageNominalThrust;
-
-			Tools.PostDebugMessage(typeof(VOID_Data), "calculating stageMassFlow from:\n" +
-				"\tstageIsp: {0}\n" +
-				"\tstageThrust: {1}\n" +
-				"\tKerbinGee: {2}\n",
-				stageIsp,
-				stageThrust,
-				KerbinGee
-			);
-
-				return stageThrust / (stageIsp * KerbinGee);
-			},
-			"Mg/s"
-		);
-
-		public static readonly VOID_DoubleValue currManeuverDeltaV = new VOID_DoubleValue(
-			"Current Maneuver Delta-V",
-			delegate()
-			{
-				if (upcomingManeuverNodes > 0)
-				{
-				return core.vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude;
-				}
-				else
-				{
-					return double.NaN;
-				}
-			},
-			"m/s"
-		);
-
-		public static readonly VOID_DoubleValue currManeuverDVRemaining = new VOID_DoubleValue(
-			"Remaining Maneuver Delta-V",
-			delegate()
-			{
-				if (upcomingManeuverNodes > 0)
-				{
-					return core.vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(core.vessel.orbit).magnitude;
-				}
-				else
-				{
-					return double.NaN;
-				}
-			},
-			"m/s"
-		);
-
-		public static readonly VOID_DoubleValue nextManeuverDeltaV = new VOID_DoubleValue(
-			"Current Maneuver Delta-V",
-			delegate()
-		{
-			if (upcomingManeuverNodes > 1)
-			{
-				return core.vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude;
-			}
-			else
-			{
-				return double.NaN;
-			}
-		},
-			"m/s"
-		);
-
-		public static readonly VOID_DoubleValue currentNodeBurnDuration = new VOID_DoubleValue(
-			"Total Burn Time",
-			delegate()
-			{
-				if (core.LastStage == null || currManeuverDeltaV.Value == double.NaN)
-				{
-					return double.NaN;
-				}
-			    
-				double stageThrust = stageNominalThrust;
-
-				return burnTime(currManeuverDeltaV.Value, totalMass, stageMassFlow, stageThrust);
-			},
-			"s"
-		);
-
-		public static readonly VOID_DoubleValue currentNodeBurnRemaining = new VOID_DoubleValue(
-			"Burn Time Remaining",
-			delegate()
-			{
-				if (core.LastStage == null || currManeuverDVRemaining == double.NaN)
-				{
-					return double.NaN;
-				}
-
-				double stageThrust = stageNominalThrust;
-
-				return burnTime(currManeuverDVRemaining, totalMass, stageMassFlow, stageThrust);
-			},
-			"s"
-		);
-
-		public static readonly VOID_DoubleValue currentNodeHalfBurnDuration = new VOID_DoubleValue(
-			"Half Burn Time",
-			delegate()
-		{
-			if (core.LastStage == null || currManeuverDeltaV.Value == double.NaN)
-			{
-				return double.NaN;
-			}
-
-			double stageThrust = stageNominalThrust;
-
-			return burnTime(currManeuverDeltaV.Value / 2d, totalMass, stageMassFlow, stageThrust);
-		},
-			"s"
-		);
-
-		public static readonly VOID_StrValue burnTimeDoneAtNode = new VOID_StrValue(
-			"Full burn time to be half done at node",
-			delegate()
-		{
-			if (core.LastStage == null && upcomingManeuverNodes < 1)
-			{
-				return "N/A";
-			}
-
-			ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0];
-
-			if ((node.UT - Planetarium.GetUniversalTime()) < 0)
-			{
-				return string.Empty;
-			}
-
-			double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime();
-
-			if (double.IsNaN(interval))
-			{
-				return string.Intern("NaN");
-			}
-
-			int sign = Math.Sign(interval);
-			interval = Math.Abs(interval);
-
-			string format;
-
-			if (sign >= 0)
-			{
-				format = string.Intern("T - {0}");
-			}
-			else
-			{
-				format = string.Intern("T + {0}");
-			}
-
-			return string.Format(format, VOID_Tools.ConvertInterval(interval));
-		}
-		);
-
-		public static readonly VOID_StrValue burnTimeHalfDoneAtNode = new VOID_StrValue(
-			"Full burn time to be half done at node",
-			delegate()
-			{
-			if (core.LastStage == null && upcomingManeuverNodes < 1)
-			{
-				return "N/A";
-			}
-
-			ManeuverNode node = core.vessel.patchedConicSolver.maneuverNodes[0];
-
-			if ((node.UT - Planetarium.GetUniversalTime()) < 0)
-			{
-				return string.Empty;
-			}
-
-			double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime();
-
-			if (double.IsNaN(interval))
-			{
-				return string.Intern("NaN");
-			}
-
-			int sign = Math.Sign(interval);
-			interval = Math.Abs(interval);
-
-			string format;
-
-			if (sign >= 0)
-			{
-				format = string.Intern("T - {0}");
-			}
-			else
-			{
-				format = string.Intern("T + {0}");
-			}
-
-			return string.Format(format, VOID_Tools.ConvertInterval(interval));
-			}
-		);
-
-		private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust)
-		{
-			Tools.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" +
-				"\tdeltaV: {0}\n" +
-				"\tinitialMass: {1}\n" +
-				"\tmassFlow: {2}\n" +
-				"\tthrust: {3}\n",
-				deltaV,
-				initialMass,
-				massFlow,
-				thrust
-			);
-			return initialMass / massFlow * (Math.Exp(deltaV * massFlow / thrust) - 1d);
-		}
-	}
 }
 

file:b/VOID_HUDModule.cs (new)
--- /dev/null
+++ b/VOID_HUDModule.cs
@@ -1,1 +1,167 @@
+// VOID
+//
+// VOID_HUDModule.cs
+//
+// Copyright © 2014, toadicus
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+//    this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be used
+//    to endorse or promote products derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+using KerbalEngineer.VesselSimulator;
+using KSP;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ToadicusTools;
+using UnityEngine;
+
+namespace VOID
+{
+	public abstract class VOID_HUDModule : VOID_Module
+	{
+		[AVOID_SaveValue("colorIndex")]
+		protected VOID_SaveValue<int> _colorIndex;
+
+		protected List<Color> textColors;
+
+		[AVOID_SaveValue("positionsLocked")]
+		protected VOID_SaveValue<bool> positionsLocked;
+
+		public virtual int ColorIndex
+		{
+			get
+			{
+				return this._colorIndex;
+			}
+			set
+			{
+				if (this._colorIndex >= this.textColors.Count - 1)
+				{
+					this._colorIndex = 0;
+					return;
+				}
+
+				this._colorIndex = value;
+			}
+		}
+
+		public virtual List<HUDWindow> Windows
+		{
+			get;
+			protected set;
+		}
+
+		public VOID_HUDModule() : base()
+		{
+			this._colorIndex = 0;
+
+			this.textColors = new List<Color>();
+
+			this.textColors.Add(Color.green);
+			this.textColors.Add(Color.black);
+			this.textColors.Add(Color.white);
+			this.textColors.Add(Color.red);
+			this.textColors.Add(Color.blue);
+			this.textColors.Add(Color.yellow);
+			this.textColors.Add(Color.gray);
+			this.textColors.Add(Color.cyan);
+			this.textColors.Add(Color.magenta);
+
+			this.positionsLocked = true;
+
+			this.Windows = new List<HUDWindow>();
+		}
+
+		public override void DrawGUI()
+		{
+			VOID_Styles.labelHud.normal.textColor = textColors [ColorIndex];
+
+			GUI.skin = this.core.Skin;
+
+			if (HighLogic.LoadedSceneIsEditor ||
+				(TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)
+			)
+			{
+				SimManager.RequestSimulation();
+			}
+
+			foreach (HUDWindow window in this.Windows)
+			{
+				window.WindowPos = GUI.Window(
+					this.core.windowID,
+					window.WindowPos,
+					VOID_Tools.GetWindowHandler(window.WindowFunction),
+					GUIContent.none,
+					GUIStyle.none
+				);
+			}
+		}
+
+		public override void DrawConfigurables()
+		{
+			if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false)))
+			{
+				++this.ColorIndex;
+			}
+
+			if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false)))
+			{
+				foreach (HUDWindow window in this.Windows)
+				{
+					window.WindowPos = new Rect(window.defaultWindowPos);
+				}
+			}
+
+			this.positionsLocked = GUILayout.Toggle(this.positionsLocked,
+				string.Intern("Lock HUD Positions"),
+				GUILayout.ExpandWidth(false));
+		}
+	}
+
+	public class HUDWindow
+	{
+		public readonly Rect defaultWindowPos;
+
+		public Action<int> WindowFunction
+		{
+			get;
+			private set;
+		}
+
+		public Rect WindowPos
+		{
+			get;
+			set;
+		}
+
+		private HUDWindow() {}
+
+		public HUDWindow(Action<int> windowFunc, Rect defaultPos)
+		{
+			this.WindowFunction = windowFunc;
+			this.defaultWindowPos = defaultPos;
+			this.WindowPos = new Rect(this.defaultWindowPos);
+		}
+	}
+}
+
+

--- a/VOID_Module.cs
+++ b/VOID_Module.cs
@@ -219,10 +219,14 @@
 		protected float defWidth;
 		protected float defHeight;
 
+		protected string inputLockName;
+
 		public VOID_WindowModule() : base()
 		{
 			this.defWidth = 250f;
 			this.defHeight = 50f;
+
+			this.inputLockName = string.Concat(this.Name, "_edlock");
 
 			this.WindowPos = new Rect(Screen.width / 2, Screen.height / 2, this.defWidth, this.defHeight);
 		}
@@ -244,7 +248,55 @@
 				GUILayout.Height(this.defHeight)
 			);
 
-			_Pos = Tools.ClampRectToScreen (_Pos);
+			bool cursorInWindow = _Pos.Contains(Mouse.screenPos);
+
+			switch (HighLogic.LoadedScene)
+			{
+				case GameScenes.EDITOR:
+					if (cursorInWindow)
+					{
+						InputLockManager.SetControlLock(
+							ControlTypes.EDITOR_ICON_HOVER | ControlTypes.EDITOR_ICON_PICK |
+							ControlTypes.EDITOR_PAD_PICK_COPY | ControlTypes.EDITOR_PAD_PICK_COPY,
+							this.inputLockName
+						);
+						EditorLogic.fetch.Lock(false, false, false, this.inputLockName);
+					}
+					else
+					{
+						EditorLogic.fetch.Unlock(this.inputLockName);
+					}
+					break;
+				case GameScenes.FLIGHT:
+					if (cursorInWindow)
+					{
+						InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS, this.inputLockName);
+					}
+					else if (InputLockManager.GetControlLock(this.inputLockName) != ControlTypes.None)
+					{
+						InputLockManager.RemoveControlLock(this.inputLockName);
+					}
+					break;
+				case GameScenes.SPACECENTER:
+					if (cursorInWindow)
+					{
+						InputLockManager.SetControlLock(ControlTypes.KSC_FACILITIES, this.inputLockName);
+					}
+					else if (InputLockManager.GetControlLock(this.inputLockName) != ControlTypes.None)
+					{
+						InputLockManager.RemoveControlLock(this.inputLockName);
+					}
+					break;
+			}
+
+			if (HighLogic.LoadedSceneIsEditor)
+			{
+				_Pos = Tools.ClampRectToEditorPad(_Pos);
+			}
+			else
+			{
+				_Pos = Tools.ClampRectToScreen(_Pos);
+			}
 
 			if (_Pos != this.WindowPos)
 			{

--- a/VOID_Orbital.cs
+++ b/VOID_Orbital.cs
@@ -121,128 +121,6 @@
 			base._SaveToConfig (config);
 		}
 	}
-
-
-	public static partial class VOID_Data
-	{
-		public static readonly VOID_StrValue primaryName = new VOID_StrValue (
-			VOID_Localization.void_primary,
-			delegate()
-		{
-			if (core.vessel == null)
-			{
-				return string.Empty;
-			}
-			return core.vessel.mainBody.name;
-		}
-		);
-
-		public static readonly VOID_DoubleValue orbitAltitude = new VOID_DoubleValue (
-			"Altitude (ASL)",
-			new Func<double> (() => core.vessel.orbit.altitude),
-			"m"
-		);
-
-		public static readonly VOID_DoubleValue orbitVelocity = new VOID_DoubleValue (
-			VOID_Localization.void_velocity,
-			new Func<double> (() => core.vessel.orbit.vel.magnitude),
-			"m/s"
-		);
-
-		public static readonly VOID_DoubleValue orbitApoAlt = new VOID_DoubleValue(
-			VOID_Localization.void_apoapsis,
-			new Func<double>(() => core.vessel.orbit.ApA),
-			"m"
-		);
-
-		public static readonly VOID_DoubleValue oribtPeriAlt = new VOID_DoubleValue(
-			VOID_Localization.void_periapsis,
-			new Func<double>(() => core.vessel.orbit.PeA),
-			"m"
-		);
-
-		public static readonly VOID_StrValue timeToApo = new VOID_StrValue(
-			"Time to Apoapsis",
-			new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.timeToAp))
-		);
-
-		public static readonly VOID_StrValue timeToPeri = new VOID_StrValue(
-			"Time to Periapsis",
-			new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.timeToPe))
-		);
-
-		public static readonly VOID_DoubleValue orbitInclination = new VOID_DoubleValue(
-			"Inclination",
-			new Func<double>(() => core.vessel.orbit.inclination),
-			"°"
-		);
-
-		public static readonly VOID_DoubleValue gravityAccel = new VOID_DoubleValue(
-			"Gravity",
-			delegate()
-		{
-			double orbitRadius = core.vessel.mainBody.Radius +
-				core.vessel.mainBody.GetAltitude(core.vessel.findWorldCenterOfMass());
-			return (VOID_Core.Constant_G * core.vessel.mainBody.Mass) /
-				(orbitRadius * orbitRadius);
-		},
-			"m/s²"
-		);
-
-		public static readonly VOID_StrValue orbitPeriod = new VOID_StrValue(
-			"Period",
-			new Func<string>(() => VOID_Tools.ConvertInterval(core.vessel.orbit.period))
-		);
-
-		public static readonly VOID_DoubleValue semiMajorAxis = new VOID_DoubleValue(
-			"Semi-Major Axis",
-			new Func<double>(() => core.vessel.orbit.semiMajorAxis),
-			"m"
-		);
-
-		public static readonly VOID_DoubleValue eccentricity = new VOID_DoubleValue(
-			"Eccentricity",
-			new Func<double>(() => core.vessel.orbit.eccentricity),
-			""
-		);
-
-		public static readonly VOID_DoubleValue meanAnomaly = new VOID_DoubleValue(
-			"Mean Anomaly",
-			new Func<double>(() => core.vessel.orbit.meanAnomaly * 180d / Math.PI),
-			"°"
-		);
-
-		public static readonly VOID_DoubleValue trueAnomaly = new VOID_DoubleValue(
-			"True Anomaly",
-			new Func<double>(() => core.vessel.orbit.trueAnomaly),
-			"°"
-		);
-
-		public static readonly VOID_DoubleValue eccAnomaly = new VOID_DoubleValue(
-			"Eccentric Anomaly",
-			new Func<double>(() => core.vessel.orbit.eccentricAnomaly * 180d / Math.PI),
-			"°"
-		);
-
-		public static readonly VOID_DoubleValue longitudeAscNode = new VOID_DoubleValue(
-			"Long. Ascending Node",
-			new Func<double>(() => core.vessel.orbit.LAN),
-			"°"
-		);
-
-		public static readonly VOID_DoubleValue argumentPeriapsis = new VOID_DoubleValue(
-			"Argument of Periapsis",
-			new Func<double>(() => core.vessel.orbit.argumentOfPeriapsis),
-			"°"
-		);
-
-		public static readonly VOID_DoubleValue localSiderealLongitude = new VOID_DoubleValue(
-			"Local Sidereal Longitude",
-			new Func<double>(() => VOID_Tools.FixDegreeDomain(
-				core.vessel.longitude + core.vessel.orbit.referenceBody.rotationAngle)),
-			"°"
-		);
-	}
 }
 
 

--- a/VOID_Rendezvous.cs
+++ b/VOID_Rendezvous.cs
@@ -67,7 +67,7 @@
 
 			//display both
 			//Show Target Info
-			GUILayout.Label("Target:", this.core.LabelStyles["center_bold"]);
+			GUILayout.Label("Target:", VOID_Styles.labelCenterBold);
 			if (FlightGlobals.fetch.VesselTarget != null)
 			{
 				//a KSP Target (body or vessel) is selected
@@ -94,13 +94,13 @@
 			else
 			{
 				//no KSP Target selected
-				GUILayout.Label("No Target Selected", this.core.LabelStyles["center_bold"]);
+				GUILayout.Label("No Target Selected", VOID_Styles.labelCenterBold);
 			}
 
 			//Show Vessel Register vessel info
 			if (untoggleRegisterInfo == false && this.RegisterModule != default(IVOID_Module))
 			{
-				GUILayout.Label("Vessel Register:", this.core.LabelStyles["center_bold"]);
+				GUILayout.Label("Vessel Register:", VOID_Styles.labelCenterBold);
 				if (this.RegisterModule.selectedVessel != null)
 				{
 					rendezvessel = this.RegisterModule.selectedVessel;
@@ -122,7 +122,7 @@
 				{
 					//vesreg Vessel is null
 					//targ = null;
-					GUILayout.Label("No Vessel Selected", this.core.LabelStyles["center_bold"]);
+					GUILayout.Label("No Vessel Selected", VOID_Styles.labelCenterBold);
 				}
 			}
 
@@ -143,7 +143,7 @@
 			{
 				//Display vessel rendezvous info
 				GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-				GUILayout.Label(v.vesselName, this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true));
+				GUILayout.Label(v.vesselName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
 				GUILayout.EndHorizontal();
 
 				if (v.situation == Vessel.Situations.ESCAPING || v.situation == Vessel.Situations.FLYING || v.situation == Vessel.Situations.ORBITING || v.situation == Vessel.Situations.SUB_ORBITAL)
@@ -196,7 +196,7 @@
 					// Toadicus edit: added local sidereal longitude.
 					GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 					GUILayout.Label("Local Sidereal Longitude:");
-					GUILayout.Label(LSL.ToString("F3") + "°", this.core.LabelStyles["right"]);
+					GUILayout.Label(LSL.ToString("F3") + "°", VOID_Styles.labelRight);
 					GUILayout.EndHorizontal();
 
 					toggleExtendedOrbital.value = GUILayout.Toggle(toggleExtendedOrbital, "Extended info");
@@ -205,7 +205,7 @@
 					{
 						GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 						GUILayout.Label("Period:");
-						GUILayout.Label(VOID_Tools.ConvertInterval(v.orbit.period), GUILayout.ExpandWidth(false));
+						GUILayout.Label(VOID_Tools.FormatInterval(v.orbit.period), GUILayout.ExpandWidth(false));
 						GUILayout.EndHorizontal();
 
 						GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
@@ -267,7 +267,7 @@
 			else if (cb != null && v == null)
 			{
 				//Display CelstialBody rendezvous info
-				GUILayout.Label(cb.bodyName, this.core.LabelStyles["center_bold"]);
+				GUILayout.Label(cb.bodyName, VOID_Styles.labelCenterBold);
 
 				GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 				GUILayout.Label("Ap/Pe:");

file:b/VOID_StageInfo.cs (new)
--- /dev/null
+++ b/VOID_StageInfo.cs
@@ -1,1 +1,218 @@
-
+// VOID © 2014 toadicus
+//
+// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a
+// copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
+
+using KerbalEngineer.VesselSimulator;
+using KSP;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using ToadicusTools;
+using UnityEngine;
+
+namespace VOID
+{
+	public class VOID_StageInfo : VOID_WindowModule
+	{
+		private Table stageTable;
+
+		private Table.Column<int> stageNumberCol;
+		private Table.Column<double> stageDeltaVCol;
+		private Table.Column<double> stageTotalDVCol;
+		private Table.Column<double> stageInvertDVCol;
+		private Table.Column<double> stageMassCol;
+		private Table.Column<double> stageTotalMassCol;
+		private Table.Column<double> stageThrustCol;
+		private Table.Column<double> stageTWRCol;
+
+		private bool stylesApplied;
+		private bool showBodyList;
+
+		private Rect bodyListPos;
+
+		private CelestialBody selectedBody;
+		[AVOID_SaveValue("bodyIdx")]
+		private VOID_SaveValue<int> bodyIdx;
+		private int lastIdx;
+
+		public VOID_StageInfo() : base()
+		{
+			this._Name = "Stage Information";
+			this.defWidth = 200f;
+			this.bodyIdx = 4;
+
+			this.stylesApplied = false;
+			this.showBodyList = false;
+
+			this.bodyListPos = new Rect();
+
+			this.stageTable = new Table();
+
+			this.stageNumberCol = new Table.Column<int>("Stage", 40f);
+			this.stageTable.Add(this.stageNumberCol);
+
+			this.stageDeltaVCol = new Table.Column<double>("DeltaV [m/s]", 60f);
+			this.stageDeltaVCol.Format = "S2";
+			this.stageTable.Add(this.stageDeltaVCol);
+
+			this.stageTotalDVCol = new Table.Column<double>("Total ΔV [m/s]", 60f);
+			this.stageTotalDVCol.Format = "S2";
+			this.stageTable.Add(this.stageTotalDVCol);
+
+			this.stageInvertDVCol = new Table.Column<double>("Invert ΔV [m/s]", 60f);
+			this.stageInvertDVCol.Format = "S2";
+			this.stageTable.Add(this.stageInvertDVCol);
+
+			this.stageMassCol = new Table.Column<double>("Mass [Mg]", 60f);
+			this.stageMassCol.Format = "#.#";
+			this.stageTable.Add(this.stageMassCol);
+
+			this.stageTotalMassCol = new Table.Column<double>("Total [Mg]", 60f);
+			this.stageTotalMassCol.Format = "#.#";
+			this.stageTable.Add(this.stageTotalMassCol);
+
+			this.stageThrustCol = new Table.Column<double>("Thrust [N]", 60f);
+			this.stageThrustCol.Format = "S2";
+			this.stageTable.Add(this.stageThrustCol);
+
+			this.stageTWRCol = new Table.Column<double>("T/W Ratio", 60f);
+			this.stageTWRCol.Format = "#.#";
+			this.stageTable.Add(this.stageTWRCol);
+		}
+
+		public override void DrawGUI()
+		{
+			base.DrawGUI();
+
+			if (this.showBodyList)
+			{
+				GUILayout.Window(core.windowID, this.bodyListPos, this.BodyPickerWindow, string.Empty);
+			}
+		}
+
+		public override void ModuleWindow(int _)
+		{
+			if (
+				HighLogic.LoadedSceneIsEditor ||
+				(TimeWarp.WarpMode == TimeWarp.Modes.LOW) ||
+				(TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)
+			)
+			{
+				KerbalEngineer.VesselSimulator.SimManager.RequestSimulation();
+			}
+
+			if (!this.stylesApplied)
+			{
+				this.stageTable.ApplyCellStyle(VOID_Styles.labelCenter);
+				this.stageTable.ApplyHeaderStyle(VOID_Styles.labelCenterBold);
+			}
+
+			this.stageTable.ClearColumns();
+
+			if (core.Stages == null || core.Stages.Length == 0)
+			{
+				GUILayout.BeginVertical();
+
+				GUILayout.Label("No stage data!");
+
+				GUILayout.EndVertical();
+
+				return;
+			}
+
+			foreach (Stage stage in core.Stages)
+			{
+				if (stage.deltaV == 0 && stage.mass == 0)
+				{
+					continue;
+				}
+
+				this.stageNumberCol.Add(stage.number);
+
+				this.stageDeltaVCol.Add(stage.deltaV);
+				this.stageTotalDVCol.Add(stage.totalDeltaV);
+				this.stageInvertDVCol.Add(stage.inverseTotalDeltaV);
+
+				this.stageMassCol.Add(stage.mass);
+				this.stageTotalMassCol.Add(stage.totalMass);      
+
+				this.stageThrustCol.Add(stage.thrust * 1000f);
+				this.stageTWRCol.Add(stage.thrustToWeight / (this.selectedBody ?? core.HomeBody).GeeASL);
+			}
+
+			this.stageTable.Render();
+
+			if (core.sortedBodyList != null)
+			{
+				GUILayout.BeginHorizontal();
+
+				if (GUILayout.Button("◄"))
+				{
+					this.bodyIdx--;
+				}
+
+				this.showBodyList = GUILayout.Toggle(this.showBodyList, (this.selectedBody ?? core.HomeBody).bodyName, GUI.skin.button);
+				Rect bodyButtonPos = GUILayoutUtility.GetLastRect();
+
+				if (Event.current.type == EventType.Repaint)
+				{
+					this.bodyListPos.width = bodyButtonPos.width;
+					this.bodyListPos.x = bodyButtonPos.xMin + this.WindowPos.xMin;
+					this.bodyListPos.y = bodyButtonPos.yMax + this.WindowPos.yMin;
+				}
+
+				if (GUILayout.Button("►"))
+				{
+					this.bodyIdx++;
+				}
+
+				this.bodyIdx %= core.sortedBodyList.Count;
+
+				if (this.bodyIdx < 0)
+				{
+					this.bodyIdx += core.sortedBodyList.Count;
+				}
+
+				if (this.lastIdx != this.bodyIdx)
+				{
+					this.lastIdx = this.bodyIdx;
+					this.selectedBody = core.sortedBodyList[this.bodyIdx];
+				}
+
+				GUILayout.EndHorizontal();
+			}
+
+			GUILayout.BeginHorizontal();
+
+			if (
+				GUILayout.Button("Engineering data powered by <i>VesselSimulator from KER</i>.",
+					VOID_Styles.labelLink)
+			)
+			{
+				Application.OpenURL("http://forum.kerbalspaceprogram.com/threads/18230");
+			}
+
+			GUILayout.EndHorizontal();
+
+			GUI.DragWindow();
+		}
+
+		private void BodyPickerWindow(int _)
+		{
+			foreach (CelestialBody body in core.sortedBodyList)
+			{
+				if (GUILayout.Button(body.bodyName, VOID_Styles.labelDefault))
+				{
+					Debug.Log("Picked new body focus: " + body.bodyName);
+					this.bodyIdx = core.sortedBodyList.IndexOf(body);
+					this.showBodyList = false;
+				}
+			}
+		}
+	}
+
+	public class VOID_StageInfoEditor : VOID_StageInfo, IVOID_EditorModule {}
+}
+
+

file:b/VOID_Styles.cs (new)
--- /dev/null
+++ b/VOID_Styles.cs
@@ -1,1 +1,129 @@
+// VOID
+//
+// cs
+//
+// Copyright © 2014, toadicus
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+//    this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be used
+//    to endorse or promote products derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+using System;
+using UnityEngine;
+
+namespace VOID
+{
+	public static class VOID_Styles
+	{
+		public static bool Ready
+		{
+			get;
+			private set;
+		}
+
+		public static GUIStyle labelDefault
+		{
+			get;
+			private set;
+		}
+
+		public static GUIStyle labelLink
+		{
+			get;
+			private set;
+		}
+
+		public static GUIStyle labelCenter
+		{
+			get;
+			private set;
+		}
+
+		public static GUIStyle labelCenterBold
+		{
+			get;
+			private set;
+		}
+
+		public static GUIStyle labelGreen
+		{
+			get;
+			private set;
+		}
+
+		public static GUIStyle labelHud
+		{
+			get;
+			private set;
+		}
+
+		public static GUIStyle labelRight
+		{
+			get;
+			private set;
+		}
+
+		public static GUIStyle labelRed
+		{
+			get;
+			private set;
+		}
+
+		public static void OnSkinChanged()
+		{
+			labelDefault = new GUIStyle(GUI.skin.label);
+
+			labelLink = new GUIStyle(GUI.skin.label);
+			labelLink.fontStyle = FontStyle.Italic;
+			labelLink.fontSize = (int)((float)labelLink.fontSize * .8f);
+
+			labelCenter = new GUIStyle(GUI.skin.label);
+			labelCenter.normal.textColor = Color.white;
+			labelCenter.alignment = TextAnchor.UpperCenter;
+
+			labelCenterBold = new GUIStyle(GUI.skin.label);
+			labelCenterBold.normal.textColor = Color.white;
+			labelCenterBold.alignment = TextAnchor.UpperCenter;
+			labelCenterBold.fontStyle = FontStyle.Bold;
+
+			labelHud = new GUIStyle(labelDefault);
+
+			labelRight = new GUIStyle(GUI.skin.label);
+			labelRight.normal.textColor = Color.white;
+			labelRight.alignment = TextAnchor.UpperRight;
+
+			labelRed = new GUIStyle(GUI.skin.label);
+			labelRed.normal.textColor = Color.red;
+
+			labelGreen = new GUIStyle(GUI.skin.label);
+			labelGreen.normal.textColor = Color.green;
+
+			Ready = true;
+		}
+
+		static VOID_Styles()
+		{
+			Ready = false;
+		}
+	}
+}
+
+

--- a/VOID_SurfAtmo.cs
+++ b/VOID_SurfAtmo.cs
@@ -65,6 +65,9 @@
 			this.precisionValues [idx]= (ushort)VOID_Data.terrainElevation.DoGUIHorizontal (this.precisionValues [idx]);
 			idx++;
 
+			this.precisionValues[idx] = (ushort)VOID_Data.downrangeDistance.DoGUIHorizontal(this.precisionValues[idx]);
+			idx++;
+
 			this.precisionValues [idx]= (ushort)VOID_Data.surfVelocity.DoGUIHorizontal (this.precisionValues [idx]);
 			idx++;
 
@@ -76,7 +79,8 @@
 
 			VOID_Data.temperature.DoGUIHorizontal ("F2");
 
-			VOID_Data.atmDensity.DoGUIHorizontal (3);
+			this.precisionValues [idx]= (ushort)VOID_Data.atmDensity.DoGUIHorizontal (this.precisionValues [idx]);
+			idx++;
 
 			VOID_Data.atmPressure.DoGUIHorizontal ("F2");
 
@@ -104,100 +108,4 @@
 			base._SaveToConfig (config);
 		}
 	}
-
-	public static partial class VOID_Data
-	{
-		public static readonly VOID_DoubleValue trueAltitude = new VOID_DoubleValue(
-			"Altitude (true)",
-			delegate()
-			{
-				double alt_true = core.vessel.orbit.altitude - core.vessel.terrainAltitude;
-				// HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,
-				// and water covers the whole surface at 0 m.
-				if (core.vessel.terrainAltitude < 0 && core.vessel.mainBody.ocean )
-					alt_true = core.vessel.orbit.altitude;
-				return alt_true;
-			},
-			"m"
-		);
-
-		public static readonly VOID_StrValue surfLatitude = new VOID_StrValue(
-			"Latitude",
-			new Func<string> (() => VOID_Tools.GetLatitudeString(core.vessel))
-		);
-
-		public static readonly VOID_StrValue surfLongitude = new VOID_StrValue(
-			"Longitude",
-			new Func<string> (() => VOID_Tools.GetLongitudeString(core.vessel))
-		);
-
-		public static readonly VOID_StrValue vesselHeading = new VOID_StrValue(
-			"Heading",
-			delegate()
-		{
-			double heading = core.vessel.getSurfaceHeading();
-			string cardinal = VOID_Tools.get_heading_text(heading);
-
-			return string.Format(
-				"{0}° {1}",
-				heading.ToString("F2"),
-				cardinal
-			);
-		}
-		);
-
-		public static readonly VOID_DoubleValue terrainElevation = new VOID_DoubleValue(
-			"Terrain elevation",
-			new Func<double> (() => core.vessel.terrainAltitude),
-			"m"
-		);
-
-		public static readonly VOID_DoubleValue surfVelocity = new VOID_DoubleValue(
-			"Surface velocity",
-			new Func<double> (() => core.vessel.srf_velocity.magnitude),
-			"m/s"
-		);
-
-		public static readonly VOID_DoubleValue vertVelocity = new VOID_DoubleValue(
-			"Vertical speed",
-			new Func<double> (() => core.vessel.verticalSpeed),
-			"m/s"
-		);
-
-		public static readonly VOID_DoubleValue horzVelocity = new VOID_DoubleValue(
-			"Horizontal speed",
-			new Func<double> (() => core.vessel.horizontalSrfSpeed),
-			"m/s"
-		);
-
-		public static readonly VOID_FloatValue temperature = new VOID_FloatValue(
-			"Temperature",
-			new Func<float> (() => core.vessel.flightIntegrator.getExternalTemperature()),
-			"°C"
-		);
-
-		public static readonly VOID_DoubleValue atmDensity = new VOID_DoubleValue (
-			"Atmosphere Density",
-			new Func<double> (() => core.vessel.atmDensity * 1000f),
-			"g/m³"
-		);
-
-		public static readonly VOID_DoubleValue atmPressure = new VOID_DoubleValue (
-			"Pressure",
-			new Func<double> (() => core.vessel.staticPressure),
-			"atm"
-		);
-
-		public static readonly VOID_FloatValue atmLimit = new VOID_FloatValue(
-			"Atmosphere Limit",
-			new Func<float> (() => core.vessel.mainBody.maxAtmosphereAltitude),
-			"m"
-		);
-
-		public static readonly VOID_StrValue currBiome = new VOID_StrValue(
-			"Biome",
-			new Func<string> (() => VOID_Tools.GetBiome(core.vessel).name)
-		);
-
-	}
 }

--- a/VOID_TWR.cs
+++ b/VOID_TWR.cs
@@ -14,8 +14,6 @@
 {
 	public class VOID_TWR : VOID_WindowModule
 	{
-		private List<CelestialBody> sortedBodyList;
-
 		public VOID_TWR() : base()
 		{
 			this._Name = "IP Thrust-to-Weight Ratios";
@@ -29,31 +27,22 @@
 				(TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)
 			)
 			{
-				Engineer.VesselSimulator.SimManager.RequestSimulation();
+				KerbalEngineer.VesselSimulator.SimManager.RequestSimulation();
 			}
 
 			GUILayout.BeginVertical();
 
-			if (this.sortedBodyList == null)
+			if (core.sortedBodyList == null)
 			{
-				if (FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
-				{
-					this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
-					this.sortedBodyList.Sort(new CBListComparer());
-					this.sortedBodyList.Reverse();
+				GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 
-					Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray())));
-				}
-				else
-				{
-					GUILayout.BeginHorizontal();
-					GUILayout.Label("Unavailable.");
-					GUILayout.EndHorizontal();
-				}
+				GUILayout.Label("Unavailable");
+
+				GUILayout.EndHorizontal();
 			}
 			else
 			{
-				foreach (CelestialBody body in this.sortedBodyList)
+				foreach (CelestialBody body in core.sortedBodyList)
 				{
 					GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 
@@ -75,23 +64,6 @@
 	}
 
 	public class VOID_EditorTWR : VOID_TWR, IVOID_EditorModule {}
-
-	public static partial class VOID_Data
-	{
-		public static readonly VOID_DoubleValue nominalThrustWeight = new VOID_DoubleValue(
-			"Thrust-to-Weight Ratio",
-			delegate()
-		{
-			if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d)
-			{
-				return maxThrustWeight.Value;
-			}
-
-			return currThrustWeight.Value;
-		},
-			""
-		);
-	}
 }
 
 

--- a/VOID_Tools.cs
+++ b/VOID_Tools.cs
@@ -95,13 +95,13 @@
 		#endregion
 
 		#region VESSEL_EXTENSIONS_SCIENCE
-		public static CBAttributeMap.MapAttribute GetBiome(this Vessel vessel)
-		{
-			CBAttributeMap.MapAttribute mapAttribute;
+		public static CBAttributeMapSO.MapAttribute GetBiome(this Vessel vessel)
+		{
+			CBAttributeMapSO.MapAttribute mapAttribute;
 
 			try
 			{
-				CBAttributeMap BiomeMap = vessel.mainBody.BiomeMap;
+				CBAttributeMapSO BiomeMap = vessel.mainBody.BiomeMap;
 
 				double lat = vessel.latitude * Math.PI / 180d;
 				double lon = vessel.longitude * Math.PI / 180d;
@@ -162,7 +162,7 @@
 			}
 			catch (NullReferenceException)
 			{
-				mapAttribute = new CBAttributeMap.MapAttribute();
+				mapAttribute = new CBAttributeMapSO.MapAttribute();
 				mapAttribute.name = "N/A";
 			}
 
@@ -335,7 +335,7 @@
 						func(id);
 					}
 					#if DEBUG
-					catch (ArgumentException ex)
+					catch (ArgumentException)
 					#else
 					catch (ArgumentException)
 					#endif
@@ -366,78 +366,171 @@
 		}
 
 		/// <summary>
-		/// Converts the interval given in seconds to a human-friendly
-		/// time period in [years], [days], hours, minutes, and seconds.
+		/// Formats the interval given in seconds as a human-friendly
+		/// time period in [[[[years, ]days, ]hours, ]minutes, and ]seconds.
 		/// 
 		/// Uses sidereal days, since "6 hours per day" is the Kerbal standard.
 		/// </summary>
 		/// <returns>Human readable interval</returns>
 		/// <param name="seconds"></param>
-		public static string ConvertInterval(double seconds)
-		{
-			double SecondsPerMinute = 60d;
-			double SecondsPerHour = 3600d;
-			double SecondsPerDay;
-			double SecondsPerYear;
-
-			if (GameSettings.KERBIN_TIME)
-			{
-				SecondsPerDay = 21600d;
-				SecondsPerYear = 9203545d;
-			}
-			else
-			{
-				SecondsPerDay = 86164.1d;
-				SecondsPerYear = 31558149d;
-			}
-
-			int years;
-			int days;
-			int hours;
-			int minutes;
-
-			years = (int)(seconds / SecondsPerYear);
-
-			seconds %= SecondsPerYear;
-
-			days = (int)(seconds / SecondsPerDay);
-
-			seconds %= SecondsPerDay;
-
-			hours = (int)(seconds / SecondsPerHour);
-
-			seconds %= SecondsPerHour;
-
-			minutes = (int)(seconds / SecondsPerMinute);
-
-			seconds %= SecondsPerMinute;
-
-			string format_1 = string.Intern("{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:00.0}s");
-			string format_2 = string.Intern("{0:D1}d {1:D2}h {2:D2}m {3:00.0}s");
-			string format_3 = string.Intern("{0:D2}h {1:D2}m {2:00.0}s");
-			string format_4 = string.Intern("{0:D2}m {1:00.0}s");
-			string format_5 = string.Intern("{0:00.0}s");
-
-			if (years > 0)
-			{
-				return string.Format(format_1, years, days, hours, minutes, seconds);
-			}
-			else if (days > 0)
-			{
-				return string.Format(format_2, days, hours, minutes, seconds);
-			}
-			else if (hours > 0)
-			{
-				return string.Format(format_3, hours, minutes, seconds);
-			}
-			else if (minutes > 0)
-			{
-				return string.Format(format_4, minutes, seconds);
-			}
-			else
-			{
-				return string.Format(format_5, seconds);
-			}
+		public static string FormatInterval(double seconds)
+		{
+			return UnpackedTime.FromSeconds(seconds).FormatAsSpan();
+		}
+
+		/// <summary>
+		/// Formats the date given in seconds since epoch as a human-friendly
+		/// date in the format YY, DD, HH:MM:SS
+		/// </summary>
+		/// <returns>The date.</returns>
+		/// <param name="seconds">Seconds.</param>
+		public static string FormatDate(double seconds)
+		{
+			return UnpackedTime.FromSeconds(seconds).FormatAsDate();
+		}
+
+		public class UnpackedTime
+		{
+			public const double SecondsPerMinute = 60d;
+			public const double SecondsPerHour = 3600d;
+
+			public static double SecondsPerDay
+			{
+				get
+				{
+					if (GameSettings.KERBIN_TIME)
+					{
+						return 21600d;
+					}
+					else
+					{
+						return 86164.1d;
+					}
+				}
+			}
+
+			public static double SecondsPerYear
+			{
+				get
+				{
+					if (GameSettings.KERBIN_TIME)
+					{
+						return 9203545d;
+					}
+					else
+					{
+						return 31558149d;
+					}
+				}
+			}
+
+			public static UnpackedTime FromSeconds(double seconds)
+			{
+				UnpackedTime time = new UnpackedTime();
+
+				time.years = (int)(seconds / SecondsPerYear);
+
+				seconds %= SecondsPerYear;
+
+				time.days = (int)(seconds / SecondsPerDay);
+
+				seconds %= SecondsPerDay;
+
+				time.hours = (int)(seconds / SecondsPerHour);
+
+				seconds %= SecondsPerHour;
+
+				time.minutes = (int)(seconds / SecondsPerMinute);
+
+				seconds %= SecondsPerMinute;
+
+				time.seconds = seconds;
+
+				return time;
+			}
+
+			public static explicit operator UnpackedTime(double seconds)
+			{
+				return FromSeconds(seconds);
+			}
+
+			public static implicit operator double(UnpackedTime time)
+			{
+				return time.ToSeconds();
+			}
+
+			public static UnpackedTime operator+ (UnpackedTime lhs, UnpackedTime rhs)
+			{
+				return FromSeconds(lhs.ToSeconds() + rhs.ToSeconds());
+			}
+
+			public static UnpackedTime operator- (UnpackedTime lhs, UnpackedTime rhs)
+			{
+				return FromSeconds(lhs.ToSeconds() - rhs.ToSeconds());
+			}
+
+			public int years;
+			public int days;
+			public int hours;
+			public int minutes;
+			public double seconds;
+
+			public double ToSeconds()
+			{
+				return (double)years * SecondsPerYear +
+					(double)days * SecondsPerDay +
+					(double)hours * SecondsPerHour +
+					(double)minutes * SecondsPerMinute +
+					seconds;
+			}
+
+			public string FormatAsSpan()
+			{
+				string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:00.0}s";
+				string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:00.0}s";
+				string format_3 = "{0:D2}h {1:D2}m {2:00.0}s";
+				string format_4 = "{0:D2}m {1:00.0}s";
+				string format_5 = "{0:00.0}s";
+
+				if (this.years > 0)
+				{
+					return string.Format(format_1, this.years, this.days, this.hours, this.minutes, this.seconds);
+				}
+				else if (this.days > 0)
+				{
+					return string.Format(format_2, this.days, this.hours, this.minutes, this.seconds);
+				}
+				else if (this.hours > 0)
+				{
+					return string.Format(format_3, this.hours, this.minutes, this.seconds);
+				}
+				else if (this.minutes > 0)
+				{
+					return string.Format(format_4, this.minutes, this.seconds);
+				}
+				else
+				{
+					return string.Format(format_5, this.seconds);
+				}
+			}
+
+			public string FormatAsDate()
+			{
+				string format = "Y{0:D1}, D{1:D1} {2:D2}:{3:D2}:{4:00.0}s";
+
+				return string.Format(format, years, days, hours, minutes, seconds);
+			}
+
+			public UnpackedTime(int years, int days, int hours, int minutes, double seconds)
+			{
+				this.years = years;
+				this.days = days;
+				this.hours = hours;
+				this.minutes = minutes;
+				this.seconds = seconds;
+			}
+
+			public UnpackedTime() : this(0, 0, 0, 0, 0d) {}
 		}
 
 		public static string UppercaseFirst(string s)

--- a/VOID_VesselInfo.cs
+++ b/VOID_VesselInfo.cs
@@ -26,8 +26,8 @@
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-using Engineer.VesselSimulator;
-using Engineer.Extensions;
+using KerbalEngineer.VesselSimulator;
+using KerbalEngineer.Extensions;
 using KSP;
 using System;
 using System.Collections.Generic;
@@ -57,7 +57,7 @@
 
 			GUILayout.Label(
 				vessel.vesselName,
-				core.LabelStyles["center_bold"],
+				VOID_Styles.labelCenterBold,
 				GUILayout.ExpandWidth(true));
 
 			VOID_Data.geeForce.DoGUIHorizontal ("F2");
@@ -89,240 +89,5 @@
 			GUI.DragWindow();
 		}
 	}
-
-	public static partial class VOID_Data
-	{
-		public static readonly VOID_DoubleValue geeForce = new VOID_DoubleValue(
-			"G-force",
-			new Func<double>(() => core.vessel.geeForce),
-			"gees"
-		);
-
-		public static readonly VOID_IntValue partCount = new VOID_IntValue(
-			"Parts",
-			new Func<int>(() => core.vessel.Parts.Count),
-			""
-		);
-
-		public static readonly VOID_DoubleValue totalMass = new VOID_DoubleValue(
-			"Total Mass",
-			delegate()
-		{
-			if (core.Stages == null || core.LastStage == null)
-			{
-				return double.NaN;
-			}
-
-			return core.LastStage.totalMass;
-		},
-			"tons"
-		);
-
-		public static readonly VOID_DoubleValue resourceMass = new VOID_DoubleValue(
-			"Resource Mass",
-			delegate()
-			{
-				if (core.Stages == null || core.LastStage == null)
-				{
-					return double.NaN;
-				}
-
-				return core.LastStage.totalMass - core.LastStage.totalBaseMass;
-			},
-			"tons"
-		);
-
-		public static readonly VOID_DoubleValue stageResourceMass = new VOID_DoubleValue(
-			"Resource Mass (Stage)",
-			delegate()
-			{
-				if (core.LastStage == null)
-				{
-					return double.NaN;
-				}
-
-				return core.LastStage.mass - core.LastStage.baseMass;
-			},
-			"tons"
-		);
-
-		public static readonly VOID_StrValue comboResourceMass = new VOID_StrValue(
-			"Resource Mass (curr / total)",
-			delegate()
-		{
-			return string.Format("{0} / {1}",
-				stageResourceMass.ValueUnitString("F3"),
-				resourceMass.ValueUnitString("F3")
-			);
-		}
-		);
-
-		public static readonly VOID_DoubleValue stageDeltaV = new VOID_DoubleValue(
-			"DeltaV (Current Stage)",
-			delegate()
-			{
-			if (core.Stages == null || core.LastStage == null)
-					return double.NaN;
-				return core.LastStage.deltaV;
-			},
-			"m/s"
-		);
-
-		public static readonly VOID_DoubleValue totalDeltaV = new VOID_DoubleValue(
-			"DeltaV (Total)",
-			delegate()
-			{
-			if (core.Stages == null || core.LastStage == null)
-					return double.NaN;
-				return core.LastStage.totalDeltaV;
-			},
-			"m/s"
-		);
-
-		public static readonly VOID_FloatValue mainThrottle = new VOID_FloatValue(
-			"Throttle",
-			new Func<float>(() => core.vessel.ctrlState.mainThrottle * 100f),
-			"%"
-		);
-
-		public static readonly VOID_StrValue currmaxThrust = new VOID_StrValue(
-			"Thrust (curr/max)",
-			delegate()
-			{
-				if (core.Stages == null || core.LastStage == null)
-					return "N/A";
-
-				double currThrust = core.LastStage.actualThrust;
-				double maxThrust = core.LastStage.thrust;
-
-				return string.Format(
-					"{0} / {1}",
-					currThrust.ToString("F1"),
-					maxThrust.ToString("F1")
-				);
-			}
-		);
-
-		public static readonly VOID_DoubleValue currThrustWeight = new VOID_DoubleValue(
-			"T:W Ratio",
-			delegate()
-		{
-			if (core.LastStage == null)
-			{
-				return double.NaN;
-			}
-
-			return core.LastStage.actualThrustToWeight;
-		},
-			""
-		);
-
-		public static readonly VOID_DoubleValue maxThrustWeight = new VOID_DoubleValue(
-			"T:W Ratio",
-			delegate()
-		{
-			if (core.LastStage == null)
-			{
-				return double.NaN;
-			}
-
-			return core.LastStage.thrustToWeight;
-		},
-			""
-		);
-
-		public static readonly VOID_StrValue currmaxThrustWeight = new VOID_StrValue(
-			"T:W (curr/max)",
-			delegate()
-			{
-				if (core.Stages == null || core.LastStage == null)
-					return "N/A";
-
-				return string.Format(
-					"{0} / {1}",
-					(VOID_Data.currThrustWeight.Value).ToString("F2"),
-					(VOID_Data.maxThrustWeight.Value).ToString("F2")
-				);
-			}
-		);
-
-		public static readonly VOID_DoubleValue surfaceThrustWeight = new VOID_DoubleValue(
-			"Max T:W @ surface",
-			delegate()
-			{
-			if (core.Stages == null || core.LastStage == null)
-					return double.NaN;
-
-				double maxThrust = core.LastStage.thrust;
-				double mass = core.LastStage.totalMass;
-				double gravity = (VOID_Core.Constant_G * core.vessel.mainBody.Mass) /
-				(core.vessel.mainBody.Radius * core.vessel.mainBody.Radius);
-				double weight = mass * gravity;
-
-				return maxThrust / weight;
-			},
-			""
-		);
-
-		public static readonly VOID_StrValue intakeAirStatus = new VOID_StrValue(
-			"Intake Air (Curr / Req)",
-			delegate()
-			{
-				double currentAmount;
-				double currentRequirement;
-
-				currentAmount = 0d;
-				currentRequirement = 0d;
-
-				foreach (Part part in core.vessel.Parts)
-				{
-					if (part.enabled)
-					{
-						ModuleEngines engineModule;
-						ModuleEnginesFX enginesFXModule;
-						List<Propellant> propellantList = null;
-
-						if (part.tryGetFirstModuleOfType<ModuleEngines>(out engineModule))
-						{
-							propellantList = engineModule.propellants;
-						}
-						else if (part.tryGetFirstModuleOfType<ModuleEnginesFX>(out enginesFXModule))
-						{
-							propellantList = enginesFXModule.propellants;
-						}
-							
-						if (propellantList != null)
-						{
-							foreach (Propellant propellant in propellantList)
-							{
-								if (propellant.name == "IntakeAir")
-								{
-									currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime;
-									break;
-								}
-							}
-						}
-					}
-
-					ModuleResourceIntake intakeModule;
-
-					if (part.enabled && part.tryGetFirstModuleOfType<ModuleResourceIntake>(out intakeModule))
-					{
-						if (intakeModule.resourceName == "IntakeAir")
-						{
-							currentAmount += intakeModule.airFlow;
-						}
-					}
-				}
-
-				if (currentAmount == 0 && currentRequirement == 0)
-				{
-					return "N/A";
-				}
-
-				return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement);
-			}
-		);
-	}
 }
 

--- a/VOID_VesselRegister.cs
+++ b/VOID_VesselRegister.cs
@@ -82,7 +82,7 @@
 				selectedBodyIdx--;
 				if (selectedBodyIdx < 0) selectedBodyIdx = this.core.allBodies.Count - 1;
 			}
-			GUILayout.Label(this.core.allBodies[selectedBodyIdx].bodyName, this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(this.core.allBodies[selectedBodyIdx].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
 			if (GUILayout.Button(">"))
 			{
 				selectedBodyIdx++;
@@ -98,7 +98,7 @@
 				selectedVesselTypeIdx--;
 				if (selectedVesselTypeIdx < 0) selectedVesselTypeIdx = this.core.allVesselTypes.Count - 1;
 			}
-			GUILayout.Label(this.core.allVesselTypes[selectedVesselTypeIdx].ToString(), this.core.LabelStyles["center_bold"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(this.core.allVesselTypes[selectedVesselTypeIdx].ToString(), VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
 			if (GUILayout.Button(">"))
 			{
 				selectedVesselTypeIdx++;
@@ -116,7 +116,7 @@
 			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 			GUILayout.Label(
 				VOID_Tools.UppercaseFirst(vesselSituation) + " " + selectedVesselType.ToString() + "s  @ " + seletedBody.bodyName,
-				this.core.LabelStyles["center"],
+				VOID_Styles.labelCenter,
 				GUILayout.ExpandWidth(true));
 			GUILayout.EndHorizontal();