Fixed crlf issue
Fixed crlf issue

--- a/KerbalEngineer.sln
+++ b/KerbalEngineer.sln
@@ -1,23 +1,23 @@
-

-Microsoft Visual Studio Solution File, Format Version 12.00

-# Visual Studio 2013

-VisualStudioVersion = 12.0.30110.0

-MinimumVisualStudioVersion = 10.0.40219.1

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerbalEngineer", "KerbalEngineer\KerbalEngineer.csproj", "{39806613-E0B7-46E0-89A6-A569EC538CBB}"

-EndProject

-Global

-	GlobalSection(SolutionConfigurationPlatforms) = preSolution

-		Debug|Any CPU = Debug|Any CPU

-		Release|Any CPU = Release|Any CPU

-	EndGlobalSection

-	GlobalSection(ProjectConfigurationPlatforms) = postSolution

-		{39806613-E0B7-46E0-89A6-A569EC538CBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{39806613-E0B7-46E0-89A6-A569EC538CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{39806613-E0B7-46E0-89A6-A569EC538CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{39806613-E0B7-46E0-89A6-A569EC538CBB}.Release|Any CPU.Build.0 = Release|Any CPU

-	EndGlobalSection

-	GlobalSection(SolutionProperties) = preSolution

-		HideSolutionNode = FALSE

-	EndGlobalSection

-EndGlobal

+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30110.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerbalEngineer", "KerbalEngineer\KerbalEngineer.csproj", "{39806613-E0B7-46E0-89A6-A569EC538CBB}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{39806613-E0B7-46E0-89A6-A569EC538CBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{39806613-E0B7-46E0-89A6-A569EC538CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{39806613-E0B7-46E0-89A6-A569EC538CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{39806613-E0B7-46E0-89A6-A569EC538CBB}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
 

--- a/KerbalEngineer/Extensions/OrbitExtensions.cs
+++ b/KerbalEngineer/Extensions/OrbitExtensions.cs
@@ -52,5 +52,28 @@
         {
             return GetTimeToTrueAnomaly(orbit, GetTrueAnomalyOfDescendingNode(orbit));
         }
+
+        public static double GetTrueAnomalyFromVector(this Orbit orbit, Vector3d vector)
+        {
+            var normal = SwappedOrbitNormal(orbit);
+            var projected = Vector3d.Exclude(normal, vector);
+
+            var vectorToAn = QuaternionD.AngleAxis(-orbit.LAN, Planetarium.up) * Planetarium.right;
+            var vectorToPe = orbit.PeR * (QuaternionD.AngleAxis(orbit.argumentOfPeriapsis, normal) * vectorToAn);
+            var angleFromPe = Vector3d.Angle(vectorToPe, projected);
+
+            if (Math.Abs(Vector3d.Angle(projected, Vector3d.Cross(normal, vectorToPe))) < 90.0)
+            {
+                return angleFromPe;
+            }
+
+            return GetTimeToTrueAnomaly(orbit, 360.0 - angleFromPe);
+        }
+
+        public static Vector3d SwappedOrbitNormal(this Orbit orbit)
+        {
+            var normal = orbit.GetOrbitNormal();
+            return -new Vector3d(normal.x, normal.z, normal.y).normalized;
+        }
     }
 }

--- a/KerbalEngineer/Extensions/PartExtensions.cs
+++ b/KerbalEngineer/Extensions/PartExtensions.cs
@@ -1,358 +1,358 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-using System;

-using System.Collections.Generic;

-using System.Linq;

-

-#endregion

-

-namespace KerbalEngineer.Extensions

-{

-    public static class PartExtensions

-    {

-        /// <summary>

-        ///     Gets whether the part contains a PartModule.

-        /// </summary>

-        public static bool HasModule<T>(this Part part)

-        {

-            return part.Modules.OfType<T>().Any();

-        }

-

-        /// <summary>

-        ///     Gets whether the part contains a PartModule.

-        /// </summary>

-        public static bool HasModule(this Part part, string className)

-        {

-            return part.Modules.Contains(className);

-        }

-

-        /// <summary>

-        ///     Gets whether the part contains a PartModule.

-        /// </summary>

-        public static bool HasModule(this Part part, int moduleId)

-        {

-            return part.Modules.Contains(moduleId);

-        }

-

-        /// <summary>

-        ///     Gets the first typed PartModule in the part's module list.

-        /// </summary>

-        public static T GetModule<T>(this Part part) where T : PartModule

-        {

-            return part.Modules.OfType<T>().FirstOrDefault();

-        }

-

-        /// <summary>

-        ///     Gets a typed PartModule.

-        /// </summary>

-        public static T GetModule<T>(this Part part, string className) where T : PartModule

-        {

-            return (T)Convert.ChangeType(part.Modules[className], typeof(T));

-        }

-

-        /// <summary>

-        ///     Gets a typed PartModule.

-        /// </summary>

-        public static T GetModule<T>(this Part part, int classId) where T : PartModule

-        {

-            return (T)Convert.ChangeType(part.Modules[classId], typeof(T));

-        }

-

-        public static List<T> GetModules<T>(this Part part) where T : PartModule

-        {

-            return part.Modules.OfType<T>().ToList();

-        }

-

-        /// <summary>

-        ///     Gets a ModuleEngines typed PartModule.

-        /// </summary>

-        public static ModuleEngines GetModuleEngines(this Part part)

-        {

-            return part.GetModule<ModuleEngines>();

-        }

-

-        /// <summary>

-        ///     Gets the current selected ModuleEnginesFX.

-        /// </summary>

-        public static ModuleEnginesFX GetModuleEnginesFx(this Part part)

-        {

-            var mode = part.GetModule<MultiModeEngine>().mode;

-            return part.Modules.OfType<ModuleEnginesFX>().FirstOrDefault(engine => engine.engineID == mode);

-        }

-

-        public static ModuleRCS GetModuleRcs(this Part part)

-        {

-            return part.GetModule<ModuleRCS>();

-        }

-

-        /// <summary>

-        ///     Gets a ModuleGimbal typed PartModule.

-        /// </summary>

-        public static ModuleGimbal GetModuleGimbal(this Part part)

-        {

-            return part.GetModule<ModuleGimbal>();

-        }

-

-        /// <summary>

-        ///     Gets a ModuleDeployableSolarPanel typed PartModule.

-        /// </summary>

-        public static ModuleDeployableSolarPanel GetModuleDeployableSolarPanel(this Part part)

-        {

-            return part.GetModule<ModuleDeployableSolarPanel>();

-        }

-

-        /// <summary>

-        ///     Gets a ModuleAlternator typed PartModule.

-        /// </summary>

-        public static ModuleAlternator GetModuleAlternator(this Part part)

-        {

-            return part.GetModule<ModuleAlternator>();

-        }

-

-        /// <summary>

-        ///     Gets a ModuleGenerator typed PartModule.

-        /// </summary>

-        public static ModuleGenerator GetModuleGenerator(this Part part)

-        {

-            return part.GetModule<ModuleGenerator>();

-        }

-

-        /// <summary>

-        ///     Gets a ModuleParachute typed PartModule.

-        /// </summary>

-        public static ModuleParachute GetModuleParachute(this Part part)

-        {

-            return part.GetModule<ModuleParachute>();

-        }

-

-        /// <summary>

-        ///     Gets the total mass of the part including resources.

-        /// </summary>

-        public static double GetWetMass(this Part part)

-        {

-            return (part.physicalSignificance == Part.PhysicalSignificance.FULL) ? part.mass + part.GetResourceMass() : part.GetResourceMass();

-        }

-

-        /// <summary>

-        ///     Gets the dry mass of the part.

-        /// </summary>

-        public static double GetDryMass(this Part part)

-        {

-            return (part.physicalSignificance == Part.PhysicalSignificance.FULL) ? part.mass : 0d;

-        }

-

-        /// <summary>

-        ///     Gets the maximum thrust of the part if it's an engine.

-        /// </summary>

-        public static double GetMaxThrust(this Part part)

-        {

-            if (part.HasModule<ModuleEngines>())

-            {

-                return part.GetModuleEngines().maxThrust;

-            }

-            if (part.HasModule<MultiModeEngine>())

-            {

-                return part.GetModuleEnginesFx().maxThrust;

-            }

-

-            return 0d;

-        }

-

-        /// <summary>

-        ///     Gets the current specific impulse for the engine.

-        /// </summary>

-        public static double GetSpecificImpulse(this Part part, float atmosphere)

-        {

-            if (part.HasModule<ModuleEngines>())

-            {

-                return part.GetModuleEngines().atmosphereCurve.Evaluate(atmosphere);

-            }

-            if (part.HasModule<MultiModeEngine>())

-            {

-                return part.GetModuleEnginesFx().atmosphereCurve.Evaluate(atmosphere);

-            }

-

-            return 0d;

-        }

-

-        /// <summary>

-        ///     Gets whether the part has fuel.

-        /// </summary>

-        public static bool EngineHasFuel(this Part part)

-        {

-            if (part.HasModule<ModuleEngines>())

-            {

-                return part.GetModuleEngines().getFlameoutState;

-            }

-            if (part.HasModule<MultiModeEngine>())

-            {

-                return part.GetModuleEnginesFx().getFlameoutState;

-            }

-

-            return false;

-        }

-

-        /// <summary>

-        ///     Gets whether the part contains resources.

-        /// </summary>

-        public static bool ContainsResources(this Part part)

-        {

-            return part.Resources.list.Count(p => p.amount > 0d) > 0;

-        }

-

-        public static bool ContainsResource(this Part part, int resourceId)

-        {

-            return part.Resources.Contains(resourceId);

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a decoupler.

-        /// </summary>

-        public static bool IsDecoupler(this Part part)

-        {

-            return part.HasModule<ModuleDecouple>() || part.HasModule<ModuleAnchoredDecoupler>();

-        }

-

-        /// <summary>

-        ///     Gets whether the part is decoupled in a specified stage.

-        /// </summary>

-        public static bool IsDecoupledInStage(this Part part, int stage)

-        {

-            if ((part.IsDecoupler() || part.IsLaunchClamp()) && part.inverseStage == stage)

-            {

-                return true;

-            }

-            if (part.parent == null)

-            {

-                return false;

-            }

-            return part.parent.IsDecoupledInStage(stage);

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a launch clamp.

-        /// </summary>

-        public static bool IsLaunchClamp(this Part part)

-        {

-            return part.HasModule<LaunchClamp>();

-        }

-

-        /// <summary>

-        ///     Gets whether the part is an active engine.

-        /// </summary>

-        public static bool IsEngine(this Part part)

-        {

-            return part.HasModule<ModuleEngines>() || part.HasModule<MultiModeEngine>();

-        }

-

-        public static bool IsRcsModule(this Part part)

-        {

-            return part.HasModule<ModuleRCS>();

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a deployable solar panel.

-        /// </summary>

-        public static bool IsSolarPanel(this Part part)

-        {

-            return part.HasModule<ModuleDeployableSolarPanel>();

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a generator.

-        /// </summary>

-        public static bool IsGenerator(this Part part)

-        {

-            return part.HasModule<ModuleGenerator>();

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a command module.

-        /// </summary>

-        public static bool IsCommandModule(this Part part)

-        {

-            return part.HasModule<ModuleCommand>();

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a parachute.

-        /// </summary>

-        public static bool IsParachute(this Part part)

-        {

-            return part.HasModule<ModuleParachute>();

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a solid rocket motor.

-        /// </summary>

-        public static bool IsSolidRocket(this Part part)

-        {

-            return part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked;

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a sepratron.

-        /// </summary>

-        public static bool IsSepratron(this Part part)

-        {

-            return (part.IsSolidRocket() && part.ActivatesEvenIfDisconnected && part.IsDecoupledInStage(part.inverseStage));

-        }

-

-        /// <summary>

-        ///     Gets whether the part is a fuel line.

-        /// </summary>

-        public static bool IsFuelLine(this Part part)

-        {

-            return (part is FuelLine);

-        }

-

-        /// <summary>

-        ///     Gets whether the part is considered a primary part on the vessel.

-        /// </summary>

-        public static bool IsPrimary(this Part part, List<Part> partsList, PartModule module)

-        {

-            foreach (var vesselPart in partsList)

-            {

-                if (!vesselPart.HasModule(module.ClassID))

-                {

-                    continue;

-                }

-

-                if (vesselPart == part)

-                {

-                    return true;

-                }

-                break;

-            }

-

-            return false;

-        }

-

-        /// <summary>

-        ///     Gets whether the part has a one shot animation.

-        /// </summary>

-        public static bool HasOneShotAnimation(this Part part)

-        {

-            return part.HasModule<ModuleAnimateGeneric>() && part.GetModule<ModuleAnimateGeneric>().isOneShot;

-        }

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+#endregion
+
+namespace KerbalEngineer.Extensions
+{
+    public static class PartExtensions
+    {
+        /// <summary>
+        ///     Gets whether the part contains a PartModule.
+        /// </summary>
+        public static bool HasModule<T>(this Part part)
+        {
+            return part.Modules.OfType<T>().Any();
+        }
+
+        /// <summary>
+        ///     Gets whether the part contains a PartModule.
+        /// </summary>
+        public static bool HasModule(this Part part, string className)
+        {
+            return part.Modules.Contains(className);
+        }
+
+        /// <summary>
+        ///     Gets whether the part contains a PartModule.
+        /// </summary>
+        public static bool HasModule(this Part part, int moduleId)
+        {
+            return part.Modules.Contains(moduleId);
+        }
+
+        /// <summary>
+        ///     Gets the first typed PartModule in the part's module list.
+        /// </summary>
+        public static T GetModule<T>(this Part part) where T : PartModule
+        {
+            return part.Modules.OfType<T>().FirstOrDefault();
+        }
+
+        /// <summary>
+        ///     Gets a typed PartModule.
+        /// </summary>
+        public static T GetModule<T>(this Part part, string className) where T : PartModule
+        {
+            return (T)Convert.ChangeType(part.Modules[className], typeof(T));
+        }
+
+        /// <summary>
+        ///     Gets a typed PartModule.
+        /// </summary>
+        public static T GetModule<T>(this Part part, int classId) where T : PartModule
+        {
+            return (T)Convert.ChangeType(part.Modules[classId], typeof(T));
+        }
+
+        public static List<T> GetModules<T>(this Part part) where T : PartModule
+        {
+            return part.Modules.OfType<T>().ToList();
+        }
+
+        /// <summary>
+        ///     Gets a ModuleEngines typed PartModule.
+        /// </summary>
+        public static ModuleEngines GetModuleEngines(this Part part)
+        {
+            return part.GetModule<ModuleEngines>();
+        }
+
+        /// <summary>
+        ///     Gets the current selected ModuleEnginesFX.
+        /// </summary>
+        public static ModuleEnginesFX GetModuleEnginesFx(this Part part)
+        {
+            var mode = part.GetModule<MultiModeEngine>().mode;
+            return part.Modules.OfType<ModuleEnginesFX>().FirstOrDefault(engine => engine.engineID == mode);
+        }
+
+        public static ModuleRCS GetModuleRcs(this Part part)
+        {
+            return part.GetModule<ModuleRCS>();
+        }
+
+        /// <summary>
+        ///     Gets a ModuleGimbal typed PartModule.
+        /// </summary>
+        public static ModuleGimbal GetModuleGimbal(this Part part)
+        {
+            return part.GetModule<ModuleGimbal>();
+        }
+
+        /// <summary>
+        ///     Gets a ModuleDeployableSolarPanel typed PartModule.
+        /// </summary>
+        public static ModuleDeployableSolarPanel GetModuleDeployableSolarPanel(this Part part)
+        {
+            return part.GetModule<ModuleDeployableSolarPanel>();
+        }
+
+        /// <summary>
+        ///     Gets a ModuleAlternator typed PartModule.
+        /// </summary>
+        public static ModuleAlternator GetModuleAlternator(this Part part)
+        {
+            return part.GetModule<ModuleAlternator>();
+        }
+
+        /// <summary>
+        ///     Gets a ModuleGenerator typed PartModule.
+        /// </summary>
+        public static ModuleGenerator GetModuleGenerator(this Part part)
+        {
+            return part.GetModule<ModuleGenerator>();
+        }
+
+        /// <summary>
+        ///     Gets a ModuleParachute typed PartModule.
+        /// </summary>
+        public static ModuleParachute GetModuleParachute(this Part part)
+        {
+            return part.GetModule<ModuleParachute>();
+        }
+
+        /// <summary>
+        ///     Gets the total mass of the part including resources.
+        /// </summary>
+        public static double GetWetMass(this Part part)
+        {
+            return (part.physicalSignificance == Part.PhysicalSignificance.FULL) ? part.mass + part.GetResourceMass() : part.GetResourceMass();
+        }
+
+        /// <summary>
+        ///     Gets the dry mass of the part.
+        /// </summary>
+        public static double GetDryMass(this Part part)
+        {
+            return (part.physicalSignificance == Part.PhysicalSignificance.FULL) ? part.mass : 0d;
+        }
+
+        /// <summary>
+        ///     Gets the maximum thrust of the part if it's an engine.
+        /// </summary>
+        public static double GetMaxThrust(this Part part)
+        {
+            if (part.HasModule<ModuleEngines>())
+            {
+                return part.GetModuleEngines().maxThrust;
+            }
+            if (part.HasModule<MultiModeEngine>())
+            {
+                return part.GetModuleEnginesFx().maxThrust;
+            }
+
+            return 0d;
+        }
+
+        /// <summary>
+        ///     Gets the current specific impulse for the engine.
+        /// </summary>
+        public static double GetSpecificImpulse(this Part part, float atmosphere)
+        {
+            if (part.HasModule<ModuleEngines>())
+            {
+                return part.GetModuleEngines().atmosphereCurve.Evaluate(atmosphere);
+            }
+            if (part.HasModule<MultiModeEngine>())
+            {
+                return part.GetModuleEnginesFx().atmosphereCurve.Evaluate(atmosphere);
+            }
+
+            return 0d;
+        }
+
+        /// <summary>
+        ///     Gets whether the part has fuel.
+        /// </summary>
+        public static bool EngineHasFuel(this Part part)
+        {
+            if (part.HasModule<ModuleEngines>())
+            {
+                return part.GetModuleEngines().getFlameoutState;
+            }
+            if (part.HasModule<MultiModeEngine>())
+            {
+                return part.GetModuleEnginesFx().getFlameoutState;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        ///     Gets whether the part contains resources.
+        /// </summary>
+        public static bool ContainsResources(this Part part)
+        {
+            return part.Resources.list.Count(p => p.amount > 0d) > 0;
+        }
+
+        public static bool ContainsResource(this Part part, int resourceId)
+        {
+            return part.Resources.Contains(resourceId);
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a decoupler.
+        /// </summary>
+        public static bool IsDecoupler(this Part part)
+        {
+            return part.HasModule<ModuleDecouple>() || part.HasModule<ModuleAnchoredDecoupler>();
+        }
+
+        /// <summary>
+        ///     Gets whether the part is decoupled in a specified stage.
+        /// </summary>
+        public static bool IsDecoupledInStage(this Part part, int stage)
+        {
+            if ((part.IsDecoupler() || part.IsLaunchClamp()) && part.inverseStage == stage)
+            {
+                return true;
+            }
+            if (part.parent == null)
+            {
+                return false;
+            }
+            return part.parent.IsDecoupledInStage(stage);
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a launch clamp.
+        /// </summary>
+        public static bool IsLaunchClamp(this Part part)
+        {
+            return part.HasModule<LaunchClamp>();
+        }
+
+        /// <summary>
+        ///     Gets whether the part is an active engine.
+        /// </summary>
+        public static bool IsEngine(this Part part)
+        {
+            return part.HasModule<ModuleEngines>() || part.HasModule<MultiModeEngine>();
+        }
+
+        public static bool IsRcsModule(this Part part)
+        {
+            return part.HasModule<ModuleRCS>();
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a deployable solar panel.
+        /// </summary>
+        public static bool IsSolarPanel(this Part part)
+        {
+            return part.HasModule<ModuleDeployableSolarPanel>();
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a generator.
+        /// </summary>
+        public static bool IsGenerator(this Part part)
+        {
+            return part.HasModule<ModuleGenerator>();
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a command module.
+        /// </summary>
+        public static bool IsCommandModule(this Part part)
+        {
+            return part.HasModule<ModuleCommand>();
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a parachute.
+        /// </summary>
+        public static bool IsParachute(this Part part)
+        {
+            return part.HasModule<ModuleParachute>();
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a solid rocket motor.
+        /// </summary>
+        public static bool IsSolidRocket(this Part part)
+        {
+            return part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked;
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a sepratron.
+        /// </summary>
+        public static bool IsSepratron(this Part part)
+        {
+            return (part.IsSolidRocket() && part.ActivatesEvenIfDisconnected && part.IsDecoupledInStage(part.inverseStage));
+        }
+
+        /// <summary>
+        ///     Gets whether the part is a fuel line.
+        /// </summary>
+        public static bool IsFuelLine(this Part part)
+        {
+            return (part is FuelLine);
+        }
+
+        /// <summary>
+        ///     Gets whether the part is considered a primary part on the vessel.
+        /// </summary>
+        public static bool IsPrimary(this Part part, List<Part> partsList, PartModule module)
+        {
+            foreach (var vesselPart in partsList)
+            {
+                if (!vesselPart.HasModule(module.ClassID))
+                {
+                    continue;
+                }
+
+                if (vesselPart == part)
+                {
+                    return true;
+                }
+                break;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        ///     Gets whether the part has a one shot animation.
+        /// </summary>
+        public static bool HasOneShotAnimation(this Part part)
+        {
+            return part.HasModule<ModuleAnimateGeneric>() && part.GetModule<ModuleAnimateGeneric>().isOneShot;
+        }
+    }
 }

--- a/KerbalEngineer/Extensions/PartResourceExtensions.cs
+++ b/KerbalEngineer/Extensions/PartResourceExtensions.cs
@@ -1,48 +1,48 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-namespace KerbalEngineer.Extensions

-{

-    public static class PartResourceExtensions

-    {

-        /// <summary>

-        ///     Gets the definition object for the resource.

-        /// </summary>

-        public static PartResourceDefinition GetDefinition(this PartResource value)

-        {

-            return PartResourceLibrary.Instance.GetDefinition(value.info.id);

-        }

-

-        /// <summary>

-        ///     Gets the density of the resource.

-        /// </summary>

-        public static double GetDensity(this PartResource value)

-        {

-            return value.GetDefinition().density;

-        }

-

-        /// <summary>

-        ///     Gets the mass of the resource.

-        /// </summary>

-        public static double GetMass(this PartResource value)

-        {

-            return value.amount * value.GetDensity();

-        }

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+namespace KerbalEngineer.Extensions
+{
+    public static class PartResourceExtensions
+    {
+        /// <summary>
+        ///     Gets the definition object for the resource.
+        /// </summary>
+        public static PartResourceDefinition GetDefinition(this PartResource value)
+        {
+            return PartResourceLibrary.Instance.GetDefinition(value.info.id);
+        }
+
+        /// <summary>
+        ///     Gets the density of the resource.
+        /// </summary>
+        public static double GetDensity(this PartResource value)
+        {
+            return value.GetDefinition().density;
+        }
+
+        /// <summary>
+        ///     Gets the mass of the resource.
+        /// </summary>
+        public static double GetMass(this PartResource value)
+        {
+            return value.amount * value.GetDensity();
+        }
+    }
 }

--- a/KerbalEngineer/Flight/FlightEngineerModule.cs
+++ b/KerbalEngineer/Flight/FlightEngineerModule.cs
@@ -1,101 +1,101 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-using System;

-using System.Linq;

-

-#endregion

-

-namespace KerbalEngineer.Flight

-{

-    /// <summary>

-    ///     Module that can be attached to parts, giving them FlightEngineerCore management.

-    /// </summary>

-    public sealed class FlightEngineerModule : PartModule

-    {

-        #region Fields

-

-        /// <summary>

-        ///     Contains the current FlightEngineerCore through the lifespan of this part.

-        /// </summary>

-        private FlightEngineerCore flightEngineerCore;

-

-        #endregion

-

-        #region Updating

-

-        /// <summary>

-        ///     Logic to create and destroy the FlightEngineerCore.

-        /// </summary>

-        private void Update()

-        {

-            try

-            {

-                if (!HighLogic.LoadedSceneIsFlight || FlightEngineerPartless.IsPartless)

-                {

-                    return;

-                }

-

-                if (this.vessel == FlightGlobals.ActiveVessel)

-                {

-                    // Checks for an existing instance of FlightEngineerCore, and if this part is the first part containing FlightEngineerModule within the vessel.

-                    if (flightEngineerCore == null && this.part == this.vessel.parts.FirstOrDefault(p => p.Modules.Contains("FlightEngineerModule")))

-                    {

-                        this.flightEngineerCore = this.gameObject.AddComponent<FlightEngineerCore>();

-                    }

-                }

-                else if (flightEngineerCore != null)

-                {

-                    // Using DestroyImmediate to force early destruction and keep saving/loading in synch when switching vessels.

-                    DestroyImmediate(flightEngineerCore);

-                }

-            }

-            catch (Exception ex)

-            {

-                Logger.Exception(ex, "FlightEngineerModule->Update");

-            }

-        }

-

-        #endregion

-

-        #region Destruction

-

-        /// <summary>

-        ///     Force the destruction of the FlightEngineerCore on part destruction.

-        /// </summary>

-        private void OnDestroy()

-        {

-            try

-            {

-                if (flightEngineerCore != null)

-                {

-                    DestroyImmediate(flightEngineerCore);

-                }

-            }

-            catch (Exception ex)

-            {

-                Logger.Exception(ex, "FlightEngineerModule->OnDestroy");

-            }

-        }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+using System;
+using System.Linq;
+
+#endregion
+
+namespace KerbalEngineer.Flight
+{
+    /// <summary>
+    ///     Module that can be attached to parts, giving them FlightEngineerCore management.
+    /// </summary>
+    public sealed class FlightEngineerModule : PartModule
+    {
+        #region Fields
+
+        /// <summary>
+        ///     Contains the current FlightEngineerCore through the lifespan of this part.
+        /// </summary>
+        private FlightEngineerCore flightEngineerCore;
+
+        #endregion
+
+        #region Updating
+
+        /// <summary>
+        ///     Logic to create and destroy the FlightEngineerCore.
+        /// </summary>
+        private void Update()
+        {
+            try
+            {
+                if (!HighLogic.LoadedSceneIsFlight || FlightEngineerPartless.IsPartless)
+                {
+                    return;
+                }
+
+                if (this.vessel == FlightGlobals.ActiveVessel)
+                {
+                    // Checks for an existing instance of FlightEngineerCore, and if this part is the first part containing FlightEngineerModule within the vessel.
+                    if (flightEngineerCore == null && this.part == this.vessel.parts.FirstOrDefault(p => p.Modules.Contains("FlightEngineerModule")))
+                    {
+                        this.flightEngineerCore = this.gameObject.AddComponent<FlightEngineerCore>();
+                    }
+                }
+                else if (flightEngineerCore != null)
+                {
+                    // Using DestroyImmediate to force early destruction and keep saving/loading in synch when switching vessels.
+                    DestroyImmediate(flightEngineerCore);
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex, "FlightEngineerModule->Update");
+            }
+        }
+
+        #endregion
+
+        #region Destruction
+
+        /// <summary>
+        ///     Force the destruction of the FlightEngineerCore on part destruction.
+        /// </summary>
+        private void OnDestroy()
+        {
+            try
+            {
+                if (flightEngineerCore != null)
+                {
+                    DestroyImmediate(flightEngineerCore);
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex, "FlightEngineerModule->OnDestroy");
+            }
+        }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/Flight/FlightEngineerPartless.cs
+++ b/KerbalEngineer/Flight/FlightEngineerPartless.cs
@@ -1,102 +1,102 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-using System;

-

-using KerbalEngineer.Settings;

-

-using UnityEngine;

-

-#endregion

-

-namespace KerbalEngineer.Flight

-{

-    [KSPAddon(KSPAddon.Startup.Flight, false)]

-    public class FlightEngineerPartless : MonoBehaviour

-    {

-        #region Fields

-

-        private FlightEngineerCore flightEngineerCore;

-

-        #endregion

-

-        #region Initialisation

-

-        static FlightEngineerPartless()

-        {

-            try

-            {

-                var handler = SettingHandler.Load("FlightEngineerPartless.xml");

-                handler.Get("isPartless", ref isPartless);

-            }

-            catch (Exception ex)

-            {

-                Logger.Exception(ex, "FlightEngineerPartless->FlightEngineerPartless");

-            }

-        }

-

-        private void Awake()

-        {

-            try

-            {

-                if (isPartless)

-                {

-                    this.flightEngineerCore = this.gameObject.AddComponent<FlightEngineerCore>();

-                }

-            }

-            catch (Exception ex)

-            {

-                Logger.Exception(ex, "FlightEngineerPartless->Awake");

-            }

-        }

-

-        #endregion

-

-        #region Properties

-

-        private static bool isPartless = true;

-

-        public static bool IsPartless

-        {

-            get { return isPartless; }

-            set

-            {

-                try

-                {

-                    if (isPartless != value)

-                    {

-                        var handler = SettingHandler.Load("FlightEngineerPartless.xml");

-                        handler.Set("isPartless", value);

-                        handler.Save("FlightEngineerPartless.xml");

-                    }

-                    isPartless = value;

-                    Logger.Log("FlightEngineerPartless->IsPartless = " + value);

-                }

-                catch (Exception ex)

-                {

-                    Logger.Exception(ex, "FlightEngineerPartless->IsPartless");

-                }

-            }

-        }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+using System;
+
+using KerbalEngineer.Settings;
+
+using UnityEngine;
+
+#endregion
+
+namespace KerbalEngineer.Flight
+{
+    [KSPAddon(KSPAddon.Startup.Flight, false)]
+    public class FlightEngineerPartless : MonoBehaviour
+    {
+        #region Fields
+
+        private FlightEngineerCore flightEngineerCore;
+
+        #endregion
+
+        #region Initialisation
+
+        static FlightEngineerPartless()
+        {
+            try
+            {
+                var handler = SettingHandler.Load("FlightEngineerPartless.xml");
+                handler.Get("isPartless", ref isPartless);
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex, "FlightEngineerPartless->FlightEngineerPartless");
+            }
+        }
+
+        private void Awake()
+        {
+            try
+            {
+                if (isPartless)
+                {
+                    this.flightEngineerCore = this.gameObject.AddComponent<FlightEngineerCore>();
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex, "FlightEngineerPartless->Awake");
+            }
+        }
+
+        #endregion
+
+        #region Properties
+
+        private static bool isPartless = true;
+
+        public static bool IsPartless
+        {
+            get { return isPartless; }
+            set
+            {
+                try
+                {
+                    if (isPartless != value)
+                    {
+                        var handler = SettingHandler.Load("FlightEngineerPartless.xml");
+                        handler.Set("isPartless", value);
+                        handler.Save("FlightEngineerPartless.xml");
+                    }
+                    isPartless = value;
+                    Logger.Log("FlightEngineerPartless->IsPartless = " + value);
+                }
+                catch (Exception ex)
+                {
+                    Logger.Exception(ex, "FlightEngineerPartless->IsPartless");
+                }
+            }
+        }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/Flight/IUpdatable.cs
+++ b/KerbalEngineer/Flight/IUpdatable.cs
@@ -1,29 +1,29 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-namespace KerbalEngineer.Flight

-{

-    /// <summary>

-    ///     Interface which enables object updating via the flight engineer core.

-    /// </summary>

-    public interface IUpdatable

-    {

-        void Update();

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+namespace KerbalEngineer.Flight
+{
+    /// <summary>
+    ///     Interface which enables object updating via the flight engineer core.
+    /// </summary>
+    public interface IUpdatable
+    {
+        void Update();
+    }
 }

--- a/KerbalEngineer/Flight/IUpdateRequest.cs
+++ b/KerbalEngineer/Flight/IUpdateRequest.cs
@@ -1,29 +1,29 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-namespace KerbalEngineer.Flight

-{

-    /// <summary>

-    ///     Interface which enables requested updates on an updatable object.

-    /// </summary>

-    public interface IUpdateRequest

-    {

-        bool UpdateRequested { get; set; }

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+namespace KerbalEngineer.Flight
+{
+    /// <summary>
+    ///     Interface which enables requested updates on an updatable object.
+    /// </summary>
+    public interface IUpdateRequest
+    {
+        bool UpdateRequested { get; set; }
+    }
 }

--- a/KerbalEngineer/Flight/Readouts/ReadoutLibrary.cs
+++ b/KerbalEngineer/Flight/Readouts/ReadoutLibrary.cs
@@ -78,6 +78,7 @@
                 readouts.Add(new OrbitalPeriod());
                 readouts.Add(new LongitudeOfAscendingNode());
                 readouts.Add(new LongitudeOfPeriapsis());
+                readouts.Add(new TrueAnomaly());
                 readouts.Add(new SemiMajorAxis());
                 readouts.Add(new SemiMinorAxis());
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/RendezvousProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/RendezvousProcessor.cs
@@ -154,7 +154,7 @@
             PhaseAngle = this.CalcCurrentPhaseAngle();
             InterceptAngle = this.CalcInterceptAngle();
             RelativeInclination = Vector3d.Angle(this.originOrbit.GetOrbitNormal(), this.targetOrbit.GetOrbitNormal());
-            TimeToAscendingNode = this.originOrbit.GetTimeToTrueAnomaly(this.GetAngle(this.originOrbit.GetOrbitNormal(), this.GetAscendingNode()) + this.originOrbit.trueAnomaly);
+            TimeToAscendingNode = this.originOrbit.GetTrueAnomalyFromVector(this.GetAscendingNode());
             AngleToAscendingNode = this.CalcAngleToAscendingNode();
             AngleToDescendingNode = this.CalcAngleToDescendingNode();
             AltitudeSeaLevel = this.targetOrbit.altitude;

--- a/KerbalEngineer/Flight/Readouts/Surface/AtmosphericProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/AtmosphericProcessor.cs
@@ -1,186 +1,186 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-using System;

-using System.Linq;

-using System.Reflection;

-

-using KerbalEngineer.Extensions;

-

-#endregion

-

-namespace KerbalEngineer.Flight.Readouts.Surface

-{

-    public class AtmosphericProcessor : IUpdatable, IUpdateRequest

-    {

-        #region Instance

-

-        private static readonly AtmosphericProcessor instance = new AtmosphericProcessor();

-

-        /// <summary>

-        ///     Gets the current instance of the atmospheric processor.

-        /// </summary>

-        public static AtmosphericProcessor Instance

-        {

-            get { return instance; }

-        }

-

-        #endregion

-

-        #region Fields

-

-        private bool hasCheckedAeroMods;

-        private MethodInfo farTerminalVelocity;

-

-        #endregion

-

-        #region Properties

-

-        /// <summary>

-        ///     Gets whether the details are ready to be shown.

-        /// </summary>

-        public static bool ShowDetails { get; private set; }

-

-        /// <summary>

-        ///     Gets whether FAR is installed.

-        /// </summary>

-        public static bool FarInstalled { get; private set; }

-

-        /// <summary>

-        ///     Gets whether NEAR is installed.

-        /// </summary>

-        public static bool NearInstalled { get; private set; }

-

-        /// <summary>

-        ///     Gets the terminal velocity of the active vessel.

-        /// </summary>

-        public static double TerminalVelocity { get; private set; }

-

-        /// <summary>

-        ///     Gets the difference between current velocity and terminal velocity.

-        /// </summary>

-        public static double Efficiency { get; private set; }

-

-        /// <summary>

-        ///     Gets the deceleration caused by drag.

-        /// </summary>

-        public static double Deceleration { get; private set; }

-

-        #endregion

-

-        #region IUpdatable Members

-

-        /// <summary>

-        ///     Updates the details by recalculating if requested.

-        /// </summary>

-        public void Update()

-        {

-            try

-            {

-                if (!this.hasCheckedAeroMods)

-                {

-                    this.CheckAeroMods();

-                }

-

-                if (FlightGlobals.ActiveVessel.atmDensity < double.Epsilon || NearInstalled)

-                {

-                    ShowDetails = false;

-                    return;

-                }

-

-                ShowDetails = true;

-

-                if (FarInstalled)

-                {

-                    TerminalVelocity = (double)this.farTerminalVelocity.Invoke(null, null);

-                }

-                else

-                {

-                    var mass = FlightGlobals.ActiveVessel.parts.Sum(p => p.GetWetMass());

-                    var drag = FlightGlobals.ActiveVessel.parts.Sum(p => p.GetWetMass() * p.maximum_drag);

-                    var grav = FlightGlobals.getGeeForceAtPosition(FlightGlobals.ship_position).magnitude;

-                    var atmo = FlightGlobals.ActiveVessel.atmDensity;

-                    var coef = FlightGlobals.DragMultiplier;

-

-                    TerminalVelocity = Math.Sqrt((2 * mass * grav) / (atmo * drag * coef));

-                }

-

-                Efficiency = FlightGlobals.ship_srfSpeed / TerminalVelocity;

-            }

-            catch (Exception ex)

-            {

-                Logger.Exception(ex, "AtmosphericProcessor->Update");

-            }

-        }

-

-        #endregion

-

-        #region IUpdateRequest Members

-

-        /// <summary>

-        ///     Gets and sets whether the updatable object should be updated.

-        /// </summary>

-        public bool UpdateRequested { get; set; }

-

-        #endregion

-

-        /// <summary>

-        ///     Request an update to calculate the details.

-        /// </summary>

-        public static void RequestUpdate()

-        {

-            instance.UpdateRequested = true;

-        }

-

-        #region Private Methods

-

-        private void CheckAeroMods()

-        {

-            try

-            {

-                this.hasCheckedAeroMods = true;

-

-                foreach (var loadedAssembly in AssemblyLoader.loadedAssemblies)

-                {

-                    switch (loadedAssembly.name)

-                    {

-                        case "FerramAerospaceResearch":

-                            farTerminalVelocity = loadedAssembly.assembly.GetType("ferram4.FARAPI").GetMethod("GetActiveControlSys_TermVel");

-                            FarInstalled = true;

-                            Logger.Log("FAR detected!");

-                            break;

-

-                        case "NEAR":

-                            NearInstalled = true;

-                            Logger.Log("NEAR detected! Turning off atmospheric details!");

-                            break;

-                    }

-                }

-            }

-            catch (Exception ex)

-            {

-                Logger.Exception(ex, "AtmosphericProcessor->CheckAeroMods");

-            }

-        }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+using System;
+using System.Linq;
+using System.Reflection;
+
+using KerbalEngineer.Extensions;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Surface
+{
+    public class AtmosphericProcessor : IUpdatable, IUpdateRequest
+    {
+        #region Instance
+
+        private static readonly AtmosphericProcessor instance = new AtmosphericProcessor();
+
+        /// <summary>
+        ///     Gets the current instance of the atmospheric processor.
+        /// </summary>
+        public static AtmosphericProcessor Instance
+        {
+            get { return instance; }
+        }
+
+        #endregion
+
+        #region Fields
+
+        private bool hasCheckedAeroMods;
+        private MethodInfo farTerminalVelocity;
+
+        #endregion
+
+        #region Properties
+
+        /// <summary>
+        ///     Gets whether the details are ready to be shown.
+        /// </summary>
+        public static bool ShowDetails { get; private set; }
+
+        /// <summary>
+        ///     Gets whether FAR is installed.
+        /// </summary>
+        public static bool FarInstalled { get; private set; }
+
+        /// <summary>
+        ///     Gets whether NEAR is installed.
+        /// </summary>
+        public static bool NearInstalled { get; private set; }
+
+        /// <summary>
+        ///     Gets the terminal velocity of the active vessel.
+        /// </summary>
+        public static double TerminalVelocity { get; private set; }
+
+        /// <summary>
+        ///     Gets the difference between current velocity and terminal velocity.
+        /// </summary>
+        public static double Efficiency { get; private set; }
+
+        /// <summary>
+        ///     Gets the deceleration caused by drag.
+        /// </summary>
+        public static double Deceleration { get; private set; }
+
+        #endregion
+
+        #region IUpdatable Members
+
+        /// <summary>
+        ///     Updates the details by recalculating if requested.
+        /// </summary>
+        public void Update()
+        {
+            try
+            {
+                if (!this.hasCheckedAeroMods)
+                {
+                    this.CheckAeroMods();
+                }
+
+                if (FlightGlobals.ActiveVessel.atmDensity < double.Epsilon || NearInstalled)
+                {
+                    ShowDetails = false;
+                    return;
+                }
+
+                ShowDetails = true;
+
+                if (FarInstalled)
+                {
+                    TerminalVelocity = (double)this.farTerminalVelocity.Invoke(null, null);
+                }
+                else
+                {
+                    var mass = FlightGlobals.ActiveVessel.parts.Sum(p => p.GetWetMass());
+                    var drag = FlightGlobals.ActiveVessel.parts.Sum(p => p.GetWetMass() * p.maximum_drag);
+                    var grav = FlightGlobals.getGeeForceAtPosition(FlightGlobals.ship_position).magnitude;
+                    var atmo = FlightGlobals.ActiveVessel.atmDensity;
+                    var coef = FlightGlobals.DragMultiplier;
+
+                    TerminalVelocity = Math.Sqrt((2 * mass * grav) / (atmo * drag * coef));
+                }
+
+                Efficiency = FlightGlobals.ship_srfSpeed / TerminalVelocity;
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex, "AtmosphericProcessor->Update");
+            }
+        }
+
+        #endregion
+
+        #region IUpdateRequest Members
+
+        /// <summary>
+        ///     Gets and sets whether the updatable object should be updated.
+        /// </summary>
+        public bool UpdateRequested { get; set; }
+
+        #endregion
+
+        /// <summary>
+        ///     Request an update to calculate the details.
+        /// </summary>
+        public static void RequestUpdate()
+        {
+            instance.UpdateRequested = true;
+        }
+
+        #region Private Methods
+
+        private void CheckAeroMods()
+        {
+            try
+            {
+                this.hasCheckedAeroMods = true;
+
+                foreach (var loadedAssembly in AssemblyLoader.loadedAssemblies)
+                {
+                    switch (loadedAssembly.name)
+                    {
+                        case "FerramAerospaceResearch":
+                            farTerminalVelocity = loadedAssembly.assembly.GetType("ferram4.FARAPI").GetMethod("GetActiveControlSys_TermVel");
+                            FarInstalled = true;
+                            Logger.Log("FAR detected!");
+                            break;
+
+                        case "NEAR":
+                            NearInstalled = true;
+                            Logger.Log("NEAR detected! Turning off atmospheric details!");
+                            break;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex, "AtmosphericProcessor->CheckAeroMods");
+            }
+        }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/Flight/Readouts/Surface/ImpactProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/ImpactProcessor.cs
@@ -1,284 +1,284 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-using System;

-

-using UnityEngine;

-

-#endregion

-

-// The calculations and functional code in this processor were generously developed by mic_e.

-

-namespace KerbalEngineer.Flight.Readouts.Surface

-{

-    public class ImpactProcessor : IUpdatable, IUpdateRequest

-    {

-        #region Instance

-

-        private static readonly ImpactProcessor instance = new ImpactProcessor();

-

-        /// <summary>

-        ///     Gets the current instance of the impact processor.

-        /// </summary>

-        public static ImpactProcessor Instance

-        {

-            get { return instance; }

-        }

-

-        #endregion

-

-        #region Fields

-

-        private double impactAltitude;

-        private string impactBiome;

-        private bool impactHappening;

-        private double impactLatitude;

-        private double impactLongitude;

-        private double impactTime;

-

-        #endregion

-

-        #region Properties

-

-        /// <summary>

-        ///     Gets whether the details are ready to be shown.

-        /// </summary>

-        public static bool ShowDetails { get; private set; }

-

-        /// <summary>

-        ///     Gets the time to impact.

-        /// </summary>

-        public static double Time { get; private set; }

-

-        /// <summary>

-        ///     Gets the longitude of the impact coordinates.

-        /// </summary>

-        public static double Longitude { get; private set; }

-

-        /// <summary>

-        ///     Gets the latitude of the impact coordinates.

-        /// </summary>

-        public static double Latitude { get; private set; }

-

-        /// <summary>

-        ///     Gets the altitude of the impact coordinates.

-        /// </summary>

-        public static double Altitude { get; private set; }

-

-        /// <summary>

-        ///     Gets the biome of the impact coordinates.

-        /// </summary>

-        public static string Biome { get; private set; }

-

-        #endregion

-

-        #region IUpdatable Members

-

-        public void Update()

-        {

-            this.impactHappening = false;

-

-            if (FlightGlobals.ActiveVessel.mainBody.pqsController != null)

-            {

-                //do impact site calculations

-                this.impactHappening = true;

-                this.impactTime = 0;

-                this.impactLongitude = 0;

-                this.impactLatitude = 0;

-                this.impactAltitude = 0;

-                this.impactBiome = "---";

-                var e = FlightGlobals.ActiveVessel.orbit.eccentricity;

-                //get current position direction vector

-                var currentpos = this.RadiusDirection(FlightGlobals.ActiveVessel.orbit.trueAnomaly);

-                //calculate longitude in inertial reference frame from that

-                var currentirflong = 180 * Math.Atan2(currentpos.x, currentpos.y) / Math.PI;

-

-                //experimentally determined; even for very flat trajectories, the errors go into the sub-millimeter area after 5 iterations or so

-                const int impactiterations = 6;

-

-                //do a few iterations of impact site calculations

-                for (var i = 0; i < impactiterations; i++)

-                {

-                    if (FlightGlobals.ActiveVessel.orbit.PeA >= this.impactAltitude)

-                    {

-                        //periapsis must be lower than impact alt

-                        this.impactHappening = false;

-                    }

-                    if ((FlightGlobals.ActiveVessel.orbit.eccentricity < 1) && (FlightGlobals.ActiveVessel.orbit.ApA <= this.impactAltitude))

-                    {

-                        //apoapsis must be higher than impact alt

-                        this.impactHappening = false;

-                    }

-                    if ((FlightGlobals.ActiveVessel.orbit.eccentricity >= 1) && (FlightGlobals.ActiveVessel.orbit.timeToPe <= 0))

-                    {

-                        //if currently escaping, we still need to be before periapsis

-                        this.impactHappening = false;

-                    }

-                    if (!this.impactHappening)

-                    {

-                        this.impactTime = 0;

-                        this.impactLongitude = 0;

-                        this.impactLatitude = 0;

-                        this.impactAltitude = 0;

-                        break;

-                    }

-

-                    double impacttheta = 0;

-                    if (e > 0)

-                    {

-                        //in this step, we are using the calculated impact altitude of the last step, to refine the impact site position

-                        impacttheta = -180 * Math.Acos((FlightGlobals.ActiveVessel.orbit.PeR * (1 + e) / (FlightGlobals.ActiveVessel.mainBody.Radius + this.impactAltitude) - 1) / e) / Math.PI;

-                    }

-

-                    //calculate time to impact

-                    this.impactTime = FlightGlobals.ActiveVessel.orbit.timeToPe - this.TimeToPeriapsis(impacttheta);

-                    //calculate position vector of impact site

-                    var impactpos = this.RadiusDirection(impacttheta);

-                    //calculate longitude of impact site in inertial reference frame

-                    var impactirflong = 180 * Math.Atan2(impactpos.x, impactpos.y) / Math.PI;

-                    var deltairflong = impactirflong - currentirflong;

-                    //get body rotation until impact

-                    var bodyrot = 360 * this.impactTime / FlightGlobals.ActiveVessel.mainBody.rotationPeriod;

-                    //get current longitude in body coordinates

-                    var currentlong = FlightGlobals.ActiveVessel.longitude;

-                    //finally, calculate the impact longitude in body coordinates

-                    this.impactLongitude = this.NormAngle(currentlong - deltairflong - bodyrot);

-                    //calculate impact latitude from impact position

-                    this.impactLatitude = 180 * Math.Asin(impactpos.z / impactpos.magnitude) / Math.PI;

-                    //calculate the actual altitude of the impact site

-                    //altitude for long/lat code stolen from some ISA MapSat forum post; who knows why this works, but it seems to.

-                    var rad = QuaternionD.AngleAxis(this.impactLongitude, Vector3d.down) * QuaternionD.AngleAxis(this.impactLatitude, Vector3d.forward) * Vector3d.right;

-                    this.impactAltitude = FlightGlobals.ActiveVessel.mainBody.pqsController.GetSurfaceHeight(rad) - FlightGlobals.ActiveVessel.mainBody.pqsController.radius;

-                    if ((this.impactAltitude < 0) && FlightGlobals.ActiveVessel.mainBody.ocean)

-                    {

-                        this.impactAltitude = 0;

-                    }

-                }

-            }

-

-            // Set accessable properties.

-            if (this.impactHappening)

-            {

-                ShowDetails = true;

-                Time = this.impactTime;

-                Longitude = this.impactLongitude;

-                Latitude = this.impactLatitude;

-                Altitude = this.impactAltitude;

-                Biome = ScienceUtil.GetExperimentBiome(FlightGlobals.ActiveVessel.mainBody, this.impactLatitude, this.impactLongitude);

-            }

-            else

-            {

-                ShowDetails = false;

-            }

-        }

-

-        #endregion

-

-        #region IUpdateRequest Members

-

-        public bool UpdateRequested { get; set; }

-

-        #endregion

-

-        public static void RequestUpdate()

-        {

-            instance.UpdateRequested = true;

-        }

-

-        #region Calculations

-

-        private double NormAngle(double ang)

-        {

-            if (ang > 180)

-            {

-                ang -= 360 * Math.Ceiling((ang - 180) / 360);

-            }

-            if (ang <= -180)

-            {

-                ang -= 360 * Math.Floor((ang + 180) / 360);

-            }

-

-            return ang;

-        }

-

-        private Vector3d RadiusDirection(double theta)

-        {

-            theta = Math.PI * theta / 180;

-            var omega = Math.PI * FlightGlobals.ActiveVessel.orbit.argumentOfPeriapsis / 180;

-            var incl = Math.PI * FlightGlobals.ActiveVessel.orbit.inclination / 180;

-

-            var costheta = Math.Cos(theta);

-            var sintheta = Math.Sin(theta);

-            var cosomega = Math.Cos(omega);

-            var sinomega = Math.Sin(omega);

-            var cosincl = Math.Cos(incl);

-            var sinincl = Math.Sin(incl);

-

-            Vector3d result;

-

-            result.x = cosomega * costheta - sinomega * sintheta;

-            result.y = cosincl * (sinomega * costheta + cosomega * sintheta);

-            result.z = sinincl * (sinomega * costheta + cosomega * sintheta);

-

-            return result;

-        }

-

-        public static double ACosh(double x)

-        {

-            return (Math.Log(x + Math.Sqrt((x * x) - 1.0)));

-        }

-

-        private double TimeToPeriapsis(double theta)

-        {

-            var e = FlightGlobals.ActiveVessel.orbit.eccentricity;

-            var a = FlightGlobals.ActiveVessel.orbit.semiMajorAxis;

-            var rp = FlightGlobals.ActiveVessel.orbit.PeR;

-            var mu = FlightGlobals.ActiveVessel.mainBody.gravParameter;

-

-            if (e == 1.0)

-            {

-                var D = Math.Tan(Math.PI * theta / 360.0);

-                var M = D + D * D * D / 3.0;

-                return (Math.Sqrt(2.0 * rp * rp * rp / mu) * M);

-            }

-            if (a > 0)

-            {

-                var cosTheta = Math.Cos(Math.PI * theta / 180.0);

-                var cosE = (e + cosTheta) / (1.0 + e * cosTheta);

-                var radE = Math.Acos(cosE);

-                var M = radE - e * Math.Sin(radE);

-                return (Math.Sqrt(a * a * a / mu) * M);

-            }

-            if (a < 0)

-            {

-                var cosTheta = Math.Cos(Math.PI * theta / 180.0);

-                var coshF = (e + cosTheta) / (1.0 + e * cosTheta);

-                var radF = ACosh(coshF);

-                var M = e * Math.Sinh(radF) - radF;

-                return (Math.Sqrt(-a * a * a / mu) * M);

-            }

-

-            return 0;

-        }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+using System;
+
+using UnityEngine;
+
+#endregion
+
+// The calculations and functional code in this processor were generously developed by mic_e.
+
+namespace KerbalEngineer.Flight.Readouts.Surface
+{
+    public class ImpactProcessor : IUpdatable, IUpdateRequest
+    {
+        #region Instance
+
+        private static readonly ImpactProcessor instance = new ImpactProcessor();
+
+        /// <summary>
+        ///     Gets the current instance of the impact processor.
+        /// </summary>
+        public static ImpactProcessor Instance
+        {
+            get { return instance; }
+        }
+
+        #endregion
+
+        #region Fields
+
+        private double impactAltitude;
+        private string impactBiome;
+        private bool impactHappening;
+        private double impactLatitude;
+        private double impactLongitude;
+        private double impactTime;
+
+        #endregion
+
+        #region Properties
+
+        /// <summary>
+        ///     Gets whether the details are ready to be shown.
+        /// </summary>
+        public static bool ShowDetails { get; private set; }
+
+        /// <summary>
+        ///     Gets the time to impact.
+        /// </summary>
+        public static double Time { get; private set; }
+
+        /// <summary>
+        ///     Gets the longitude of the impact coordinates.
+        /// </summary>
+        public static double Longitude { get; private set; }
+
+        /// <summary>
+        ///     Gets the latitude of the impact coordinates.
+        /// </summary>
+        public static double Latitude { get; private set; }
+
+        /// <summary>
+        ///     Gets the altitude of the impact coordinates.
+        /// </summary>
+        public static double Altitude { get; private set; }
+
+        /// <summary>
+        ///     Gets the biome of the impact coordinates.
+        /// </summary>
+        public static string Biome { get; private set; }
+
+        #endregion
+
+        #region IUpdatable Members
+
+        public void Update()
+        {
+            this.impactHappening = false;
+
+            if (FlightGlobals.ActiveVessel.mainBody.pqsController != null)
+            {
+                //do impact site calculations
+                this.impactHappening = true;
+                this.impactTime = 0;
+                this.impactLongitude = 0;
+                this.impactLatitude = 0;
+                this.impactAltitude = 0;
+                this.impactBiome = "---";
+                var e = FlightGlobals.ActiveVessel.orbit.eccentricity;
+                //get current position direction vector
+                var currentpos = this.RadiusDirection(FlightGlobals.ActiveVessel.orbit.trueAnomaly);
+                //calculate longitude in inertial reference frame from that
+                var currentirflong = 180 * Math.Atan2(currentpos.x, currentpos.y) / Math.PI;
+
+                //experimentally determined; even for very flat trajectories, the errors go into the sub-millimeter area after 5 iterations or so
+                const int impactiterations = 6;
+
+                //do a few iterations of impact site calculations
+                for (var i = 0; i < impactiterations; i++)
+                {
+                    if (FlightGlobals.ActiveVessel.orbit.PeA >= this.impactAltitude)
+                    {
+                        //periapsis must be lower than impact alt
+                        this.impactHappening = false;
+                    }
+                    if ((FlightGlobals.ActiveVessel.orbit.eccentricity < 1) && (FlightGlobals.ActiveVessel.orbit.ApA <= this.impactAltitude))
+                    {
+                        //apoapsis must be higher than impact alt
+                        this.impactHappening = false;
+                    }
+                    if ((FlightGlobals.ActiveVessel.orbit.eccentricity >= 1) && (FlightGlobals.ActiveVessel.orbit.timeToPe <= 0))
+                    {
+                        //if currently escaping, we still need to be before periapsis
+                        this.impactHappening = false;
+                    }
+                    if (!this.impactHappening)
+                    {
+                        this.impactTime = 0;
+                        this.impactLongitude = 0;
+                        this.impactLatitude = 0;
+                        this.impactAltitude = 0;
+                        break;
+                    }
+
+                    double impacttheta = 0;
+                    if (e > 0)
+                    {
+                        //in this step, we are using the calculated impact altitude of the last step, to refine the impact site position
+                        impacttheta = -180 * Math.Acos((FlightGlobals.ActiveVessel.orbit.PeR * (1 + e) / (FlightGlobals.ActiveVessel.mainBody.Radius + this.impactAltitude) - 1) / e) / Math.PI;
+                    }
+
+                    //calculate time to impact
+                    this.impactTime = FlightGlobals.ActiveVessel.orbit.timeToPe - this.TimeToPeriapsis(impacttheta);
+                    //calculate position vector of impact site
+                    var impactpos = this.RadiusDirection(impacttheta);
+                    //calculate longitude of impact site in inertial reference frame
+                    var impactirflong = 180 * Math.Atan2(impactpos.x, impactpos.y) / Math.PI;
+                    var deltairflong = impactirflong - currentirflong;
+                    //get body rotation until impact
+                    var bodyrot = 360 * this.impactTime / FlightGlobals.ActiveVessel.mainBody.rotationPeriod;
+                    //get current longitude in body coordinates
+                    var currentlong = FlightGlobals.ActiveVessel.longitude;
+                    //finally, calculate the impact longitude in body coordinates
+                    this.impactLongitude = this.NormAngle(currentlong - deltairflong - bodyrot);
+                    //calculate impact latitude from impact position
+                    this.impactLatitude = 180 * Math.Asin(impactpos.z / impactpos.magnitude) / Math.PI;
+                    //calculate the actual altitude of the impact site
+                    //altitude for long/lat code stolen from some ISA MapSat forum post; who knows why this works, but it seems to.
+                    var rad = QuaternionD.AngleAxis(this.impactLongitude, Vector3d.down) * QuaternionD.AngleAxis(this.impactLatitude, Vector3d.forward) * Vector3d.right;
+                    this.impactAltitude = FlightGlobals.ActiveVessel.mainBody.pqsController.GetSurfaceHeight(rad) - FlightGlobals.ActiveVessel.mainBody.pqsController.radius;
+                    if ((this.impactAltitude < 0) && FlightGlobals.ActiveVessel.mainBody.ocean)
+                    {
+                        this.impactAltitude = 0;
+                    }
+                }
+            }
+
+            // Set accessable properties.
+            if (this.impactHappening)
+            {
+                ShowDetails = true;
+                Time = this.impactTime;
+                Longitude = this.impactLongitude;
+                Latitude = this.impactLatitude;
+                Altitude = this.impactAltitude;
+                Biome = ScienceUtil.GetExperimentBiome(FlightGlobals.ActiveVessel.mainBody, this.impactLatitude, this.impactLongitude);
+            }
+            else
+            {
+                ShowDetails = false;
+            }
+        }
+
+        #endregion
+
+        #region IUpdateRequest Members
+
+        public bool UpdateRequested { get; set; }
+
+        #endregion
+
+        public static void RequestUpdate()
+        {
+            instance.UpdateRequested = true;
+        }
+
+        #region Calculations
+
+        private double NormAngle(double ang)
+        {
+            if (ang > 180)
+            {
+                ang -= 360 * Math.Ceiling((ang - 180) / 360);
+            }
+            if (ang <= -180)
+            {
+                ang -= 360 * Math.Floor((ang + 180) / 360);
+            }
+
+            return ang;
+        }
+
+        private Vector3d RadiusDirection(double theta)
+        {
+            theta = Math.PI * theta / 180;
+            var omega = Math.PI * FlightGlobals.ActiveVessel.orbit.argumentOfPeriapsis / 180;
+            var incl = Math.PI * FlightGlobals.ActiveVessel.orbit.inclination / 180;
+
+            var costheta = Math.Cos(theta);
+            var sintheta = Math.Sin(theta);
+            var cosomega = Math.Cos(omega);
+            var sinomega = Math.Sin(omega);
+            var cosincl = Math.Cos(incl);
+            var sinincl = Math.Sin(incl);
+
+            Vector3d result;
+
+            result.x = cosomega * costheta - sinomega * sintheta;
+            result.y = cosincl * (sinomega * costheta + cosomega * sintheta);
+            result.z = sinincl * (sinomega * costheta + cosomega * sintheta);
+
+            return result;
+        }
+
+        public static double ACosh(double x)
+        {
+            return (Math.Log(x + Math.Sqrt((x * x) - 1.0)));
+        }
+
+        private double TimeToPeriapsis(double theta)
+        {
+            var e = FlightGlobals.ActiveVessel.orbit.eccentricity;
+            var a = FlightGlobals.ActiveVessel.orbit.semiMajorAxis;
+            var rp = FlightGlobals.ActiveVessel.orbit.PeR;
+            var mu = FlightGlobals.ActiveVessel.mainBody.gravParameter;
+
+            if (e == 1.0)
+            {
+                var D = Math.Tan(Math.PI * theta / 360.0);
+                var M = D + D * D * D / 3.0;
+                return (Math.Sqrt(2.0 * rp * rp * rp / mu) * M);
+            }
+            if (a > 0)
+            {
+                var cosTheta = Math.Cos(Math.PI * theta / 180.0);
+                var cosE = (e + cosTheta) / (1.0 + e * cosTheta);
+                var radE = Math.Acos(cosE);
+                var M = radE - e * Math.Sin(radE);
+                return (Math.Sqrt(a * a * a / mu) * M);
+            }
+            if (a < 0)
+            {
+                var cosTheta = Math.Cos(Math.PI * theta / 180.0);
+                var coshF = (e + cosTheta) / (1.0 + e * cosTheta);
+                var radF = ACosh(coshF);
+                var M = e * Math.Sinh(radF) - radF;
+                return (Math.Sqrt(-a * a * a / mu) * M);
+            }
+
+            return 0;
+        }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/Flight/Readouts/Vessel/SimulationProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/SimulationProcessor.cs
@@ -1,70 +1,70 @@
-using System;

-using System.Collections.Generic;

-using System.Linq;

-using System.Text;

-

-using KerbalEngineer.VesselSimulator;

-

-namespace KerbalEngineer.Flight.Readouts.Vessel

-{

-    public class SimulationProcessor : IUpdatable, IUpdateRequest

-    {

-        #region Instance

-        private static readonly SimulationProcessor instance = new SimulationProcessor();

-

-        /// <summary>

-        ///     Gets the current instance of the simulation processor.

-        /// </summary>

-        public static SimulationProcessor Instance

-        {

-            get { return instance; }

-        }

-        #endregion

-

-        #region Properies

-

-        /// <summary>

-        ///     Gets whether the details are ready to be shown.

-        /// </summary>

-        public static bool ShowDetails { get; private set; }

-

-        /// <summary>

-        ///     Gets an array of the vessel stages.

-        /// </summary>

-        public static Stage[] Stages { get; private set; }

-

-        /// <summary>

-        ///     Gets the currently active vessel stage.

-        /// </summary>

-        public static Stage LastStage { get; private set; }

-

-        #endregion

-

-        public void Update()

-        {

-            SimManager.RequestSimulation();

-            SimManager.TryStartSimulation();

-

-            if (!SimManager.ResultsReady())

-            {

-                return;

-            }

-

-            Stages = SimManager.Stages;

-            LastStage = SimManager.LastStage;

-

-            if (Stages != null && LastStage != null)

-            {

-                ShowDetails = true;

-            }

-        }

-

-        public bool UpdateRequested { get; set; }

-

-        public static void RequestUpdate()

-        {

-            instance.UpdateRequested = true;

-        }

-    }

-}

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
 
+using KerbalEngineer.VesselSimulator;
+
+namespace KerbalEngineer.Flight.Readouts.Vessel
+{
+    public class SimulationProcessor : IUpdatable, IUpdateRequest
+    {
+        #region Instance
+        private static readonly SimulationProcessor instance = new SimulationProcessor();
+
+        /// <summary>
+        ///     Gets the current instance of the simulation processor.
+        /// </summary>
+        public static SimulationProcessor Instance
+        {
+            get { return instance; }
+        }
+        #endregion
+
+        #region Properies
+
+        /// <summary>
+        ///     Gets whether the details are ready to be shown.
+        /// </summary>
+        public static bool ShowDetails { get; private set; }
+
+        /// <summary>
+        ///     Gets an array of the vessel stages.
+        /// </summary>
+        public static Stage[] Stages { get; private set; }
+
+        /// <summary>
+        ///     Gets the currently active vessel stage.
+        /// </summary>
+        public static Stage LastStage { get; private set; }
+
+        #endregion
+
+        public void Update()
+        {
+            SimManager.RequestSimulation();
+            SimManager.TryStartSimulation();
+
+            if (!SimManager.ResultsReady())
+            {
+                return;
+            }
+
+            Stages = SimManager.Stages;
+            LastStage = SimManager.LastStage;
+
+            if (Stages != null && LastStage != null)
+            {
+                ShowDetails = true;
+            }
+        }
+
+        public bool UpdateRequested { get; set; }
+
+        public static void RequestUpdate()
+        {
+            instance.UpdateRequested = true;
+        }
+    }
+}
+

--- a/KerbalEngineer/Flight/Sections/SectionWindow.cs
+++ b/KerbalEngineer/Flight/Sections/SectionWindow.cs
@@ -1,156 +1,156 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region

-

-using KerbalEngineer.Extensions;

-

-using UnityEngine;

-

-#endregion

-

-namespace KerbalEngineer.Flight.Sections

-{

-    public class SectionWindow : MonoBehaviour

-    {

-        #region Fields

-

-        private bool resizeRequested;

-        private int windowId;

-        private Rect windowPosition;

-

-        #endregion

-

-        #region Constructors

-

-        /// <summary>

-        ///     Initialises the object's state on creation.

-        /// </summary>

-        private void Start()

-        {

-            this.windowId = this.GetHashCode();

-            this.InitialiseStyles();

-            RenderingManager.AddToPostDrawQueue(0, this.Draw);

-            GuiDisplaySize.OnSizeChanged += this.OnSizeChanged;

-        }

-

-        #endregion

-

-        #region Properties

-

-        /// <summary>

-        ///     Gets and sets the parent section for the floating section window.

-        /// </summary>

-        public SectionModule ParentSection { get; set; }

-

-        /// <summary>

-        ///     Gets and sets the window position.

-        /// </summary>

-        public Rect WindowPosition

-        {

-            get { return this.windowPosition; }

-            set { this.windowPosition = value; }

-        }

-

-        #endregion

-

-        #region GUIStyles

-

-        private GUIStyle windowStyle;

-

-        /// <summary>

-        ///     Initialises all the styles required for this object.

-        /// </summary>

-        private void InitialiseStyles()

-        {

-            this.windowStyle = new GUIStyle(HighLogic.Skin.window)

-            {

-                margin = new RectOffset(),

-                padding = new RectOffset(5, 5, 0, 5),

-            };

-        }

-

-        private void OnSizeChanged()

-        {

-            this.InitialiseStyles();

-            this.RequestResize();

-        }

-

-        #endregion

-

-        #region Drawing

-

-        /// <summary>

-        ///     Called to draw the floating section window when the UI is enabled.

-        /// </summary>

-        private void Draw()

-        {

-            if (!DisplayStack.Instance.Hidden && (this.ParentSection != null && this.ParentSection.IsVisible))

-            {

-                if (this.resizeRequested)

-                {

-                    this.windowPosition.width = 0;

-                    this.windowPosition.height = 0;

-                    this.resizeRequested = false;

-                }

-                GUI.skin = null;

-                this.windowPosition = GUILayout.Window(this.windowId, this.windowPosition, this.Window, string.Empty, this.windowStyle).ClampToScreen();

-                this.ParentSection.FloatingPositionX = this.windowPosition.x;

-                this.ParentSection.FloatingPositionY = this.windowPosition.y;

-            }

-        }

-

-        /// <summary>

-        ///     Draws the floating section window.

-        /// </summary>

-        private void Window(int windowId)

-        {

-            this.ParentSection.Draw();

-

-            GUI.DragWindow();

-        }

-

-        #endregion

-

-        #region Destruction

-

-        /// <summary>

-        ///     Runs when the object is destroyed.

-        /// </summary>

-        private void OnDestroy()

-        {

-            RenderingManager.RemoveFromPostDrawQueue(0, this.Draw);

-            GuiDisplaySize.OnSizeChanged -= this.OnSizeChanged;

-        }

-

-        #endregion

-

-        #region Methods

-

-        /// <summary>

-        ///     Request that the floating section window's size is reset in the next draw call.

-        /// </summary>

-        public void RequestResize()

-        {

-            this.resizeRequested = true;

-        }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region
+
+using KerbalEngineer.Extensions;
+
+using UnityEngine;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Sections
+{
+    public class SectionWindow : MonoBehaviour
+    {
+        #region Fields
+
+        private bool resizeRequested;
+        private int windowId;
+        private Rect windowPosition;
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        ///     Initialises the object's state on creation.
+        /// </summary>
+        private void Start()
+        {
+            this.windowId = this.GetHashCode();
+            this.InitialiseStyles();
+            RenderingManager.AddToPostDrawQueue(0, this.Draw);
+            GuiDisplaySize.OnSizeChanged += this.OnSizeChanged;
+        }
+
+        #endregion
+
+        #region Properties
+
+        /// <summary>
+        ///     Gets and sets the parent section for the floating section window.
+        /// </summary>
+        public SectionModule ParentSection { get; set; }
+
+        /// <summary>
+        ///     Gets and sets the window position.
+        /// </summary>
+        public Rect WindowPosition
+        {
+            get { return this.windowPosition; }
+            set { this.windowPosition = value; }
+        }
+
+        #endregion
+
+        #region GUIStyles
+
+        private GUIStyle windowStyle;
+
+        /// <summary>
+        ///     Initialises all the styles required for this object.
+        /// </summary>
+        private void InitialiseStyles()
+        {
+            this.windowStyle = new GUIStyle(HighLogic.Skin.window)
+            {
+                margin = new RectOffset(),
+                padding = new RectOffset(5, 5, 0, 5),
+            };
+        }
+
+        private void OnSizeChanged()
+        {
+            this.InitialiseStyles();
+            this.RequestResize();
+        }
+
+        #endregion
+
+        #region Drawing
+
+        /// <summary>
+        ///     Called to draw the floating section window when the UI is enabled.
+        /// </summary>
+        private void Draw()
+        {
+            if (!DisplayStack.Instance.Hidden && (this.ParentSection != null && this.ParentSection.IsVisible))
+            {
+                if (this.resizeRequested)
+                {
+                    this.windowPosition.width = 0;
+                    this.windowPosition.height = 0;
+                    this.resizeRequested = false;
+                }
+                GUI.skin = null;
+                this.windowPosition = GUILayout.Window(this.windowId, this.windowPosition, this.Window, string.Empty, this.windowStyle).ClampToScreen();
+                this.ParentSection.FloatingPositionX = this.windowPosition.x;
+                this.ParentSection.FloatingPositionY = this.windowPosition.y;
+            }
+        }
+
+        /// <summary>
+        ///     Draws the floating section window.
+        /// </summary>
+        private void Window(int windowId)
+        {
+            this.ParentSection.Draw();
+
+            GUI.DragWindow();
+        }
+
+        #endregion
+
+        #region Destruction
+
+        /// <summary>
+        ///     Runs when the object is destroyed.
+        /// </summary>
+        private void OnDestroy()
+        {
+            RenderingManager.RemoveFromPostDrawQueue(0, this.Draw);
+            GuiDisplaySize.OnSizeChanged -= this.OnSizeChanged;
+        }
+
+        #endregion
+
+        #region Methods
+
+        /// <summary>
+        ///     Request that the floating section window's size is reset in the next draw call.
+        /// </summary>
+        public void RequestResize()
+        {
+            this.resizeRequested = true;
+        }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/GuiDisplaySize.cs
+++ b/KerbalEngineer/GuiDisplaySize.cs
@@ -1,128 +1,128 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-using System;

-

-using KerbalEngineer.Settings;

-

-#endregion

-

-namespace KerbalEngineer

-{

-    public class GuiDisplaySize

-    {

-        #region Delegates

-

-        public delegate void SizeChanged();

-

-        #endregion

-

-        #region Fields

-

-        private static float multiplier = 1.1f;

-        private static int increment;

-        private static float offset;

-        public static event SizeChanged OnSizeChanged;

-

-        #endregion

-

-        #region Constructor

-

-        static GuiDisplaySize()

-        {

-            try

-            {

-                var handler = SettingHandler.Load("GuiDisplaySize.xml");

-                handler.GetSet("multiplier", ref multiplier);

-                handler.GetSet("increment", ref increment);

-                handler.Save("GuiDisplaySize.xml");

-                offset = 1 + (increment * multiplier) - increment;

-            }

-            catch (Exception ex)

-            {

-                Logger.Exception(ex, "GuiDisplaySize->GuiDisplaySize");

-            }

-        }

-

-        #endregion

-

-        #region Properties

-

-        public static float Multiplier

-        {

-            get { return multiplier; }

-            set

-            {

-                try

-                {

-                    if (multiplier == value)

-                    {

-                        return;

-                    }

-

-                    multiplier = value;

-                    var handler = SettingHandler.Load("GuiDisplaySize.xml");

-                    handler.Set("multiplier", multiplier);

-                    handler.Save("GuiDisplaySize.xml");

-                    offset = 1 + (increment * multiplier) - increment;

-                    OnSizeChanged();

-                }

-                catch (Exception ex)

-                {

-                    Logger.Exception(ex, "GuiDisplaySize->Multiplier");

-                }

-            }

-        }

-

-        public static int Increment

-        {

-            get { return increment; }

-            set

-            {

-                try

-                {

-                    if (increment == value)

-                    {

-                        return;

-                    }

-

-                    increment = value;

-                    var handler = SettingHandler.Load("GuiDisplaySize.xml");

-                    handler.Set("increment", increment);

-                    handler.Save("GuiDisplaySize.xml");

-                    offset = 1 + (increment * multiplier) - increment;

-                    OnSizeChanged();

-                }

-                catch (Exception ex)

-                {

-                    Logger.Exception(ex, "GuiDisplaySize->Increment");

-                }

-            }

-        }

-

-        public static float Offset

-        {

-            get { return offset; }

-        }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+using System;
+
+using KerbalEngineer.Settings;
+
+#endregion
+
+namespace KerbalEngineer
+{
+    public class GuiDisplaySize
+    {
+        #region Delegates
+
+        public delegate void SizeChanged();
+
+        #endregion
+
+        #region Fields
+
+        private static float multiplier = 1.1f;
+        private static int increment;
+        private static float offset;
+        public static event SizeChanged OnSizeChanged;
+
+        #endregion
+
+        #region Constructor
+
+        static GuiDisplaySize()
+        {
+            try
+            {
+                var handler = SettingHandler.Load("GuiDisplaySize.xml");
+                handler.GetSet("multiplier", ref multiplier);
+                handler.GetSet("increment", ref increment);
+                handler.Save("GuiDisplaySize.xml");
+                offset = 1 + (increment * multiplier) - increment;
+            }
+            catch (Exception ex)
+            {
+                Logger.Exception(ex, "GuiDisplaySize->GuiDisplaySize");
+            }
+        }
+
+        #endregion
+
+        #region Properties
+
+        public static float Multiplier
+        {
+            get { return multiplier; }
+            set
+            {
+                try
+                {
+                    if (multiplier == value)
+                    {
+                        return;
+                    }
+
+                    multiplier = value;
+                    var handler = SettingHandler.Load("GuiDisplaySize.xml");
+                    handler.Set("multiplier", multiplier);
+                    handler.Save("GuiDisplaySize.xml");
+                    offset = 1 + (increment * multiplier) - increment;
+                    OnSizeChanged();
+                }
+                catch (Exception ex)
+                {
+                    Logger.Exception(ex, "GuiDisplaySize->Multiplier");
+                }
+            }
+        }
+
+        public static int Increment
+        {
+            get { return increment; }
+            set
+            {
+                try
+                {
+                    if (increment == value)
+                    {
+                        return;
+                    }
+
+                    increment = value;
+                    var handler = SettingHandler.Load("GuiDisplaySize.xml");
+                    handler.Set("increment", increment);
+                    handler.Save("GuiDisplaySize.xml");
+                    offset = 1 + (increment * multiplier) - increment;
+                    OnSizeChanged();
+                }
+                catch (Exception ex)
+                {
+                    Logger.Exception(ex, "GuiDisplaySize->Increment");
+                }
+            }
+        }
+
+        public static float Offset
+        {
+            get { return offset; }
+        }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/KerbalEngineer.csproj
+++ b/KerbalEngineer/KerbalEngineer.csproj
@@ -65,6 +65,7 @@
     <Compile Include="Flight\FlightEngineerPartless.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\Separator.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\GuiSizeAdjustor.cs" />
+    <Compile Include="Flight\Readouts\Orbital\TrueAnomaly.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToAscendingNode.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToDescendingNode.cs" />
     <Compile Include="Flight\Readouts\Rendezvous\TimeToAscendingNode.cs" />

--- a/KerbalEngineer/LogMsg.cs
+++ b/KerbalEngineer/LogMsg.cs
@@ -1,7 +1,7 @@
-using System.Text;

-

-using UnityEngine;

-

+using System.Text;
+
+using UnityEngine;
+
 namespace KerbalEngineer
 {
     public class LogMsg

--- a/KerbalEngineer/Settings/SettingHandler.cs
+++ b/KerbalEngineer/Settings/SettingHandler.cs
@@ -1,256 +1,256 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-using System;

-using System.Collections.Generic;

-using System.IO;

-using System.Linq;

-using System.Xml.Serialization;

-

-#endregion

-

-namespace KerbalEngineer.Settings

-{

-    /// <summary>

-    ///     Handles the management of setting items.

-    /// </summary>

-    public class SettingHandler

-    {

-        #region Static Fields

-

-        /// <summary>

-        ///     Stores the root settings directory for where all files will be saved.

-        /// </summary>

-        private static string settingsDirectory;

-

-        #endregion

-

-        #region Constructors

-

-        /// <summary>

-        ///     Sets the root settings directory if statically loaded.

-        /// </summary>

-        static SettingHandler()

-        {

-            if (settingsDirectory == null)

-            {

-                settingsDirectory = Path.Combine(EngineerGlobals.AssemblyPath, "Settings");

-            }

-        }

-

-        /// <summary>

-        ///     Creates an empty handler for managing setting items.

-        /// </summary>

-        public SettingHandler()

-        {

-            if (settingsDirectory == null)

-            {

-                settingsDirectory = Path.Combine(EngineerGlobals.AssemblyPath, "Settings");

-            }

-

-            this.Items = new List<SettingItem>();

-        }

-

-        #endregion

-

-        #region Properties

-

-        /// <summary>

-        ///     Gets and sets the list of items.

-        /// </summary>

-        public List<SettingItem> Items { get; set; }

-

-        #endregion

-

-        #region Get Methods

-

-        /// <summary>

-        ///     Gets a setting object from its name or returns the default object.

-        /// </summary>

-        public T Get<T>(string name, T defaultObject)

-        {

-            foreach (var item in this.Items)

-            {

-                if (item.Name == name)

-                {

-                    return (T)Convert.ChangeType(item.Value, typeof(T));

-                }

-            }

-            return defaultObject;

-        }

-

-        /// <summary>

-        ///     Gets a setting object from its name and inputs it into the output object.  Returns true if a setting was found,

-        ///     false if not.

-        /// </summary>

-        public bool Get<T>(string name, ref T outputObject)

-        {

-            foreach (var item in this.Items)

-            {

-                if (item.Name == name)

-                {

-                    outputObject = (T)Convert.ChangeType(item.Value, typeof(T));

-                    return true;

-                }

-            }

-            return false;

-        }

-

-        #endregion

-

-        #region Set Methods

-

-        /// <summary>

-        ///     Sets a setting object from its name or creates one if it does not already exist.

-        /// </summary>

-        public void Set(string name, object value)

-        {

-            foreach (var item in this.Items)

-            {

-                if (item.Name == name)

-                {

-                    item.Value = value;

-                    return;

-                }

-            }

-            this.Items.Add(new SettingItem(name, value));

-        }

-

-        #endregion

-

-        #region GetSet Methods

-

-        /// <summary>

-        ///     Gets a setting from its name or return the default object. Will add the object to the handler if it does not exist.

-        /// </summary>

-        public T GetSet<T>(string name, T defaultObject)

-        {

-            foreach (var item in this.Items)

-            {

-                if (item.Name == name)

-                {

-                    return (T)Convert.ChangeType(item.Value, typeof(T));

-                }

-            }

-            if (defaultObject != null)

-            {

-                this.Items.Add(new SettingItem(name, defaultObject));

-            }

-            return defaultObject;

-        }

-

-        /// <summary>

-        ///     Gets a setting from its name and inputs it into the output object. Will add the object to the handler if it does

-        ///     not exist.

-        /// </summary>

-        public bool GetSet<T>(string name, ref T outputObject)

-        {

-            foreach (var item in this.Items)

-            {

-                if (item.Name == name)

-                {

-                    outputObject = (T)Convert.ChangeType(item.Value, typeof(T));

-                    return true;

-                }

-            }

-            if (outputObject != null)

-            {

-                this.Items.Add(new SettingItem(name, outputObject));

-            }

-            return false;

-        }

-

-        #endregion

-

-        #region Saving

-

-        /// <summary>

-        ///     Saves all the items in the handler into the specified file.

-        /// </summary>

-        public void Save(string fileName)

-        {

-            fileName = Path.Combine(settingsDirectory, fileName);

-

-            this.Serialise(fileName);

-        }

-

-        /// <summary>

-        ///     Serialises all the items into an xml file.

-        /// </summary>

-        private void Serialise(string fileName)

-        {

-            this.CreateDirectory(fileName);

-            using (var stream = new FileStream(fileName, FileMode.Create))

-            {

-                new XmlSerializer(typeof(List<SettingItem>), this.Items.Select(s => s.Value.GetType()).ToArray()).Serialize(stream, this.Items);

-                stream.Close();

-            }

-        }

-

-        /// <summary>

-        ///     Creates a directory if it does not already exist.

-        /// </summary>

-        private void CreateDirectory(string fileName)

-        {

-            var filePath = new FileInfo(fileName).DirectoryName;

-            if (!Directory.Exists(filePath))

-            {

-                Directory.CreateDirectory(filePath);

-            }

-        }

-

-        #endregion

-

-        #region Loading

-

-        /// <summary>

-        ///     Returns a SettingHandler object created from the specified file. (Optional extra types are required for

-        ///     non-primitive items.)

-        /// </summary>

-        public static SettingHandler Load(string fileName, Type[] extraTypes = null)

-        {

-            fileName = Path.Combine(settingsDirectory, fileName);

-

-            return Deserialise(fileName, extraTypes);

-        }

-

-        /// <summary>

-        ///     Returns a SettingHandler object containing items deserialized from the specified file.

-        /// </summary>

-        private static SettingHandler Deserialise(string fileName, Type[] extraTypes)

-        {

-            if (!File.Exists(fileName))

-            {

-                return new SettingHandler();

-            }

-

-            var handler = new SettingHandler();

-            using (var stream = new FileStream(fileName, FileMode.Open))

-            {

-                handler.Items = new XmlSerializer(typeof(List<SettingItem>), extraTypes).Deserialize(stream) as List<SettingItem>;

-                stream.Close();

-            }

-            return handler;

-        }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml.Serialization;
+
+#endregion
+
+namespace KerbalEngineer.Settings
+{
+    /// <summary>
+    ///     Handles the management of setting items.
+    /// </summary>
+    public class SettingHandler
+    {
+        #region Static Fields
+
+        /// <summary>
+        ///     Stores the root settings directory for where all files will be saved.
+        /// </summary>
+        private static string settingsDirectory;
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        ///     Sets the root settings directory if statically loaded.
+        /// </summary>
+        static SettingHandler()
+        {
+            if (settingsDirectory == null)
+            {
+                settingsDirectory = Path.Combine(EngineerGlobals.AssemblyPath, "Settings");
+            }
+        }
+
+        /// <summary>
+        ///     Creates an empty handler for managing setting items.
+        /// </summary>
+        public SettingHandler()
+        {
+            if (settingsDirectory == null)
+            {
+                settingsDirectory = Path.Combine(EngineerGlobals.AssemblyPath, "Settings");
+            }
+
+            this.Items = new List<SettingItem>();
+        }
+
+        #endregion
+
+        #region Properties
+
+        /// <summary>
+        ///     Gets and sets the list of items.
+        /// </summary>
+        public List<SettingItem> Items { get; set; }
+
+        #endregion
+
+        #region Get Methods
+
+        /// <summary>
+        ///     Gets a setting object from its name or returns the default object.
+        /// </summary>
+        public T Get<T>(string name, T defaultObject)
+        {
+            foreach (var item in this.Items)
+            {
+                if (item.Name == name)
+                {
+                    return (T)Convert.ChangeType(item.Value, typeof(T));
+                }
+            }
+            return defaultObject;
+        }
+
+        /// <summary>
+        ///     Gets a setting object from its name and inputs it into the output object.  Returns true if a setting was found,
+        ///     false if not.
+        /// </summary>
+        public bool Get<T>(string name, ref T outputObject)
+        {
+            foreach (var item in this.Items)
+            {
+                if (item.Name == name)
+                {
+                    outputObject = (T)Convert.ChangeType(item.Value, typeof(T));
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        #endregion
+
+        #region Set Methods
+
+        /// <summary>
+        ///     Sets a setting object from its name or creates one if it does not already exist.
+        /// </summary>
+        public void Set(string name, object value)
+        {
+            foreach (var item in this.Items)
+            {
+                if (item.Name == name)
+                {
+                    item.Value = value;
+                    return;
+                }
+            }
+            this.Items.Add(new SettingItem(name, value));
+        }
+
+        #endregion
+
+        #region GetSet Methods
+
+        /// <summary>
+        ///     Gets a setting from its name or return the default object. Will add the object to the handler if it does not exist.
+        /// </summary>
+        public T GetSet<T>(string name, T defaultObject)
+        {
+            foreach (var item in this.Items)
+            {
+                if (item.Name == name)
+                {
+                    return (T)Convert.ChangeType(item.Value, typeof(T));
+                }
+            }
+            if (defaultObject != null)
+            {
+                this.Items.Add(new SettingItem(name, defaultObject));
+            }
+            return defaultObject;
+        }
+
+        /// <summary>
+        ///     Gets a setting from its name and inputs it into the output object. Will add the object to the handler if it does
+        ///     not exist.
+        /// </summary>
+        public bool GetSet<T>(string name, ref T outputObject)
+        {
+            foreach (var item in this.Items)
+            {
+                if (item.Name == name)
+                {
+                    outputObject = (T)Convert.ChangeType(item.Value, typeof(T));
+                    return true;
+                }
+            }
+            if (outputObject != null)
+            {
+                this.Items.Add(new SettingItem(name, outputObject));
+            }
+            return false;
+        }
+
+        #endregion
+
+        #region Saving
+
+        /// <summary>
+        ///     Saves all the items in the handler into the specified file.
+        /// </summary>
+        public void Save(string fileName)
+        {
+            fileName = Path.Combine(settingsDirectory, fileName);
+
+            this.Serialise(fileName);
+        }
+
+        /// <summary>
+        ///     Serialises all the items into an xml file.
+        /// </summary>
+        private void Serialise(string fileName)
+        {
+            this.CreateDirectory(fileName);
+            using (var stream = new FileStream(fileName, FileMode.Create))
+            {
+                new XmlSerializer(typeof(List<SettingItem>), this.Items.Select(s => s.Value.GetType()).ToArray()).Serialize(stream, this.Items);
+                stream.Close();
+            }
+        }
+
+        /// <summary>
+        ///     Creates a directory if it does not already exist.
+        /// </summary>
+        private void CreateDirectory(string fileName)
+        {
+            var filePath = new FileInfo(fileName).DirectoryName;
+            if (!Directory.Exists(filePath))
+            {
+                Directory.CreateDirectory(filePath);
+            }
+        }
+
+        #endregion
+
+        #region Loading
+
+        /// <summary>
+        ///     Returns a SettingHandler object created from the specified file. (Optional extra types are required for
+        ///     non-primitive items.)
+        /// </summary>
+        public static SettingHandler Load(string fileName, Type[] extraTypes = null)
+        {
+            fileName = Path.Combine(settingsDirectory, fileName);
+
+            return Deserialise(fileName, extraTypes);
+        }
+
+        /// <summary>
+        ///     Returns a SettingHandler object containing items deserialized from the specified file.
+        /// </summary>
+        private static SettingHandler Deserialise(string fileName, Type[] extraTypes)
+        {
+            if (!File.Exists(fileName))
+            {
+                return new SettingHandler();
+            }
+
+            var handler = new SettingHandler();
+            using (var stream = new FileStream(fileName, FileMode.Open))
+            {
+                handler.Items = new XmlSerializer(typeof(List<SettingItem>), extraTypes).Deserialize(stream) as List<SettingItem>;
+                stream.Close();
+            }
+            return handler;
+        }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/Settings/SettingItem.cs
+++ b/KerbalEngineer/Settings/SettingItem.cs
@@ -1,63 +1,63 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-#endregion

-

-namespace KerbalEngineer.Settings

-{

-    /// <summary>

-    ///     A serialisable object for storing an item's name and value.

-    /// </summary>

-    public class SettingItem

-    {

-        #region Constructors

-

-        /// <summary>

-        ///     Creates and empty item object.

-        /// </summary>

-        public SettingItem() { }

-

-        /// <summary>

-        ///     Creates an item object containing a name and value.

-        /// </summary>

-        public SettingItem(string name, object value)

-        {

-            this.Name = name;

-            this.Value = value;

-        }

-

-        #endregion

-

-        #region Properties

-

-        /// <summary>

-        ///     Gets and sets the name of the item.

-        /// </summary>

-        public string Name { get; set; }

-

-        /// <summary>

-        ///     Gets and sets the object value of the item.

-        /// </summary>

-        public object Value { get; set; }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+#endregion
+
+namespace KerbalEngineer.Settings
+{
+    /// <summary>
+    ///     A serialisable object for storing an item's name and value.
+    /// </summary>
+    public class SettingItem
+    {
+        #region Constructors
+
+        /// <summary>
+        ///     Creates and empty item object.
+        /// </summary>
+        public SettingItem() { }
+
+        /// <summary>
+        ///     Creates an item object containing a name and value.
+        /// </summary>
+        public SettingItem(string name, object value)
+        {
+            this.Name = name;
+            this.Value = value;
+        }
+
+        #endregion
+
+        #region Properties
+
+        /// <summary>
+        ///     Gets and sets the name of the item.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        ///     Gets and sets the object value of the item.
+        /// </summary>
+        public object Value { get; set; }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/TapeDriveAnimator.cs
+++ b/KerbalEngineer/TapeDriveAnimator.cs
@@ -1,389 +1,389 @@
-// 

-//     Kerbal Engineer Redux

-// 

-//     Copyright (C) 2014 CYBUTEK

-// 

-//     This program is free software: you can redistribute it and/or modify

-//     it under the terms of the GNU General Public License as published by

-//     the Free Software Foundation, either version 3 of the License, or

-//     (at your option) any later version.

-// 

-//     This program is distributed in the hope that it will be useful,

-//     but WITHOUT ANY WARRANTY; without even the implied warranty of

-//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

-//     GNU General Public License for more details.

-// 

-//     You should have received a copy of the GNU General Public License

-//     along with this program.  If not, see <http://www.gnu.org/licenses/>.

-// 

-

-#region Using Directives

-

-using UnityEngine;

-

-using Random = System.Random;

-

-#endregion

-

-namespace KerbalEngineer

-{

-    public class TapeDriveAnimator : PartModule

-    {

-        #region Public Fields

-

-        [KSPField] public string Lights1 = "";

-        [KSPField] public float Lights1Speed = 0;

-        [KSPField] public string Lights2 = "";

-        [KSPField] public float Lights2Speed = 0;

-        [KSPField] public string Lights3 = "";

-        [KSPField] public float Lights3Speed = 0;

-        [KSPField] public string Lights4 = "";

-        [KSPField] public float Lights4Speed = 0;

-        [KSPField] public string Lights5 = "";

-        [KSPField] public float Lights5Speed = 0;

-        [KSPField] public string Lights6 = "";

-        [KSPField] public float Lights6Speed = 0;

-        [KSPField] public int MaxReelSpeed = 0;

-        [KSPField] public int MaxRepeatTime = 0;

-        [KSPField] public int MinReelSpeed = 0;

-        [KSPField] public int MinRepeatTime = 0;

-        [KSPField] public string Reel1 = "";

-        [KSPField] public float Reel1SpeedRatio = 1;

-        [KSPField] public string Reel2 = "";

-        [KSPField] public float Reel2SpeedRatio = 1;

-        [KSPField] public float RepeatTimeDenominator = 1;

-        [KSPField] public float SpeedChangeAmount = 0;

-        [KSPField] public float SpeedDeadZone = 0;

-        [KSPField] public float SpeedStopZone = 0;

-        [KSPField] public bool UseBakedAnimation = false;

-

-        #endregion

-

-        #region Private Fields

-

-        private float currentTime;

-        private float deltaTime;

-        private Shader lights1ShaderOff;

-        private Transform lights1Transform;

-        private Shader lights2ShaderOff;

-        private Transform lights2Transform;

-        private Shader lights3ShaderOff;

-        private Transform lights3Transform;

-        private Shader lights4ShaderOff;

-        private Transform lights4Transform;

-        private Shader lights5ShaderOff;

-        private Transform lights5Transform;

-        private Shader lights6ShaderOff;

-        private Transform lights6Transform;

-        private Shader lightsShaderOn;

-        private Random random;

-        private Transform reel1Transform;

-        private Transform reel2Transform;

-        private float repeatTime;

-        private bool sceneIsEditor;

-        private float speed;

-        private float targetSpeed;

-

-        #endregion

-

-        #region Properties

-

-        private bool isRunning;

-

-        public bool IsRunning

-        {

-            get { return this.isRunning; }

-            set

-            {

-                this.isRunning = value;

-

-                if (this.isRunning)

-                {

-                    if (this.UseBakedAnimation)

-                    {

-                        this.StartBakedAnimation();

-                    }

-                }

-                else

-                {

-                    if (this.UseBakedAnimation)

-                    {

-                        this.StopBakedAnimation();

-                    }

-                }

-            }

-        }

-

-        #endregion

-

-        #region Initialisation

-

-        public override void OnStart(StartState state)

-        {

-            this.random = new Random();

-

-            this.StopBakedAnimation();

-            this.IsRunning = false;

-

-            if (HighLogic.LoadedSceneIsEditor)

-            {

-                this.part.OnEditorAttach += this.OnEditorAttach;

-                this.part.OnEditorDetach += this.OnEditorDetach;

-

-                this.sceneIsEditor = true;

-

-                if (this.part.parent != null)

-                {

-                    this.IsRunning = true;

-                }

-            }

-            else if (HighLogic.LoadedSceneIsFlight)

-            {

-                this.IsRunning = true;

-            }

-

-            if (!this.UseBakedAnimation)

-            {

-                this.InitialiseReels();

-                this.InitialiseLights();

-            }

-        }

-

-        private void InitialiseReels()

-        {

-            if (this.Reel1 != "")

-            {

-                this.reel1Transform = this.part.FindModelTransform(this.Reel1);

-            }

-

-            if (this.Reel2 != "")

-            {

-                this.reel2Transform = this.part.FindModelTransform(this.Reel2);

-            }

-        }

-

-        private void InitialiseLights()

-        {

-            if (this.Lights1 != "")

-            {

-                this.lights1Transform = this.part.FindModelTransform(this.Lights1);

-                this.lights1ShaderOff = this.lights1Transform.renderer.material.shader;

-            }

-

-            if (this.Lights2 != "")

-            {

-                this.lights2Transform = this.part.FindModelTransform(this.Lights2);

-                this.lights2ShaderOff = this.lights2Transform.renderer.material.shader;

-            }

-

-            if (this.Lights3 != "")

-            {

-                this.lights3Transform = this.part.FindModelTransform(this.Lights3);

-                this.lights3ShaderOff = this.lights3Transform.renderer.material.shader;

-            }

-

-            if (this.Lights4 != "")

-            {

-                this.lights4Transform = this.part.FindModelTransform(this.Lights4);

-                this.lights4ShaderOff = this.lights4Transform.renderer.material.shader;

-            }

-

-            if (this.Lights5 != "")

-            {

-                this.lights5Transform = this.part.FindModelTransform(this.Lights5);

-                this.lights5ShaderOff = this.lights5Transform.renderer.material.shader;

-            }

-

-            if (this.Lights6 != "")

-            {

-                this.lights6Transform = this.part.FindModelTransform(this.Lights6);

-                this.lights6ShaderOff = this.lights6Transform.renderer.material.shader;

-            }

-

-            this.lightsShaderOn = Shader.Find("Unlit/Texture");

-        }

-

-        #endregion

-

-        #region Updating

-

-        public override void OnUpdate()

-        {

-            if (!this.UseBakedAnimation)

-            {

-                this.deltaTime = this.sceneIsEditor ? Time.deltaTime : TimeWarp.deltaTime;

-

-                if (TimeWarp.CurrentRate != 1.0f && TimeWarp.WarpMode != TimeWarp.Modes.LOW)

-                {

-                    return;

-                }

-

-                if (this.IsRunning)

-                {

-                    this.UpdateTimerCycle();

-                    this.UpdateSpeed();

-                    this.UpdateReels();

-                    this.UpdateLights();

-                }

-                else

-                {

-                    this.targetSpeed = 0;

-

-                    if (this.speed != 0)

-                    {

-                        this.UpdateSpeed();

-                        this.UpdateReels();

-                        this.UpdateLights();

-                    }

-                }

-            }

-        }

-

-        private void Update()

-        {

-            if (this.sceneIsEditor)

-            {

-                this.OnUpdate();

-            }

-        }

-

-        private void OnEditorAttach()

-        {

-            this.IsRunning = true;

-        }

-

-        private void OnEditorDetach()

-        {

-            this.IsRunning = false;

-        }

-

-        private void StopBakedAnimation()

-        {

-            foreach (var animator in this.part.FindModelAnimators())

-            {

-                animator.Stop();

-            }

-        }

-

-        private void StartBakedAnimation()

-        {

-            foreach (var animator in this.part.FindModelAnimators())

-            {

-                animator.Play();

-            }

-        }

-

-        private void UpdateTimerCycle()

-        {

-            this.currentTime += this.deltaTime;

-

-            if (this.currentTime >= this.repeatTime)

-            {

-                this.targetSpeed = this.random.Next(this.MinReelSpeed, this.MaxReelSpeed);

-

-                if (this.targetSpeed > -this.SpeedStopZone && this.targetSpeed < this.SpeedStopZone)

-                {

-                    this.targetSpeed = 0;

-                }

-

-                this.repeatTime = this.random.Next(this.MinRepeatTime, this.MaxRepeatTime);

-

-                if (this.RepeatTimeDenominator != 0)

-                {

-                    this.repeatTime /= this.RepeatTimeDenominator;

-                }

-

-                this.currentTime -= this.repeatTime;

-            }

-        }

-

-        private void UpdateSpeed()

-        {

-            if (this.speed < this.targetSpeed)

-            {

-                if (this.speed < this.targetSpeed - this.SpeedDeadZone)

-                {

-                    this.speed += this.SpeedChangeAmount * this.deltaTime;

-                }

-                else

-                {

-                    this.speed = this.targetSpeed;

-                }

-            }

-            else if (this.speed > this.targetSpeed)

-            {

-                if (this.speed > this.targetSpeed + this.SpeedDeadZone)

-                {

-                    this.speed -= this.SpeedChangeAmount * this.deltaTime;

-                }

-                else

-                {

-                    this.speed = this.targetSpeed;

-                }

-            }

-        }

-

-        private void UpdateReels()

-        {

-            if (this.reel1Transform != null && this.speed != 0)

-            {

-                this.reel1Transform.transform.Rotate(Vector3.right, this.speed * this.Reel1SpeedRatio);

-            }

-

-            if (this.reel2Transform != null && this.speed != 0)

-            {

-                this.reel2Transform.transform.Rotate(Vector3.right, this.speed * this.Reel2SpeedRatio);

-            }

-        }

-

-        private void UpdateLights()

-        {

-            if (this.lights1Transform != null)

-            {

-                this.UpdateLightTransform(this.lights1Transform, this.lightsShaderOn, this.lights1ShaderOff, this.Lights1Speed);

-            }

-            if (this.lights2Transform != null)

-            {

-                this.UpdateLightTransform(this.lights2Transform, this.lightsShaderOn, this.lights2ShaderOff, this.Lights2Speed);

-            }

-            if (this.lights3Transform != null)

-            {

-                this.UpdateLightTransform(this.lights3Transform, this.lightsShaderOn, this.lights3ShaderOff, this.Lights3Speed);

-            }

-            if (this.lights4Transform != null)

-            {

-                this.UpdateLightTransform(this.lights4Transform, this.lightsShaderOn, this.lights4ShaderOff, this.Lights4Speed);

-            }

-            if (this.lights5Transform != null)

-            {

-                this.UpdateLightTransform(this.lights5Transform, this.lightsShaderOn, this.lights5ShaderOff, this.Lights5Speed);

-            }

-            if (this.lights6Transform != null)

-            {

-                this.UpdateLightTransform(this.lights6Transform, this.lightsShaderOn, this.lights6ShaderOff, this.Lights6Speed);

-            }

-        }

-

-        private void UpdateLightTransform(Component lights, Shader on, Shader off, float targetSpeed)

-        {

-            bool lightsOn;

-

-            if (targetSpeed > 0)

-            {

-                lightsOn = (this.speed > targetSpeed);

-            }

-            else if (targetSpeed < 0)

-            {

-                lightsOn = (this.speed < targetSpeed);

-            }

-            else

-            {

-                lightsOn = (this.speed == 0);

-            }

-

-            lights.renderer.material.shader = lightsOn ? @on : off;

-        }

-

-        #endregion

-    }

+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
+
+#region Using Directives
+
+using UnityEngine;
+
+using Random = System.Random;
+
+#endregion
+
+namespace KerbalEngineer
+{
+    public class TapeDriveAnimator : PartModule
+    {
+        #region Public Fields
+
+        [KSPField] public string Lights1 = "";
+        [KSPField] public float Lights1Speed = 0;
+        [KSPField] public string Lights2 = "";
+        [KSPField] public float Lights2Speed = 0;
+        [KSPField] public string Lights3 = "";
+        [KSPField] public float Lights3Speed = 0;
+        [KSPField] public string Lights4 = "";
+        [KSPField] public float Lights4Speed = 0;
+        [KSPField] public string Lights5 = "";
+        [KSPField] public float Lights5Speed = 0;
+        [KSPField] public string Lights6 = "";
+        [KSPField] public float Lights6Speed = 0;
+        [KSPField] public int MaxReelSpeed = 0;
+        [KSPField] public int MaxRepeatTime = 0;
+        [KSPField] public int MinReelSpeed = 0;
+        [KSPField] public int MinRepeatTime = 0;
+        [KSPField] public string Reel1 = "";
+        [KSPField] public float Reel1SpeedRatio = 1;
+        [KSPField] public string Reel2 = "";
+        [KSPField] public float Reel2SpeedRatio = 1;
+        [KSPField] public float RepeatTimeDenominator = 1;
+        [KSPField] public float SpeedChangeAmount = 0;
+        [KSPField] public float SpeedDeadZone = 0;
+        [KSPField] public float SpeedStopZone = 0;
+        [KSPField] public bool UseBakedAnimation = false;
+
+        #endregion
+
+        #region Private Fields
+
+        private float currentTime;
+        private float deltaTime;
+        private Shader lights1ShaderOff;
+        private Transform lights1Transform;
+        private Shader lights2ShaderOff;
+        private Transform lights2Transform;
+        private Shader lights3ShaderOff;
+        private Transform lights3Transform;
+        private Shader lights4ShaderOff;
+        private Transform lights4Transform;
+        private Shader lights5ShaderOff;
+        private Transform lights5Transform;
+        private Shader lights6ShaderOff;
+        private Transform lights6Transform;
+        private Shader lightsShaderOn;
+        private Random random;
+        private Transform reel1Transform;
+        private Transform reel2Transform;
+        private float repeatTime;
+        private bool sceneIsEditor;
+        private float speed;
+        private float targetSpeed;
+
+        #endregion
+
+        #region Properties
+
+        private bool isRunning;
+
+        public bool IsRunning
+        {
+            get { return this.isRunning; }
+            set
+            {
+                this.isRunning = value;
+
+                if (this.isRunning)
+                {
+                    if (this.UseBakedAnimation)
+                    {
+                        this.StartBakedAnimation();
+                    }
+                }
+                else
+                {
+                    if (this.UseBakedAnimation)
+                    {
+                        this.StopBakedAnimation();
+                    }
+                }
+            }
+        }
+
+        #endregion
+
+        #region Initialisation
+
+        public override void OnStart(StartState state)
+        {
+            this.random = new Random();
+
+            this.StopBakedAnimation();
+            this.IsRunning = false;
+
+            if (HighLogic.LoadedSceneIsEditor)
+            {
+                this.part.OnEditorAttach += this.OnEditorAttach;
+                this.part.OnEditorDetach += this.OnEditorDetach;
+
+                this.sceneIsEditor = true;
+
+                if (this.part.parent != null)
+                {
+                    this.IsRunning = true;
+                }
+            }
+            else if (HighLogic.LoadedSceneIsFlight)
+            {
+                this.IsRunning = true;
+            }
+
+            if (!this.UseBakedAnimation)
+            {
+                this.InitialiseReels();
+                this.InitialiseLights();
+            }
+        }
+
+        private void InitialiseReels()
+        {
+            if (this.Reel1 != "")
+            {
+                this.reel1Transform = this.part.FindModelTransform(this.Reel1);
+            }
+
+            if (this.Reel2 != "")
+            {
+                this.reel2Transform = this.part.FindModelTransform(this.Reel2);
+            }
+        }
+
+        private void InitialiseLights()
+        {
+            if (this.Lights1 != "")
+            {
+                this.lights1Transform = this.part.FindModelTransform(this.Lights1);
+                this.lights1ShaderOff = this.lights1Transform.renderer.material.shader;
+            }
+
+            if (this.Lights2 != "")
+            {
+                this.lights2Transform = this.part.FindModelTransform(this.Lights2);
+                this.lights2ShaderOff = this.lights2Transform.renderer.material.shader;
+            }
+
+            if (this.Lights3 != "")
+            {
+                this.lights3Transform = this.part.FindModelTransform(this.Lights3);
+                this.lights3ShaderOff = this.lights3Transform.renderer.material.shader;
+            }
+
+            if (this.Lights4 != "")
+            {
+                this.lights4Transform = this.part.FindModelTransform(this.Lights4);
+                this.lights4ShaderOff = this.lights4Transform.renderer.material.shader;
+            }
+
+            if (this.Lights5 != "")
+            {
+                this.lights5Transform = this.part.FindModelTransform(this.Lights5);
+                this.lights5ShaderOff = this.lights5Transform.renderer.material.shader;
+            }
+
+            if (this.Lights6 != "")
+            {
+                this.lights6Transform = this.part.FindModelTransform(this.Lights6);
+                this.lights6ShaderOff = this.lights6Transform.renderer.material.shader;
+            }
+
+            this.lightsShaderOn = Shader.Find("Unlit/Texture");
+        }
+
+        #endregion
+
+        #region Updating
+
+        public override void OnUpdate()
+        {
+            if (!this.UseBakedAnimation)
+            {
+                this.deltaTime = this.sceneIsEditor ? Time.deltaTime : TimeWarp.deltaTime;
+
+                if (TimeWarp.CurrentRate != 1.0f && TimeWarp.WarpMode != TimeWarp.Modes.LOW)
+                {
+                    return;
+                }
+
+                if (this.IsRunning)
+                {
+                    this.UpdateTimerCycle();
+                    this.UpdateSpeed();
+                    this.UpdateReels();
+                    this.UpdateLights();
+                }
+                else
+                {
+                    this.targetSpeed = 0;
+
+                    if (this.speed != 0)
+                    {
+                        this.UpdateSpeed();
+                        this.UpdateReels();
+                        this.UpdateLights();
+                    }
+                }
+            }
+        }
+
+        private void Update()
+        {
+            if (this.sceneIsEditor)
+            {
+                this.OnUpdate();
+            }
+        }
+
+        private void OnEditorAttach()
+        {
+            this.IsRunning = true;
+        }
+
+        private void OnEditorDetach()
+        {
+            this.IsRunning = false;
+        }
+
+        private void StopBakedAnimation()
+        {
+            foreach (var animator in this.part.FindModelAnimators())
+            {
+                animator.Stop();
+            }
+        }
+
+        private void StartBakedAnimation()
+        {
+            foreach (var animator in this.part.FindModelAnimators())
+            {
+                animator.Play();
+            }
+        }
+
+        private void UpdateTimerCycle()
+        {
+            this.currentTime += this.deltaTime;
+
+            if (this.currentTime >= this.repeatTime)
+            {
+                this.targetSpeed = this.random.Next(this.MinReelSpeed, this.MaxReelSpeed);
+
+                if (this.targetSpeed > -this.SpeedStopZone && this.targetSpeed < this.SpeedStopZone)
+                {
+                    this.targetSpeed = 0;
+                }
+
+                this.repeatTime = this.random.Next(this.MinRepeatTime, this.MaxRepeatTime);
+
+                if (this.RepeatTimeDenominator != 0)
+                {
+                    this.repeatTime /= this.RepeatTimeDenominator;
+                }
+
+                this.currentTime -= this.repeatTime;
+            }
+        }
+
+        private void UpdateSpeed()
+        {
+            if (this.speed < this.targetSpeed)
+            {
+                if (this.speed < this.targetSpeed - this.SpeedDeadZone)
+                {
+                    this.speed += this.SpeedChangeAmount * this.deltaTime;
+                }
+                else
+                {
+                    this.speed = this.targetSpeed;
+                }
+            }
+            else if (this.speed > this.targetSpeed)
+            {
+                if (this.speed > this.targetSpeed + this.SpeedDeadZone)
+                {
+                    this.speed -= this.SpeedChangeAmount * this.deltaTime;
+                }
+                else
+                {
+                    this.speed = this.targetSpeed;
+                }
+            }
+        }
+
+        private void UpdateReels()
+        {
+            if (this.reel1Transform != null && this.speed != 0)
+            {
+                this.reel1Transform.transform.Rotate(Vector3.right, this.speed * this.Reel1SpeedRatio);
+            }
+
+            if (this.reel2Transform != null && this.speed != 0)
+            {
+                this.reel2Transform.transform.Rotate(Vector3.right, this.speed * this.Reel2SpeedRatio);
+            }
+        }
+
+        private void UpdateLights()
+        {
+            if (this.lights1Transform != null)
+            {
+                this.UpdateLightTransform(this.lights1Transform, this.lightsShaderOn, this.lights1ShaderOff, this.Lights1Speed);
+            }
+            if (this.lights2Transform != null)
+            {
+                this.UpdateLightTransform(this.lights2Transform, this.lightsShaderOn, this.lights2ShaderOff, this.Lights2Speed);
+            }
+            if (this.lights3Transform != null)
+            {
+                this.UpdateLightTransform(this.lights3Transform, this.lightsShaderOn, this.lights3ShaderOff, this.Lights3Speed);
+            }
+            if (this.lights4Transform != null)
+            {
+                this.UpdateLightTransform(this.lights4Transform, this.lightsShaderOn, this.lights4ShaderOff, this.Lights4Speed);
+            }
+            if (this.lights5Transform != null)
+            {
+                this.UpdateLightTransform(this.lights5Transform, this.lightsShaderOn, this.lights5ShaderOff, this.Lights5Speed);
+            }
+            if (this.lights6Transform != null)
+            {
+                this.UpdateLightTransform(this.lights6Transform, this.lightsShaderOn, this.lights6ShaderOff, this.Lights6Speed);
+            }
+        }
+
+        private void UpdateLightTransform(Component lights, Shader on, Shader off, float targetSpeed)
+        {
+            bool lightsOn;
+
+            if (targetSpeed > 0)
+            {
+                lightsOn = (this.speed > targetSpeed);
+            }
+            else if (targetSpeed < 0)
+            {
+                lightsOn = (this.speed < targetSpeed);
+            }
+            else
+            {
+                lightsOn = (this.speed == 0);
+            }
+
+            lights.renderer.material.shader = lightsOn ? @on : off;
+        }
+
+        #endregion
+    }
 }

--- a/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
+++ b/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
@@ -1,6 +1,6 @@
-using System;

-using System.Text;

-

+using System;
+using System.Text;
+
 namespace KerbalEngineer.VesselSimulator
 {
     class AttachNodeSim

--- a/KerbalEngineer/VesselSimulator/EngineSim.cs
+++ b/KerbalEngineer/VesselSimulator/EngineSim.cs
@@ -1,364 +1,364 @@
-// Kerbal Engineer Redux

-// Author:  CYBUTEK

-// License: Attribution-NonCommercial-ShareAlike 3.0 Unported

-

-#region

-

-using System;

-using System.Collections.Generic;

-using System.Linq;

-using System.Text;

-

-using UnityEngine;

-

-#endregion

-

-namespace KerbalEngineer.VesselSimulator

-{

-    public class EngineSim

-    {

-        private readonly ResourceContainer resourceConsumptions = new ResourceContainer();

-

-        public double actualThrust = 0;

-        public bool isActive = false;

-        public double isp = 0;

-        public PartSim partSim;

-

-        public double thrust = 0;

-

-        // Add thrust vector to account for directional losses

-        public Vector3 thrustVec;

-

-        public EngineSim(PartSim theEngine,

-                         double atmosphere,

-                         double velocity,

-                         float maxThrust,

-                         float minThrust,

-                         float thrustPercentage,

-                         float requestedThrust,

-                         Vector3 vecThrust,

-                         float realIsp,

-                         FloatCurve atmosphereCurve,

-                         FloatCurve velocityCurve,

-                         bool throttleLocked,

-                         List<Propellant> propellants,

-                         bool active,

-                         bool correctThrust)

-        {

-            StringBuilder buffer = null;

-            //MonoBehaviour.print("Create EngineSim for " + theEngine.name);

-            //MonoBehaviour.print("maxThrust = " + maxThrust);

-            //MonoBehaviour.print("thrustPercentage = " + thrustPercentage);

-            //MonoBehaviour.print("requestedThrust = " + requestedThrust);

-            //MonoBehaviour.print("velocity = " + velocity);

-

-            this.partSim = theEngine;

-

-            this.isActive = active;

-            this.thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust;

-            //MonoBehaviour.print("thrust = " + thrust);

-

-            this.thrustVec = vecThrust;

-

-            double flowRate = 0d;

-            if (this.partSim.hasVessel)

-            {

-                //MonoBehaviour.print("hasVessel is true");

-                this.actualThrust = requestedThrust;

-                if (velocityCurve != null)

-                {

-                    this.actualThrust *= velocityCurve.Evaluate((float)velocity);

-                    //MonoBehaviour.print("actualThrust at velocity = " + actualThrust);

-                }

-

-                this.isp = atmosphereCurve.Evaluate((float)this.partSim.part.staticPressureAtm);

-                if (this.isp == 0d)

-                {

-                    MonoBehaviour.print("Isp at " + this.partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN");

-                }

-

-                if (correctThrust && realIsp == 0)

-                {

-                    float ispsl = atmosphereCurve.Evaluate(0);

-                    if (ispsl != 0)

-                    {

-                        this.thrust = this.thrust * this.isp / ispsl;

-                    }

-                    else

-                    {

-                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");

-                    }

-                    //MonoBehaviour.print("corrected thrust = " + thrust);

-                }

-

-                if (velocityCurve != null)

-                {

-                    this.thrust *= velocityCurve.Evaluate((float)velocity);

-                    //MonoBehaviour.print("thrust at velocity = " + thrust);

-                }

-

-                if (throttleLocked)

-                {

-                    //MonoBehaviour.print("throttleLocked is true");

-                    flowRate = this.thrust / (this.isp * 9.81d);

-                }

-                else

-                {

-                    if (this.partSim.isLanded)

-                    {

-                        //MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle);

-                        flowRate = Math.Max(0.000001d, this.thrust * FlightInputHandler.state.mainThrottle) / (this.isp * 9.81d);

-                    }

-                    else

-                    {

-                        if (requestedThrust > 0)

-                        {

-                            if (velocityCurve != null)

-                            {

-                                requestedThrust *= velocityCurve.Evaluate((float)velocity);

-                                //MonoBehaviour.print("requestedThrust at velocity = " + requestedThrust);

-                            }

-

-                            //MonoBehaviour.print("requestedThrust > 0");

-                            flowRate = requestedThrust / (this.isp * 9.81d);

-                        }

-                        else

-                        {

-                            //MonoBehaviour.print("requestedThrust <= 0");

-                            flowRate = this.thrust / (this.isp * 9.81d);

-                        }

-                    }

-                }

-            }

-            else

-            {

-                //MonoBehaviour.print("hasVessel is false");

-                this.isp = atmosphereCurve.Evaluate((float)atmosphere);

-                if (this.isp == 0d)

-                {

-                    MonoBehaviour.print("Isp at " + atmosphere + " is zero. Flow rate will be NaN");

-                }

-                if (correctThrust)

-                {

-                    float ispsl = atmosphereCurve.Evaluate(0);

-                    if (ispsl != 0)

-                    {

-                        this.thrust = this.thrust * this.isp / ispsl;

-                    }

-                    else

-                    {

-                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");

-                    }

-                    //MonoBehaviour.print("corrected thrust = " + thrust);

-                }

-

-                if (velocityCurve != null)

-                {

-                    this.thrust *= velocityCurve.Evaluate((float)velocity);

-                    //MonoBehaviour.print("thrust at velocity = " + thrust);

-                }

-

-                flowRate = this.thrust / (this.isp * 9.81d);

-            }

-

-            if (SimManager.logOutput)

-            {

-                buffer = new StringBuilder(1024);

-                buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);

-            }

-

-            float flowMass = 0f;

-            foreach (Propellant propellant in propellants)

-            {

-                flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);

-            }

-

-            if (SimManager.logOutput)

-            {

-                buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);

-            }

-

-            foreach (Propellant propellant in propellants)

-            {

-                if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")

-                {

-                    continue;

-                }

-

-                double consumptionRate = propellant.ratio * flowRate / flowMass;

-                if (SimManager.logOutput)

-                {

-                    buffer.AppendFormat("Add consumption({0}, {1}:{2:d}) = {3:g6}\n", ResourceContainer.GetResourceName(propellant.id), theEngine.name, theEngine.partId, consumptionRate);

-                }

-                this.resourceConsumptions.Add(propellant.id, consumptionRate);

-            }

-

-            if (SimManager.logOutput)

-            {

-                MonoBehaviour.print(buffer);

-            }

-        }

-

-        public ResourceContainer ResourceConsumptions

-        {

-            get { return this.resourceConsumptions; }

-        }

-

-        public bool SetResourceDrains(List<PartSim> allParts, List<PartSim> allFuelLines, HashSet<PartSim> drainingParts)

-        {

-            LogMsg log = null;

-

-            // A dictionary to hold a set of parts for each resource

-            Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>();

-

-            foreach (int type in this.resourceConsumptions.Types)

-            {

-                HashSet<PartSim> sourcePartSet = null;

-                switch (ResourceContainer.GetResourceFlowMode(type))

-                {

-                    case ResourceFlowMode.NO_FLOW:

-                        if (this.partSim.resources[type] > SimManager.RESOURCE_MIN)

-                        {

-                            sourcePartSet = new HashSet<PartSim>();

-                            //MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this");

-                            sourcePartSet.Add(this.partSim);

-                        }

-                        break;

-

-                    case ResourceFlowMode.ALL_VESSEL:

-                        foreach (PartSim aPartSim in allParts)

-                        {

-                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)

-                            {

-                                if (sourcePartSet == null)

-                                {

-                                    sourcePartSet = new HashSet<PartSim>();

-                                }

-

-                                sourcePartSet.Add(aPartSim);

-                            }

-                        }

-                        break;

-

-                    case ResourceFlowMode.STAGE_PRIORITY_FLOW:

-                    {

-                        Dictionary<int, HashSet<PartSim>> stagePartSets = new Dictionary<int, HashSet<PartSim>>();

-                        int maxStage = -1;

-                        foreach (PartSim aPartSim in allParts)

-                        {

-                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)

-                            {

-                                //int stage = aPartSim.decoupledInStage;            // Use the number of the stage the tank is decoupled in

-                                int stage = aPartSim.DecouplerCount(); // Use the count of decouplers between tank and root

-                                if (stage > maxStage)

-                                {

-                                    maxStage = stage;

-                                }

-                                if (stagePartSets.ContainsKey(stage))

-                                {

-                                    sourcePartSet = stagePartSets[stage];

-                                }

-                                else

-                                {

-                                    sourcePartSet = new HashSet<PartSim>();

-                                    stagePartSets.Add(stage, sourcePartSet);

-                                }

-

-                                sourcePartSet.Add(aPartSim);

-                            }

-                        }

-

-                        while (maxStage >= 0)

-                        {

-                            if (stagePartSets.ContainsKey(maxStage))

-                            {

-                                if (stagePartSets[maxStage].Count() > 0)

-                                {

-                                    sourcePartSet = stagePartSets[maxStage];

-                                    break;

-                                }

-                            }

-                            maxStage--;

-                        }

-                    }

-                        break;

-

-                    case ResourceFlowMode.STACK_PRIORITY_SEARCH:

-                        HashSet<PartSim> visited = new HashSet<PartSim>();

-

-                        if (SimManager.logOutput)

-                        {

-                            log = new LogMsg();

-                            log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + this.partSim.name + ":" + this.partSim.partId);

-                        }

-                        sourcePartSet = this.partSim.GetSourceSet(type, allParts, visited, log, "");

-                        if (SimManager.logOutput)

-                        {

-                            MonoBehaviour.print(log.buf);

-                        }

-                        break;

-

-                    default:

-                        MonoBehaviour.print("SetResourceDrains(" + this.partSim.name + ":" + this.partSim.partId + ") Unexpected flow type for " + ResourceContainer.GetResourceName(type) + ")");

-                        break;

-                }

-

-                if (sourcePartSet != null && sourcePartSet.Count > 0)

-                {

-                    sourcePartSets[type] = sourcePartSet;

-                    if (SimManager.logOutput)

-                    {

-                        log = new LogMsg();

-                        log.buf.AppendLine("Source parts for " + ResourceContainer.GetResourceName(type) + ":");

-                        foreach (PartSim partSim in sourcePartSet)

-                        {

-                            log.buf.AppendLine(partSim.name + ":" + partSim.partId);

-                        }

-                        MonoBehaviour.print(log.buf);

-                    }

-                }

-            }

-

-            // If we don't have sources for all the needed resources then return false without setting up any drains

-            foreach (int type in this.resourceConsumptions.Types)

-            {

-                if (!sourcePartSets.ContainsKey(type))

-                {

-                    if (SimManager.logOutput)

-                    {

-                        MonoBehaviour.print("No source of " + ResourceContainer.GetResourceName(type));

-                    }

-

-                    this.isActive = false;

-                    return false;

-                }

-            }

-

-            // Now we set the drains on the members of the sets and update the draining parts set

-            foreach (int type in this.resourceConsumptions.Types)

-            {

-                HashSet<PartSim> sourcePartSet = sourcePartSets[type];

-                // Loop through the members of the set 

-                double amount = this.resourceConsumptions[type] / sourcePartSet.Count;

-                foreach (PartSim partSim in sourcePartSet)

-                {

-                    if (SimManager.logOutput)

-                    {

-                        MonoBehaviour.print("Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" + partSim.partId);

-                    }

-

-                    partSim.resourceDrains.Add(type, amount);

-                    drainingParts.Add(partSim);

-                }

-            }

-

-            return true;

-        }

-

-        public void DumpEngineToBuffer(StringBuilder buffer, String prefix)

-        {

-            buffer.Append(prefix);

-            buffer.AppendFormat("[thrust = {0:g6}, actual = {1:g6}, isp = {2:g6}\n", this.thrust, this.actualThrust, this.isp);

-        }

-    }

+// Kerbal Engineer Redux
+// Author:  CYBUTEK
+// License: Attribution-NonCommercial-ShareAlike 3.0 Unported
+
+#region
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using UnityEngine;
+
+#endregion
+
+namespace KerbalEngineer.VesselSimulator
+{
+    public class EngineSim
+    {
+        private readonly ResourceContainer resourceConsumptions = new ResourceContainer();
+
+        public double actualThrust = 0;
+        public bool isActive = false;
+        public double isp = 0;
+        public PartSim partSim;
+
+        public double thrust = 0;
+
+        // Add thrust vector to account for directional losses
+        public Vector3 thrustVec;
+
+        public EngineSim(PartSim theEngine,
+                         double atmosphere,
+                         double velocity,
+                         float maxThrust,
+                         float minThrust,
+                         float thrustPercentage,
+                         float requestedThrust,
+                         Vector3 vecThrust,
+                         float realIsp,
+                         FloatCurve atmosphereCurve,
+                         FloatCurve velocityCurve,
+                         bool throttleLocked,
+                         List<Propellant> propellants,
+                         bool active,
+                         bool correctThrust)
+        {
+            StringBuilder buffer = null;
+            //MonoBehaviour.print("Create EngineSim for " + theEngine.name);
+            //MonoBehaviour.print("maxThrust = " + maxThrust);
+            //MonoBehaviour.print("thrustPercentage = " + thrustPercentage);
+            //MonoBehaviour.print("requestedThrust = " + requestedThrust);
+            //MonoBehaviour.print("velocity = " + velocity);
+
+            this.partSim = theEngine;
+
+            this.isActive = active;
+            this.thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust;
+            //MonoBehaviour.print("thrust = " + thrust);
+
+            this.thrustVec = vecThrust;
+
+            double flowRate = 0d;
+            if (this.partSim.hasVessel)
+            {
+                //MonoBehaviour.print("hasVessel is true");
+                this.actualThrust = requestedThrust;
+                if (velocityCurve != null)
+                {
+                    this.actualThrust *= velocityCurve.Evaluate((float)velocity);
+                    //MonoBehaviour.print("actualThrust at velocity = " + actualThrust);
+                }
+
+                this.isp = atmosphereCurve.Evaluate((float)this.partSim.part.staticPressureAtm);
+                if (this.isp == 0d)
+                {
+                    MonoBehaviour.print("Isp at " + this.partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN");
+                }
+
+                if (correctThrust && realIsp == 0)
+                {
+                    float ispsl = atmosphereCurve.Evaluate(0);
+                    if (ispsl != 0)
+                    {
+                        this.thrust = this.thrust * this.isp / ispsl;
+                    }
+                    else
+                    {
+                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
+                    }
+                    //MonoBehaviour.print("corrected thrust = " + thrust);
+                }
+
+                if (velocityCurve != null)
+                {
+                    this.thrust *= velocityCurve.Evaluate((float)velocity);
+                    //MonoBehaviour.print("thrust at velocity = " + thrust);
+                }
+
+                if (throttleLocked)
+                {
+                    //MonoBehaviour.print("throttleLocked is true");
+                    flowRate = this.thrust / (this.isp * 9.81d);
+                }
+                else
+                {
+                    if (this.partSim.isLanded)
+                    {
+                        //MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle);
+                        flowRate = Math.Max(0.000001d, this.thrust * FlightInputHandler.state.mainThrottle) / (this.isp * 9.81d);
+                    }
+                    else
+                    {
+                        if (requestedThrust > 0)
+                        {
+                            if (velocityCurve != null)
+                            {
+                                requestedThrust *= velocityCurve.Evaluate((float)velocity);
+                                //MonoBehaviour.print("requestedThrust at velocity = " + requestedThrust);
+                            }
+
+                            //MonoBehaviour.print("requestedThrust > 0");
+                            flowRate = requestedThrust / (this.isp * 9.81d);
+                        }
+                        else
+                        {
+                            //MonoBehaviour.print("requestedThrust <= 0");
+                            flowRate = this.thrust / (this.isp * 9.81d);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                //MonoBehaviour.print("hasVessel is false");
+                this.isp = atmosphereCurve.Evaluate((float)atmosphere);
+                if (this.isp == 0d)
+                {
+                    MonoBehaviour.print("Isp at " + atmosphere + " is zero. Flow rate will be NaN");
+                }
+                if (correctThrust)
+                {
+                    float ispsl = atmosphereCurve.Evaluate(0);
+                    if (ispsl != 0)
+                    {
+                        this.thrust = this.thrust * this.isp / ispsl;
+                    }
+                    else
+                    {
+                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
+                    }
+                    //MonoBehaviour.print("corrected thrust = " + thrust);
+                }
+
+                if (velocityCurve != null)
+                {
+                    this.thrust *= velocityCurve.Evaluate((float)velocity);
+                    //MonoBehaviour.print("thrust at velocity = " + thrust);
+                }
+
+                flowRate = this.thrust / (this.isp * 9.81d);
+            }
+
+            if (SimManager.logOutput)
+            {
+                buffer = new StringBuilder(1024);
+                buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);
+            }
+
+            float flowMass = 0f;
+            foreach (Propellant propellant in propellants)
+            {
+                flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
+            }
+
+            if (SimManager.logOutput)
+            {
+                buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);
+            }
+
+            foreach (Propellant propellant in propellants)
+            {
+                if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
+                {
+                    continue;
+                }
+
+                double consumptionRate = propellant.ratio * flowRate / flowMass;
+                if (SimManager.logOutput)
+                {
+                    buffer.AppendFormat("Add consumption({0}, {1}:{2:d}) = {3:g6}\n", ResourceContainer.GetResourceName(propellant.id), theEngine.name, theEngine.partId, consumptionRate);
+                }
+                this.resourceConsumptions.Add(propellant.id, consumptionRate);
+            }
+
+            if (SimManager.logOutput)
+            {
+                MonoBehaviour.print(buffer);
+            }
+        }
+
+        public ResourceContainer ResourceConsumptions
+        {
+            get { return this.resourceConsumptions; }
+        }
+
+        public bool SetResourceDrains(List<PartSim> allParts, List<PartSim> allFuelLines, HashSet<PartSim> drainingParts)
+        {
+            LogMsg log = null;
+
+            // A dictionary to hold a set of parts for each resource
+            Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>();
+
+            foreach (int type in this.resourceConsumptions.Types)
+            {
+                HashSet<PartSim> sourcePartSet = null;
+                switch (ResourceContainer.GetResourceFlowMode(type))
+                {
+                    case ResourceFlowMode.NO_FLOW:
+                        if (this.partSim.resources[type] > SimManager.RESOURCE_MIN)
+                        {
+                            sourcePartSet = new HashSet<PartSim>();
+                            //MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this");
+                            sourcePartSet.Add(this.partSim);
+                        }
+                        break;
+
+                    case ResourceFlowMode.ALL_VESSEL:
+                        foreach (PartSim aPartSim in allParts)
+                        {
+                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)
+                            {
+                                if (sourcePartSet == null)
+                                {
+                                    sourcePartSet = new HashSet<PartSim>();
+                                }
+
+                                sourcePartSet.Add(aPartSim);
+                            }
+                        }
+                        break;
+
+                    case ResourceFlowMode.STAGE_PRIORITY_FLOW:
+                    {
+                        Dictionary<int, HashSet<PartSim>> stagePartSets = new Dictionary<int, HashSet<PartSim>>();
+                        int maxStage = -1;
+                        foreach (PartSim aPartSim in allParts)
+                        {
+                            if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)
+                            {
+                                //int stage = aPartSim.decoupledInStage;            // Use the number of the stage the tank is decoupled in
+                                int stage = aPartSim.DecouplerCount(); // Use the count of decouplers between tank and root
+                                if (stage > maxStage)
+                                {
+                                    maxStage = stage;
+                                }
+                                if (stagePartSets.ContainsKey(stage))
+                                {
+                                    sourcePartSet = stagePartSets[stage];
+                                }
+                                else
+                                {
+                                    sourcePartSet = new HashSet<PartSim>();
+                                    stagePartSets.Add(stage, sourcePartSet);
+                                }
+
+                                sourcePartSet.Add(aPartSim);
+                            }
+                        }
+
+                        while (maxStage >= 0)
+                        {
+                            if (stagePartSets.ContainsKey(maxStage))
+                            {
+                                if (stagePartSets[maxStage].Count() > 0)
+                                {
+                                    sourcePartSet = stagePartSets[maxStage];
+                                    break;
+                                }
+                            }
+                            maxStage--;
+                        }
+                    }
+                        break;
+
+                    case ResourceFlowMode.STACK_PRIORITY_SEARCH:
+                        HashSet<PartSim> visited = new HashSet<PartSim>();
+
+                        if (SimManager.logOutput)
+                        {
+                            log = new LogMsg();
+                            log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + this.partSim.name + ":" + this.partSim.partId);
+                        }
+                        sourcePartSet = this.partSim.GetSourceSet(type, allParts, visited, log, "");
+                        if (SimManager.logOutput)
+                        {
+                            MonoBehaviour.print(log.buf);
+                        }
+                        break;
+
+                    default:
+                        MonoBehaviour.print("SetResourceDrains(" + this.partSim.name + ":" + this.partSim.partId + ") Unexpected flow type for " + ResourceContainer.GetResourceName(type) + ")");
+                        break;
+                }
+
+                if (sourcePartSet != null && sourcePartSet.Count > 0)
+                {
+                    sourcePartSets[type] = sourcePartSet;
+                    if (SimManager.logOutput)
+                    {
+                        log = new LogMsg();
+                        log.buf.AppendLine("Source parts for " + ResourceContainer.GetResourceName(type) + ":");
+                        foreach (PartSim partSim in sourcePartSet)
+                        {
+                            log.buf.AppendLine(partSim.name + ":" + partSim.partId);
+                        }
+                        MonoBehaviour.print(log.buf);
+                    }
+                }
+            }
+
+            // If we don't have sources for all the needed resources then return false without setting up any drains
+            foreach (int type in this.resourceConsumptions.Types)
+            {
+                if (!sourcePartSets.ContainsKey(type))
+                {
+                    if (SimManager.logOutput)
+                    {
+                        MonoBehaviour.print("No source of " + ResourceContainer.GetResourceName(type));
+                    }
+
+                    this.isActive = false;
+                    return false;
+                }
+            }
+
+            // Now we set the drains on the members of the sets and update the draining parts set
+            foreach (int type in this.resourceConsumptions.Types)
+            {
+                HashSet<PartSim> sourcePartSet = sourcePartSets[type];
+                // Loop through the members of the set 
+                double amount = this.resourceConsumptions[type] / sourcePartSet.Count;
+                foreach (PartSim partSim in sourcePartSet)
+                {
+                    if (SimManager.logOutput)
+                    {
+                        MonoBehaviour.print("Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" + partSim.partId);
+                    }
+
+                    partSim.resourceDrains.Add(type, amount);
+                    drainingParts.Add(partSim);
+                }
+            }
+
+            return true;
+        }
+
+        public void DumpEngineToBuffer(StringBuilder buffer, String prefix)
+        {
+            buffer.Append(prefix);
+            buffer.AppendFormat("[thrust = {0:g6}, actual = {1:g6}, isp = {2:g6}\n", this.thrust, this.actualThrust, this.isp);
+        }
+    }
 }

--- a/KerbalEngineer/VesselSimulator/PartSim.cs
+++ b/KerbalEngineer/VesselSimulator/PartSim.cs
@@ -4,17 +4,17 @@
 //
 // This class has taken a lot of inspiration from r4m0n's MuMech FuelFlowSimulator.  Although extremely
 // similar to the code used within MechJeb, it is a clean re-write.  The similarities are a testiment
-// to how well the MuMech code works and the robustness of the simulation algorithem used.

-

-using System;

-using System.Collections.Generic;

-using System.Linq;

-using System.Text;

-

-using KerbalEngineer.Extensions;

-

-using UnityEngine;

-

+// to how well the MuMech code works and the robustness of the simulation algorithem used.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using KerbalEngineer.Extensions;
+
+using UnityEngine;
+
 namespace KerbalEngineer.VesselSimulator
 {
     public class PartSim

--- a/KerbalEngineer/VesselSimulator/ResourceContainer.cs
+++ b/KerbalEngineer/VesselSimulator/ResourceContainer.cs
@@ -1,10 +1,10 @@
 // Kerbal Engineer Redux
 // Author:  CYBUTEK
-// License: Attribution-NonCommercial-ShareAlike 3.0 Unported

-

-using System.Collections;

-using System.Collections.Generic;

-

+// License: Attribution-NonCommercial-ShareAlike 3.0 Unported
+
+using System.Collections;
+using System.Collections.Generic;
+
 namespace KerbalEngineer.VesselSimulator
 {
     public class ResourceContainer

--- a/KerbalEngineer/VesselSimulator/SimManager.cs
+++ b/KerbalEngineer/VesselSimulator/SimManager.cs
@@ -1,13 +1,13 @@
-using System;

-using System.Collections.Generic;

-using System.Diagnostics;

-using System.Linq;

-using System.Threading;

-

-using KerbalEngineer.Flight;

-

-using UnityEngine;

-

+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+
+using KerbalEngineer.Flight;
+
+using UnityEngine;
+
 namespace KerbalEngineer.VesselSimulator
 {
     public class SimManager
@@ -251,7 +251,7 @@
                     return "Flag";
             }
             return "Undefined";
-        }

+        }
     }
 }
 

--- a/KerbalEngineer/VesselSimulator/Simulation.cs
+++ b/KerbalEngineer/VesselSimulator/Simulation.cs
@@ -4,15 +4,15 @@
 //
 // This class has taken a lot of inspiration from r4m0n's MuMech FuelFlowSimulator.  Although extremely
 // similar to the code used within MechJeb, it is a clean re-write.  The similarities are a testiment
-// to how well the MuMech code works and the robustness of the simulation algorithem used.

-

-using System;

-using System.Collections.Generic;

-using System.Diagnostics;

-using System.Text;

-

-using UnityEngine;

-

+// to how well the MuMech code works and the robustness of the simulation algorithem used.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+using UnityEngine;
+
 namespace KerbalEngineer.VesselSimulator
 {
     public class Simulation

--- a/KerbalEngineer/VesselSimulator/Stage.cs
+++ b/KerbalEngineer/VesselSimulator/Stage.cs
@@ -1,11 +1,11 @@
 // Kerbal Engineer Redux
 // Author:  CYBUTEK
-// License: Attribution-NonCommercial-ShareAlike 3.0 Unported

-

-using System.Text;

-

-using UnityEngine;

-

+// License: Attribution-NonCommercial-ShareAlike 3.0 Unported
+
+using System.Text;
+
+using UnityEngine;
+
 namespace KerbalEngineer.VesselSimulator
 {
     public class Stage

 Binary files a/Output/KerbalEngineer/KerbalEngineer.dll and b/Output/KerbalEngineer/KerbalEngineer.dll differ
 Binary files a/Output/KerbalEngineer/MiniAVC.dll and b/Output/KerbalEngineer/MiniAVC.dll differ
--- a/Output/ReadMe.htm
+++ b/Output/ReadMe.htm
@@ -78,11 +78,11 @@
 			background-color: black;
 		}
 
-		#changelog > li {
+		.nested_list > li {
 			margin-top: 1em;
 		}
 
-		#changelog > li:first-child {
+		.nested_list > li:first-child {
 			margin-top: 0.5em;
 		}
 
@@ -153,7 +153,14 @@
 
 		<section>
 			<h3>Change Log</h3>
-			<ul id='changelog'>
+			<ul class='nested_list'>
+				<li>1.0.6.0
+					<ul>
+						<li>Added: Time to equatorial ascending &amp; descending nodes in the orbital display.</li>
+						<li>Fixed: Updated MiniAVC to v1.0.2.1 (fixes remote check as well as other minor bugs).</li>
+					</ul>
+				</li>
+				</li>
 				<li>1.0.5.0
 					<ul>
 						<li>Added: Acceleration readout to the Vessel category (current / maximum).</li>