Refactored creation of EngineSim objects to avoid passing 20 params to a function.
Refactored creation of EngineSim objects to avoid passing 20 params to a function.

--- a/Documents/CHANGES.txt
+++ b/Documents/CHANGES.txt
@@ -1,4 +1,15 @@
-1.0.19.0
+1.0.19.4, 12-02-16
+    Fixed: Only 'STAGE_STACK_FLOW' and 'STAGE_STACK_FLOW_BALANCE' resources include surface mounted parts as fuel targets.
+    Fixed: Fairing mass being doubled in the VAB (removed workaround for a KSP bug which has been fixed).
+
+1.0.19.3, 09-02-16
+    Fixed: Fuel cross-feed from surface attached parts.
+
+1.0.19.2, 19-11-15
+    Rebuild for KSP 1.0.5.1028 silent update.
+    
+1.0.19.1, 09-11-15
+    Added: Key binding editor accessible under 'Settings' on the Build Engineer.
     Added: Added current vessel name readout. (antplant)
     Added: 'Relative Radial Velocity' and 'Time To Rendezvous' readouts. (itwtx)
     Added: Readout help strings. (harryyoung)

--- a/KerbalEngineer/EngineerGlobals.cs
+++ b/KerbalEngineer/EngineerGlobals.cs
@@ -25,7 +25,7 @@
         /// <summary>
         ///     Current version of the Kerbal Engineer assembly.
         /// </summary>
-        public const string ASSEMBLY_VERSION = "1.0.18.1";
+        public const string ASSEMBLY_VERSION = "1.0.19.4";
 
         private static string assemblyFile;
         private static string assemblyName;

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/LogSimToggle.cs
@@ -1,1 +1,56 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Miscellaneous
+{
+    #region Using Directives
+
+    using Sections;
+    using UnityEngine;
+    using VesselSimulator;
+
+    #endregion
+
+    public class LogSimToggle : ReadoutModule
+    {
+        #region Constructors
+
+        public LogSimToggle()
+        {
+            this.Name = "Log Simulation";
+            this.Category = ReadoutCategory.GetCategory("Miscellaneous");
+            this.HelpString = "Shows a button that allows you to make the next run of the simulation code dump extra debugging output.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods
+
+        public override void Draw(SectionModule section)
+        {
+            GUILayout.BeginHorizontal();
+            GUILayout.Label("Log Simulation: ", this.NameStyle);
+            SimManager.logOutput = GUILayout.Toggle(SimManager.logOutput, "ENABLED", this.ButtonStyle);
+            GUILayout.EndHorizontal();
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/ReadoutLibrary.cs
+++ b/KerbalEngineer/Flight/Readouts/ReadoutLibrary.cs
@@ -192,6 +192,7 @@
                 readouts.Add(new SimulationDelay());
                 readouts.Add(new VectoredThrustToggle());
                 readouts.Add(new SystemTime());
+                readouts.Add(new LogSimToggle());
 
                 LoadHelpStrings();
             }

--- a/KerbalEngineer/Flight/Readouts/Surface/HorizontalSpeed.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/HorizontalSpeed.cs
@@ -45,11 +45,12 @@
 
         public override void Draw(SectionModule section)
         {
-            // Used to do this but the bug-fix to horizontalSrfSpeed in KSP 1.0.3 actually made it worse so workaround
-            //this.DrawLine(FlightGlobals.ActiveVessel.horizontalSrfSpeed.ToSpeed(), section.IsHud);
-            var ves = FlightGlobals.ActiveVessel;
-            double horizSpeed = Math.Sqrt(ves.srfSpeed * ves.srfSpeed - ves.verticalSpeed * ves.verticalSpeed);
-            this.DrawLine(horizSpeed.ToSpeed(), section.IsHud);
+            this.DrawLine(FlightGlobals.ActiveVessel.horizontalSrfSpeed.ToSpeed(), section.IsHud);
+
+            // This workaround was used for KSP 1.0.3 and 1.0.4 where horizontalSrfSpeed was really badly broken
+            //var ves = FlightGlobals.ActiveVessel;
+            //double horizSpeed = Math.Sqrt(ves.srfSpeed * ves.srfSpeed - ves.verticalSpeed * ves.verticalSpeed);
+            //this.DrawLine(horizSpeed.ToSpeed(), section.IsHud);
         }
 
         #endregion

--- a/KerbalEngineer/KerbalEngineer.csproj
+++ b/KerbalEngineer/KerbalEngineer.csproj
@@ -51,6 +51,7 @@
     <Compile Include="Extensions\StringExtensions.cs" />
     <Compile Include="Flight\ActionMenuGui.cs" />
     <Compile Include="Flight\Presets\Preset.cs" />
+    <Compile Include="Flight\Readouts\Miscellaneous\LogSimToggle.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\SystemTime.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\VectoredThrustToggle.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\Separator.cs" />
@@ -238,7 +239,7 @@
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Assembly-CSharp">
-      <HintPath>..\Game\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
+      <HintPath>..\..\Game\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
       <Private>False</Private>
     </Reference>
     <Reference Include="System">
@@ -250,7 +251,7 @@
       <Private>False</Private>
     </Reference>
     <Reference Include="UnityEngine">
-      <HintPath>..\Game\KSP_Data\Managed\UnityEngine.dll</HintPath>
+      <HintPath>..\..\Game\KSP_Data\Managed\UnityEngine.dll</HintPath>
       <Private>False</Private>
     </Reference>
   </ItemGroup>
@@ -269,7 +270,7 @@
         $(PostBuildEventDependsOn);
         PostBuildMacros;
       </PostBuildEventDependsOn>
-    <PostBuildEvent>xcopy "$(SolutionDir)Output\*" "$(SolutionDir)Game\GameData\*" /E /Y
+    <PostBuildEvent>xcopy "$(SolutionDir)Output\*" "$(SolutionDir)..\Game\GameData\*" /E /Y
 del "$(SolutionDir)Release\*" /Q
 xcopy "$(SolutionDir)Documents\*" "$(SolutionDir)Release\Documents\*" /E /Y
 7z.exe a -tzip -mx3 "$(SolutionDir)Release\$(ProjectName)-@(VersionNumber).zip" "$(SolutionDir)Output\*"

--- a/KerbalEngineer/VesselSimulator/EngineSim.cs
+++ b/KerbalEngineer/VesselSimulator/EngineSim.cs
@@ -72,26 +72,30 @@
         }
 
         public static EngineSim New(PartSim theEngine,
-                         double atmosphere,
-                         float machNumber,
-                         float maxFuelFlow,
-                         float minFuelFlow,
-                         float thrustPercentage,
-                         Vector3 vecThrust,
-                         FloatCurve atmosphereCurve,
-                         bool atmChangeFlow,
-                         FloatCurve atmCurve,
-                         FloatCurve velCurve,
-                         float currentThrottle,
-                         float IspG,
-                         bool throttleLocked,
-                         List<Propellant> propellants,
-                         bool active,
-                         float resultingThrust,
-                         List<Transform> thrustTransforms,
-                        LogMsg log)
-        {
-            EngineSim engineSim = pool.Borrow();
+									ModuleEngines engineMod,
+									double atmosphere,
+									float machNumber,
+									bool vectoredThrust,
+									bool fullThrust,
+									LogMsg log)
+        {
+            float maxFuelFlow = engineMod.maxFuelFlow;
+            float minFuelFlow = engineMod.minFuelFlow;
+            float thrustPercentage = engineMod.thrustPercentage;
+            Vector3 vecThrust = CalculateThrustVector(vectoredThrust ? engineMod.thrustTransforms : null, log);
+            FloatCurve atmosphereCurve = engineMod.atmosphereCurve;
+            bool atmChangeFlow = engineMod.atmChangeFlow;
+            FloatCurve atmCurve = engineMod.useAtmCurve ? engineMod.atmCurve : null;
+            FloatCurve velCurve = engineMod.useVelCurve ? engineMod.velCurve : null;
+            float currentThrottle = engineMod.currentThrottle;
+            float IspG = engineMod.g;
+            bool throttleLocked = engineMod.throttleLocked || fullThrust;
+            List<Propellant> propellants = engineMod.propellants;
+            bool active = engineMod.isOperational;
+            float resultingThrust = engineMod.resultingThrust;
+            List<Transform> thrustTransforms = engineMod.thrustTransforms;
+			
+			EngineSim engineSim = pool.Borrow();
 
             engineSim.isp = 0.0;
             engineSim.maxMach = 0.0f;
@@ -120,7 +124,7 @@
                     log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
                 }
 
-                if (throttleLocked)
+				if (throttleLocked)
                 {
                     if (log != null) log.buf.AppendLine("throttleLocked is true, using thrust for flowRate");
                     flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
@@ -129,7 +133,8 @@
                 {
                     if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
                     {
-                        if (log != null) log.buf.AppendLine("throttled up and not landed, using actualThrust for flowRate");
+						// TODO: This bit doesn't work for RF engines
+						if (log != null) log.buf.AppendLine("throttled up and not landed, using actualThrust for flowRate");
                         flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                     }
                     else
@@ -204,6 +209,32 @@
             return engineSim;
         }
 
+		private static Vector3 CalculateThrustVector(List<Transform> thrustTransforms, LogMsg log)
+		{
+			if (thrustTransforms == null)
+			{
+				return Vector3.forward;
+			}
+
+			Vector3 thrustvec = Vector3.zero;
+			for (int i = 0; i < thrustTransforms.Count; ++i)
+			{
+				Transform trans = thrustTransforms[i];
+
+				if (log != null) log.buf.AppendFormat("Transform = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", trans.forward.x, trans.forward.y, trans.forward.z, trans.forward.magnitude);
+
+				thrustvec -= trans.forward;
+			}
+
+			if (log != null) log.buf.AppendFormat("ThrustVec  = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
+
+			thrustvec.Normalize();
+
+			if (log != null) log.buf.AppendFormat("ThrustVecN = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
+
+			return thrustvec;
+		}
+
         public ResourceContainer ResourceConsumptions
         {
             get
@@ -327,6 +358,7 @@
                         break;
 
                     case ResourceFlowMode.ALL_VESSEL:
+                    case ResourceFlowMode.ALL_VESSEL_BALANCE:
                         for (int i = 0; i < allParts.Count; i++)
                         {
                             PartSim aPartSim = allParts[i];
@@ -338,6 +370,7 @@
                         break;
 
                     case ResourceFlowMode.STAGE_PRIORITY_FLOW:
+                    case ResourceFlowMode.STAGE_PRIORITY_FLOW_BALANCE:
 
                         foreach (HashSet<PartSim> stagePartSet in stagePartSets.Values)
                         {
@@ -393,8 +426,24 @@
                             log = new LogMsg();
                             log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + partSim.name + ":" + partSim.partId);
                         }
-                        partSim.GetSourceSet(type, allParts, visited, sourcePartSet, log, "");
+                        partSim.GetSourceSet(type, PhysicsGlobals.Stack_PriUsesSurf, allParts, visited, sourcePartSet, log, "");
+                        if (SimManager.logOutput && log != null)
+                        {
+                            MonoBehaviour.print(log.buf);
+                        }
+                        break;
+
+                    case ResourceFlowMode.STAGE_STACK_FLOW:
+                    case ResourceFlowMode.STAGE_STACK_FLOW_BALANCE:
+                        visited.Clear();
+
                         if (SimManager.logOutput)
+                        {
+                            log = new LogMsg();
+                            log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + partSim.name + ":" + partSim.partId);
+                        }
+                        partSim.GetSourceSet(type, true, allParts, visited, sourcePartSet, log, "");
+                        if (SimManager.logOutput && log != null)
                         {
                             MonoBehaviour.print(log.buf);
                         }

--- a/KerbalEngineer/VesselSimulator/PartSim.cs
+++ b/KerbalEngineer/VesselSimulator/PartSim.cs
@@ -42,6 +42,7 @@
         public int decoupledInStage;
         public bool fuelCrossFeed;
         public List<PartSim> fuelTargets = new List<PartSim>();
+        public List<PartSim> surfaceMountFuelTargets = new List<PartSim>();
         public bool hasModuleEngines;
         public bool hasMultiModeEngine;
 
@@ -233,27 +234,13 @@
                     {
                         if (log != null) log.buf.AppendLine("Module: " + engine.moduleName);
 
-                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
                         EngineSim engineSim = EngineSim.New(
                             this,
-                            atmosphere,
+							engine,
+							atmosphere,
                             (float)mach,
-                            engine.maxFuelFlow,
-                            engine.minFuelFlow,
-                            engine.thrustPercentage,
-                            thrustvec,
-                            engine.atmosphereCurve,
-                            engine.atmChangeFlow,
-                            engine.useAtmCurve ? engine.atmCurve : null,
-                            engine.useVelCurve ? engine.velCurve : null,
-                            engine.currentThrottle,
-                            engine.g,
-                            engine.throttleLocked || fullThrust,
-                            engine.propellants,
-                            engine.isOperational,
-                            engine.resultingThrust,
-                            engine.thrustTransforms,
+							vectoredThrust,
+							fullThrust,
                             log);
                         allEngines.Add(engineSim);
                     }
@@ -267,28 +254,14 @@
                     ModuleEngines engine = engines[i];
                     if (log != null) log.buf.AppendLine("Module: " + engine.moduleName);
 
-                    Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
                     EngineSim engineSim = EngineSim.New(
                         this,
+						engine,
                         atmosphere,
                         (float)mach,
-                        engine.maxFuelFlow,
-                        engine.minFuelFlow,
-                        engine.thrustPercentage,
-                        thrustvec,
-                        engine.atmosphereCurve,
-                        engine.atmChangeFlow,
-                        engine.useAtmCurve ? engine.atmCurve : null,
-                        engine.useVelCurve ? engine.velCurve : null,
-                        engine.currentThrottle,
-                        engine.g,
-                        engine.throttleLocked || fullThrust,
-                        engine.propellants,
-                        engine.isOperational,
-                        engine.resultingThrust,
-                        engine.thrustTransforms,
-                        log);
+						vectoredThrust,
+						fullThrust,
+						log);
                     allEngines.Add(engineSim);
                 }
             }
@@ -416,11 +389,7 @@
                 mass += resources.GetResourceMass(resources.Types[i]);
             }
 
-            if (hasVessel == false && isFairing && currentStage > inverseStage)
-            {
-                mass += fairingMass;
-            }
-            else if (hasVessel && isFairing && currentStage <= inverseStage)
+            if (isFairing && currentStage <= inverseStage)
             {
                 mass -= fairingMass;
             }
@@ -451,7 +420,7 @@
         // All functions below this point must not rely on the part member (it may be null)
         //
 
-        public void GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, HashSet<PartSim> allSources, LogMsg log, String indent)
+        public void GetSourceSet(int type, bool includeSurfaceMountedParts, List<PartSim> allParts, HashSet<PartSim> visited, HashSet<PartSim> allSources, LogMsg log, String indent)
         {
             if (log != null)
             {
@@ -489,7 +458,29 @@
                     {
                         if (log != null) log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
 
-                        partSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
+                        partSim.GetSourceSet(type, includeSurfaceMountedParts, allParts, visited, allSources, log, indent);
+                    }
+                }
+            }
+
+            // check surface mounted fuel targets
+            if (includeSurfaceMountedParts)
+            {
+                for (int i = 0; i < surfaceMountFuelTargets.Count; i++)
+                {
+                    PartSim partSim = this.surfaceMountFuelTargets[i];
+                    if (partSim != null)
+                    {
+                        if (visited.Contains(partSim))
+                        {
+                            if (log != null) log.buf.AppendLine(indent + "Fuel target already visited, skipping (" + partSim.name + ":" + partSim.partId + ")");
+                        }
+                        else
+                        {
+                            if (log != null) log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
+
+                            partSim.GetSourceSet(type, true, allParts, visited, allSources, log, indent);
+                        }
                     }
                 }
             }
@@ -519,9 +510,7 @@
                     {
                         if (attachSim.nodeType == AttachNode.NodeType.Stack)
                         {
-                            if (
-                                !(this.noCrossFeedNodeKey != null && this.noCrossFeedNodeKey.Length > 0 &&
-                                  attachSim.id.Contains(this.noCrossFeedNodeKey)))
+                            if ((string.IsNullOrEmpty(noCrossFeedNodeKey) == false && attachSim.id.Contains(noCrossFeedNodeKey)) == false)
                             {
                                 if (visited.Contains(attachSim.attachedPartSim))
                                 {
@@ -531,7 +520,7 @@
                                 {
                                     if (log != null) log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
 
-                                    attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
+                                    attachSim.attachedPartSim.GetSourceSet(type, includeSurfaceMountedParts, allParts, visited, allSources, log, indent);
                                 }
                             }
                         }
@@ -549,7 +538,7 @@
             // type was not disabled [Experiment]) and it contains fuel, it returns itself.
             // Rule 6: If the part is fuel container for searched type of fuel (i.e. it has capability to contain that type of fuel and the fuel 
             // type was not disabled) but it does not contain the requested fuel, it returns empty list. [Experiment]
-            if (resources.HasType(type) && resourceFlowStates[type] != 0)
+            if (resources.HasType(type) && resourceFlowStates[type] > 0.0)
             {
                 if (resources[type] > SimManager.RESOURCE_MIN)
                 {
@@ -578,7 +567,7 @@
                     else
                     {
                         lastCount = allSources.Count;
-                        this.parent.GetSourceSet(type, allParts, visited, allSources, log, indent);
+                        this.parent.GetSourceSet(type, includeSurfaceMountedParts, allParts, visited, allSources, log, indent);
                         if (allSources.Count > lastCount)
                         {
                             if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count  - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")");
@@ -681,6 +670,11 @@
                 if (partSimLookup.TryGetValue(part.parent, out parent))
                 {
                     if (log != null) log.buf.AppendLine("Parent part is " + parent.name + ":" + parent.partId);
+                    if (part.attachMode == AttachModes.SRF_ATTACH && part.attachRules.srfAttach && part.fuelCrossFeed && part.parent.fuelCrossFeed)
+                    {
+                        if (log != null) log.buf.AppendLine("Added " + name + " to " + parent.name + " surface mounted fuel targets.");
+                        parent.surfaceMountFuelTargets.Add(this);
+                    }
                 }
                 else
                 {

 Binary files a/Output/KerbalEngineer/KerbalEngineer.dll and b/Output/KerbalEngineer/KerbalEngineer.dll differ
--- a/Output/KerbalEngineer/KerbalEngineer.version
+++ b/Output/KerbalEngineer/KerbalEngineer.version
@@ -5,14 +5,14 @@
 	{
 		"MAJOR":1,
 		"MINOR":0,
-		"PATCH":18,
-		"BUILD":0
+		"PATCH":19,
+		"BUILD":4
 	},
 	"KSP_VERSION":
 	{
 		"MAJOR":1,
 		"MINOR":0,
-		"PATCH":4
+		"PATCH":5
 	}
 }