Altitude (terrain) will no longer give a reading below sea level.
Altitude (terrain) will no longer give a reading below sea level.

1.0.11.0 1.0.12.1
  Added: New readouts to the vessel category:
  - Heading Rate
  - Pitch Rate
  - Roll Rate
   
  Fixed: Editor Overlay now loads the saved visibility value properly.
  Fixed: Altitude (Terrain) will no longer give a reading below sea level.
   
  1.0.12.0, 01-12-2014
  Added: Setting in Build Engineer to enable/disable vectored thrust calculations.
  Added: Thrust torque field in Build Engineer (courtesy of mic_e).
  Added: New readouts to the vessel category:
  - Thrust Offset Angle (courtesy of mic_e)
  - Thrust Torque (courtesy of mic_e)
  - Part Count: stage/total
  - Heading
  - Pitch
  - Roll
   
  Added: New readouts to the surface category:
  - Situation
   
  Added: New readouts to the miscellaneous category:
  - Vectored Thrust Toggle
   
  Fixed: The category selection within the section editors now do not always reset back to 'Orbital'.
  Fixed: Issue where the vessel simulation can sometimes permanently freeze.
  Fixed: Issue where the vessel simulation would not show updates when the delay was set lower than the frame rate.
   
  1.0.11.3, 11-11-2014
  Changed: Gravity measurements for Isp to 9.82.
   
  1.0.11.2, 10-11-2014
  Changed: Gravity measurements for Isp calculations from 9.81 to 9.8066 for accuracy.
  Changed: Manoeuvre node burn times are now more accurate.
  Fixed: Bug in the manoeuvre node burn time calculations where it was not averaging acceleration correctly.
   
  1.0.11.1, 07-11-2014
  Changed: Build Engineer now shows stage part count as well as total.
  Changed: Build Overlay Vessel tab data:
  DeltaV: stage / total
  Mass: stage / total
  TWR: start (max) <- shows for bottom stage only.
  Parts: stage / total
   
  Fixed: Issue with the vessel tab vanishing from the editor.
   
  1.0.11.0, 06-11-2014
Added: New readouts to the orbital category: Added: New readouts to the orbital category:
- Current SOI - Current SOI
- Manoeuvre Node DeltaV (Prograde) - Manoeuvre Node DeltaV (Prograde)
- Manoeuvre Node DeltaV (Normal) - Manoeuvre Node DeltaV (Normal)
- Manoeuvre Node DeltaV (Radial) - Manoeuvre Node DeltaV (Radial)
- Manoeuvre Node DeltaV (Total) - Manoeuvre Node DeltaV (Total)
- Manoeuvre Node Burn Time - Manoeuvre Node Burn Time
- Manoeuvre Node Half Burn Time - Manoeuvre Node Half Burn Time
- Manoeuvre Node Angle to Prograde - Manoeuvre Node Angle to Prograde
- Manoeuvre Node Angle to Retrograde - Manoeuvre Node Angle to Retrograde
- Time to Manoeuvre Node - Time to Manoeuvre Node
- Time to Manoeuvre Burn - Time to Manoeuvre Burn
   
Added: Readout help strings by ClassyJakey. Added: Readout help strings by ClassyJakey.
   
Fixed: Issue with separators in HUDs. Fixed: Issue with separators in HUDs.
Fixed: Issue with HUDs with backgrounds that have no displayed lines. Fixed: Issue with HUDs with backgrounds that have no displayed lines.
   
Padishar's Fixes: Padishar's Fixes:
Fixed: Issue with multicouplers when attached to parent by bottom node. Fixed: Issue with multicouplers when attached to parent by bottom node.
Fixed: Issue with sepratrons on solid rocket boosters. Fixed: Issue with sepratrons on solid rocket boosters.
   
1.0.10.0, 19-10-2014 1.0.10.0, 19-10-2014
UPDATE NOTICE: If you are updating from a previous version of Kerbal Engineer 1.0, please UPDATE NOTICE: If you are updating from a previous version of Kerbal Engineer 1.0, please
delete the 'Settings/SectionLibrary.xml' file, or remove the old install first. This will delete the 'Settings/SectionLibrary.xml' file, or remove the old install first. This will
reset the Flight Engineer sections to their default values and enable the new HUD functionality. reset the Flight Engineer sections to their default values and enable the new HUD functionality.
   
Added: New reaouts to the vessel category: Added: New reaouts to the vessel category:
- Suicide Burn Altitude (height above terrain to start burn) - Suicide Burn Altitude (height above terrain to start burn)
- Suicide Burn Distance (distance to suicide burn altitude) - Suicide Burn Distance (distance to suicide burn altitude)
- Suicide Burn DeltaV (velocity change required to zero vertical speed) - Suicide Burn DeltaV (velocity change required to zero vertical speed)
*** F5 for safety and use at your own risk! *** *** F5 for safety and use at your own risk! ***
   
Added: HUD type sections to the Flight Engineer. Added: HUD type sections to the Flight Engineer.
Added: HUD sections can have a smoked background for easy visibility. Added: HUD sections can have a smoked background for easy visibility.
Added: 'Switch to Target' button on the Target Selector readout. Added: 'Switch to Target' button on the Target Selector readout.
Changed: The default installed readouts to reduce new user brain melt. Changed: The default installed readouts to reduce new user brain melt.
Fixed: Flight Engineer not saving its hidden state. Fixed: Flight Engineer not saving its hidden state.
Fixed: Bug in the phase angle calculations. Fixed: Bug in the phase angle calculations.
Fixed: Bug where the Build Engineer would stay locked after hiding with the shortcut key. Fixed: Bug where the Build Engineer would stay locked after hiding with the shortcut key.
   
1.0.9.3, 08-10-2014 1.0.9.3, 08-10-2014
Added: Title of the build engineer in compact mode now shows if you are using atmospheric data. Added: Title of the build engineer in compact mode now shows if you are using atmospheric data.
Added: New readout to the surface category: Added: New readout to the surface category:
- Vertical Acceleration - Vertical Acceleration
- Horizontal Acceleration - Horizontal Acceleration
Changed: Atmospheric efficiency readout now shows as a percentage. Changed: Atmospheric efficiency readout now shows as a percentage.
Changed: Atmospheric settings (pressure/velocity) in the editor condensed onto a single line. Changed: Atmospheric settings (pressure/velocity) in the editor condensed onto a single line.
Fixed: Bug where the overlays in the editor would stay open outside of parts screen. Fixed: Bug where the overlays in the editor would stay open outside of parts screen.
   
1.0.9.2, 07-10-2014 1.0.9.2, 07-10-2014
Updated for KSP v0.25.0 Updated for KSP v0.25.0
Changed: Prettyfied Latitude and Longitude readouts. Changed: Prettyfied Latitude and Longitude readouts.
Changed: ModuleLandingGear now uses the physical significance flag. Changed: ModuleLandingGear now uses the physical significance flag.
Changed: Updated MiniAVC to 1.0.2.4. Changed: Updated MiniAVC to 1.0.2.4.
   
1.0.9.1, 17-09-2014 1.0.9.1, 17-09-2014
Fixed: Part size bug caused by TweakScale's cost calculator. Fixed: Part size bug caused by TweakScale's cost calculator.
   
1.0.9.0, 15-09-2014 1.0.9.0, 15-09-2014
Added: Build Engineer now also implements the '\' backslash show/hide shortcut. Added: Build Engineer now also implements the '\' backslash show/hide shortcut.
Added: New readouts to the vessel category: Added: New readouts to the vessel category:
- Current Stage DeltaV - Current Stage DeltaV
- Surface Thrust to Weight Ratio - Surface Thrust to Weight Ratio
   
Added: New editor overlay system. Added: New editor overlay system.
- Sleeker design. - Sleeker design.
- Hover over part information options: - Hover over part information options:
- Name only - Name only
- Middle click to show - Middle click to show
- Always show - Always show
- Slide out overlay displays: - Slide out overlay displays:
- Vessel information - Vessel information
- Resources list - Resources list
   
Fixed: Cost calculation now works with mods implementing IPartCostModifier. Fixed: Cost calculation now works with mods implementing IPartCostModifier.
   
1.0.8.1, 06-09-2014 1.0.8.1, 06-09-2014
Fixed: Bug which caused rendezvous readouts to freeze the game or show all zeros. Fixed: Bug which caused rendezvous readouts to freeze the game or show all zeros.
   
1.0.8.0, 06-09-2014 1.0.8.0, 06-09-2014
Added: New readouts to the vessel category: Added: New readouts to the vessel category:
- Intake Air (Usage) - Intake Air (Usage)
   
Added: New readouts to the rendezvous category: Added: New readouts to the rendezvous category:
- Relative Velocity - Relative Velocity
- Relative Speed - Relative Speed
   
Fixed: An issue where deltaV would not be calculated whilst flying. Fixed: An issue where deltaV would not be calculated whilst flying.
Fixed: NullRef whilst loading the in flight Action Menu. Fixed: NullRef whilst loading the in flight Action Menu.
   
1.0.7.1, 02-09-2014 1.0.7.1, 02-09-2014
Changed: Reversed Intake Air readout from 'S/D' to 'D/S' for easier reading. Changed: Reversed Intake Air readout from 'S/D' to 'D/S' for easier reading.
Changed: Increased Intake Air readout precision to 4 decimal places. Changed: Increased Intake Air readout precision to 4 decimal places.
Fixed: Issue where Intake Air supply was not representative of total supply. Fixed: Issue where Intake Air supply was not representative of total supply.
Fixed: Bug where actual thrust does not reset to zero on deactivated engines. Fixed: Bug where actual thrust does not reset to zero on deactivated engines.
Fixed: Thrust now scales with velocity for atmospheric engines. (Padishar's fix) Fixed: Thrust now scales with velocity for atmospheric engines. (Padishar's fix)
   
1.0.7.0, 01-09-2014 1.0.7.0, 01-09-2014
Added: Part count information to the Build Engineer. Added: Part count information to the Build Engineer.
Added: Reset button to the G-Force readout. Added: Reset button to the G-Force readout.
Added: Preset system to the Flight Engineer. Added: Preset system to the Flight Engineer.
Added: New stock presets: Added: New stock presets:
- Orbital - Orbital
- Surface - Surface
- Vessel - Vessel
- Rendezvous - Rendezvous
   
Added: New readouts to the orbital category: Added: New readouts to the orbital category:
- True Anomaly - True Anomaly
- Eccentric Anomaly - Eccentric Anomaly
- Mean Anomaly - Mean Anomaly
- Argument of Periapsis - Argument of Periapsis
- Angle to Prograde - Angle to Prograde
- Angle to Retrograde - Angle to Retrograde
   
Added: New readouts to the vessel category: Added: New readouts to the vessel category:
- Intake Air (Demand) - Intake Air (Demand)
- Intake Air (Supply) - Intake Air (Supply)
- Intake Air (Supply/Demand) - Intake Air (Supply/Demand)
   
Added: New readouts to the rendezvous category. Added: New readouts to the rendezvous category.
- Semi-major Axis - Semi-major Axis
- Semi-minor Axis - Semi-minor Axis
   
Added: Time formatter which can show time as referenced by any celestial body. Added: Time formatter which can show time as referenced by any celestial body.
Added: New readouts to the miscellaneous category: Added: New readouts to the miscellaneous category:
- Time Reference Adjuster - Time Reference Adjuster
   
Changed: Moved Sim Delay readout into the Miscellaneous category. Changed: Moved Sim Delay readout into the Miscellaneous category.
Changed: Updated MiniAVC to v1.0.2.3. Changed: Updated MiniAVC to v1.0.2.3.
Fixed: Issues with large value wrap around in the Flight Engineer. Fixed: Issues with large value wrap around in the Flight Engineer.
Fixed: Bug in the phase angle calculation. Fixed: Bug in the phase angle calculation.
   
1.0.6.0, 23-08-2014 1.0.6.0, 23-08-2014
Added: Time and Angle to equatorial ascending/descending nodes in the orbital display. Added: Time and Angle to equatorial ascending/descending nodes in the orbital display.
Added: Time and Angle to relative ascending/descending nodes in the rendezvous display. Added: Time and Angle to relative ascending/descending nodes in the rendezvous display.
Added: Overlay tooltip information delay adjustment slider to the Build Engineer settings. Added: Overlay tooltip information delay adjustment slider to the Build Engineer settings.
Added: Ability to rename the stock displays in the Flight Engineer. Added: Ability to rename the stock displays in the Flight Engineer.
Changed: Build Engineer is now hidden when not in parts view. Changed: Build Engineer is now hidden when not in parts view.
Changed: Custom display panels will only show in the control bar if an abbreviation is set. Changed: Custom display panels will only show in the control bar if an abbreviation is set.
Changed: Licensing and readme structures are now more verbose to satisfy the new add-on rules. Changed: Licensing and readme structures are now more verbose to satisfy the new add-on rules.
Fixed: Updated MiniAVC to v1.0.2.1 (fixes remote check bug as well as other minor bugs). Fixed: Updated MiniAVC to v1.0.2.1 (fixes remote check bug as well as other minor bugs).
   
1.0.5.0, 13-08-2014 1.0.5.0, 13-08-2014
Added: Acceleration readout to the Vessel category (current / maximum). Added: Acceleration readout to the Vessel category (current / maximum).
Added: Category library system for the Flight Engineer readouts. Added: Category library system for the Flight Engineer readouts.
Added: Drop-down category selection to better support the new system. Added: Drop-down category selection to better support the new system.
Changed: Misc category now called Miscellaneous (this will cause previously added readouts from this category to vanish). Changed: Misc category now called Miscellaneous (this will cause previously added readouts from this category to vanish).
Fixed: Bug with the Build Engineer toolbar button. Fixed: Bug with the Build Engineer toolbar button.
Fixed: Some buggyness when trying to close the bodies drop-down in the Build Engineer via the button. Fixed: Some buggyness when trying to close the bodies drop-down in the Build Engineer via the button.
Fixed: Flight Engineer toolbar menu now hides when hiding the GUI with F2. Fixed: Flight Engineer toolbar menu now hides when hiding the GUI with F2.
Fixed: Flight Engineer toolbar button now disables when in module mode and no engineer is running. Fixed: Flight Engineer toolbar button now disables when in module mode and no engineer is running.
   
1.0.4.0, 12-08-2014 1.0.4.0, 12-08-2014
Added: Better stock toolbar support in the flight engineer. Added: Better stock toolbar support in the flight engineer.
Added: Dynamically generated celestial body library for supporting add-ons that modify the star system. Added: Dynamically generated celestial body library for supporting add-ons that modify the star system.
Changed: Reference bodies are now listed with a nestable menu system. Changed: Reference bodies are now listed with a nestable menu system.
Changed: Extended logging system has been improved. Changed: Extended logging system has been improved.
Changed: Swapped out integrated MiniAVC in place of the official bundle version. Changed: Swapped out integrated MiniAVC in place of the official bundle version.
Changed: Increased general distance precision to 1 decimal place. Changed: Increased general distance precision to 1 decimal place.
Changed: Increased Semi-major/minor axis precision to 3 decimal places. Changed: Increased Semi-major/minor axis precision to 3 decimal places.
Fixed: Impact altitude was mistakenly formatted as an angle, it is now formatted correctly as a distance. Fixed: Impact altitude was mistakenly formatted as an angle, it is now formatted correctly as a distance.
   
1.0.3.0, 30-07-2014 1.0.3.0, 30-07-2014
Added: Integrated KSP-AVC support with MiniAVC. Added: Integrated KSP-AVC support with MiniAVC.
Added: Setting to change the simulation delay in the Build Engineer. Added: Setting to change the simulation delay in the Build Engineer.
Added: Setting to enable and disable the build overlay system. Added: Setting to enable and disable the build overlay system.
Added: Burn time to Delta-V readouts. Added: Burn time to Delta-V readouts.
Added: Atmospheric readouts fully support FAR. Added: Atmospheric readouts fully support FAR.
Added: Atmospheric readouts are disabled with NEAR. Added: Atmospheric readouts are disabled with NEAR.
Changed: Force formatting inversely scales decimal precision with value. Changed: Force formatting inversely scales decimal precision with value.
Fixed: Flickering in VAB and Vessel display. Fixed: Flickering in VAB and Vessel display.
Fixed: Bug saving the GUI display size. Fixed: Bug saving the GUI display size.
   
1.0.2.0, 27-07-2014 1.0.2.0, 27-07-2014
Added: Separator readout module under Misc in the Flight Engineer. Added: Separator readout module under Misc in the Flight Engineer.
Added: Adjustable GUI display size. Added: Adjustable GUI display size.
Added: Display size can be adjusted in the Build Engineer settings. Added: Display size can be adjusted in the Build Engineer settings.
Added: Misc readout for adjusting display size in the Flight Engineer. Added: Misc readout for adjusting display size in the Flight Engineer.
Changed: The rendezvous readout for the target's Orbital Period has higher precision. Changed: The rendezvous readout for the target's Orbital Period has higher precision.
Fixed: White toolbar icon by manually importing the texture if it cannot be found in the game database. Fixed: White toolbar icon by manually importing the texture if it cannot be found in the game database.
Fixed: Engines that have a minimum thrust are now calculated properly. (Thanks to nosscire.) Fixed: Engines that have a minimum thrust are now calculated properly. (Thanks to nosscire.)
Fixed: Compact collapse mode is now saved in the Build Engineer. Fixed: Compact collapse mode is now saved in the Build Engineer.
   
1.0.1.0, 26-07-2014 1.0.1.0, 26-07-2014
Added: Part-less Flight Engineer. Added: Part-less Flight Engineer.
Added: Ability to collapse the Build Engineer into compact mode from left or right. Added: Ability to collapse the Build Engineer into compact mode from left or right.
Added: Settings in Build Engineer for compact collapse mode and partless/module Flight Engineer. Added: Settings in Build Engineer for compact collapse mode and partless/module Flight Engineer.
Added: Biome, Impact Biome and Slope readouts. Added: Biome, Impact Biome and Slope readouts.
Added: Extra logging and exception handling. Added: Extra logging and exception handling.
Added: The original Engineer Chip part. Added: The original Engineer Chip part.
Added: "Show Engineer" toggle on the Flight Engineer toolbar. Added: "Show Engineer" toggle on the Flight Engineer toolbar.
Changed: Extended logging system now also writes to the standard KSP logs. Changed: Extended logging system now also writes to the standard KSP logs.
Changed: Extended logging saves next to the .dll file. Changed: Extended logging saves next to the .dll file.
Changed: ER7500 part has no physical significance. Changed: ER7500 part has no physical significance.
Fixed: ActionMenu and DisplayStack destruction bug. Fixed: ActionMenu and DisplayStack destruction bug.
   
1.0.0.1, 24-07-2014 1.0.0.1, 24-07-2014
Added: Stock toolbar support in the Flight Engineer. Added: Stock toolbar support in the Flight Engineer.
Changed: Orbital Period has higher precision. Changed: Orbital Period has higher precision.
Fixed: Various NullRefs in editor window and overlay. Fixed: Various NullRefs in editor window and overlay.
1.0.0.0, 24-07-2014 1.0.0.0, 24-07-2014
Initial release for public testing. Initial release for public testing.
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives  
   
using System;  
using System.Linq;  
   
using KerbalEngineer.Extensions;  
using KerbalEngineer.Flight;  
using KerbalEngineer.Helpers;  
using KerbalEngineer.Settings;  
using KerbalEngineer.UIControls;  
using KerbalEngineer.VesselSimulator;  
   
using UnityEngine;  
   
#endregion  
   
namespace KerbalEngineer.Editor namespace KerbalEngineer.Editor
{ {
  #region Using Directives
   
  using System;
  using System.Linq;
  using Extensions;
  using Flight;
  using Helpers;
  using Settings;
  using UIControls;
  using UnityEngine;
  using VesselSimulator;
   
  #endregion
   
[KSPAddon(KSPAddon.Startup.EditorAny, false)] [KSPAddon(KSPAddon.Startup.EditorAny, false)]
public class BuildAdvanced : MonoBehaviour public class BuildAdvanced : MonoBehaviour
{ {
#region Fields #region Fields
   
private GUIStyle areaSettingStyle; private GUIStyle areaSettingStyle;
private GUIStyle areaStyle; private GUIStyle areaStyle;
private float atmosphericPercentage = 1.0f; private float atmosphericPercentage = 1.0f;
private float atmosphericVelocity; private float atmosphericVelocity;
private GUIStyle bodiesButtonActiveStyle; private GUIStyle bodiesButtonActiveStyle;
private GUIStyle bodiesButtonStyle; private GUIStyle bodiesButtonStyle;
private DropDown bodiesList; private DropDown bodiesList;
private Rect bodiesListPosition; private Rect bodiesListPosition;
private GUIStyle buttonStyle; private GUIStyle buttonStyle;
private int compactCheck; private int compactCheck;
private bool compactCollapseRight; private bool compactCollapseRight;
private bool compactMode; private bool compactMode;
private float compactRight; private float compactRight;
private bool hasChanged; private bool hasChanged;
private GUIStyle infoStyle; private GUIStyle infoStyle;
private bool isEditorLocked; private bool isEditorLocked;
private int numberOfStages; private int numberOfStages;
private Rect position = new Rect(265.0f, 45.0f, 0, 0); private Rect position = new Rect(265.0f, 45.0f, 0, 0);
private GUIStyle settingAtmoStyle; private GUIStyle settingAtmoStyle;
private GUIStyle settingStyle; private GUIStyle settingStyle;
private bool showAllStages; private bool showAllStages;
private bool showAtmosphericDetails; private bool showAtmosphericDetails;
private bool showSettings; private bool showSettings;
private Stage[] stages; private Stage[] stages;
private GUIStyle titleStyle; private GUIStyle titleStyle;
private bool visible = true; private bool visible = true;
private GUIStyle windowStyle; private GUIStyle windowStyle;
   
#endregion #endregion
   
#region Properties #region Properties
   
/// <summary> /// <summary>
/// Gets the current instance if started or returns null. /// Gets the current instance if started or returns null.
/// </summary> /// </summary>
public static BuildAdvanced Instance { get; private set; } public static BuildAdvanced Instance { get; private set; }
   
/// <summary> /// <summary>
/// Gets and sets whether to show in compact mode. /// Gets and sets whether to show in compact mode.
/// </summary> /// </summary>
public bool CompactMode public bool CompactMode
{ {
get { return this.compactMode; } get { return this.compactMode; }
set { this.compactMode = value; } set { this.compactMode = value; }
} }
   
/// <summary> /// <summary>
/// Gets and sets whether to show all stages. /// Gets and sets whether to show all stages.
/// </summary> /// </summary>
public bool ShowAllStages public bool ShowAllStages
{ {
get { return this.showAllStages; } get { return this.showAllStages; }
set { this.showAllStages = value; } set { this.showAllStages = value; }
} }
   
/// <summary> /// <summary>
/// Gets and sets whether to use atmospheric details. /// Gets and sets whether to use atmospheric details.
/// </summary> /// </summary>
public bool ShowAtmosphericDetails public bool ShowAtmosphericDetails
{ {
get { return this.showAtmosphericDetails; } get { return this.showAtmosphericDetails; }
set { this.showAtmosphericDetails = value; } set { this.showAtmosphericDetails = value; }
} }
   
/// <summary> /// <summary>
/// Gets and sets whether to show the settings display. /// Gets and sets whether to show the settings display.
/// </summary> /// </summary>
public bool ShowSettings public bool ShowSettings
{ {
get { return this.showSettings; } get { return this.showSettings; }
set { this.showSettings = value; } set { this.showSettings = value; }
} }
   
/// <summary> /// <summary>
/// Gets and sets whether the display is enabled. /// Gets and sets whether the display is enabled.
/// </summary> /// </summary>
public bool Visible public bool Visible
{ {
get { return this.visible; } get { return this.visible; }
set { this.visible = value; } set { this.visible = value; }
} }
   
#endregion #endregion
   
#region Methods: protected #region Methods
   
protected void Awake() protected void Awake()
{ {
try try
{ {
Instance = this; Instance = this;
this.bodiesList = this.gameObject.AddComponent<DropDown>(); this.bodiesList = this.gameObject.AddComponent<DropDown>();
this.bodiesList.DrawCallback = this.DrawBodiesList; this.bodiesList.DrawCallback = this.DrawBodiesList;
this.Load(); this.Load();
   
  SimManager.OnReady -= this.GetStageInfo;
  SimManager.OnReady += this.GetStageInfo;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
/// <summary> /// <summary>
/// Saves the settings when this object is destroyed. /// Saves the settings when this object is destroyed.
/// </summary> /// </summary>
protected void OnDestroy() protected void OnDestroy()
{ {
try try
{ {
var handler = new SettingHandler(); var handler = new SettingHandler();
handler.Set("visible", this.visible); handler.Set("visible", this.visible);
handler.Set("windowPositionX", this.position.x); handler.Set("windowPositionX", this.position.x);
handler.Set("windowPositionY", this.position.y); handler.Set("windowPositionY", this.position.y);
handler.Set("compactMode", this.compactMode); handler.Set("compactMode", this.compactMode);
handler.Set("compactCollapseRight", this.compactCollapseRight); handler.Set("compactCollapseRight", this.compactCollapseRight);
handler.Set("showAllStages", this.showAllStages); handler.Set("showAllStages", this.showAllStages);
handler.Set("showAtmosphericDetails", this.showAtmosphericDetails); handler.Set("showAtmosphericDetails", this.showAtmosphericDetails);
handler.Set("showSettings", this.showSettings); handler.Set("showSettings", this.showSettings);
handler.Set("selectedBodyName", CelestialBodies.SelectedBody.Name); handler.Set("selectedBodyName", CelestialBodies.SelectedBody.Name);
handler.Save("BuildAdvanced.xml"); handler.Save("BuildAdvanced.xml");
GuiDisplaySize.OnSizeChanged -= this.OnSizeChanged; GuiDisplaySize.OnSizeChanged -= this.OnSizeChanged;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
  private void GetStageInfo()
  {
  this.stages = SimManager.Stages;
  }
   
protected void OnGUI() protected void OnGUI()
{ {
try try
{ {
if (!this.visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0 || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts) if (!this.visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0 || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts)
{ {
return; return;
} }
   
if (SimManager.ResultsReady())  
{  
this.stages = SimManager.Stages;  
}  
   
SimManager.RequestSimulation();  
   
if (this.stages == null) if (this.stages == null)
{ {
return; return;
} }
   
// Change the window title based on whether in compact mode or not. // Change the window title based on whether in compact mode or not.
var title = !this.compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion : "K.E.R. " + EngineerGlobals.AssemblyVersion + (this.showAtmosphericDetails ? " (ATMOS.)" : String.Empty); var title = !this.compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion : "K.E.R. " + EngineerGlobals.AssemblyVersion + (this.showAtmosphericDetails ? " (ATMOS.)" : String.Empty);
   
// Reset the window size when the staging or something else has changed. // Reset the window size when the staging or something else has changed.
var stageCount = this.stages.Count(stage => this.showAllStages || stage.deltaV > 0); var stageCount = this.stages.Count(stage => this.showAllStages || stage.deltaV > 0);
if (this.hasChanged || stageCount != this.numberOfStages) if (this.hasChanged || stageCount != this.numberOfStages)
{ {
this.hasChanged = false; this.hasChanged = false;
this.numberOfStages = stageCount; this.numberOfStages = stageCount;
   
this.position.width = 0; this.position.width = 0;
this.position.height = 0; this.position.height = 0;
} }
   
GUI.skin = null; GUI.skin = null;
this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, title, this.windowStyle).ClampToScreen(); this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, title, this.windowStyle).ClampToScreen();
   
if (this.compactCheck > 0 && this.compactCollapseRight) if (this.compactCheck > 0 && this.compactCollapseRight)
{ {
this.position.x = this.compactRight - this.position.width; this.position.x = this.compactRight - this.position.width;
this.compactCheck--; this.compactCheck--;
} }
else if (this.compactCheck > 0) else if (this.compactCheck > 0)
{ {
this.compactCheck = 0; this.compactCheck = 0;
} }
   
// Check editor lock to manage click-through. // Check editor lock to manage click-through.
this.CheckEditorLock(); this.CheckEditorLock();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void Start() protected void Start()
{ {
try try
{ {
this.InitialiseStyles(); this.InitialiseStyles();
GuiDisplaySize.OnSizeChanged += this.OnSizeChanged; GuiDisplaySize.OnSizeChanged += this.OnSizeChanged;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void Update() protected void Update()
{ {
try try
{ {
if (Input.GetKeyDown(KeyBinder.EditorShowHide)) if (Input.GetKeyDown(KeyBinder.EditorShowHide))
{ {
this.visible = !this.visible; this.visible = !this.visible;
if (!this.visible) if (!this.visible)
{ {
this.EditorLock(false); this.EditorLock(false);
} }
} }
   
if (!this.visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0) if (!this.visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0)
{ {
this.bodiesList.enabled = false; this.bodiesList.enabled = false;
return; return;
} }
   
// Configure the simulation parameters based on the selected reference body. // Configure the simulation parameters based on the selected reference body.
SimManager.Gravity = CelestialBodies.SelectedBody.Gravity; SimManager.Gravity = CelestialBodies.SelectedBody.Gravity;
   
if (this.showAtmosphericDetails) if (this.showAtmosphericDetails)
{ {
SimManager.Atmosphere = CelestialBodies.SelectedBody.Atmosphere * 0.01d * this.atmosphericPercentage; SimManager.Atmosphere = CelestialBodies.SelectedBody.Atmosphere * 0.01d * this.atmosphericPercentage;
} }
else else
{ {
SimManager.Atmosphere = 0; SimManager.Atmosphere = 0;
} }
   
SimManager.Velocity = this.atmosphericVelocity; SimManager.Velocity = this.atmosphericVelocity;
   
  SimManager.RequestSimulation();
SimManager.TryStartSimulation(); SimManager.TryStartSimulation();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced->Update"); Logger.Exception(ex, "BuildAdvanced->Update");
} }
} }
   
#endregion  
   
#region Methods: private  
   
/// <summary> /// <summary>
/// Checks whether the editor should be locked to stop click-through. /// Checks whether the editor should be locked to stop click-through.
/// </summary> /// </summary>
private void CheckEditorLock() private void CheckEditorLock()
{ {
if ((this.position.MouseIsOver() || this.bodiesList.Position.MouseIsOver()) && !this.isEditorLocked) if ((this.position.MouseIsOver() || this.bodiesList.Position.MouseIsOver()) && !this.isEditorLocked)
{ {
this.EditorLock(true); this.EditorLock(true);
} }
else if (!this.position.MouseIsOver() && !this.bodiesList.Position.MouseIsOver() && this.isEditorLocked) else if (!this.position.MouseIsOver() && !this.bodiesList.Position.MouseIsOver() && this.isEditorLocked)
{ {
this.EditorLock(false); this.EditorLock(false);
} }
} }
   
/// <summary> /// <summary>
/// Draws the atmospheric settings. /// Draws the atmospheric settings.
/// </summary> /// </summary>
private void DrawAtmosphericDetails() private void DrawAtmosphericDetails()
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.BeginVertical(); GUILayout.BeginVertical();
GUILayout.Label("Pressure: " + (this.atmosphericPercentage * 100.0f).ToString("F1") + "%", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset)); GUILayout.Label("Pressure: " + (this.atmosphericPercentage * 100.0f).ToString("F1") + "%", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
this.atmosphericPercentage = GUILayout.HorizontalSlider(this.atmosphericPercentage, 0, 1.0f); this.atmosphericPercentage = GUILayout.HorizontalSlider(this.atmosphericPercentage, 0, 1.0f);
GUI.skin = null; GUI.skin = null;
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.Space(5.0f); GUILayout.Space(5.0f);
   
GUILayout.BeginVertical(); GUILayout.BeginVertical();
GUILayout.Label("Velocity: " + this.atmosphericVelocity.ToString("F1") + "m/s", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset)); GUILayout.Label("Velocity: " + this.atmosphericVelocity.ToString("F1") + "m/s", this.settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
this.atmosphericVelocity = GUILayout.HorizontalSlider(this.atmosphericVelocity, 0, 2500f); this.atmosphericVelocity = GUILayout.HorizontalSlider(this.atmosphericVelocity, 0, 2500f);
GUI.skin = null; GUI.skin = null;
GUILayout.EndVertical(); GUILayout.EndVertical();
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
private void DrawBodiesList() private void DrawBodiesList()
{ {
if (CelestialBodies.SystemBody == CelestialBodies.SelectedBody) if (CelestialBodies.SystemBody == CelestialBodies.SelectedBody)
{ {
this.DrawBody(CelestialBodies.SystemBody); this.DrawBody(CelestialBodies.SystemBody);
} }
else else
{ {
foreach (var body in CelestialBodies.SystemBody.Children) foreach (var body in CelestialBodies.SystemBody.Children)
{ {
this.DrawBody(body); this.DrawBody(body);
} }
} }
} }
   
private void DrawBody(CelestialBodies.BodyInfo bodyInfo, int depth = 0) private void DrawBody(CelestialBodies.BodyInfo bodyInfo, int depth = 0)
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Space(20.0f * depth); GUILayout.Space(20.0f * depth);
if (GUILayout.Button(bodyInfo.Children.Count > 0 ? bodyInfo.Name + " [" + bodyInfo.Children.Count + "]" : bodyInfo.Name, bodyInfo.Selected && bodyInfo.SelectedDepth == 0 ? this.bodiesButtonActiveStyle : this.bodiesButtonStyle)) if (GUILayout.Button(bodyInfo.Children.Count > 0 ? bodyInfo.Name + " [" + bodyInfo.Children.Count + "]" : bodyInfo.Name, bodyInfo.Selected && bodyInfo.SelectedDepth == 0 ? this.bodiesButtonActiveStyle : this.bodiesButtonStyle))
{ {
CelestialBodies.SetSelectedBody(bodyInfo.Name); CelestialBodies.SetSelectedBody(bodyInfo.Name);
this.bodiesList.Resize = true; this.bodiesList.Resize = true;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (bodyInfo.Selected) if (bodyInfo.Selected)
{ {
foreach (var body in bodyInfo.Children) foreach (var body in bodyInfo.Children)
{ {
this.DrawBody(body, depth + 1); this.DrawBody(body, depth + 1);
} }
} }
} }
   
/// <summary> /// <summary>
/// Draws the burn time column. /// Draws the burn time column.
/// </summary> /// </summary>
private void DrawBurnTime() private void DrawBurnTime()
{ {
GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
GUILayout.Label("BURN", this.titleStyle); GUILayout.Label("BURN", this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label(TimeFormatter.ConvertToString(stage.time), this.infoStyle); GUILayout.Label(TimeFormatter.ConvertToString(stage.time), this.infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the cost column. /// Draws the cost column.
/// </summary> /// </summary>
private void DrawCost() private void DrawCost()
{ {
GUILayout.BeginVertical(GUILayout.Width(110.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(110.0f * GuiDisplaySize.Offset));
GUILayout.Label("COST", this.titleStyle); GUILayout.Label("COST", this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label(Units.Concat(stage.cost, stage.totalCost), this.infoStyle); GUILayout.Label(Units.Concat(stage.cost, stage.totalCost), this.infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the deltaV column. /// Draws the deltaV column.
/// </summary> /// </summary>
private void DrawDeltaV() private void DrawDeltaV()
{ {
GUILayout.BeginVertical(GUILayout.Width(100.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.Label("DELTA-V", this.titleStyle); GUILayout.Label("DELTA-V", this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label(stage.deltaV.ToString("N0") + " / " + stage.inverseTotalDeltaV.ToString("N0") + "m/s", this.infoStyle); GUILayout.Label(stage.deltaV.ToString("N0") + " / " + stage.inverseTotalDeltaV.ToString("N0") + "m/s", this.infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the specific impluse column. /// Draws the specific impluse column.
/// </summary> /// </summary>
private void DrawIsp() private void DrawIsp()
{ {
GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
GUILayout.Label("ISP", this.titleStyle); GUILayout.Label("ISP", this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label(stage.isp.ToString("F1") + "s", this.infoStyle); GUILayout.Label(stage.isp.ToString("F1") + "s", this.infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the mass column. /// Draws the mass column.
/// </summary> /// </summary>
private void DrawMass() private void DrawMass()
{ {
GUILayout.BeginVertical(GUILayout.Width(110.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(110.0f * GuiDisplaySize.Offset));
GUILayout.Label("MASS", this.titleStyle); GUILayout.Label("MASS", this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label(Units.ToMass(stage.mass, stage.totalMass), this.infoStyle); GUILayout.Label(Units.ToMass(stage.mass, stage.totalMass), this.infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the part count column. /// Draws the part count column.
/// </summary> /// </summary>
private void DrawPartCount() private void DrawPartCount()
{ {
GUILayout.BeginVertical(GUILayout.Width(50.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(50.0f * GuiDisplaySize.Offset));
GUILayout.Label("PARTS", this.titleStyle); GUILayout.Label("PARTS", this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label(stage.partCount.ToString("N0"), this.infoStyle); GUILayout.Label(stage.partCount + " / " + stage.totalPartCount, this.infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the settings panel. /// Draws the settings panel.
/// </summary> /// </summary>
private void DrawSettings() private void DrawSettings()
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Compact mode collapses to the:", this.settingStyle); GUILayout.Label("Compact mode collapses to the:", this.settingStyle);
this.compactCollapseRight = !GUILayout.Toggle(!this.compactCollapseRight, "LEFT", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); this.compactCollapseRight = !GUILayout.Toggle(!this.compactCollapseRight, "LEFT", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
this.compactCollapseRight = GUILayout.Toggle(this.compactCollapseRight, "RIGHT", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); this.compactCollapseRight = GUILayout.Toggle(this.compactCollapseRight, "RIGHT", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
  GUILayout.EndHorizontal();
   
  GUILayout.BeginHorizontal();
  GUILayout.Label("Simulate using vectored thrust values:");
  SimManager.vectoredThrust = GUILayout.Toggle(SimManager.vectoredThrust, "ENABLED", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Build Engineer Overlay:", this.settingStyle); GUILayout.Label("Build Engineer Overlay:", this.settingStyle);
BuildOverlay.Visible = GUILayout.Toggle(BuildOverlay.Visible, "VISIBLE", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); BuildOverlay.Visible = GUILayout.Toggle(BuildOverlay.Visible, "VISIBLE", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
BuildOverlayPartInfo.NamesOnly = GUILayout.Toggle(BuildOverlayPartInfo.NamesOnly, "NAMES ONLY", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); BuildOverlayPartInfo.NamesOnly = GUILayout.Toggle(BuildOverlayPartInfo.NamesOnly, "NAMES ONLY", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
BuildOverlayPartInfo.ClickToOpen = GUILayout.Toggle(BuildOverlayPartInfo.ClickToOpen, "CLICK TO OPEN", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); BuildOverlayPartInfo.ClickToOpen = GUILayout.Toggle(BuildOverlayPartInfo.ClickToOpen, "CLICK TO OPEN", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Flight Engineer activation mode:", this.settingStyle); GUILayout.Label("Flight Engineer activation mode:", this.settingStyle);
FlightEngineerPartless.IsPartless = GUILayout.Toggle(FlightEngineerPartless.IsPartless, "PARTLESS", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); FlightEngineerPartless.IsPartless = GUILayout.Toggle(FlightEngineerPartless.IsPartless, "PARTLESS", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
FlightEngineerPartless.IsPartless = !GUILayout.Toggle(!FlightEngineerPartless.IsPartless, "MODULE", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); FlightEngineerPartless.IsPartless = !GUILayout.Toggle(!FlightEngineerPartless.IsPartless, "MODULE", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("GUI Size: " + GuiDisplaySize.Increment, this.settingStyle); GUILayout.Label("GUI Size: " + GuiDisplaySize.Increment, this.settingStyle);
if (GUILayout.Button("<", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset))) if (GUILayout.Button("<", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)))
{ {
GuiDisplaySize.Increment--; GuiDisplaySize.Increment--;
} }
if (GUILayout.Button(">", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset))) if (GUILayout.Button(">", this.buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)))
{ {
GuiDisplaySize.Increment++; GuiDisplaySize.Increment++;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime + "ms", this.settingStyle); GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.Milliseconds + "ms", this.settingStyle);
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
SimManager.minSimTime = (long)GUILayout.HorizontalSlider(SimManager.minSimTime, 0, 2000.0f); SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 2000.0f));
GUI.skin = null; GUI.skin = null;
} }
   
/// <summary> /// <summary>
/// Draws the stage number column. /// Draws the stage number column.
/// </summary> /// </summary>
private void DrawStageNumbers() private void DrawStageNumbers()
{ {
GUILayout.BeginVertical(GUILayout.Width(30.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(30.0f * GuiDisplaySize.Offset));
GUILayout.Label(string.Empty, this.titleStyle); GUILayout.Label(string.Empty, this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label("S" + stage.number, this.titleStyle); GUILayout.Label("S" + stage.number, this.titleStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the thrust column. /// Draws the thrust column.
/// </summary> /// </summary>
private void DrawThrust() private void DrawThrust()
{ {
GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
GUILayout.Label("THRUST", this.titleStyle); GUILayout.Label("THRUST", this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label(stage.thrust.ToForce(), this.infoStyle); GUILayout.Label(stage.thrust.ToForce(), this.infoStyle);
  }
  }
  GUILayout.EndVertical();
  }
   
  /// <summary>
  /// Draws the torque column.
  /// </summary>
  private void DrawTorque()
  {
  GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
  GUILayout.Label("TORQUE", this.titleStyle);
  foreach (var stage in this.stages)
  {
  if (this.showAllStages || stage.deltaV > 0)
  {
  GUILayout.Label(stage.maxThrustTorque.ToTorque(), this.infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Drwas the thrust to weight ratio column. /// Drwas the thrust to weight ratio column.
/// </summary> /// </summary>
private void DrawTwr() private void DrawTwr()
{ {
GUILayout.BeginVertical(GUILayout.Width(100.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.Label("TWR (MAX)", this.titleStyle); GUILayout.Label("TWR (MAX)", this.titleStyle);
foreach (var stage in this.stages) foreach (var stage in this.stages)
{ {
if (this.showAllStages || stage.deltaV > 0) if (this.showAllStages || stage.deltaV > 0)
{ {
GUILayout.Label(stage.thrustToWeight.ToString("F2") + " (" + stage.maxThrustToWeight.ToString("F2") + ")", this.infoStyle); GUILayout.Label(stage.thrustToWeight.ToString("F2") + " (" + stage.maxThrustToWeight.ToString("F2") + ")", this.infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
private void EditorLock(bool state) private void EditorLock(bool state)
{ {
if (state) if (state)
{ {
EditorLogic.fetch.Lock(true, true, true, "KER_BuildAdvanced"); EditorLogic.fetch.Lock(true, true, true, "KER_BuildAdvanced");
BuildOverlayPartInfo.Hidden = true; BuildOverlayPartInfo.Hidden = true;
this.isEditorLocked = true; this.isEditorLocked = true;
} }
else else
{ {
EditorLogic.fetch.Unlock("KER_BuildAdvanced"); EditorLogic.fetch.Unlock("KER_BuildAdvanced");
BuildOverlayPartInfo.Hidden = false; BuildOverlayPartInfo.Hidden = false;
this.isEditorLocked = false; this.isEditorLocked = false;
} }
} }
   
/// <summary> /// <summary>
/// Initialises all the styles that are required. /// Initialises all the styles that are required.
/// </summary> /// </summary>
private void InitialiseStyles() private void InitialiseStyles()
{ {
this.windowStyle = new GUIStyle(HighLogic.Skin.window) this.windowStyle = new GUIStyle(HighLogic.Skin.window)
{ {
alignment = TextAnchor.UpperLeft alignment = TextAnchor.UpperLeft
}; };
   
this.areaStyle = new GUIStyle(HighLogic.Skin.box) this.areaStyle = new GUIStyle(HighLogic.Skin.box)
{ {
padding = new RectOffset(0, 0, 9, 0) padding = new RectOffset(0, 0, 9, 0)
}; };
   
this.areaSettingStyle = new GUIStyle(HighLogic.Skin.box) this.areaSettingStyle = new GUIStyle(HighLogic.Skin.box)
{ {
padding = new RectOffset(10, 10, 10, 10) padding = new RectOffset(10, 10, 10, 10)
}; };
   
this.buttonStyle = new GUIStyle(HighLogic.Skin.button) this.buttonStyle = new GUIStyle(HighLogic.Skin.button)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
alignment = TextAnchor.MiddleCenter alignment = TextAnchor.MiddleCenter
}; };
   
this.titleStyle = new GUIStyle(HighLogic.Skin.label) this.titleStyle = new GUIStyle(HighLogic.Skin.label)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
stretchWidth = true, stretchWidth = true,
}; };
   
this.infoStyle = new GUIStyle(HighLogic.Skin.label) this.infoStyle = new GUIStyle(HighLogic.Skin.label)
{ {
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
stretchWidth = true stretchWidth = true
}; };
   
this.settingStyle = new GUIStyle(this.titleStyle) this.settingStyle = new GUIStyle(this.titleStyle)
{ {
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
stretchWidth = true, stretchWidth = true,
stretchHeight = true stretchHeight = true
}; };
   
this.settingAtmoStyle = new GUIStyle(this.titleStyle) this.settingAtmoStyle = new GUIStyle(this.titleStyle)
{ {
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(), padding = new RectOffset(),
alignment = TextAnchor.UpperLeft alignment = TextAnchor.UpperLeft
}; };
   
this.bodiesButtonStyle = new GUIStyle(HighLogic.Skin.button) this.bodiesButtonStyle = new GUIStyle(HighLogic.Skin.button)
{ {
margin = new RectOffset(0, 0, 2, 0), margin = new RectOffset(0, 0, 2, 0),
padding = new RectOffset(5, 5, 5, 5), padding = new RectOffset(5, 5, 5, 5),
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
active = active =
{ {
textColor = Color.white textColor = Color.white
}, },
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
fixedHeight = 20.0f fixedHeight = 20.0f
}; };
   
this.bodiesButtonActiveStyle = new GUIStyle(this.bodiesButtonStyle) this.bodiesButtonActiveStyle = new GUIStyle(this.bodiesButtonStyle)
{ {
normal = this.bodiesButtonStyle.onNormal, normal = this.bodiesButtonStyle.onNormal,
hover = this.bodiesButtonStyle.onHover hover = this.bodiesButtonStyle.onHover
}; };
} }
   
/// <summary> /// <summary>
/// Loads the settings when this object is created. /// Loads the settings when this object is created.
/// </summary> /// </summary>
private void Load() private void Load()
{ {
try try
{ {
var handler = SettingHandler.Load("BuildAdvanced.xml"); var handler = SettingHandler.Load("BuildAdvanced.xml");
handler.Get("visible", ref this.visible); handler.Get("visible", ref this.visible);
this.position.x = handler.Get("windowPositionX", this.position.x); this.position.x = handler.Get("windowPositionX", this.position.x);
this.position.y = handler.Get("windowPositionY", this.position.y); this.position.y = handler.Get("windowPositionY", this.position.y);
handler.Get("compactMode", ref this.compactMode); handler.Get("compactMode", ref this.compactMode);
handler.Get("compactCollapseRight", ref this.compactCollapseRight); handler.Get("compactCollapseRight", ref this.compactCollapseRight);
handler.Get("showAllStages", ref this.showAllStages); handler.Get("showAllStages", ref this.showAllStages);
handler.Get("showAtmosphericDetails", ref this.showAtmosphericDetails); handler.Get("showAtmosphericDetails", ref this.showAtmosphericDetails);
handler.Get("showSettings", ref this.showSettings); handler.Get("showSettings", ref this.showSettings);
CelestialBodies.SetSelectedBody(handler.Get("selectedBodyName", CelestialBodies.SelectedBody.Name)); CelestialBodies.SetSelectedBody(handler.Get("selectedBodyName", CelestialBodies.SelectedBody.Name));
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced->Load"); Logger.Exception(ex, "BuildAdvanced->Load");
} }
} }
   
private void OnSizeChanged() private void OnSizeChanged()
{ {
this.InitialiseStyles(); this.InitialiseStyles();
this.hasChanged = true; this.hasChanged = true;
} }
   
/// <summary> /// <summary>
/// Draws the OnGUI window. /// Draws the OnGUI window.
/// </summary> /// </summary>
private void Window(int windowId) private void Window(int windowId)
{ {
try try
{ {
// Draw the compact mode toggle. // Draw the compact mode toggle.
if (GUI.Toggle(new Rect(this.position.width - 70.0f * GuiDisplaySize.Offset, 5.0f, 65.0f * GuiDisplaySize.Offset, 20.0f), this.compactMode, "COMPACT", this.buttonStyle) != this.compactMode) if (GUI.Toggle(new Rect(this.position.width - 70.0f * GuiDisplaySize.Offset, 5.0f, 65.0f * GuiDisplaySize.Offset, 20.0f), this.compactMode, "COMPACT", this.buttonStyle) != this.compactMode)
{ {
this.hasChanged = true; this.hasChanged = true;
this.compactCheck = 2; this.compactCheck = 2;
this.compactRight = this.position.xMax; this.compactRight = this.position.xMax;
this.compactMode = !this.compactMode; this.compactMode = !this.compactMode;
} }
   
// When not in compact mode draw the 'All Stages' and 'Atmospheric' toggles. // When not in compact mode draw the 'All Stages' and 'Atmospheric' toggles.
if (!this.compactMode) if (!this.compactMode)
{ {
if (GUI.Toggle(new Rect(this.position.width - 143.0f * GuiDisplaySize.Offset, 5.0f, 70.0f * GuiDisplaySize.Offset, 20.0f), this.showSettings, "SETTINGS", this.buttonStyle) != this.showSettings) if (GUI.Toggle(new Rect(this.position.width - 143.0f * GuiDisplaySize.Offset, 5.0f, 70.0f * GuiDisplaySize.Offset, 20.0f), this.showSettings, "SETTINGS", this.buttonStyle) != this.showSettings)
{ {
this.hasChanged = true; this.hasChanged = true;
this.showSettings = !this.showSettings; this.showSettings = !this.showSettings;
} }
   
if (GUI.Toggle(new Rect(this.position.width - 226.0f * GuiDisplaySize.Offset, 5.0f, 80.0f * GuiDisplaySize.Offset, 20.0f), this.showAllStages, "ALL STAGES", this.buttonStyle) != this.showAllStages) if (GUI.Toggle(new Rect(this.position.width - 226.0f * GuiDisplaySize.Offset, 5.0f, 80.0f * GuiDisplaySize.Offset, 20.0f), this.showAllStages, "ALL STAGES", this.buttonStyle) != this.showAllStages)
{ {
this.hasChanged = true; this.hasChanged = true;
this.showAllStages = !this.showAllStages; this.showAllStages = !this.showAllStages;
} }
   
if (GUI.Toggle(new Rect(this.position.width - 324.0f * GuiDisplaySize.Offset, 5.0f, 95.0f * GuiDisplaySize.Offset, 20.0f), this.showAtmosphericDetails, "ATMOSPHERIC", this.buttonStyle) != this.showAtmosphericDetails) if (GUI.Toggle(new Rect(this.position.width - 324.0f * GuiDisplaySize.Offset, 5.0f, 95.0f * GuiDisplaySize.Offset, 20.0f), this.showAtmosphericDetails, "ATMOSPHERIC", this.buttonStyle) != this.showAtmosphericDetails)
{ {
this.hasChanged = true; this.hasChanged = true;
this.showAtmosphericDetails = !this.showAtmosphericDetails; this.showAtmosphericDetails = !this.showAtmosphericDetails;
} }
   
this.bodiesListPosition = new Rect(this.position.width - 452.0f * GuiDisplaySize.Offset, 5.0f, 125.0f * GuiDisplaySize.Offset, 20.0f); this.bodiesListPosition = new Rect(this.position.width - 452.0f * GuiDisplaySize.Offset, 5.0f, 125.0f * GuiDisplaySize.Offset, 20.0f);
this.bodiesList.enabled = GUI.Toggle(this.bodiesListPosition, this.bodiesList.enabled, "BODY: " + CelestialBodies.SelectedBody.Name.ToUpper(), this.buttonStyle); this.bodiesList.enabled = GUI.Toggle(this.bodiesListPosition, this.bodiesList.enabled, "BODY: " + CelestialBodies.SelectedBody.Name.ToUpper(), this.buttonStyle);
this.bodiesList.SetPosition(this.bodiesListPosition.Translate(this.position)); this.bodiesList.SetPosition(this.bodiesListPosition.Translate(this.position));
} }
   
// Draw the main informational display box. // Draw the main informational display box.
if (!this.compactMode) if (!this.compactMode)
{ {
GUILayout.BeginHorizontal(this.areaStyle); GUILayout.BeginHorizontal(this.areaStyle);
this.DrawStageNumbers(); this.DrawStageNumbers();
this.DrawPartCount(); this.DrawPartCount();
this.DrawCost(); this.DrawCost();
this.DrawMass(); this.DrawMass();
this.DrawIsp(); this.DrawIsp();
this.DrawThrust(); this.DrawThrust();
  this.DrawTorque();
this.DrawTwr(); this.DrawTwr();
this.DrawDeltaV(); this.DrawDeltaV();
this.DrawBurnTime(); this.DrawBurnTime();
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (this.showAtmosphericDetails) if (this.showAtmosphericDetails)
{ {
GUILayout.BeginVertical(this.areaSettingStyle); GUILayout.BeginVertical(this.areaSettingStyle);
this.DrawAtmosphericDetails(); this.DrawAtmosphericDetails();
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
if (this.showSettings) if (this.showSettings)
{ {
GUILayout.BeginVertical(this.areaSettingStyle); GUILayout.BeginVertical(this.areaSettingStyle);
this.DrawSettings(); this.DrawSettings();
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
} }
else // Draw only a few details when in compact mode. else // Draw only a few details when in compact mode.
{ {
GUILayout.BeginHorizontal(this.areaStyle); GUILayout.BeginHorizontal(this.areaStyle);
this.DrawStageNumbers(); this.DrawStageNumbers();
this.DrawTwr(); this.DrawTwr();
this.DrawDeltaV(); this.DrawDeltaV();
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
GUI.DragWindow(); GUI.DragWindow();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
   
using KerbalEngineer.Helpers; using KerbalEngineer.Helpers;
using KerbalEngineer.Settings; using KerbalEngineer.Settings;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Editor namespace KerbalEngineer.Editor
{ {
[KSPAddon(KSPAddon.Startup.EditorAny, false)] [KSPAddon(KSPAddon.Startup.EditorAny, false)]
public class BuildOverlay : MonoBehaviour public class BuildOverlay : MonoBehaviour
{ {
#region Fields #region Fields
   
private static BuildOverlayPartInfo buildOverlayPartInfo; private static BuildOverlayPartInfo buildOverlayPartInfo;
private static BuildOverlayResources buildOverlayResources; private static BuildOverlayResources buildOverlayResources;
private static BuildOverlayVessel buildOverlayVessel; private static BuildOverlayVessel buildOverlayVessel;
private static BuildOverlay instance; private static BuildOverlay instance;
   
private static float minimumWidth = 200.0f; private static float minimumWidth = 200.0f;
private static GUIStyle nameStyle; private static GUIStyle nameStyle;
private static float tabSpeed = 5.0f; private static float tabSpeed = 5.0f;
private static GUIStyle tabStyle; private static GUIStyle tabStyle;
private static GUIStyle titleStyle; private static GUIStyle titleStyle;
private static GUIStyle valueStyle; private static GUIStyle valueStyle;
private static GUIStyle windowStyle; private static GUIStyle windowStyle;
   
#endregion #endregion
   
#region Properties #region Properties
   
public static BuildOverlayPartInfo BuildOverlayPartInfo public static BuildOverlayPartInfo BuildOverlayPartInfo
{ {
get { return buildOverlayPartInfo; } get { return buildOverlayPartInfo; }
} }
   
public static BuildOverlayResources BuildOverlayResources public static BuildOverlayResources BuildOverlayResources
{ {
get { return buildOverlayResources; } get { return buildOverlayResources; }
} }
   
public static BuildOverlayVessel BuildOverlayVessel public static BuildOverlayVessel BuildOverlayVessel
{ {
get { return buildOverlayVessel; } get { return buildOverlayVessel; }
} }
   
public static float MinimumWidth public static float MinimumWidth
{ {
get { return minimumWidth; } get { return minimumWidth; }
set { minimumWidth = value; } set { minimumWidth = value; }
} }
   
public static GUIStyle NameStyle public static GUIStyle NameStyle
{ {
get get
{ {
return nameStyle ?? (nameStyle = new GUIStyle return nameStyle ?? (nameStyle = new GUIStyle
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
fontSize = 11, fontSize = 11,
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
alignment = TextAnchor.UpperLeft, alignment = TextAnchor.UpperLeft,
stretchWidth = true stretchWidth = true
}); });
} }
} }
   
public static float TabSpeed public static float TabSpeed
{ {
get { return tabSpeed; } get { return tabSpeed; }
set { tabSpeed = value; } set { tabSpeed = value; }
} }
   
public static GUIStyle TabStyle public static GUIStyle TabStyle
{ {
get get
{ {
return tabStyle ?? (tabStyle = new GUIStyle return tabStyle ?? (tabStyle = new GUIStyle
{ {
normal = normal =
{ {
background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.5f)), background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.5f)),
textColor = Color.yellow textColor = Color.yellow
}, },
hover = hover =
{ {
background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.75f)), background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.75f)),
textColor = Color.yellow textColor = Color.yellow
}, },
onNormal = onNormal =
{ {
background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.5f)), background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.5f)),
textColor = Color.yellow textColor = Color.yellow
}, },
onHover = onHover =
{ {
background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.75f)), background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.75f)),
textColor = Color.yellow textColor = Color.yellow
}, },
padding = new RectOffset(20, 20, 0, 0), padding = new RectOffset(20, 20, 0, 0),
fontSize = 11, fontSize = 11,
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
fixedHeight = 15.0f, fixedHeight = 15.0f,
stretchWidth = true stretchWidth = true
}); });
} }
} }
   
public static GUIStyle TitleStyle public static GUIStyle TitleStyle
{ {
get get
{ {
return titleStyle ?? (titleStyle = new GUIStyle return titleStyle ?? (titleStyle = new GUIStyle
{ {
normal = normal =
{ {
textColor = Color.yellow textColor = Color.yellow
}, },
fontSize = 11, fontSize = 11,
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
stretchWidth = true stretchWidth = true
}); });
} }
} }
   
public static GUIStyle ValueStyle public static GUIStyle ValueStyle
{ {
get get
{ {
return valueStyle ?? (valueStyle = new GUIStyle return valueStyle ?? (valueStyle = new GUIStyle
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
fontSize = 11, fontSize = 11,
fontStyle = FontStyle.Normal, fontStyle = FontStyle.Normal,
alignment = TextAnchor.UpperRight, alignment = TextAnchor.UpperRight,
stretchWidth = true stretchWidth = true
}); });
} }
} }
   
public static bool Visible public static bool Visible
{ {
get { return BuildOverlayPartInfo.Visible && BuildOverlayVessel.Visible && BuildOverlayResources.Visible; } get { return BuildOverlayPartInfo.Visible && BuildOverlayVessel.Visible && BuildOverlayResources.Visible; }
set { BuildOverlayPartInfo.Visible = BuildOverlayVessel.Visible = BuildOverlayResources.Visible = value; } set { BuildOverlayPartInfo.Visible = BuildOverlayVessel.Visible = BuildOverlayResources.Visible = value; }
} }
   
public static GUIStyle WindowStyle public static GUIStyle WindowStyle
{ {
get get
{ {
return windowStyle ?? (windowStyle = new GUIStyle return windowStyle ?? (windowStyle = new GUIStyle
{ {
normal = normal =
{ {
background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.5f)) background = TextureHelper.CreateTextureFromColour(new Color(0.0f, 0.0f, 0.0f, 0.5f))
}, },
padding = new RectOffset(5, 5, 3, 3), padding = new RectOffset(5, 5, 3, 3),
}); });
} }
} }
   
#endregion #endregion
   
#region Methods: public #region Methods: public
   
public static void Load() public static void Load()
{ {
var handler = SettingHandler.Load("BuildOverlay.xml"); var handler = SettingHandler.Load("BuildOverlay.xml");
handler.GetSet("visible", Visible); Visible = handler.GetSet("visible", Visible);
BuildOverlayPartInfo.NamesOnly = handler.GetSet("namesOnly", BuildOverlayPartInfo.NamesOnly); BuildOverlayPartInfo.NamesOnly = handler.GetSet("namesOnly", BuildOverlayPartInfo.NamesOnly);
BuildOverlayPartInfo.ClickToOpen = handler.GetSet("clickToOpen", BuildOverlayPartInfo.ClickToOpen); BuildOverlayPartInfo.ClickToOpen = handler.GetSet("clickToOpen", BuildOverlayPartInfo.ClickToOpen);
buildOverlayVessel.Open = handler.GetSet("vesselOpen", buildOverlayVessel.Open); buildOverlayVessel.Open = handler.GetSet("vesselOpen", buildOverlayVessel.Open);
buildOverlayResources.Open = handler.GetSet("resourcesOpen", buildOverlayResources.Open); buildOverlayResources.Open = handler.GetSet("resourcesOpen", buildOverlayResources.Open);
handler.Save("BuildOverlay.xml"); handler.Save("BuildOverlay.xml");
} }
   
public static void Save() public static void Save()
{ {
var handler = SettingHandler.Load("BuildOverlay.xml"); var handler = SettingHandler.Load("BuildOverlay.xml");
handler.Set("visible", Visible); handler.Set("visible", Visible);
handler.Set("namesOnly", BuildOverlayPartInfo.NamesOnly); handler.Set("namesOnly", BuildOverlayPartInfo.NamesOnly);
handler.Set("clickToOpen", BuildOverlayPartInfo.ClickToOpen); handler.Set("clickToOpen", BuildOverlayPartInfo.ClickToOpen);
handler.Set("vesselOpen", buildOverlayVessel.Open); handler.Set("vesselOpen", buildOverlayVessel.Open);
handler.Set("resourcesOpen", buildOverlayResources.Open); handler.Set("resourcesOpen", buildOverlayResources.Open);
handler.Save("BuildOverlay.xml"); handler.Save("BuildOverlay.xml");
} }
   
#endregion #endregion
   
#region Methods: protected #region Methods: protected
   
protected void Awake() protected void Awake()
{ {
try try
{ {
if (instance != null) if (instance != null)
{ {
Destroy(this); Destroy(this);
return; return;
} }
instance = this; instance = this;
buildOverlayPartInfo = this.gameObject.AddComponent<BuildOverlayPartInfo>(); buildOverlayPartInfo = this.gameObject.AddComponent<BuildOverlayPartInfo>();
buildOverlayVessel = this.gameObject.AddComponent<BuildOverlayVessel>(); buildOverlayVessel = this.gameObject.AddComponent<BuildOverlayVessel>();
buildOverlayResources = this.gameObject.AddComponent<BuildOverlayResources>(); buildOverlayResources = this.gameObject.AddComponent<BuildOverlayResources>();
Load(); Load();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void OnDestroy() protected void OnDestroy()
{ {
try try
{ {
Save(); Save();
if (buildOverlayPartInfo != null) if (buildOverlayPartInfo != null)
{ {
Destroy(buildOverlayPartInfo); Destroy(buildOverlayPartInfo);
} }
if (buildOverlayVessel != null) if (buildOverlayVessel != null)
{ {
Destroy(buildOverlayVessel); Destroy(buildOverlayVessel);
} }
if (buildOverlayResources != null) if (buildOverlayResources != null)
{ {
Destroy(buildOverlayResources); Destroy(buildOverlayResources);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
   
using KerbalEngineer.Extensions; using KerbalEngineer.Extensions;
using KerbalEngineer.Helpers; using KerbalEngineer.Helpers;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Editor namespace KerbalEngineer.Editor
{ {
public class BuildOverlayPartInfo : MonoBehaviour public class BuildOverlayPartInfo : MonoBehaviour
{ {
#region Fields #region Fields
   
private static bool clickToOpen = true; private static bool clickToOpen = true;
private static bool namesOnly; private static bool namesOnly;
private static bool visible = true; private static bool visible = true;
   
private readonly List<PartInfoItem> infoItems = new List<PartInfoItem>(); private readonly List<PartInfoItem> infoItems = new List<PartInfoItem>();
   
private Rect position; private Rect position;
private Part selectedPart; private Part selectedPart;
private bool showInfo; private bool showInfo;
private bool skipFrame; private bool skipFrame;
   
#endregion #endregion
   
#region Properties #region Properties
   
public static bool ClickToOpen public static bool ClickToOpen
{ {
get { return clickToOpen; } get { return clickToOpen; }
set { clickToOpen = value; } set { clickToOpen = value; }
} }
   
public static bool Hidden { get; set; } public static bool Hidden { get; set; }
   
public static bool NamesOnly public static bool NamesOnly
{ {
get { return namesOnly; } get { return namesOnly; }
set { namesOnly = value; } set { namesOnly = value; }
} }
   
public static bool Visible public static bool Visible
{ {
get { return visible; } get { return visible; }
set { visible = value; } set { visible = value; }
} }
   
#endregion #endregion
   
#region Methods: protected #region Methods: protected
   
protected void OnGUI() protected void OnGUI()
{ {
try try
{ {
if (!Visible || Hidden || this.selectedPart == null) if (!Visible || Hidden || this.selectedPart == null)
{ {
return; return;
} }
   
this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, String.Empty, BuildOverlay.WindowStyle); this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, String.Empty, BuildOverlay.WindowStyle);
} }
catch (Exception ex) catch (Exception ex)
   
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void Update() protected void Update()
{ {
try try
{ {
if (!Visible || Hidden || EditorLogic.startPod == null || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts) if (!Visible || Hidden || EditorLogic.startPod == null || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts)
{ {
return; return;
} }
   
this.position.x = Mathf.Clamp(Input.mousePosition.x + 16.0f, 0.0f, Screen.width - this.position.width); this.position.x = Mathf.Clamp(Input.mousePosition.x + 16.0f, 0.0f, Screen.width - this.position.width);
this.position.y = Mathf.Clamp(Screen.height - Input.mousePosition.y, 0.0f, Screen.height - this.position.height); this.position.y = Mathf.Clamp(Screen.height - Input.mousePosition.y, 0.0f, Screen.height - this.position.height);
if (this.position.x < Input.mousePosition.x + 20.0f) if (this.position.x < Input.mousePosition.x + 20.0f)
{ {
this.position.y = Mathf.Clamp(this.position.y + 20.0f, 0.0f, Screen.height - this.position.height); this.position.y = Mathf.Clamp(this.position.y + 20.0f, 0.0f, Screen.height - this.position.height);
} }
if (this.position.x < Input.mousePosition.x + 16.0f && this.position.y < Screen.height - Input.mousePosition.y) if (this.position.x < Input.mousePosition.x + 16.0f && this.position.y < Screen.height - Input.mousePosition.y)
{ {
this.position.x = Input.mousePosition.x - 3 - this.position.width; this.position.x = Input.mousePosition.x - 3 - this.position.width;
} }
   
this.infoItems.Clear(); this.infoItems.Clear();
var part = EditorLogic.fetch.ship.parts.Find(p => p.stackIcon.highlightIcon) ?? EditorLogic.SelectedPart; var part = EditorLogic.fetch.ship.parts.Find(p => p.stackIcon.highlightIcon) ?? EditorLogic.SelectedPart;
if (part != null) if (part != null)
{ {
if (!part.Equals(this.selectedPart)) if (!part.Equals(this.selectedPart))
{ {
this.selectedPart = part; this.selectedPart = part;
this.ResetInfo(); this.ResetInfo();
} }
if (NamesOnly || this.skipFrame) if (NamesOnly || this.skipFrame)
{ {
this.skipFrame = false; this.skipFrame = false;
return; return;
} }
   
this.SetCostInfo(); this.SetCostInfo();
this.SetMassItems(); this.SetMassItems();
this.SetResourceItems(); this.SetResourceItems();
this.SetEngineInfo(); this.SetEngineInfo();
this.SetAlternatorInfo(); this.SetAlternatorInfo();
this.SetGimbalInfo(); this.SetGimbalInfo();
this.SetRcsInfo(); this.SetRcsInfo();
this.SetParachuteInfo(); this.SetParachuteInfo();
this.SetSasInfo(); this.SetSasInfo();
this.SetReactionWheelInfo(); this.SetReactionWheelInfo();
this.SetSolarPanelInfo(); this.SetSolarPanelInfo();
this.SetGeneratorInfo(); this.SetGeneratorInfo();
this.SetDecouplerInfo(); this.SetDecouplerInfo();
this.SetTransmitterInfo(); this.SetTransmitterInfo();
this.SetScienceExperimentInfo(); this.SetScienceExperimentInfo();
this.SetScienceContainerInfo(); this.SetScienceContainerInfo();
this.SetSingleActivationInfo(); this.SetSingleActivationInfo();
   
if (!this.showInfo && Input.GetMouseButtonDown(2)) if (!this.showInfo && Input.GetMouseButtonDown(2))
{ {
this.showInfo = true; this.showInfo = true;
} }
else if (ClickToOpen && this.showInfo && Input.GetMouseButtonDown(2)) else if (ClickToOpen && this.showInfo && Input.GetMouseButtonDown(2))
{ {
this.ResetInfo(); this.ResetInfo();
} }
} }
else else
{ {
this.selectedPart = null; this.selectedPart = null;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
   
#region Methods: private #region Methods: private
   
private void ResetInfo() private void ResetInfo()
{ {
this.showInfo = !clickToOpen; this.showInfo = !clickToOpen;
this.skipFrame = true; this.skipFrame = true;
this.position.width = namesOnly || clickToOpen ? 0.0f : 200.0f; this.position.width = namesOnly || clickToOpen ? 0.0f : 200.0f;
this.position.height = 0.0f; this.position.height = 0.0f;
} }
   
private void SetAlternatorInfo() private void SetAlternatorInfo()
{ {
if (!this.selectedPart.HasModule<ModuleAlternator>()) if (!this.selectedPart.HasModule<ModuleAlternator>())
{ {
return; return;
} }
   
var alternator = this.selectedPart.GetModule<ModuleAlternator>(); var alternator = this.selectedPart.GetModule<ModuleAlternator>();
this.infoItems.Add(new PartInfoItem("Alternator")); this.infoItems.Add(new PartInfoItem("Alternator"));
foreach (var resource in alternator.outputResources) foreach (var resource in alternator.outputResources)
{ {
this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate())); this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate()));
} }
} }
   
private void SetCostInfo() private void SetCostInfo()
{ {
this.infoItems.Add(new PartInfoItem("Cost", Units.Concat(this.selectedPart.GetCostDry(), this.selectedPart.GetCostWet()))); this.infoItems.Add(new PartInfoItem("Cost", Units.Concat(this.selectedPart.GetCostDry(), this.selectedPart.GetCostWet())));
} }
   
private void SetDecouplerInfo() private void SetDecouplerInfo()
{ {
if (!this.selectedPart.IsDecoupler()) if (!this.selectedPart.IsDecoupler())
{ {
return; return;
} }
   
var decoupler = this.selectedPart.GetProtoModuleDecoupler(); var decoupler = this.selectedPart.GetProtoModuleDecoupler();
this.infoItems.Add(new PartInfoItem("Ejection Force", decoupler.EjectionForce.ToForce())); this.infoItems.Add(new PartInfoItem("Ejection Force", decoupler.EjectionForce.ToForce()));
if (decoupler.IsOmniDecoupler) if (decoupler.IsOmniDecoupler)
{ {
this.infoItems.Add(new PartInfoItem("Omni-directional")); this.infoItems.Add(new PartInfoItem("Omni-directional"));
} }
} }
   
private void SetEngineInfo() private void SetEngineInfo()
{ {
if (!this.selectedPart.IsEngine()) if (!this.selectedPart.IsEngine())
{ {
return; return;
} }
   
var engine = this.selectedPart.GetProtoModuleEngine(); var engine = this.selectedPart.GetProtoModuleEngine();
this.infoItems.Add(new PartInfoItem("Thrust", Units.ToForce(engine.MinimumThrust, engine.MaximumThrust))); this.infoItems.Add(new PartInfoItem("Thrust", Units.ToForce(engine.MinimumThrust, engine.MaximumThrust)));
this.infoItems.Add(new PartInfoItem("Isp", Units.Concat(engine.GetSpecificImpulse(1.0f), engine.GetSpecificImpulse(0.0f)) + "s")); this.infoItems.Add(new PartInfoItem("Isp", Units.Concat(engine.GetSpecificImpulse(1.0f), engine.GetSpecificImpulse(0.0f)) + "s"));
if (engine.Propellants.Count > 0) if (engine.Propellants.Count > 0)
{ {
this.infoItems.Add(new PartInfoItem("Propellants")); this.infoItems.Add(new PartInfoItem("Propellants"));
var totalRatio = engine.Propellants.Sum(p => p.ratio); var totalRatio = engine.Propellants.Sum(p => p.ratio);
foreach (var propellant in engine.Propellants) foreach (var propellant in engine.Propellants)
{ {
this.infoItems.Add(new PartInfoItem("\t" + propellant.name, (propellant.ratio / totalRatio).ToPercent())); this.infoItems.Add(new PartInfoItem("\t" + propellant.name, (propellant.ratio / totalRatio).ToPercent()));
} }
} }
} }
   
private void SetGeneratorInfo() private void SetGeneratorInfo()
{ {
if (!this.selectedPart.HasModule<ModuleGenerator>()) if (!this.selectedPart.HasModule<ModuleGenerator>())
{ {
return; return;
} }
   
var generator = this.selectedPart.GetModule<ModuleGenerator>(); var generator = this.selectedPart.GetModule<ModuleGenerator>();
if (generator.inputList.Count > 0) if (generator.inputList.Count > 0)
{ {
this.infoItems.Add(new PartInfoItem("Generator Input")); this.infoItems.Add(new PartInfoItem("Generator Input"));
foreach (var resource in generator.inputList) foreach (var resource in generator.inputList)
{ {
this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate())); this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate()));
} }
} }
if (generator.outputList.Count > 0) if (generator.outputList.Count > 0)
{ {
this.infoItems.Add(new PartInfoItem("Generator Output")); this.infoItems.Add(new PartInfoItem("Generator Output"));
foreach (var resource in generator.outputList) foreach (var resource in generator.outputList)
{ {
this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate())); this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate()));
} }
} }
if (generator.isAlwaysActive) if (generator.isAlwaysActive)
{ {
this.infoItems.Add(new PartInfoItem("Generator is Always Active")); this.infoItems.Add(new PartInfoItem("Generator is Always Active"));
} }
} }
   
private void SetGimbalInfo() private void SetGimbalInfo()
{ {
if (!this.selectedPart.HasModule<ModuleGimbal>()) if (!this.selectedPart.HasModule<ModuleGimbal>())
{ {
return; return;
} }
   
var gimbal = this.selectedPart.GetModule<ModuleGimbal>(); var gimbal = this.selectedPart.GetModule<ModuleGimbal>();
this.infoItems.Add(new PartInfoItem("Thrust Vectoring", gimbal.gimbalRange.ToString("F2"))); this.infoItems.Add(new PartInfoItem("Thrust Vectoring", gimbal.gimbalRange.ToString("F2")));
} }
   
private void SetMassItems() private void SetMassItems()
{ {
if (this.selectedPart.physicalSignificance == Part.PhysicalSignificance.FULL) if (this.selectedPart.physicalSignificance == Part.PhysicalSignificance.FULL)
{ {
this.infoItems.Add(new PartInfoItem("Mass", Units.ToMass(this.selectedPart.GetDryMass(), this.selectedPart.GetWetMass()))); this.infoItems.Add(new PartInfoItem("Mass", Units.ToMass(this.selectedPart.GetDryMass(), this.selectedPart.GetWetMass())));
} }
} }
   
private void SetParachuteInfo() private void SetParachuteInfo()
{ {
if (!this.selectedPart.HasModule<ModuleParachute>()) if (!this.selectedPart.HasModule<ModuleParachute>())
{ {
return; return;
} }
   
var parachute = this.selectedPart.GetModule<ModuleParachute>(); var parachute = this.selectedPart.GetModule<ModuleParachute>();
this.infoItems.Add(new PartInfoItem("Deployed Drag", Units.Concat(parachute.semiDeployedDrag, parachute.fullyDeployedDrag))); this.infoItems.Add(new PartInfoItem("Deployed Drag", Units.Concat(parachute.semiDeployedDrag, parachute.fullyDeployedDrag)));
this.infoItems.Add(new PartInfoItem("Deployment Altitude", parachute.deployAltitude.ToDistance())); this.infoItems.Add(new PartInfoItem("Deployment Altitude", parachute.deployAltitude.ToDistance()));
this.infoItems.Add(new PartInfoItem("Deployment Pressure", parachute.minAirPressureToOpen.ToString("F2"))); this.infoItems.Add(new PartInfoItem("Deployment Pressure", parachute.minAirPressureToOpen.ToString("F2")));
} }
   
private void SetRcsInfo() private void SetRcsInfo()
{ {
if (!this.selectedPart.HasModule<ModuleRCS>()) if (!this.selectedPart.HasModule<ModuleRCS>())
{ {
return; return;
} }
   
var rcs = this.selectedPart.GetModule<ModuleRCS>(); var rcs = this.selectedPart.GetModule<ModuleRCS>();
this.infoItems.Add(new PartInfoItem("Thruster Power", rcs.thrusterPower.ToForce())); this.infoItems.Add(new PartInfoItem("Thruster Power", rcs.thrusterPower.ToForce()));
this.infoItems.Add(new PartInfoItem("Specific Impulse", Units.Concat(rcs.atmosphereCurve.Evaluate(1.0f), rcs.atmosphereCurve.Evaluate(0.0f)) + "s")); this.infoItems.Add(new PartInfoItem("Specific Impulse", Units.Concat(rcs.atmosphereCurve.Evaluate(1.0f), rcs.atmosphereCurve.Evaluate(0.0f)) + "s"));
} }
   
private void SetReactionWheelInfo() private void SetReactionWheelInfo()
{ {
if (!this.selectedPart.HasModule<ModuleReactionWheel>()) if (!this.selectedPart.HasModule<ModuleReactionWheel>())
{ {
return; return;
} }
   
var reactionWheel = this.selectedPart.GetModule<ModuleReactionWheel>(); var reactionWheel = this.selectedPart.GetModule<ModuleReactionWheel>();
this.infoItems.Add(new PartInfoItem("Reaction Wheel Torque")); this.infoItems.Add(new PartInfoItem("Reaction Wheel Torque"));
this.infoItems.Add(new PartInfoItem("\tPitch", reactionWheel.PitchTorque.ToForce())); this.infoItems.Add(new PartInfoItem("\tPitch", reactionWheel.PitchTorque.ToTorque()));
this.infoItems.Add(new PartInfoItem("\tRoll", reactionWheel.RollTorque.ToForce())); this.infoItems.Add(new PartInfoItem("\tRoll", reactionWheel.RollTorque.ToTorque()));
this.infoItems.Add(new PartInfoItem("\tYaw", reactionWheel.YawTorque.ToForce())); this.infoItems.Add(new PartInfoItem("\tYaw", reactionWheel.YawTorque.ToTorque()));
foreach (var resource in reactionWheel.inputResources) foreach (var resource in reactionWheel.inputResources)
{ {
this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate())); this.infoItems.Add(new PartInfoItem("\t" + resource.name, resource.rate.ToRate()));
} }
} }
   
private void SetResourceItems() private void SetResourceItems()
{ {
if (this.selectedPart.Resources.list.Any(r => !r.hideFlow)) if (this.selectedPart.Resources.list.Any(r => !r.hideFlow))
{ {
this.infoItems.Add(new PartInfoItem("Resources")); this.infoItems.Add(new PartInfoItem("Resources"));
foreach (var resource in this.selectedPart.Resources.list.Where(r => !r.hideFlow)) foreach (var resource in this.selectedPart.Resources.list.Where(r => !r.hideFlow))
{ {
this.infoItems.Add(resource.GetDensity() > 0 this.infoItems.Add(resource.GetDensity() > 0
? new PartInfoItem("\t" + resource.info.name, "(" + resource.GetMass().ToMass() + ") " + resource.amount.ToString("F1")) ? new PartInfoItem("\t" + resource.info.name, "(" + resource.GetMass().ToMass() + ") " + resource.amount.ToString("F1"))
: new PartInfoItem("\t" + resource.info.name, resource.amount.ToString("F1"))); : new PartInfoItem("\t" + resource.info.name, resource.amount.ToString("F1")));
} }
} }
} }
   
private void SetSasInfo() private void SetSasInfo()
{ {
if (this.selectedPart.HasModule<ModuleSAS>()) if (this.selectedPart.HasModule<ModuleSAS>())
{ {
this.infoItems.Add(new PartInfoItem("SAS Equiped")); this.infoItems.Add(new PartInfoItem("SAS Equiped"));
} }
} }
   
private void SetScienceContainerInfo() private void SetScienceContainerInfo()
{ {
if (this.selectedPart.HasModule<ModuleScienceContainer>()) if (this.selectedPart.HasModule<ModuleScienceContainer>())
{ {
this.infoItems.Add(new PartInfoItem("Science Container")); this.infoItems.Add(new PartInfoItem("Science Container"));
} }
} }
   
private void SetScienceExperimentInfo() private void SetScienceExperimentInfo()
{ {
if (!this.selectedPart.HasModule<ModuleScienceExperiment>()) if (!this.selectedPart.HasModule<ModuleScienceExperiment>())
{ {
return; return;
} }
   
var experiment = this.selectedPart.GetModule<ModuleScienceExperiment>(); var experiment = this.selectedPart.GetModule<ModuleScienceExperiment>();
this.infoItems.Add(new PartInfoItem("Science Experiment", experiment.experimentActionName)); this.infoItems.Add(new PartInfoItem("Science Experiment", experiment.experimentActionName));
this.infoItems.Add(new PartInfoItem("\tTransmit Efficiency", experiment.xmitDataScalar.ToPercent())); this.infoItems.Add(new PartInfoItem("\tTransmit Efficiency", experiment.xmitDataScalar.ToPercent()));
if (!experiment.rerunnable) if (!experiment.rerunnable)
{ {
this.infoItems.Add(new PartInfoItem("\tSingle Usage")); this.infoItems.Add(new PartInfoItem("\tSingle Usage"));
} }
} }
   
private void SetSingleActivationInfo() private void SetSingleActivationInfo()
{ {
if (this.selectedPart.HasModule<ModuleAnimateGeneric>(m => m.isOneShot)) if (this.selectedPart.HasModule<ModuleAnimateGeneric>(m => m.isOneShot))
{ {
this.infoItems.Add(new PartInfoItem("Single Activation")); this.infoItems.Add(new PartInfoItem("Single Activation"));
} }
} }
   
private void SetSolarPanelInfo() private void SetSolarPanelInfo()
{ {
if (!this.selectedPart.HasModule<ModuleDeployableSolarPanel>()) if (!this.selectedPart.HasModule<ModuleDeployableSolarPanel>())
{ {
return; return;
} }
   
var solarPanel = this.selectedPart.GetModule<ModuleDeployableSolarPanel>(); var solarPanel = this.selectedPart.GetModule<ModuleDeployableSolarPanel>();
this.infoItems.Add(new PartInfoItem("Charge Rate", solarPanel.chargeRate.ToRate())); this.infoItems.Add(new PartInfoItem("Charge Rate", solarPanel.chargeRate.ToRate()));
if (solarPanel.isBreakable) if (solarPanel.isBreakable)
{ {
this.infoItems.Add(new PartInfoItem("Breakable")); this.infoItems.Add(new PartInfoItem("Breakable"));
} }
if (solarPanel.sunTracking) if (solarPanel.sunTracking)
{ {
this.infoItems.Add(new PartInfoItem("Sun Tracking")); this.infoItems.Add(new PartInfoItem("Sun Tracking"));
} }
} }
   
private void SetTransmitterInfo() private void SetTransmitterInfo()
{ {
if (!this.selectedPart.HasModule<ModuleDataTransmitter>()) if (!this.selectedPart.HasModule<ModuleDataTransmitter>())
{ {
return; return;
} }
   
var transmitter = this.selectedPart.GetModule<ModuleDataTransmitter>(); var transmitter = this.selectedPart.GetModule<ModuleDataTransmitter>();
this.infoItems.Add(new PartInfoItem("Packet Size", transmitter.packetSize.ToString("F2") + " Mits")); this.infoItems.Add(new PartInfoItem("Packet Size", transmitter.packetSize.ToString("F2") + " Mits"));
this.infoItems.Add(new PartInfoItem("Bandwidth", (transmitter.packetInterval * transmitter.packetSize).ToString("F2") + "Mits/sec")); this.infoItems.Add(new PartInfoItem("Bandwidth", (transmitter.packetInterval * transmitter.packetSize).ToString("F2") + "Mits/sec"));
this.infoItems.Add(new PartInfoItem(transmitter.requiredResource, transmitter.packetResourceCost.ToString("F2") + "/Packet")); this.infoItems.Add(new PartInfoItem(transmitter.requiredResource, transmitter.packetResourceCost.ToString("F2") + "/Packet"));
} }
   
private void Window(int windowId) private void Window(int windowId)
{ {
try try
{ {
GUILayout.Label(this.selectedPart.partInfo.title, BuildOverlay.TitleStyle); GUILayout.Label(this.selectedPart.partInfo.title, BuildOverlay.TitleStyle);
if (this.showInfo) if (this.showInfo)
{ {
foreach (var item in this.infoItems) foreach (var item in this.infoItems)
{ {
GUILayout.Space(2.0f); GUILayout.Space(2.0f);
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
if (item.Value != null) if (item.Value != null)
{ {
GUILayout.Label(item.Name + ":", BuildOverlay.NameStyle); GUILayout.Label(item.Name + ":", BuildOverlay.NameStyle);
GUILayout.Space(25.0f); GUILayout.Space(25.0f);
GUILayout.Label(item.Value, BuildOverlay.ValueStyle); GUILayout.Label(item.Value, BuildOverlay.ValueStyle);
} }
else else
{ {
GUILayout.Label(item.Name, BuildOverlay.NameStyle); GUILayout.Label(item.Name, BuildOverlay.NameStyle);
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
} }
else if (this.infoItems.Count > 0) else if (this.infoItems.Count > 0)
{ {
GUILayout.Space(2.0f); GUILayout.Space(2.0f);
GUILayout.Label("Click middle mouse to show more info...", BuildOverlay.NameStyle); GUILayout.Label("Click middle mouse to show more info...", BuildOverlay.NameStyle);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
   
using KerbalEngineer.Extensions; using KerbalEngineer.Extensions;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Editor namespace KerbalEngineer.Editor
{ {
public class BuildOverlayResources : MonoBehaviour public class BuildOverlayResources : MonoBehaviour
{ {
#region Fields #region Fields
   
private static bool visible = true; private static bool visible = true;
   
private readonly Dictionary<int, ResourceInfoItem> resources = new Dictionary<int, ResourceInfoItem>(); private readonly Dictionary<int, ResourceInfoItem> resources = new Dictionary<int, ResourceInfoItem>();
   
private bool open = true; private bool open = true;
private float openPercent; private float openPercent;
private GUIContent tabContent; private GUIContent tabContent;
private Rect tabPosition; private Rect tabPosition;
private Vector2 tabSize; private Vector2 tabSize;
private Rect windowPosition = new Rect(0.0f, 0.0f, BuildOverlay.MinimumWidth, 0.0f); private Rect windowPosition = new Rect(0.0f, 0.0f, BuildOverlay.MinimumWidth, 0.0f);
   
#endregion #endregion
   
#region Properties #region Properties
   
public static bool Visible public static bool Visible
{ {
get { return visible; } get { return visible; }
set { visible = value; } set { visible = value; }
} }
   
public bool Open public bool Open
{ {
get { return this.open; } get { return this.open; }
set { this.open = value; } set { this.open = value; }
} }
   
#endregion #endregion
   
#region Methods: protected #region Methods: protected
   
protected void OnGUI() protected void OnGUI()
{ {
try try
{ {
if (!BuildOverlay.Visible || this.resources.Count == 0 || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts) if (!Visible || this.resources.Count == 0 || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts)
{ {
return; return;
} }
   
this.open = GUI.Toggle(this.tabPosition, this.open, this.tabContent, BuildOverlay.TabStyle); this.open = GUI.Toggle(this.tabPosition, this.open, this.tabContent, BuildOverlay.TabStyle);
if (this.openPercent > 0.0) if (this.openPercent > 0.0)
{ {
this.windowPosition = GUILayout.Window(this.GetInstanceID(), this.windowPosition, this.Window, String.Empty, BuildOverlay.WindowStyle); this.windowPosition = GUILayout.Window(this.GetInstanceID(), this.windowPosition, this.Window, String.Empty, BuildOverlay.WindowStyle);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void Start() protected void Start()
{ {
try try
{ {
this.tabContent = new GUIContent("RESOURCES"); this.tabContent = new GUIContent("RESOURCES");
this.tabSize = BuildOverlay.TabStyle.CalcSize(this.tabContent); this.tabSize = BuildOverlay.TabStyle.CalcSize(this.tabContent);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void Update() protected void Update()
{ {
try try
{ {
if (!BuildOverlay.Visible) if (!Visible)
{ {
return; return;
} }
   
this.SetResources(); this.SetResources();
this.SetSlidePosition(); this.SetSlidePosition();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
   
#region Methods: private #region Methods: private
   
private void SetResources() private void SetResources()
{ {
var previousCount = this.resources.Count; var previousCount = this.resources.Count;
this.resources.Clear(); this.resources.Clear();
foreach (var resource in EditorLogic.fetch.ship.parts.SelectMany(p => p.Resources.list).Where(r => r.amount > 0.0)) foreach (var resource in EditorLogic.fetch.ship.parts.SelectMany(p => p.Resources.list).Where(r => r.amount > 0.0))
{ {
if (this.resources.ContainsKey(resource.info.id)) if (this.resources.ContainsKey(resource.info.id))
{ {
this.resources[resource.info.id].Amount += resource.amount; this.resources[resource.info.id].Amount += resource.amount;
} }
else else
{ {
this.resources.Add(resource.info.id, new ResourceInfoItem(resource)); this.resources.Add(resource.info.id, new ResourceInfoItem(resource));
} }
} }
   
if (this.resources.Count < previousCount) if (this.resources.Count < previousCount)
{ {
this.windowPosition.height = 0; this.windowPosition.height = 0;
} }
} }
   
private void SetSlidePosition() private void SetSlidePosition()
{ {
if (this.open && this.openPercent < 1.0f) if (this.open && this.openPercent < 1.0f)
{ {
this.openPercent = Mathf.Clamp(this.openPercent + Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f); this.openPercent = Mathf.Clamp(this.openPercent + Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
} }
else if (!this.open && this.openPercent > 0.0f) else if (!this.open && this.openPercent > 0.0f)
{ {
this.openPercent = Mathf.Clamp(this.openPercent - Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f); this.openPercent = Mathf.Clamp(this.openPercent - Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
} }
   
this.windowPosition.x = BuildOverlay.BuildOverlayVessel.WindowPosition.xMax + 5.0f; this.windowPosition.x = BuildOverlay.BuildOverlayVessel.WindowPosition.xMax + 5.0f;
this.windowPosition.y = Mathf.Lerp(Screen.height, Screen.height - this.windowPosition.height, this.openPercent); this.windowPosition.y = Mathf.Lerp(Screen.height, Screen.height - this.windowPosition.height, this.openPercent);
this.tabPosition.width = this.tabSize.x; this.tabPosition.width = this.tabSize.x;
this.tabPosition.height = this.tabSize.y; this.tabPosition.height = this.tabSize.y;
this.tabPosition.x = this.windowPosition.x; this.tabPosition.x = this.windowPosition.x;
this.tabPosition.y = this.windowPosition.y - this.tabPosition.height; this.tabPosition.y = this.windowPosition.y - this.tabPosition.height;
} }
   
private void Window(int windowId) private void Window(int windowId)
{ {
try try
{ {
var firstItem = true; var firstItem = true;
foreach (var resource in this.resources) foreach (var resource in this.resources)
{ {
if (!firstItem) if (!firstItem)
{ {
GUILayout.Space(2.0f); GUILayout.Space(2.0f);
} }
firstItem = false; firstItem = false;
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
   
GUILayout.Label(resource.Value.Name + ":", BuildOverlay.NameStyle); GUILayout.Label(resource.Value.Name + ":", BuildOverlay.NameStyle);
GUILayout.Space(50.0f); GUILayout.Space(50.0f);
if (resource.Value.Mass > 0.0) if (resource.Value.Mass > 0.0)
{ {
GUILayout.Label("(" + resource.Value.Mass.ToMass() + ") " + resource.Value.Amount.ToString("N1"), BuildOverlay.ValueStyle); GUILayout.Label("(" + resource.Value.Mass.ToMass() + ") " + resource.Value.Amount.ToString("N1"), BuildOverlay.ValueStyle);
} }
else else
{ {
GUILayout.Label(resource.Value.Amount.ToString("N1"), BuildOverlay.ValueStyle); GUILayout.Label(resource.Value.Amount.ToString("N1"), BuildOverlay.ValueStyle);
} }
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
   
using KerbalEngineer.Extensions; using KerbalEngineer.Helpers;
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Editor namespace KerbalEngineer.Editor
{ {
public class BuildOverlayVessel : MonoBehaviour public class BuildOverlayVessel : MonoBehaviour
{ {
  #region Constants
   
  private const float Width = 175.0f;
   
  #endregion
   
#region Fields #region Fields
   
private static bool visible = true; private static bool visible = true;
   
private readonly List<PartInfoItem> infoItems = new List<PartInfoItem>(); private readonly List<PartInfoItem> infoItems = new List<PartInfoItem>();
   
private Stage lastStage; private Stage lastStage;
private bool open = true; private bool open = true;
private float openPercent; private float openPercent;
private GUIContent tabContent; private GUIContent tabContent;
private Rect tabPosition; private Rect tabPosition;
private Vector2 tabSize; private Vector2 tabSize;
private Rect windowPosition = new Rect(300.0f, 0.0f, BuildOverlay.MinimumWidth, 0.0f); private Rect windowPosition = new Rect(300.0f, 0.0f, Width, 0.0f);
   
#endregion #endregion
   
#region Properties #region Properties
   
public static bool Visible public static bool Visible
{ {
get { return visible; } get { return visible; }
set { visible = value; } set { visible = value; }
} }
   
public bool Open public bool Open
{ {
get { return this.open; } get { return this.open; }
set { this.open = value; } set { this.open = value; }
} }
   
public Rect WindowPosition public Rect WindowPosition
{ {
get { return this.windowPosition; } get { return this.windowPosition; }
} }
   
#endregion #endregion
   
#region Methods: protected #region Methods: protected
   
protected void OnGUI() protected void OnGUI()
{ {
try try
{ {
if (!Visible || EditorLogic.startPod == null || this.lastStage == null || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts) if (!Visible || EditorLogic.startPod == null || EditorLogic.fetch.editorScreen != EditorLogic.EditorScreen.Parts)
{ {
return; return;
} }
   
this.open = GUI.Toggle(this.tabPosition, this.open, this.tabContent, BuildOverlay.TabStyle); this.open = GUI.Toggle(this.tabPosition, this.open, this.tabContent, BuildOverlay.TabStyle);
if (this.openPercent > 0.0) if (this.openPercent > 0.0)
{ {
this.windowPosition = GUILayout.Window(this.GetInstanceID(), this.windowPosition, this.VesselWindow, String.Empty, BuildOverlay.WindowStyle); this.windowPosition = GUILayout.Window(this.GetInstanceID(), this.windowPosition, this.VesselWindow, String.Empty, BuildOverlay.WindowStyle);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
  protected void Awake()
  {
  try
  {
  SimManager.OnReady -= this.GetStageInfo;
  SimManager.OnReady += this.GetStageInfo;
  }
  catch (Exception ex)
  {
  Logger.Exception(ex);
  }
  }
   
protected void Start() protected void Start()
{ {
try try
{ {
this.tabContent = new GUIContent("VESSEL"); this.tabContent = new GUIContent("VESSEL");
this.tabSize = BuildOverlay.TabStyle.CalcSize(this.tabContent); this.tabSize = BuildOverlay.TabStyle.CalcSize(this.tabContent);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void Update() protected void Update()
{ {
try try
{ {
if (!BuildOverlay.Visible || EditorLogic.startPod == null) if (!Visible || EditorLogic.startPod == null)
{ {
return; return;
} }
   
if (this.openPercent > 0.0) if (this.openPercent > 0.0)
{ {
this.SetVesselInfo(); this.SetVesselInfo();
} }
   
this.SetSlidePosition(); this.SetSlidePosition();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
   
#region Methods: private #region Methods: private
   
private void SetSlidePosition() private void SetSlidePosition()
{ {
if (this.open && this.openPercent < 1.0f) if (this.open && this.openPercent < 1.0f)
{ {
this.openPercent = Mathf.Clamp(this.openPercent + Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f); this.openPercent = Mathf.Clamp(this.openPercent + Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
} }
else if (!this.open && this.openPercent > 0.0f) else if (!this.open && this.openPercent > 0.0f)
{ {
this.openPercent = Mathf.Clamp(this.openPercent - Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f); this.openPercent = Mathf.Clamp(this.openPercent - Time.deltaTime * BuildOverlay.TabSpeed, 0.0f, 1.0f);
} }
   
this.windowPosition.y = Mathf.Lerp(Screen.height, Screen.height - this.windowPosition.height, this.openPercent); this.windowPosition.y = Mathf.Lerp(Screen.height, Screen.height - this.windowPosition.height, this.openPercent);
  if (this.windowPosition.width < Width)
  {
  this.windowPosition.width = Width;
  }
this.tabPosition.width = this.tabSize.x; this.tabPosition.width = this.tabSize.x;
this.tabPosition.height = this.tabSize.y; this.tabPosition.height = this.tabSize.y;
this.tabPosition.x = this.windowPosition.x; this.tabPosition.x = this.windowPosition.x;
this.tabPosition.y = this.windowPosition.y - this.tabPosition.height; this.tabPosition.y = this.windowPosition.y - this.tabPosition.height;
} }
   
  private void GetStageInfo()
  {
  this.lastStage = SimManager.LastStage;
  }
   
private void SetVesselInfo() private void SetVesselInfo()
{ {
SimManager.Gravity = CelestialBodies.SelectedBody.Gravity; SimManager.Gravity = CelestialBodies.SelectedBody.Gravity;
   
if (BuildAdvanced.Instance.ShowAtmosphericDetails) if (BuildAdvanced.Instance.ShowAtmosphericDetails)
{ {
SimManager.Atmosphere = CelestialBodies.SelectedBody.Atmosphere * 0.01; SimManager.Atmosphere = CelestialBodies.SelectedBody.Atmosphere * 0.01;
} }
else else
{ {
SimManager.Atmosphere = 0.0; SimManager.Atmosphere = 0.0;
} }
   
SimManager.RequestSimulation(); SimManager.RequestSimulation();
SimManager.TryStartSimulation(); SimManager.TryStartSimulation();
   
if (SimManager.ResultsReady())  
{  
this.lastStage = SimManager.LastStage;  
}  
   
if (this.lastStage != null) if (this.lastStage != null)
{ {
this.infoItems.Clear(); this.infoItems.Clear();
this.infoItems.Add(new PartInfoItem("Delta-V", this.lastStage.totalDeltaV.ToString("N0") + "m/s")); this.infoItems.Add(new PartInfoItem("Delta-V", this.lastStage.deltaV.ToString("N0") + " / " + this.lastStage.totalDeltaV.ToString("N0") + "m/s"));
this.infoItems.Add(new PartInfoItem("Mass", this.lastStage.totalMass.ToMass())); this.infoItems.Add(new PartInfoItem("Mass", Units.ToMass(this.lastStage.mass, this.lastStage.totalMass)));
this.infoItems.Add(new PartInfoItem("TWR", this.lastStage.thrustToWeight.ToString("F2"))); this.infoItems.Add(new PartInfoItem("TWR", this.lastStage.thrustToWeight.ToString("F2") + " (" + this.lastStage.maxThrustToWeight.ToString("F2") + ")"));
this.infoItems.Add(new PartInfoItem("Parts", this.lastStage.partCount.ToString("N0"))); this.infoItems.Add(new PartInfoItem("Parts", this.lastStage.partCount + " / " + this.lastStage.totalPartCount));
} }
} }
   
private void VesselWindow(int windowId) private void VesselWindow(int windowId)
{ {
try try
{ {
var firstItem = true; var firstItem = true;
foreach (var item in this.infoItems) foreach (var item in this.infoItems)
{ {
if (!firstItem) if (!firstItem)
{ {
GUILayout.Space(2.0f); GUILayout.Space(2.0f);
} }
firstItem = false; firstItem = false;
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
if (item.Value != null) if (item.Value != null)
{ {
GUILayout.Label(item.Name + ":", BuildOverlay.NameStyle); GUILayout.Label(item.Name + ":", BuildOverlay.NameStyle);
GUILayout.Space(50.0f); GUILayout.FlexibleSpace();
GUILayout.Label(item.Value, BuildOverlay.ValueStyle); GUILayout.Label(item.Value, BuildOverlay.ValueStyle);
} }
else else
{ {
GUILayout.Label(item.Name, BuildOverlay.NameStyle); GUILayout.Label(item.Name, BuildOverlay.NameStyle);
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
   
#endregion #endregion
   
namespace KerbalEngineer namespace KerbalEngineer
{ {
public class EngineerGlobals public class EngineerGlobals
{ {
#region Constants #region Constants
   
/// <summary> /// <summary>
/// Current version of the Kerbal Engineer assembly. /// Current version of the Kerbal Engineer assembly.
/// </summary> /// </summary>
public const string AssemblyVersion = "1.0.11"; public const string AssemblyVersion = "1.0.12.1";
   
#endregion #endregion
   
#region Fields #region Fields
   
private static string assemblyFile; private static string assemblyFile;
private static string assemblyName; private static string assemblyName;
private static string assemblyPath; private static string assemblyPath;
   
#endregion #endregion
   
#region Properties #region Properties
   
/// <summary> /// <summary>
/// Gets the Kerbal Engineer assembly's path including the file name. /// Gets the Kerbal Engineer assembly's path including the file name.
/// </summary> /// </summary>
public static string AssemblyFile public static string AssemblyFile
{ {
get { return assemblyFile ?? (assemblyFile = Assembly.GetExecutingAssembly().Location); } get { return assemblyFile ?? (assemblyFile = Assembly.GetExecutingAssembly().Location); }
} }
   
/// <summary> /// <summary>
/// Gets the Kerbal Engineer assembly's file name. /// Gets the Kerbal Engineer assembly's file name.
/// </summary> /// </summary>
public static string AssemblyName public static string AssemblyName
{ {
get { return assemblyName ?? (assemblyName = new FileInfo(AssemblyFile).Name); } get { return assemblyName ?? (assemblyName = new FileInfo(AssemblyFile).Name); }
} }
   
/// <summary> /// <summary>
/// Gets the Kerbal Engineer assembly's path excluding the file name. /// Gets the Kerbal Engineer assembly's path excluding the file name.
/// </summary> /// </summary>
public static string AssemblyPath public static string AssemblyPath
{ {
get { return assemblyPath ?? (assemblyPath = AssemblyFile.Replace(new FileInfo(AssemblyFile).Name, "")); } get { return assemblyPath ?? (assemblyPath = AssemblyFile.Replace(new FileInfo(AssemblyFile).Name, "")); }
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using KerbalEngineer.Helpers; using KerbalEngineer.Helpers;
   
#endregion #endregion
   
namespace KerbalEngineer.Extensions namespace KerbalEngineer.Extensions
{ {
public static class DoubleExtensions public static class DoubleExtensions
{ {
#region Methods: public #region Methods: public
   
  public static double Clamp(this double value, double lower, double higher)
  {
  return value < lower ? lower : value > higher ? higher : value;
  }
   
public static string ToAcceleration(this double value) public static string ToAcceleration(this double value)
{ {
return Units.ToAcceleration(value); return Units.ToAcceleration(value);
} }
   
public static string ToAngle(this double value) public static string ToAngle(this double value)
{ {
return Units.ToAngle(value); return Units.ToAngle(value);
} }
   
public static string ToDistance(this double value) public static string ToDistance(this double value)
{ {
return Units.ToDistance(value); return Units.ToDistance(value);
  }
   
  public static string ToTorque(this double value)
  {
  return Units.ToTorque(value);
} }
   
public static string ToForce(this double value) public static string ToForce(this double value)
{ {
return Units.ToForce(value); return Units.ToForce(value);
} }
   
public static string ToMass(this double value) public static string ToMass(this double value)
{ {
return Units.ToMass(value); return Units.ToMass(value);
} }
   
public static string ToPercent(this double value) public static string ToPercent(this double value)
{ {
return Units.ToPercent(value); return Units.ToPercent(value);
} }
   
public static string ToRate(this double value) public static string ToRate(this double value)
{ {
return Units.ToRate(value); return Units.ToRate(value);
} }
   
public static string ToSpeed(this double value) public static string ToSpeed(this double value)
{ {
return Units.ToSpeed(value); return Units.ToSpeed(value);
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using KerbalEngineer.Helpers; using KerbalEngineer.Helpers;
   
#endregion #endregion
   
namespace KerbalEngineer.Extensions namespace KerbalEngineer.Extensions
{ {
public static class FloatExtensions public static class FloatExtensions
{ {
#region Methods: public #region Methods: public
   
public static string ToAcceleration(this float value) public static string ToAcceleration(this float value)
{ {
return Units.ToAcceleration(value); return Units.ToAcceleration(value);
} }
   
public static string ToAngle(this float value) public static string ToAngle(this float value)
{ {
return Units.ToAngle(value); return Units.ToAngle(value);
} }
   
public static string ToDistance(this float value) public static string ToDistance(this float value)
{ {
return Units.ToDistance(value); return Units.ToDistance(value);
} }
   
public static string ToForce(this float value) public static string ToForce(this float value)
{ {
return Units.ToForce(value); return Units.ToForce(value);
} }
   
  public static string ToTorque(this float value)
  {
  return Units.ToTorque(value);
  }
   
public static string ToMass(this float value) public static string ToMass(this float value)
{ {
return Units.ToMass(value); return Units.ToMass(value);
} }
   
public static string ToPercent(this float value) public static string ToPercent(this float value)
{ {
return Units.ToPercent(value); return Units.ToPercent(value);
} }
   
public static string ToRate(this float value) public static string ToRate(this float value)
{ {
return Units.ToRate(value); return Units.ToRate(value);
} }
   
public static string ToSpeed(this float value) public static string ToSpeed(this float value)
{ {
return Units.ToSpeed(value); return Units.ToSpeed(value);
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using KerbalEngineer.Flight.Sections; using KerbalEngineer.Flight.Sections;
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Miscellaneous namespace KerbalEngineer.Flight.Readouts.Miscellaneous
{ {
  using System;
   
public class SimulationDelay : ReadoutModule public class SimulationDelay : ReadoutModule
{ {
#region Constructors #region Constructors
   
public SimulationDelay() public SimulationDelay()
{ {
this.Name = "Minimum Simulation Delay"; this.Name = "Minimum Simulation Delay";
this.Category = ReadoutCategory.GetCategory("Miscellaneous"); this.Category = ReadoutCategory.GetCategory("Miscellaneous");
this.HelpString = "Controls the minimum delay between processing vessel simulations."; this.HelpString = "Controls the minimum delay between processing vessel simulations.";
this.IsDefault = true; this.IsDefault = true;
} }
   
#endregion #endregion
   
#region Methods: public #region Methods: public
   
public override void Draw(SectionModule section) public override void Draw(SectionModule section)
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Sim Delay", this.NameStyle); GUILayout.Label("Sim Delay", this.NameStyle);
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
SimManager.minSimTime = (long)GUILayout.HorizontalSlider(SimManager.minSimTime, 0, 1000.0f); SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 1000.0f));
GUI.skin = null; GUI.skin = null;
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
#endregion #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/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Miscellaneous
  {
  #region Using Directives
 
  using Sections;
  using UnityEngine;
  using VesselSimulator;
 
  #endregion
 
  public class VectoredThrustToggle : ReadoutModule
  {
  #region Constructors
 
  public VectoredThrustToggle()
  {
  this.Name = "Vectored Thrust";
  this.Category = ReadoutCategory.GetCategory("Miscellaneous");
  this.HelpString = "Shows a control that will allow you to adjust whether the vessel simulation should account for vectored thrust.";
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods
 
  public override void Draw(SectionModule section)
  {
  GUILayout.BeginHorizontal();
  GUILayout.Label("Vectored Thrust: ", this.NameStyle);
  SimManager.vectoredThrust = GUILayout.Toggle(SimManager.vectoredThrust, "ENABLED", this.ButtonStyle);
  GUILayout.EndHorizontal();
  }
 
  #endregion
  }
  }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
   
using KerbalEngineer.Extensions; using KerbalEngineer.Extensions;
using KerbalEngineer.Flight.Readouts.Vessel; using KerbalEngineer.Flight.Readouts.Vessel;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
{ {
public class ManoeuvreProcessor : IUpdatable, IUpdateRequest public class ManoeuvreProcessor : IUpdatable, IUpdateRequest
{ {
#region Fields #region Fields
   
private static readonly ManoeuvreProcessor instance = new ManoeuvreProcessor(); private static readonly ManoeuvreProcessor instance = new ManoeuvreProcessor();
   
#endregion #endregion
   
#region Properties #region Properties
   
public static double AngleToPrograde { get; private set; } public static double AngleToPrograde { get; private set; }
   
public static double AngleToRetrograde { get; private set; } public static double AngleToRetrograde { get; private set; }
   
public static double AvailableDeltaV { get; private set; } public static double AvailableDeltaV { get; private set; }
   
public static double BurnTime { get; private set; } public static double BurnTime { get; private set; }
   
public static int FinalStage { get; private set; } public static int FinalStage { get; private set; }
   
public static double HalfBurnTime { get; private set; } public static double HalfBurnTime { get; private set; }
   
public static bool HasDeltaV { get; private set; } public static bool HasDeltaV { get; private set; }
   
public static ManoeuvreProcessor Instance public static ManoeuvreProcessor Instance
{ {
get { return instance; } get { return instance; }
} }
   
public static double NormalDeltaV { get; private set; } public static double NormalDeltaV { get; private set; }
   
public static double ProgradeDeltaV { get; private set; } public static double ProgradeDeltaV { get; private set; }
   
public static double RadialDeltaV { get; private set; } public static double RadialDeltaV { get; private set; }
   
public static bool ShowDetails { get; set; } public static bool ShowDetails { get; set; }
   
public static double TotalDeltaV { get; private set; } public static double TotalDeltaV { get; private set; }
   
public static double UniversalTime { get; private set; } public static double UniversalTime { get; private set; }
   
public bool UpdateRequested { get; set; } public bool UpdateRequested { get; set; }
   
#endregion #endregion
   
#region Methods: public #region Methods: public
   
public static void RequestUpdate() public static void RequestUpdate()
{ {
instance.UpdateRequested = true; instance.UpdateRequested = true;
SimulationProcessor.RequestUpdate(); SimulationProcessor.RequestUpdate();
} }
   
public static void Reset() public static void Reset()
{ {
FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance); FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance);
FlightEngineerCore.Instance.AddUpdatable(instance); FlightEngineerCore.Instance.AddUpdatable(instance);
} }
   
public void Update() public void Update()
{ {
if (FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0 || !SimulationProcessor.ShowDetails) if (FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0 || !SimulationProcessor.ShowDetails)
{ {
ShowDetails = false; ShowDetails = false;
return; return;
} }
   
var node = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0]; var node = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0];
var deltaV = node.DeltaV; var deltaV = node.DeltaV;
   
ProgradeDeltaV = deltaV.z; ProgradeDeltaV = deltaV.z;
NormalDeltaV = deltaV.y; NormalDeltaV = deltaV.y;
RadialDeltaV = deltaV.x; RadialDeltaV = deltaV.x;
TotalDeltaV = node.GetBurnVector(FlightGlobals.ship_orbit).magnitude; TotalDeltaV = node.GetBurnVector(FlightGlobals.ship_orbit).magnitude;
   
UniversalTime = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].UT; UniversalTime = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].UT;
AngleToPrograde = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].patch.GetAngleToPrograde(UniversalTime); AngleToPrograde = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].patch.GetAngleToPrograde(UniversalTime);
AngleToRetrograde = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].patch.GetAngleToRetrograde(UniversalTime); AngleToRetrograde = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].patch.GetAngleToRetrograde(UniversalTime);
   
var burnTime = 0.0; var burnTime = 0.0;
var midPointTime = 0.0; var midPointTime = 0.0;
HasDeltaV = GetBurnTime((float)TotalDeltaV, ref burnTime, ref midPointTime); HasDeltaV = GetBurnTime(TotalDeltaV, ref burnTime, ref midPointTime);
AvailableDeltaV = SimulationProcessor.LastStage.totalDeltaV; AvailableDeltaV = SimulationProcessor.LastStage.totalDeltaV;
   
BurnTime = burnTime; BurnTime = burnTime;
HalfBurnTime = midPointTime; HalfBurnTime = midPointTime;
   
ShowDetails = true; ShowDetails = true;
} }
   
#endregion #endregion
   
#region Methods: private #region Methods: private
   
private static bool GetBurnTime(float deltaV, ref double burnTime, ref double midPointTime) private static bool GetBurnTime(double deltaV, ref double burnTime, ref double midPointTime)
{ {
var setMidPoint = false; var setMidPoint = false;
var deltaVMidPoint = deltaV * 0.5f; var deltaVMidPoint = deltaV * 0.5;
   
for (var i = SimulationProcessor.Stages.Length - 1; i >= 0; i--) for (var i = SimulationProcessor.Stages.Length - 1; i > -1; i--)
{ {
var stage = SimulationProcessor.Stages[i]; var stage = SimulationProcessor.Stages[i];
var stageDeltaV = (float)stage.deltaV; var stageDeltaV = stage.deltaV;
  var startMass = stage.totalMass;
   
ProcessStageDrain: ProcessStageDrain:
if (deltaV <= Single.Epsilon) if (deltaV <= Double.Epsilon)
{ {
FinalStage = ++i; break;
return true;  
} }
if (stageDeltaV <= Single.Epsilon) if (stageDeltaV <= Double.Epsilon)
{ {
continue; continue;
} }
   
float deltaVDrain; FinalStage = i;
   
  double deltaVDrain;
if (deltaVMidPoint > 0.0) if (deltaVMidPoint > 0.0)
{ {
deltaVDrain = Mathf.Clamp(deltaV, 0.0f, Mathf.Clamp(deltaVMidPoint, 0.0f, stageDeltaV)); deltaVDrain = deltaV.Clamp(0.0, stageDeltaV.Clamp(0.0, deltaVMidPoint));
deltaVMidPoint -= deltaVDrain; deltaVMidPoint -= deltaVDrain;
setMidPoint = deltaVMidPoint <= Single.Epsilon; setMidPoint = deltaVMidPoint <= Double.Epsilon;
} }
else else
{ {
deltaVDrain = Mathf.Clamp(deltaV, 0.0f, stageDeltaV); deltaVDrain = deltaV.Clamp(0.0, stageDeltaV);
} }
   
var startMass = stage.totalMass - (stage.resourceMass * (1.0f - (stageDeltaV / stage.deltaV))); var exhaustVelocity = stage.isp * 9.82;
var endMass = startMass - (stage.resourceMass * (deltaVDrain / stageDeltaV)); var flowRate = stage.thrust / exhaustVelocity;
var minimumAcceleration = stage.thrust / startMass; var endMass = Math.Exp(Math.Log(startMass) - deltaVDrain / exhaustVelocity);
var maximumAcceleration = stage.thrust / endMass; var deltaMass = (startMass - endMass) * Math.Exp(-(deltaVDrain * 0.001) / exhaustVelocity);
  burnTime += deltaMass / flowRate;
   
burnTime += deltaVDrain / ((minimumAcceleration + maximumAcceleration) * 0.5);  
deltaV -= deltaVDrain; deltaV -= deltaVDrain;
stageDeltaV -= deltaVDrain; stageDeltaV -= deltaVDrain;
  startMass -= deltaMass;
   
if (setMidPoint) if (setMidPoint)
{ {
midPointTime = burnTime; midPointTime = burnTime;
setMidPoint = false; setMidPoint = false;
goto ProcessStageDrain; goto ProcessStageDrain;
} }
} }
return false; return deltaV <= Double.Epsilon;
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts namespace KerbalEngineer.Flight.Readouts
{ {
public class ReadoutCategory public class ReadoutCategory
{ {
#region Constructors #region Constructors
   
public ReadoutCategory(string name) public ReadoutCategory(string name)
{ {
this.Name = name; this.Name = name;
} }
   
public ReadoutCategory(string name, string description) public ReadoutCategory(string name, string description)
{ {
this.Name = name; this.Name = name;
this.Description = description; this.Description = description;
} }
   
static ReadoutCategory() static ReadoutCategory()
{ {
Categories = new List<ReadoutCategory>(); Categories = new List<ReadoutCategory>();
} }
   
#endregion #endregion
   
#region Properties #region Properties
   
public static List<ReadoutCategory> Categories { get; private set; } public static List<ReadoutCategory> Categories { get; private set; }
   
public static ReadoutCategory Selected { get; set; } public static ReadoutCategory Selected { get; set; }
   
public string Description { get; set; } public string Description { get; set; }
   
public string Name { get; set; } public string Name { get; set; }
   
#endregion #endregion
   
#region Public Methods #region Public Methods
   
/// <summary> /// <summary>
/// Gets a category with the specified non-case sensitive name or creates it if required. /// Gets a category with the specified non-case sensitive name or creates it if required.
/// </summary> /// </summary>
public static ReadoutCategory GetCategory(string name) public static ReadoutCategory GetCategory(string name)
{ {
if (Categories.Any(c => c.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase))) if (Categories.Any(c => c.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase)))
{ {
return Categories.Find(c => c.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase)); return Categories.Find(c => c.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase));
} }
   
var category = new ReadoutCategory(name); var category = new ReadoutCategory(name);
Categories.Add(category); Categories.Add(category);
return category; return category;
} }
   
public static void SetCategory(string name) public static void SetCategory(string name)
{ {
var category = GetCategory(name); var category = GetCategory(name);
category.Name = name; category.Name = name;
} }
   
public static void SetCategory(string name, string description) public static void SetCategory(string name, string description)
{ {
var category = GetCategory(name); var category = GetCategory(name);
category.Name = name; category.Name = name;
category.Description = description; category.Description = description;
} }
   
public override string ToString() public override string ToString()
{ {
return this.Name; return this.Name;
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives  
   
using System;  
using System.Collections.Generic;  
using System.Linq;  
   
using KerbalEngineer.Flight.Readouts.Miscellaneous;  
using KerbalEngineer.Flight.Readouts.Orbital;  
using KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode;  
using KerbalEngineer.Flight.Readouts.Rendezvous;  
using KerbalEngineer.Flight.Readouts.Surface;  
using KerbalEngineer.Flight.Readouts.Vessel;  
using KerbalEngineer.Settings;  
   
using AltitudeSeaLevel = KerbalEngineer.Flight.Readouts.Surface.AltitudeSeaLevel;  
using ApoapsisHeight = KerbalEngineer.Flight.Readouts.Orbital.ApoapsisHeight;  
using OrbitalPeriod = KerbalEngineer.Flight.Readouts.Orbital.OrbitalPeriod;  
using PeriapsisHeight = KerbalEngineer.Flight.Readouts.Orbital.PeriapsisHeight;  
using SemiMajorAxis = KerbalEngineer.Flight.Readouts.Orbital.SemiMajorAxis;  
using SemiMinorAxis = KerbalEngineer.Flight.Readouts.Orbital.SemiMinorAxis;  
using TimeToApoapsis = KerbalEngineer.Flight.Readouts.Orbital.TimeToApoapsis;  
using TimeToPeriapsis = KerbalEngineer.Flight.Readouts.Orbital.TimeToPeriapsis;  
   
#endregion  
   
namespace KerbalEngineer.Flight.Readouts namespace KerbalEngineer.Flight.Readouts
{ {
  #region Using Directives
   
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using Miscellaneous;
  using Orbital;
  using Orbital.ManoeuvreNode;
  using Rendezvous;
  using Settings;
  using Surface;
  using Vessel;
  using AltitudeSeaLevel = Surface.AltitudeSeaLevel;
  using ApoapsisHeight = Orbital.ApoapsisHeight;
  using OrbitalPeriod = Orbital.OrbitalPeriod;
  using PeriapsisHeight = Orbital.PeriapsisHeight;
  using SemiMajorAxis = Orbital.SemiMajorAxis;
  using SemiMinorAxis = Orbital.SemiMinorAxis;
  using TimeToApoapsis = Orbital.TimeToApoapsis;
  using TimeToPeriapsis = Orbital.TimeToPeriapsis;
   
  #endregion
   
public static class ReadoutLibrary public static class ReadoutLibrary
{ {
#region Fields #region Fields
   
private static List<ReadoutModule> readouts = new List<ReadoutModule>(); private static List<ReadoutModule> readouts = new List<ReadoutModule>();
   
#endregion #endregion
   
#region Constructors #region Constructors
   
/// <summary> /// <summary>
/// Sets up and populates the readout library with the stock readouts. /// Sets up and populates the readout library with the stock readouts.
/// </summary> /// </summary>
static ReadoutLibrary() static ReadoutLibrary()
{ {
try try
{ {
ReadoutCategory.SetCategory("Orbital", "Readout for orbital manovoeures."); ReadoutCategory.SetCategory("Orbital", "Readout for orbital manovoeures.");
ReadoutCategory.SetCategory("Surface", "Surface and atmospheric readouts."); ReadoutCategory.SetCategory("Surface", "Surface and atmospheric readouts.");
ReadoutCategory.SetCategory("Vessel", "Vessel performance statistics."); ReadoutCategory.SetCategory("Vessel", "Vessel performance statistics.");
ReadoutCategory.SetCategory("Rendezvous", "Readouts for rendezvous manovoeures."); ReadoutCategory.SetCategory("Rendezvous", "Readouts for rendezvous manovoeures.");
ReadoutCategory.SetCategory("Miscellaneous", "Miscellaneous readouts."); ReadoutCategory.SetCategory("Miscellaneous", "Miscellaneous readouts.");
  ReadoutCategory.Selected = ReadoutCategory.GetCategory("Orbital");
   
// Orbital // Orbital
readouts.Add(new ApoapsisHeight()); readouts.Add(new ApoapsisHeight());
readouts.Add(new PeriapsisHeight()); readouts.Add(new PeriapsisHeight());
readouts.Add(new TimeToApoapsis()); readouts.Add(new TimeToApoapsis());
readouts.Add(new TimeToPeriapsis()); readouts.Add(new TimeToPeriapsis());
readouts.Add(new Inclination()); readouts.Add(new Inclination());
readouts.Add(new TimeToEquatorialAscendingNode()); readouts.Add(new TimeToEquatorialAscendingNode());
readouts.Add(new TimeToEquatorialDescendingNode()); readouts.Add(new TimeToEquatorialDescendingNode());
readouts.Add(new AngleToEquatorialAscendingNode()); readouts.Add(new AngleToEquatorialAscendingNode());
readouts.Add(new AngleToEquatorialDescendingNode()); readouts.Add(new AngleToEquatorialDescendingNode());
readouts.Add(new Eccentricity()); readouts.Add(new Eccentricity());
readouts.Add(new OrbitalSpeed()); readouts.Add(new OrbitalSpeed());
readouts.Add(new OrbitalPeriod()); readouts.Add(new OrbitalPeriod());
readouts.Add(new CurrentSoi()); readouts.Add(new CurrentSoi());
readouts.Add(new LongitudeOfAscendingNode()); readouts.Add(new LongitudeOfAscendingNode());
readouts.Add(new LongitudeOfPeriapsis()); readouts.Add(new LongitudeOfPeriapsis());
readouts.Add(new ArgumentOfPeriapsis()); readouts.Add(new ArgumentOfPeriapsis());
readouts.Add(new TrueAnomaly()); readouts.Add(new TrueAnomaly());
readouts.Add(new MeanAnomaly()); readouts.Add(new MeanAnomaly());
readouts.Add(new EccentricAnomaly()); readouts.Add(new EccentricAnomaly());
readouts.Add(new SemiMajorAxis()); readouts.Add(new SemiMajorAxis());
readouts.Add(new SemiMinorAxis()); readouts.Add(new SemiMinorAxis());
readouts.Add(new AngleToPrograde()); readouts.Add(new AngleToPrograde());
readouts.Add(new AngleToRetrograde()); readouts.Add(new AngleToRetrograde());
readouts.Add(new NodeProgradeDeltaV()); readouts.Add(new NodeProgradeDeltaV());
readouts.Add(new NodeNormalDeltaV()); readouts.Add(new NodeNormalDeltaV());
readouts.Add(new NodeRadialDeltaV()); readouts.Add(new NodeRadialDeltaV());
readouts.Add(new NodeTotalDeltaV()); readouts.Add(new NodeTotalDeltaV());
readouts.Add(new NodeBurnTime()); readouts.Add(new NodeBurnTime());
readouts.Add(new NodeHalfBurnTime()); readouts.Add(new NodeHalfBurnTime());
readouts.Add(new NodeTimeToManoeuvre()); readouts.Add(new NodeTimeToManoeuvre());
readouts.Add(new NodeTimeToHalfBurn()); readouts.Add(new NodeTimeToHalfBurn());
readouts.Add(new NodeAngleToPrograde()); readouts.Add(new NodeAngleToPrograde());
readouts.Add(new NodeAngleToRetrograde()); readouts.Add(new NodeAngleToRetrograde());
   
// Surface // Surface
readouts.Add(new AltitudeSeaLevel()); readouts.Add(new AltitudeSeaLevel());
readouts.Add(new AltitudeTerrain()); readouts.Add(new AltitudeTerrain());
readouts.Add(new VerticalSpeed()); readouts.Add(new VerticalSpeed());
readouts.Add(new VerticalAcceleration()); readouts.Add(new VerticalAcceleration());
readouts.Add(new HorizontalSpeed()); readouts.Add(new HorizontalSpeed());
readouts.Add(new HorizontalAcceleration()); readouts.Add(new HorizontalAcceleration());
readouts.Add(new Latitude()); readouts.Add(new Latitude());
readouts.Add(new Longitude()); readouts.Add(new Longitude());
readouts.Add(new GeeForce()); readouts.Add(new GeeForce());
readouts.Add(new TerminalVelocity()); readouts.Add(new TerminalVelocity());
readouts.Add(new AtmosphericEfficiency()); readouts.Add(new AtmosphericEfficiency());
readouts.Add(new Biome()); readouts.Add(new Biome());
readouts.Add(new Situation()); readouts.Add(new Situation());
readouts.Add(new Slope()); readouts.Add(new Slope());
readouts.Add(new ImpactTime()); readouts.Add(new ImpactTime());
readouts.Add(new ImpactLongitude()); readouts.Add(new ImpactLongitude());
readouts.Add(new ImpactLatitude()); readouts.Add(new ImpactLatitude());
readouts.Add(new ImpactAltitude()); readouts.Add(new ImpactAltitude());
readouts.Add(new ImpactBiome()); readouts.Add(new ImpactBiome());
   
// Vessel // Vessel
readouts.Add(new DeltaVStaged()); readouts.Add(new DeltaVStaged());
readouts.Add(new DeltaVCurrent()); readouts.Add(new DeltaVCurrent());
readouts.Add(new DeltaVTotal()); readouts.Add(new DeltaVTotal());
readouts.Add(new DeltaVCurrentTotal()); readouts.Add(new DeltaVCurrentTotal());
readouts.Add(new SpecificImpulse()); readouts.Add(new SpecificImpulse());
readouts.Add(new Mass()); readouts.Add(new Mass());
readouts.Add(new Thrust()); readouts.Add(new Thrust());
readouts.Add(new ThrustToWeight()); readouts.Add(new ThrustToWeight());
  readouts.Add(new ThrustOffsetAngle());
  readouts.Add(new ThrustTorque());
readouts.Add(new SurfaceThrustToWeight()); readouts.Add(new SurfaceThrustToWeight());
readouts.Add(new Acceleration()); readouts.Add(new Acceleration());
readouts.Add(new SuicideBurnAltitude()); readouts.Add(new SuicideBurnAltitude());
readouts.Add(new SuicideBurnDistance()); readouts.Add(new SuicideBurnDistance());
readouts.Add(new SuicideBurnDeltaV()); readouts.Add(new SuicideBurnDeltaV());
readouts.Add(new IntakeAirUsage()); readouts.Add(new IntakeAirUsage());
readouts.Add(new IntakeAirDemand()); readouts.Add(new IntakeAirDemand());
readouts.Add(new IntakeAirSupply()); readouts.Add(new IntakeAirSupply());
readouts.Add(new IntakeAirDemandSupply()); readouts.Add(new IntakeAirDemandSupply());
  readouts.Add(new PartCount());
  readouts.Add(new Heading());
  readouts.Add(new Pitch());
  readouts.Add(new Roll());
  readouts.Add(new HeadingRate());
  readouts.Add(new PitchRate());
  readouts.Add(new RollRate());
   
// Rendezvous // Rendezvous
readouts.Add(new TargetSelector()); readouts.Add(new TargetSelector());
readouts.Add(new PhaseAngle()); readouts.Add(new PhaseAngle());
readouts.Add(new InterceptAngle()); readouts.Add(new InterceptAngle());
readouts.Add(new RelativeVelocity()); readouts.Add(new RelativeVelocity());
readouts.Add(new RelativeSpeed()); readouts.Add(new RelativeSpeed());
readouts.Add(new RelativeInclination()); readouts.Add(new RelativeInclination());
readouts.Add(new TimeToRelativeAscendingNode()); readouts.Add(new TimeToRelativeAscendingNode());
readouts.Add(new TimeToRelativeDescendingNode()); readouts.Add(new TimeToRelativeDescendingNode());
readouts.Add(new AngleToRelativeAscendingNode()); readouts.Add(new AngleToRelativeAscendingNode());
readouts.Add(new AngleToRelativeDescendingNode()); readouts.Add(new AngleToRelativeDescendingNode());
readouts.Add(new Rendezvous.AltitudeSeaLevel()); readouts.Add(new Rendezvous.AltitudeSeaLevel());
readouts.Add(new Rendezvous.ApoapsisHeight()); readouts.Add(new Rendezvous.ApoapsisHeight());
readouts.Add(new Rendezvous.PeriapsisHeight()); readouts.Add(new Rendezvous.PeriapsisHeight());
readouts.Add(new Rendezvous.TimeToApoapsis()); readouts.Add(new Rendezvous.TimeToApoapsis());
readouts.Add(new Rendezvous.TimeToPeriapsis()); readouts.Add(new Rendezvous.TimeToPeriapsis());
readouts.Add(new Distance()); readouts.Add(new Distance());
readouts.Add(new Rendezvous.OrbitalPeriod()); readouts.Add(new Rendezvous.OrbitalPeriod());
readouts.Add(new Rendezvous.SemiMajorAxis()); readouts.Add(new Rendezvous.SemiMajorAxis());
readouts.Add(new Rendezvous.SemiMinorAxis()); readouts.Add(new Rendezvous.SemiMinorAxis());
   
// Misc // Misc
readouts.Add(new Separator()); readouts.Add(new Separator());
readouts.Add(new GuiSizeAdjustor()); readouts.Add(new GuiSizeAdjustor());
readouts.Add(new SimulationDelay()); readouts.Add(new SimulationDelay());
readouts.Add(new TimeReference()); readouts.Add(new TimeReference());
  readouts.Add(new VectoredThrustToggle());
   
LoadHelpStrings(); LoadHelpStrings();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
   
#region Properties #region Properties
   
/// <summary> /// <summary>
/// Gets and sets the available readout modules. /// Gets and sets the available readout modules.
/// </summary> /// </summary>
public static List<ReadoutModule> Readouts public static List<ReadoutModule> Readouts
{ {
get { return readouts; } get { return readouts; }
set { readouts = value; } set { readouts = value; }
} }
   
#endregion #endregion
   
#region Methods: public #region Methods
   
/// <summary> /// <summary>
/// Gets a list of readout modules which are associated with the specified category. /// Gets a list of readout modules which are associated with the specified category.
/// </summary> /// </summary>
public static List<ReadoutModule> GetCategory(ReadoutCategory category) public static List<ReadoutModule> GetCategory(ReadoutCategory category)
{ {
return readouts.Where(r => r.Category == category).ToList(); return readouts.Where(r => r.Category == category).ToList();
} }
   
/// <summary> /// <summary>
/// Gets a readout module with the specified name or class name. (Returns null if not found.) /// Gets a readout module with the specified name or class name. (Returns null if not found.)
/// </summary> /// </summary>
public static ReadoutModule GetReadout(string name) public static ReadoutModule GetReadout(string name)
{ {
return readouts.FirstOrDefault(r => r.Name == name || r.GetType().Name == name || r.Category + "." + r.GetType().Name == name); return readouts.FirstOrDefault(r => r.Name == name || r.GetType().Name == name || r.Category + "." + r.GetType().Name == name);
} }
   
/// <summary> /// <summary>
/// Resets all the readout modules. /// Resets all the readout modules.
/// </summary> /// </summary>
public static void Reset() public static void Reset()
{ {
foreach (var readout in readouts) foreach (var readout in readouts)
{ {
readout.Reset(); readout.Reset();
} }
} }
   
#endregion  
   
#region Methods: private  
   
/// <summary> /// <summary>
/// Loads the help strings from file. /// Loads the help strings from file.
/// </summary> /// </summary>
private static void LoadHelpStrings() private static void LoadHelpStrings()
{ {
try try
{ {
var handler = SettingHandler.Load("HelpStrings.xml"); var handler = SettingHandler.Load("HelpStrings.xml");
foreach (var readout in readouts) foreach (var readout in readouts)
{ {
readout.HelpString = handler.GetSet(readout.Category + "." + readout.GetType().Name, readout.HelpString); readout.HelpString = handler.GetSet(readout.Category + "." + readout.GetType().Name, readout.HelpString);
} }
handler.Save("HelpStrings.xml"); handler.Save("HelpStrings.xml");
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using KerbalEngineer.Extensions;  
using KerbalEngineer.Flight.Sections;  
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Surface namespace KerbalEngineer.Flight.Readouts.Surface
{ {
  #region Using Directives
   
  using Extensions;
  using Sections;
   
  #endregion
   
public class AltitudeTerrain : ReadoutModule public class AltitudeTerrain : ReadoutModule
{ {
#region Constructors #region Constructors
   
public AltitudeTerrain() public AltitudeTerrain()
{ {
this.Name = "Altitude (Terrain)"; this.Name = "Altitude (Terrain)";
this.Category = ReadoutCategory.GetCategory("Surface"); this.Category = ReadoutCategory.GetCategory("Surface");
this.HelpString = "Shows the vessel's altitude above the terrain."; this.HelpString = "Shows the vessel's altitude above the terrain.";
this.IsDefault = true; this.IsDefault = true;
} }
   
#endregion #endregion
   
#region Methods: public #region Methods
   
public override void Draw(SectionModule section) public override void Draw(SectionModule section)
{ {
this.DrawLine((FlightGlobals.ship_altitude - FlightGlobals.ActiveVessel.terrainAltitude).ToDistance(), section.IsHud); if (FlightGlobals.ActiveVessel.terrainAltitude > 0.0)
  {
  this.DrawLine((FlightGlobals.ship_altitude - FlightGlobals.ActiveVessel.terrainAltitude).ToDistance(), section.IsHud);
  }
  else
  {
  this.DrawLine((FlightGlobals.ship_altitude).ToDistance(), section.IsHud);
  }
} }
   
#endregion #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/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  #region Using Directives
 
  using UnityEngine;
 
  #endregion
 
  public class AttitudeProcessor : IUpdatable, IUpdateRequest
  {
  #region Fields
 
  private static readonly AttitudeProcessor instance = new AttitudeProcessor();
 
  private Vector3 centreOfMass = Vector3.zero;
 
  private double heading;
  private double headingRate;
  private Vector3 north = Vector3.zero;
  private double pitch;
  private double pitchRate;
  private double previousHeading;
  private double previousPitch;
  private double previousRoll;
  private double roll;
  private double rollRate;
  private Quaternion surfaceRotation;
  private Vector3 up = Vector3.zero;
 
  #endregion
 
  #region Properties
 
  public static double Heading
  {
  get { return instance.heading; }
  }
 
  public static double HeadingRate
  {
  get { return instance.headingRate; }
  }
 
  public static AttitudeProcessor Instance
  {
  get { return instance; }
  }
 
  public static double Pitch
  {
  get { return instance.pitch; }
  }
 
  public static double PitchRate
  {
  get { return instance.pitchRate; }
  }
 
  public static double Roll
  {
  get { return instance.roll; }
  }
 
  public static double RollRate
  {
  get { return instance.rollRate; }
  }
 
  public bool UpdateRequested { get; set; }
 
  #endregion
 
  #region Methods
 
  public static void RequestUpdate()
  {
  instance.UpdateRequested = true;
  }
 
  public void Update()
  {
  this.surfaceRotation = this.GetSurfaceRotation();
 
  this.previousHeading = this.heading;
  this.previousPitch = this.pitch;
  this.previousRoll = this.roll;
 
  // This code was derived from MechJeb2's implementation for getting the vessel's surface relative rotation.
  this.heading = this.surfaceRotation.eulerAngles.y;
  this.pitch = this.surfaceRotation.eulerAngles.x > 180.0f
  ? 360.0f - this.surfaceRotation.eulerAngles.x
  : -this.surfaceRotation.eulerAngles.x;
  this.roll = this.surfaceRotation.eulerAngles.z > 180.0f
  ? this.surfaceRotation.eulerAngles.z - 360.0f
  : this.surfaceRotation.eulerAngles.z;
 
  this.headingRate = this.heading - this.previousHeading;
  this.pitchRate = this.pitch - this.previousPitch;
  this.rollRate = this.roll - this.previousRoll;
  }
 
  private Quaternion GetSurfaceRotation()
  {
  // This code was derived from MechJeb2's implementation for getting the vessel's surface relative rotation.
  this.centreOfMass = FlightGlobals.ActiveVessel.findWorldCenterOfMass();
  this.up = (this.centreOfMass - FlightGlobals.ActiveVessel.mainBody.position).normalized;
  this.north = Vector3.Exclude(this.up, (FlightGlobals.ActiveVessel.mainBody.position + FlightGlobals.ActiveVessel.mainBody.transform.up * (float)FlightGlobals.ActiveVessel.mainBody.Radius) - this.centreOfMass).normalized;
  return Quaternion.Inverse(Quaternion.Euler(90.0f, 0.0f, 0.0f) * Quaternion.Inverse(FlightGlobals.ActiveVessel.transform.rotation) * Quaternion.LookRotation(this.north, this.up));
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  #region Using Directives
 
  using Helpers;
  using Sections;
 
  #endregion
 
  public class Heading : ReadoutModule
  {
  #region Constructors
 
  public Heading()
  {
  this.Name = "Heading";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = string.Empty;
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods
 
  public override void Draw(SectionModule section)
  {
  this.DrawLine(Units.ToAngle(AttitudeProcessor.Heading), section.IsHud);
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
  }
 
  public override void Update()
  {
  AttitudeProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  #region Using Directives
 
  using Helpers;
  using Sections;
 
  #endregion
 
  public class HeadingRate : ReadoutModule
  {
  #region Constructors
 
  public HeadingRate()
  {
  this.Name = "Heading Rate";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = string.Empty;
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods
 
  public override void Draw(SectionModule section)
  {
  this.DrawLine(Units.ToAngle(AttitudeProcessor.HeadingRate) + "/sec", section.IsHud);
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
  }
 
  public override void Update()
  {
  AttitudeProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  #region Using Directives
 
  using Helpers;
  using Sections;
 
  #endregion
 
  public class PartCount : ReadoutModule
  {
  #region Constructors
 
  public PartCount()
  {
  this.Name = "Part Count";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = string.Empty;
  this.IsDefault = true;
  }
 
  #endregion
 
  #region Methods
 
  public override void Draw(SectionModule section)
  {
  if (SimulationProcessor.ShowDetails)
  {
  this.DrawLine(Units.Concat(SimulationProcessor.LastStage.partCount, SimulationProcessor.LastStage.totalPartCount), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance);
  }
 
  public override void Update()
  {
  SimulationProcessor.RequestUpdate();
  }
 
  #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/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  #region Using Directives
 
  using Helpers;
  using Sections;
 
  #endregion
 
  public class Pitch : ReadoutModule
  {
  #region Constructors
 
  public Pitch()
  {
  this.Name = "Pitch";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = string.Empty;
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods
 
  public override void Draw(SectionModule section)
  {
  this.DrawLine(Units.ToAngle(AttitudeProcessor.Pitch), section.IsHud);
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
  }
 
  public override void Update()
  {
  AttitudeProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  #region Using Directives
 
  using Helpers;
  using Sections;
 
  #endregion
 
  public class PitchRate : ReadoutModule
  {
  #region Constructors
 
  public PitchRate()
  {
  this.Name = "Pitch Rate";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = string.Empty;
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods
 
  public override void Draw(SectionModule section)
  {
  this.DrawLine(Units.ToAngle(AttitudeProcessor.PitchRate) + "/sec", section.IsHud);
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
  }
 
  public override void Update()
  {
  AttitudeProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  #region Using Directives
 
  using Helpers;
  using Sections;
 
  #endregion
 
  public class Roll : ReadoutModule
  {
  #region Constructors
 
  public Roll()
  {
  this.Name = "Roll";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = string.Empty;
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods
 
  public override void Draw(SectionModule section)
  {
  this.DrawLine(Units.ToAngle(AttitudeProcessor.Roll), section.IsHud);
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
  }
 
  public override void Update()
  {
  AttitudeProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  #region Using Directives
 
  using Helpers;
  using Sections;
 
  #endregion
 
  public class RollRate : ReadoutModule
  {
  #region Constructors
 
  public RollRate()
  {
  this.Name = "Roll Rate";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = string.Empty;
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods
 
  public override void Draw(SectionModule section)
  {
  this.DrawLine(Units.ToAngle(AttitudeProcessor.RollRate) + "/sec", section.IsHud);
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(AttitudeProcessor.Instance);
  }
 
  public override void Update()
  {
  AttitudeProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System;  
   
using KerbalEngineer.VesselSimulator;  
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Vessel namespace KerbalEngineer.Flight.Readouts.Vessel
{ {
  #region Using Directives
   
  using System;
  using VesselSimulator;
   
  #endregion
   
public class SimulationProcessor : IUpdatable, IUpdateRequest public class SimulationProcessor : IUpdatable, IUpdateRequest
{ {
#region Instance #region Instance
   
#region Fields #region Fields
   
private static readonly SimulationProcessor instance = new SimulationProcessor(); private static readonly SimulationProcessor instance = new SimulationProcessor();
   
  #endregion
   
  #region Constructors
   
  static SimulationProcessor()
  {
  SimManager.OnReady += GetStageInfo;
  }
   
#endregion #endregion
   
#region Properties #region Properties
   
/// <summary> /// <summary>
/// Gets the current instance of the simulation processor. /// Gets the current instance of the simulation processor.
/// </summary> /// </summary>
public static SimulationProcessor Instance public static SimulationProcessor Instance
{ {
get { return instance; } get { return instance; }
} }
   
#endregion #endregion
   
#endregion #endregion
   
#region Properties #region Properties
   
/// <summary> /// <summary>
/// Gets the currently active vessel stage. /// Gets the currently active vessel stage.
/// </summary> /// </summary>
public static Stage LastStage { get; private set; } public static Stage LastStage { get; private set; }
   
/// <summary> /// <summary>
/// Gets whether the details are ready to be shown. /// Gets whether the details are ready to be shown.
/// </summary> /// </summary>
public static bool ShowDetails { get; private set; } public static bool ShowDetails { get; private set; }
   
/// <summary> /// <summary>
/// Gets an array of the vessel stages. /// Gets an array of the vessel stages.
/// </summary> /// </summary>
public static Stage[] Stages { get; private set; } public static Stage[] Stages { get; private set; }
   
public bool UpdateRequested { get; set; } public bool UpdateRequested { get; set; }
   
#endregion #endregion
   
#region Methods: public #region Methods
   
  private static void GetStageInfo()
  {
  Stages = SimManager.Stages;
  LastStage = SimManager.LastStage;
  }
   
public static void RequestUpdate() public static void RequestUpdate()
{ {
instance.UpdateRequested = true; instance.UpdateRequested = true;
} }
   
public void Update() public void Update()
{ {
SimManager.RequestSimulation(); SimManager.RequestSimulation();
SimManager.TryStartSimulation(); SimManager.TryStartSimulation();
   
if (!SimManager.ResultsReady()) if (!SimManager.ResultsReady())
{ {
return; return;
} }
   
Stages = SimManager.Stages;  
LastStage = SimManager.LastStage;  
   
if (Stages != null && LastStage != null) if (Stages != null && LastStage != null)
{ {
ShowDetails = true; ShowDetails = true;
} }
   
if (FlightGlobals.ActiveVessel != null) if (FlightGlobals.ActiveVessel != null)
{ {
SimManager.Gravity = FlightGlobals.ActiveVessel.mainBody.gravParameter / SimManager.Gravity = FlightGlobals.ActiveVessel.mainBody.gravParameter /
Math.Pow(FlightGlobals.ActiveVessel.mainBody.Radius + Math.Pow(FlightGlobals.ActiveVessel.mainBody.Radius +
FlightGlobals.ActiveVessel.mainBody.GetAltitude(FlightGlobals.ActiveVessel.CoM), 2); FlightGlobals.ActiveVessel.mainBody.GetAltitude(FlightGlobals.ActiveVessel.CoM), 2);
SimManager.Velocity = FlightGlobals.ActiveVessel.srfSpeed; SimManager.Velocity = FlightGlobals.ActiveVessel.srfSpeed;
} }
   
// Cybutek: We should be allowing this to be set too but not sure where you want to put the control  
//SimManager.vectoredThrust = vectoredThrust;  
} }
   
#endregion #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 KerbalEngineer.Flight.Sections;
  using KerbalEngineer.Helpers;
 
  #endregion
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  public class ThrustOffsetAngle : ReadoutModule
  {
  #region Constructors
 
  public ThrustOffsetAngle()
  {
  this.Name = "Thrust offset angle";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = "Thrust angle offset due to vessel asymmetries and gimballing";
  this.IsDefault = true;
  }
 
  #endregion
 
  #region Methods: public
 
  public override void Draw(SectionModule section)
  {
  if (SimulationProcessor.ShowDetails)
  {
  this.DrawLine(Units.ToAngle(SimulationProcessor.LastStage.thrustOffsetAngle, 1), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance);
  }
 
  public override void Update()
  {
  SimulationProcessor.RequestUpdate();
  }
 
  #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 KerbalEngineer.Flight.Sections;
  using KerbalEngineer.Helpers;
 
  #endregion
 
  namespace KerbalEngineer.Flight.Readouts.Vessel
  {
  public class ThrustTorque : ReadoutModule
  {
  #region Constructors
 
  public ThrustTorque()
  {
  this.Name = "Thrust torque";
  this.Category = ReadoutCategory.GetCategory("Vessel");
  this.HelpString = "Thrust torque due to vessel asymmetries and gimballing";
  this.IsDefault = true;
  }
 
  #endregion
 
  #region Methods: public
 
  public override void Draw(SectionModule section)
  {
  if (SimulationProcessor.ShowDetails)
  {
  this.DrawLine(Units.ToTorque(SimulationProcessor.LastStage.maxThrustTorque), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance);
  }
 
  public override void Update()
  {
  SimulationProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
 
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
   
using KerbalEngineer.Extensions; using KerbalEngineer.Extensions;
using KerbalEngineer.Flight.Presets; using KerbalEngineer.Flight.Presets;
using KerbalEngineer.Flight.Readouts; using KerbalEngineer.Flight.Readouts;
using KerbalEngineer.UIControls; using KerbalEngineer.UIControls;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Sections namespace KerbalEngineer.Flight.Sections
{ {
public class SectionEditor : MonoBehaviour public class SectionEditor : MonoBehaviour
{ {
#region Constants #region Constants
   
public const float Height = 500.0f; public const float Height = 500.0f;
public const float Width = 500.0f; public const float Width = 500.0f;
   
#endregion #endregion
   
#region Fields #region Fields
   
private GUIStyle categoryButtonActiveStyle; private GUIStyle categoryButtonActiveStyle;
private GUIStyle categoryButtonStyle; private GUIStyle categoryButtonStyle;
private DropDown categoryList; private DropDown categoryList;
private GUIStyle categoryTitleButtonStyle; private GUIStyle categoryTitleButtonStyle;
private GUIStyle helpBoxStyle; private GUIStyle helpBoxStyle;
private GUIStyle helpTextStyle; private GUIStyle helpTextStyle;
private GUIStyle panelTitleStyle; private GUIStyle panelTitleStyle;
private Rect position; private Rect position;
private DropDown presetList; private DropDown presetList;
private GUIStyle readoutButtonStyle; private GUIStyle readoutButtonStyle;
private GUIStyle readoutNameStyle; private GUIStyle readoutNameStyle;
private Vector2 scrollPositionAvailable; private Vector2 scrollPositionAvailable;
private Vector2 scrollPositionInstalled; private Vector2 scrollPositionInstalled;
private GUIStyle textStyle; private GUIStyle textStyle;
private GUIStyle windowStyle; private GUIStyle windowStyle;
   
#endregion #endregion
   
#region Properties #region Properties
   
/// <summary> /// <summary>
/// Gets and sets the parent section for the section editor. /// Gets and sets the parent section for the section editor.
/// </summary> /// </summary>
public SectionModule ParentSection { get; set; } public SectionModule ParentSection { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets the window position. /// Gets and sets the window position.
/// </summary> /// </summary>
public Rect Position public Rect Position
{ {
get { return this.position; } get { return this.position; }
set { this.position = value; } set { this.position = value; }
} }
   
#endregion #endregion
   
#region Methods: protected #region Methods: protected
   
protected void Awake() protected void Awake()
{ {
try try
{ {
this.categoryList = this.gameObject.AddComponent<DropDown>(); this.categoryList = this.gameObject.AddComponent<DropDown>();
this.categoryList.DrawCallback = this.DrawCategories; this.categoryList.DrawCallback = this.DrawCategories;
this.presetList = this.gameObject.AddComponent<DropDown>(); this.presetList = this.gameObject.AddComponent<DropDown>();
this.presetList.DrawCallback = this.DrawPresets; this.presetList.DrawCallback = this.DrawPresets;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
/// <summary> /// <summary>
/// Runs when the object is destroyed. /// Runs when the object is destroyed.
/// </summary> /// </summary>
protected void OnDestroy() protected void OnDestroy()
{ {
try try
{ {
RenderingManager.RemoveFromPostDrawQueue(0, this.Draw); RenderingManager.RemoveFromPostDrawQueue(0, this.Draw);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
/// <summary> /// <summary>
/// Initialises the object's state on creation. /// Initialises the object's state on creation.
/// </summary> /// </summary>
protected void Start() protected void Start()
{ {
try try
{ {
this.InitialiseStyles(); this.InitialiseStyles();
ReadoutCategory.Selected = ReadoutCategory.GetCategory("Orbital"); //ReadoutCategory.Selected = ReadoutCategory.GetCategory("Orbital");
RenderingManager.AddToPostDrawQueue(0, this.Draw); RenderingManager.AddToPostDrawQueue(0, this.Draw);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
   
#region Methods: private #region Methods: private
   
/// <summary> /// <summary>
/// Called to draw the editor when the UI is enabled. /// Called to draw the editor when the UI is enabled.
/// </summary> /// </summary>
private void Draw() private void Draw()
{ {
this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, "EDIT SECTION - " + this.ParentSection.Name.ToUpper(), this.windowStyle).ClampToScreen(); this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, "EDIT SECTION - " + this.ParentSection.Name.ToUpper(), this.windowStyle).ClampToScreen();
this.ParentSection.EditorPositionX = this.position.x; this.ParentSection.EditorPositionX = this.position.x;
this.ParentSection.EditorPositionY = this.position.y; this.ParentSection.EditorPositionY = this.position.y;
} }
   
/// <summary> /// <summary>
/// Draws the available readouts panel. /// Draws the available readouts panel.
/// </summary> /// </summary>
private void DrawAvailableReadouts() private void DrawAvailableReadouts()
{ {
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
this.scrollPositionAvailable = GUILayout.BeginScrollView(this.scrollPositionAvailable, false, true, GUILayout.Height(200.0f)); this.scrollPositionAvailable = GUILayout.BeginScrollView(this.scrollPositionAvailable, false, true, GUILayout.Height(200.0f));
GUI.skin = null; GUI.skin = null;
   
GUILayout.Label("AVAILABLE", this.panelTitleStyle); GUILayout.Label("AVAILABLE", this.panelTitleStyle);
   
foreach (var readout in ReadoutLibrary.GetCategory(ReadoutCategory.Selected)) foreach (var readout in ReadoutLibrary.GetCategory(ReadoutCategory.Selected))
{ {
if (!this.ParentSection.ReadoutModules.Contains(readout) || readout.Cloneable) if (!this.ParentSection.ReadoutModules.Contains(readout) || readout.Cloneable)
{ {
GUILayout.BeginHorizontal(GUILayout.Height(30.0f)); GUILayout.BeginHorizontal(GUILayout.Height(30.0f));
GUILayout.Label(readout.Name, this.readoutNameStyle); GUILayout.Label(readout.Name, this.readoutNameStyle);
readout.ShowHelp = GUILayout.Toggle(readout.ShowHelp, "?", this.readoutButtonStyle, GUILayout.Width(30.0f)); readout.ShowHelp = GUILayout.Toggle(readout.ShowHelp, "?", this.readoutButtonStyle, GUILayout.Width(30.0f));
if (GUILayout.Button("INSTALL", this.readoutButtonStyle, GUILayout.Width(125.0f))) if (GUILayout.Button("INSTALL", this.readoutButtonStyle, GUILayout.Width(125.0f)))
{ {
this.ParentSection.ReadoutModules.Add(readout); this.ParentSection.ReadoutModules.Add(readout);
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
this.ShowHelpMessage(readout); this.ShowHelpMessage(readout);
} }
} }
   
GUILayout.EndScrollView(); GUILayout.EndScrollView();
} }
   
/// <summary> /// <summary>
/// Draws the categories list drop down UI. /// Draws the categories list drop down UI.
/// </summary> /// </summary>
private void DrawCategories() private void DrawCategories()
{ {
foreach (var category in ReadoutCategory.Categories) foreach (var category in ReadoutCategory.Categories)
{ {
var description = category.Description; var description = category.Description;
if (description.Length > 50) if (description.Length > 50)
{ {
description = description.Substring(0, 50 - 1) + "..."; description = description.Substring(0, 50 - 1) + "...";
} }
   
if (GUILayout.Button("<b>" + category.Name.ToUpper() + "</b>" + (string.IsNullOrEmpty(category.Description) ? string.Empty : "\n<i>" + description + "</i>"), category == ReadoutCategory.Selected ? this.categoryButtonActiveStyle : this.categoryButtonStyle)) if (GUILayout.Button("<b>" + category.Name.ToUpper() + "</b>" + (string.IsNullOrEmpty(category.Description) ? string.Empty : "\n<i>" + description + "</i>"), category == ReadoutCategory.Selected ? this.categoryButtonActiveStyle : this.categoryButtonStyle))
{ {
ReadoutCategory.Selected = category; ReadoutCategory.Selected = category;
this.categoryList.enabled = false; this.categoryList.enabled = false;
} }
} }
} }
   
/// <summary> /// <summary>
/// Draws the readoutCategories selection list. /// Draws the readoutCategories selection list.
/// </summary> /// </summary>
private void DrawCategorySelector() private void DrawCategorySelector()
{ {
this.categoryList.enabled = GUILayout.Toggle(this.categoryList.enabled, "▼ SELECTED CATEGORY: " + ReadoutCategory.Selected.ToString().ToUpper() + " ▼", this.categoryTitleButtonStyle); this.categoryList.enabled = GUILayout.Toggle(this.categoryList.enabled, "▼ SELECTED CATEGORY: " + ReadoutCategory.Selected.ToString().ToUpper() + " ▼", this.categoryTitleButtonStyle);
if (Event.current.type == EventType.repaint) if (Event.current.type == EventType.repaint)
{ {
this.categoryList.SetPosition(GUILayoutUtility.GetLastRect().Translate(this.position)); this.categoryList.SetPosition(GUILayoutUtility.GetLastRect().Translate(this.position));
} }
} }
   
/// <summary> /// <summary>
/// Draws the options for editing custom sections. /// Draws the options for editing custom sections.
/// </summary> /// </summary>
private void DrawCustomOptions() private void DrawCustomOptions()
{ {
GUILayout.BeginHorizontal(GUILayout.Height(25.0f)); GUILayout.BeginHorizontal(GUILayout.Height(25.0f));
this.ParentSection.Name = GUILayout.TextField(this.ParentSection.Name, this.textStyle); this.ParentSection.Name = GUILayout.TextField(this.ParentSection.Name, this.textStyle);
var isShowingInControlBar = !string.IsNullOrEmpty(this.ParentSection.Abbreviation); var isShowingInControlBar = !string.IsNullOrEmpty(this.ParentSection.Abbreviation);
this.ParentSection.Abbreviation = GUILayout.TextField(this.ParentSection.Abbreviation, this.textStyle, GUILayout.Width(75.0f)); this.ParentSection.Abbreviation = GUILayout.TextField(this.ParentSection.Abbreviation, this.textStyle, GUILayout.Width(75.0f));
if (this.ParentSection.IsCustom) if (this.ParentSection.IsCustom)
{ {
if (isShowingInControlBar && string.IsNullOrEmpty(this.ParentSection.Abbreviation)) if (isShowingInControlBar && string.IsNullOrEmpty(this.ParentSection.Abbreviation))
{ {
DisplayStack.Instance.RequestResize(); DisplayStack.Instance.RequestResize();
} }
if (this.ParentSection.IsHud = GUILayout.Toggle(this.ParentSection.IsHud, "HUD", this.readoutButtonStyle, GUILayout.Width(50.0f))) if (this.ParentSection.IsHud = GUILayout.Toggle(this.ParentSection.IsHud, "HUD", this.readoutButtonStyle, GUILayout.Width(50.0f)))
{ {
this.ParentSection.IsHudBackground = GUILayout.Toggle(this.ParentSection.IsHudBackground, "BG", this.readoutButtonStyle, GUILayout.Width(50.0f)); this.ParentSection.IsHudBackground = GUILayout.Toggle(this.ParentSection.IsHudBackground, "BG", this.readoutButtonStyle, GUILayout.Width(50.0f));
} }
   
if (GUILayout.Button("DELETE SECTION", this.readoutButtonStyle, GUILayout.Width(150.0f))) if (GUILayout.Button("DELETE SECTION", this.readoutButtonStyle, GUILayout.Width(150.0f)))
{ {
this.ParentSection.IsFloating = false; this.ParentSection.IsFloating = false;
this.ParentSection.IsEditorVisible = false; this.ParentSection.IsEditorVisible = false;
SectionLibrary.CustomSections.Remove(this.ParentSection); SectionLibrary.CustomSections.Remove(this.ParentSection);
DisplayStack.Instance.RequestResize(); DisplayStack.Instance.RequestResize();
} }
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
/// <summary> /// <summary>
/// Draws the installed readouts panel. /// Draws the installed readouts panel.
/// </summary> /// </summary>
private void DrawInstalledReadouts() private void DrawInstalledReadouts()
{ {
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
this.scrollPositionInstalled = GUILayout.BeginScrollView(this.scrollPositionInstalled, false, true); this.scrollPositionInstalled = GUILayout.BeginScrollView(this.scrollPositionInstalled, false, true);
GUI.skin = null; GUI.skin = null;
   
GUILayout.Label("INSTALLED", this.panelTitleStyle); GUILayout.Label("INSTALLED", this.panelTitleStyle);
var removeReadout = false; var removeReadout = false;
var removeReadoutIndex = 0; var removeReadoutIndex = 0;
   
for (var i = 0; i < this.ParentSection.ReadoutModules.Count; i++) for (var i = 0; i < this.ParentSection.ReadoutModules.Count; i++)
{ {
var readout = this.ParentSection.ReadoutModules[i]; var readout = this.ParentSection.ReadoutModules[i];
   
GUILayout.BeginHorizontal(GUILayout.Height(30.0f)); GUILayout.BeginHorizontal(GUILayout.Height(30.0f));
GUILayout.Label(readout.Name, this.readoutNameStyle); GUILayout.Label(readout.Name, this.readoutNameStyle);
if (GUILayout.Button("▲", this.readoutButtonStyle, GUILayout.Width(30.0f))) if (GUILayout.Button("▲", this.readoutButtonStyle, GUILayout.Width(30.0f)))
{ {
if (i > 0) if (i > 0)
{ {
this.ParentSection.ReadoutModules[i] = this.ParentSection.ReadoutModules[i - 1]; this.ParentSection.ReadoutModules[i] = this.ParentSection.ReadoutModules[i - 1];
this.ParentSection.ReadoutModules[i - 1] = readout; this.ParentSection.ReadoutModules[i - 1] = readout;
} }
} }
if (GUILayout.Button("▼", this.readoutButtonStyle, GUILayout.Width(30.0f))) if (GUILayout.Button("▼", this.readoutButtonStyle, GUILayout.Width(30.0f)))
{ {
if (i < this.ParentSection.ReadoutModules.Count - 1) if (i < this.ParentSection.ReadoutModules.Count - 1)
{ {
this.ParentSection.ReadoutModules[i] = this.ParentSection.ReadoutModules[i + 1]; this.ParentSection.ReadoutModules[i] = this.ParentSection.ReadoutModules[i + 1];
this.ParentSection.ReadoutModules[i + 1] = readout; this.ParentSection.ReadoutModules[i + 1] = readout;
} }
} }
readout.ShowHelp = GUILayout.Toggle(readout.ShowHelp, "?", this.readoutButtonStyle, GUILayout.Width(30.0f)); readout.ShowHelp = GUILayout.Toggle(readout.ShowHelp, "?", this.readoutButtonStyle, GUILayout.Width(30.0f));
if (GUILayout.Button("REMOVE", this.readoutButtonStyle, GUILayout.Width(125.0f))) if (GUILayout.Button("REMOVE", this.readoutButtonStyle, GUILayout.Width(125.0f)))
{ {
removeReadout = true; removeReadout = true;
removeReadoutIndex = i; removeReadoutIndex = i;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
this.ShowHelpMessage(readout); this.ShowHelpMessage(readout);
} }
   
GUILayout.EndScrollView(); GUILayout.EndScrollView();
   
if (removeReadout) if (removeReadout)
{ {
this.ParentSection.ReadoutModules.RemoveAt(removeReadoutIndex); this.ParentSection.ReadoutModules.RemoveAt(removeReadoutIndex);
} }
} }
   
private void DrawPresetButton(Preset preset) private void DrawPresetButton(Preset preset)
{ {
if (!GUILayout.Button("<b>" + preset.Name.ToUpper() + "</b>", this.categoryButtonStyle)) if (!GUILayout.Button("<b>" + preset.Name.ToUpper() + "</b>", this.categoryButtonStyle))
{ {
return; return;
} }
   
this.ParentSection.Name = preset.Name; this.ParentSection.Name = preset.Name;
this.ParentSection.Abbreviation = preset.Abbreviation; this.ParentSection.Abbreviation = preset.Abbreviation;
this.ParentSection.ReadoutModuleNames = preset.ReadoutNames; this.ParentSection.ReadoutModuleNames = preset.ReadoutNames;
this.ParentSection.IsHud = preset.IsHud; this.ParentSection.IsHud = preset.IsHud;
this.ParentSection.IsHudBackground = preset.IsHudBackground; this.ParentSection.IsHudBackground = preset.IsHudBackground;
this.presetList.enabled = false; this.presetList.enabled = false;
} }
   
private void DrawPresetSaveButton() private void DrawPresetSaveButton()
{ {
if (!GUILayout.Button("<b>SAVE PRESET</b>", this.categoryButtonStyle)) if (!GUILayout.Button("<b>SAVE PRESET</b>", this.categoryButtonStyle))
{ {
return; return;
} }
   
this.SavePreset(PresetLibrary.Presets.Find(p => String.Equals(p.Name, this.ParentSection.Name, StringComparison.CurrentCultureIgnoreCase))); this.SavePreset(PresetLibrary.Presets.Find(p => String.Equals(p.Name, this.ParentSection.Name, StringComparison.CurrentCultureIgnoreCase)));
} }
   
/// <summary> /// <summary>
/// Draws the presetsList selection list. /// Draws the presetsList selection list.
/// </summary> /// </summary>
private void DrawPresetSelector() private void DrawPresetSelector()
{ {
this.presetList.enabled = GUILayout.Toggle(this.presetList.enabled, "▼ PRESETS ▼", this.categoryTitleButtonStyle, GUILayout.Width(150.0f)); this.presetList.enabled = GUILayout.Toggle(this.presetList.enabled, "▼ PRESETS ▼", this.categoryTitleButtonStyle, GUILayout.Width(150.0f));
if (Event.current.type == EventType.repaint) if (Event.current.type == EventType.repaint)
{ {
this.presetList.SetPosition(GUILayoutUtility.GetLastRect().Translate(this.position)); this.presetList.SetPosition(GUILayoutUtility.GetLastRect().Translate(this.position));
} }
} }
   
/// <summary> /// <summary>
/// Draws the preset list drop down UI. /// Draws the preset list drop down UI.
/// </summary> /// </summary>
private void DrawPresets() private void DrawPresets()
{ {
Preset removePreset = null; Preset removePreset = null;
foreach (var preset in PresetLibrary.Presets) foreach (var preset in PresetLibrary.Presets)
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
this.DrawPresetButton(preset); this.DrawPresetButton(preset);
if (GUILayout.Button("<b>X</b>", this.categoryButtonStyle, GUILayout.Width(30.0f))) if (GUILayout.Button("<b>X</b>", this.categoryButtonStyle, GUILayout.Width(30.0f)))
{ {
removePreset = preset; removePreset = preset;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
if (removePreset != null && PresetLibrary.Remove(removePreset)) if (removePreset != null && PresetLibrary.Remove(removePreset))
{ {
this.presetList.Resize = true; this.presetList.Resize = true;
} }
   
this.DrawPresetSaveButton(); this.DrawPresetSaveButton();
} }
   
/// <summary> /// <summary>
/// Initialises all the styles required for this object. /// Initialises all the styles required for this object.
/// </summary> /// </summary>
private void InitialiseStyles() private void InitialiseStyles()
{ {
this.windowStyle = new GUIStyle(HighLogic.Skin.window); this.windowStyle = new GUIStyle(HighLogic.Skin.window);
   
this.categoryButtonStyle = new GUIStyle(HighLogic.Skin.button) this.categoryButtonStyle = new GUIStyle(HighLogic.Skin.button)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
margin = new RectOffset(0, 0, 2, 0), margin = new RectOffset(0, 0, 2, 0),
padding = new RectOffset(5, 5, 5, 5), padding = new RectOffset(5, 5, 5, 5),
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
fontSize = 12, fontSize = 12,
fontStyle = FontStyle.Normal, fontStyle = FontStyle.Normal,
richText = true richText = true
}; };
   
this.categoryButtonActiveStyle = new GUIStyle(this.categoryButtonStyle) this.categoryButtonActiveStyle = new GUIStyle(this.categoryButtonStyle)
{ {
normal = this.categoryButtonStyle.onNormal, normal = this.categoryButtonStyle.onNormal,
hover = this.categoryButtonStyle.onHover hover = this.categoryButtonStyle.onHover
}; };
   
this.panelTitleStyle = new GUIStyle(HighLogic.Skin.label) this.panelTitleStyle = new GUIStyle(HighLogic.Skin.label)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(), padding = new RectOffset(),
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
fontSize = 12, fontSize = 12,
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
fixedHeight = 30.0f, fixedHeight = 30.0f,
stretchWidth = true stretchWidth = true
}; };
   
this.textStyle = new GUIStyle(HighLogic.Skin.textField) this.textStyle = new GUIStyle(HighLogic.Skin.textField)
{ {
margin = new RectOffset(3, 3, 3, 3), margin = new RectOffset(3, 3, 3, 3),
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
stretchWidth = true, stretchWidth = true,
stretchHeight = true stretchHeight = true
}; };
   
this.readoutNameStyle = new GUIStyle(HighLogic.Skin.label) this.readoutNameStyle = new GUIStyle(HighLogic.Skin.label)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(10, 0, 0, 0), padding = new RectOffset(10, 0, 0, 0),
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
fontSize = 12, fontSize = 12,
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
stretchWidth = true, stretchWidth = true,
stretchHeight = true stretchHeight = true
}; };
   
this.readoutButtonStyle = new GUIStyle(HighLogic.Skin.button) this.readoutButtonStyle = new GUIStyle(HighLogic.Skin.button)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
margin = new RectOffset(2, 2, 2, 2), margin = new RectOffset(2, 2, 2, 2),
padding = new RectOffset(), padding = new RectOffset(),
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
fontSize = 12, fontSize = 12,
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
stretchHeight = true stretchHeight = true
}; };
   
this.helpBoxStyle = new GUIStyle(HighLogic.Skin.box) this.helpBoxStyle = new GUIStyle(HighLogic.Skin.box)
{ {
margin = new RectOffset(2, 2, 2, 10), margin = new RectOffset(2, 2, 2, 10),
padding = new RectOffset(10, 10, 10, 10) padding = new RectOffset(10, 10, 10, 10)
}; };
   
this.helpTextStyle = new GUIStyle(HighLogic.Skin.label) this.helpTextStyle = new GUIStyle(HighLogic.Skin.label)
{ {
normal = normal =
{ {
textColor = Color.yellow textColor = Color.yellow
}, },
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(), padding = new RectOffset(),
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
fontSize = 13, fontSize = 13,
fontStyle = FontStyle.Normal, fontStyle = FontStyle.Normal,
stretchWidth = true, stretchWidth = true,
richText = true richText = true
}; };
   
this.categoryTitleButtonStyle = new GUIStyle(this.readoutButtonStyle) this.categoryTitleButtonStyle = new GUIStyle(this.readoutButtonStyle)
{ {
fixedHeight = 30.0f, fixedHeight = 30.0f,
stretchHeight = false stretchHeight = false
}; };
} }
   
private void SavePreset(Preset preset) private void SavePreset(Preset preset)
{ {
if (preset == null) if (preset == null)
{ {
preset = new Preset(); preset = new Preset();
} }
   
preset.Name = this.ParentSection.Name; preset.Name = this.ParentSection.Name;
preset.Abbreviation = this.ParentSection.Abbreviation; preset.Abbreviation = this.ParentSection.Abbreviation;
preset.ReadoutNames = this.ParentSection.ReadoutModuleNames; preset.ReadoutNames = this.ParentSection.ReadoutModuleNames;
preset.IsHud = this.ParentSection.IsHud; preset.IsHud = this.ParentSection.IsHud;
preset.IsHudBackground = this.ParentSection.IsHudBackground; preset.IsHudBackground = this.ParentSection.IsHudBackground;
   
PresetLibrary.Save(preset); PresetLibrary.Save(preset);
} }
   
private void ShowHelpMessage(ReadoutModule readout) private void ShowHelpMessage(ReadoutModule readout)
{ {
if (!readout.ShowHelp) if (!readout.ShowHelp)
{ {
return; return;
} }
   
GUILayout.BeginVertical(this.helpBoxStyle); GUILayout.BeginVertical(this.helpBoxStyle);
GUILayout.Label(!String.IsNullOrEmpty(readout.HelpString) ? readout.HelpString : "Sorry, no help information has been provided for this readout module.", this.helpTextStyle); GUILayout.Label(!String.IsNullOrEmpty(readout.HelpString) ? readout.HelpString : "Sorry, no help information has been provided for this readout module.", this.helpTextStyle);
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the editor window. /// Draws the editor window.
/// </summary> /// </summary>
private void Window(int windowId) private void Window(int windowId)
{ {
try try
{ {
this.DrawCustomOptions(); this.DrawCustomOptions();
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
this.DrawCategorySelector(); this.DrawCategorySelector();
this.DrawPresetSelector(); this.DrawPresetSelector();
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
this.DrawAvailableReadouts(); this.DrawAvailableReadouts();
GUILayout.Space(5.0f); GUILayout.Space(5.0f);
this.DrawInstalledReadouts(); this.DrawInstalledReadouts();
   
if (GUILayout.Button("CLOSE EDITOR", this.categoryTitleButtonStyle)) if (GUILayout.Button("CLOSE EDITOR", this.categoryTitleButtonStyle))
{ {
this.ParentSection.IsEditorVisible = false; this.ParentSection.IsEditorVisible = false;
} }
   
GUI.DragWindow(); GUI.DragWindow();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #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/>.
  //
 
  using System;
 
  namespace KerbalEngineer
  {
  public class VectorAverager
  {
  private Vector3d sum = Vector3d.zero;
  private uint count = 0;
 
  public void Add(Vector3d v) {
  sum += v;
  count += 1;
  }
 
  public Vector3d Get() {
  if (count > 0) {
  return sum / count;
  } else {
  return Vector3d.zero;
  }
  }
  }
 
  public class WeightedVectorAverager
  {
  private Vector3d sum = Vector3d.zero;
  private double totalweight = 0;
 
  public void Add(Vector3d v, double weight) {
  sum += v * weight;
  totalweight += weight;
  }
 
  public Vector3d Get() {
  if (totalweight > 0) {
  return sum / totalweight;
  } else {
  return Vector3d.zero;
  }
  }
 
  public double GetTotalWeight() {
  return totalweight;
  }
  }
  }
 
 
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  using System;
  using System.Collections.Generic;
 
  namespace KerbalEngineer
  {
  // a (force, application point) tuple
  public class AppliedForce
  {
  public Vector3d vector;
  public Vector3d applicationPoint;
 
  public AppliedForce(Vector3d vector, Vector3d applicationPoint) {
  this.vector = vector;
  this.applicationPoint = applicationPoint;
  }
  }
 
  // This class was mostly adapted from FARCenterQuery, part of FAR, by ferram4, GPLv3
  // https://github.com/ferram4/Ferram-Aerospace-Research/blob/master/FerramAerospaceResearch/FARCenterQuery.cs
  // Also see https://en.wikipedia.org/wiki/Resultant_force
 
  // It accumulates forces and their points of applications, and provides methods for
  // calculating the effective torque at any position, as well as the minimum-torque net force application point.
  //
  // The latter is a non-trivial issue; there is a 1-dimensional line of physically-equivalent solutions parallel
  // to the resulting force vector; the solution closest to the weighted average of force positions is chosen.
  // In the case of non-parallel forces, there usually is an infinite number of such lines, all of which have
  // some amount of residual torque. The line with the least amount of residual torque is chosen.
  public class ForceAccumulator
  {
  // Total force.
  private Vector3d totalForce = Vector3d.zero;
  // Torque needed to compensate if force were applied at origin.
  private Vector3d totalZeroOriginTorque = Vector3d.zero;
 
  // Weighted average of force application points.
  private WeightedVectorAverager avgApplicationPoint = new WeightedVectorAverager();
 
  // Feed an force to the accumulator.
  public void AddForce(Vector3d applicationPoint, Vector3d force)
  {
  totalForce += force;
  totalZeroOriginTorque += Vector3d.Cross(applicationPoint, force);
  avgApplicationPoint.Add(applicationPoint, force.magnitude);
  }
 
  public Vector3d GetAverageForceApplicationPoint() {
  return avgApplicationPoint.Get();
  }
 
  public void AddForce(AppliedForce force) {
  AddForce(force.applicationPoint, force.vector);
  }
 
  // Residual torque for given force application point.
  public Vector3d TorqueAt(Vector3d origin)
  {
  return totalZeroOriginTorque - Vector3d.Cross(origin, totalForce);
  }
 
  // Total force vector.
  public Vector3d GetTotalForce()
  {
  return totalForce;
  }
 
  // Returns the minimum-residual-torque force application point that is closest to origin.
  // Note that TorqueAt(GetMinTorquePos()) is always parallel to totalForce.
  public Vector3d GetMinTorqueForceApplicationPoint(Vector3d origin)
  {
  double fmag = totalForce.sqrMagnitude;
  if (fmag <= 0) {
  return origin;
  }
 
  return origin + Vector3d.Cross(totalForce, TorqueAt(origin)) / fmag;
  }
 
  public Vector3d GetMinTorqueForceApplicationPoint()
  {
  return GetMinTorqueForceApplicationPoint(avgApplicationPoint.Get());
  }
  }
  }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives  
   
using System;  
   
#endregion  
   
namespace KerbalEngineer.Helpers namespace KerbalEngineer.Helpers
{ {
  #region Using Directives
   
  using System;
   
  #endregion
   
public static class Units public static class Units
{ {
#region Methods: public #region Methods
   
  public static string Concat(int value1, int value2)
  {
  return value1 + " / " + value2;
  }
   
public static string Concat(double value1, double value2, int decimals = 1) public static string Concat(double value1, double value2, int decimals = 1)
{ {
return value1.ToString("F" + decimals) + " / " + value2.ToString("F" + decimals); return value1.ToString("F" + decimals) + " / " + value2.ToString("F" + decimals);
} }
   
public static string Concat(double value1, double value2, double value3, int decimals = 1) public static string Concat(double value1, double value2, double value3, int decimals = 1)
{ {
return value1.ToString("F" + decimals) + " / " + value2.ToString("F" + decimals) + " / " + value3.ToString("F" + decimals); return value1.ToString("F" + decimals) + " / " + value2.ToString("F" + decimals) + " / " + value3.ToString("F" + decimals);
} }
   
public static string ToAcceleration(double value, int decimals = 2) public static string ToAcceleration(double value, int decimals = 2)
{ {
return value.ToString("N" + decimals) + "m/s²"; return value.ToString("N" + decimals) + "m/s²";
} }
   
public static string ToAcceleration(double value1, double value2, int decimals = 2) public static string ToAcceleration(double value1, double value2, int decimals = 2)
{ {
return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals) + "m/s²"; return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals) + "m/s²";
} }
   
public static string ToAngle(double value, int decimals = 5) public static string ToAngle(double value, int decimals = 5)
{ {
return value.ToString("F" + decimals) + "°"; return value.ToString("F" + decimals) + "°";
} }
   
public static string ToDistance(double value, int decimals = 1) public static string ToDistance(double value, int decimals = 1)
{ {
if (Math.Abs(value) < 1000000.0) if (Math.Abs(value) < 1000000.0)
{ {
if (Math.Abs(value) >= 10.0) if (Math.Abs(value) >= 10.0)
{ {
return value.ToString("N" + decimals) + "m"; return value.ToString("N" + decimals) + "m";
} }
   
value *= 100.0; value *= 100.0;
if (Math.Abs(value) >= 100.0) if (Math.Abs(value) >= 100.0)
{ {
return value.ToString("N" + decimals) + "cm"; return value.ToString("N" + decimals) + "cm";
} }
   
value *= 10.0; value *= 10.0;
return value.ToString("N" + decimals) + "mm"; return value.ToString("N" + decimals) + "mm";
} }
   
value /= 1000.0; value /= 1000.0;
if (Math.Abs(value) < 1000000.0) if (Math.Abs(value) < 1000000.0)
{ {
return value.ToString("N" + decimals) + "km"; return value.ToString("N" + decimals) + "km";
} }
   
value /= 1000.0; value /= 1000.0;
return value.ToString("N" + decimals) + "Mm"; return value.ToString("N" + decimals) + "Mm";
} }
   
public static string ToForce(double value) public static string ToForce(double value)
{ {
return value.ToString((value < 100000.0) ? (value < 10000.0) ? (value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0") + "kN"; return value.ToString((value < 100000.0) ? (value < 10000.0) ? (value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0") + "kN";
} }
   
public static string ToForce(double value1, double value2) public static string ToForce(double value1, double value2)
{ {
var format1 = (value1 < 100000.0) ? (value1 < 10000.0) ? (value1 < 100.0) ? (Math.Abs(value1) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0"; var format1 = (value1 < 100000.0) ? (value1 < 10000.0) ? (value1 < 100.0) ? (Math.Abs(value1) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0";
var format2 = (value2 < 100000.0) ? (value2 < 10000.0) ? (value2 < 100.0) ? (Math.Abs(value2) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0"; var format2 = (value2 < 100000.0) ? (value2 < 10000.0) ? (value2 < 100.0) ? (Math.Abs(value2) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0";
return value1.ToString(format1) + " / " + value2.ToString(format2) + "kN"; return value1.ToString(format1) + " / " + value2.ToString(format2) + "kN";
} }
   
public static string ToMass(double value, int decimals = 0) public static string ToMass(double value, int decimals = 0)
{ {
value *= 1000.0; value *= 1000.0;
return value.ToString("N" + decimals) + "kg"; return value.ToString("N" + decimals) + "kg";
} }
   
public static string ToMass(double value1, double value2, int decimals = 0) public static string ToMass(double value1, double value2, int decimals = 0)
{ {
value1 *= 1000.0; value1 *= 1000.0;
value2 *= 1000.0; value2 *= 1000.0;
return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals) + "kg"; return value1.ToString("N" + decimals) + " / " + value2.ToString("N" + decimals) + "kg";
} }
   
public static string ToPercent(double value, int decimals = 2) public static string ToPercent(double value, int decimals = 2)
{ {
value *= 100.0; value *= 100.0;
return value.ToString("F" + decimals) + "%"; return value.ToString("F" + decimals) + "%";
} }
   
public static string ToRate(double value, int decimals = 1) public static string ToRate(double value, int decimals = 1)
{ {
return value < 1.0 ? (value * 60.0).ToString("F" + decimals) + "/min" : value.ToString("F" + decimals) + "/sec"; return value < 1.0 ? (value * 60.0).ToString("F" + decimals) + "/min" : value.ToString("F" + decimals) + "/sec";
} }
   
public static string ToSpeed(double value, int decimals = 2) public static string ToSpeed(double value, int decimals = 2)
{ {
if (Math.Abs(value) < 1.0) if (Math.Abs(value) < 1.0)
{ {
return (value * 1000.0).ToString("N" + decimals) + "mm/s"; return (value * 1000.0).ToString("N" + decimals) + "mm/s";
} }
return value.ToString("N" + decimals) + "m/s"; return value.ToString("N" + decimals) + "m/s";
} }
   
public static string ToTime(double value) public static string ToTime(double value)
{ {
return TimeFormatter.ConvertToString(value); return TimeFormatter.ConvertToString(value);
} }
   
  public static string ToTorque(double value)
  {
  return value.ToString((value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N1" : "N0") + "kNm";
  }
   
#endregion #endregion
} }
} }
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{39806613-E0B7-46E0-89A6-A569EC538CBB}</ProjectGuid> <ProjectGuid>{39806613-E0B7-46E0-89A6-A569EC538CBB}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>KerbalEngineer</RootNamespace> <RootNamespace>KerbalEngineer</RootNamespace>
<AssemblyName>KerbalEngineer</AssemblyName> <AssemblyName>KerbalEngineer</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>false</DebugSymbols> <DebugSymbols>false</DebugSymbols>
<DebugType>none</DebugType> <DebugType>none</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>..\Output\KerbalEngineer\</OutputPath> <OutputPath>..\Output\KerbalEngineer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>..\Output\KerbalEngineer\</OutputPath> <OutputPath>..\Output\KerbalEngineer\</OutputPath>
<DefineConstants> <DefineConstants>
</DefineConstants> </DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks> <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Control\IControlPanel.cs" /> <Compile Include="Control\IControlPanel.cs" />
<Compile Include="Control\Panels\BuildOverlayPanel.cs" /> <Compile Include="Control\Panels\BuildOverlayPanel.cs" />
<Compile Include="Control\Panels\BuildEngineerPanel.cs" /> <Compile Include="Control\Panels\BuildEngineerPanel.cs" />
<Compile Include="Editor\BuildAdvanced.cs" /> <Compile Include="Editor\BuildAdvanced.cs" />
<Compile Include="Editor\BuildOverlay.cs" /> <Compile Include="Editor\BuildOverlay.cs" />
<Compile Include="CelestialBodies.cs" /> <Compile Include="CelestialBodies.cs" />
<Compile Include="Editor\BuildOverlayPartInfo.cs" /> <Compile Include="Editor\BuildOverlayPartInfo.cs" />
<Compile Include="Editor\BuildOverlayResources.cs" /> <Compile Include="Editor\BuildOverlayResources.cs" />
<Compile Include="Editor\BuildOverlayVessel.cs" /> <Compile Include="Editor\BuildOverlayVessel.cs" />
<Compile Include="Editor\BuildToolbar.cs" /> <Compile Include="Editor\BuildToolbar.cs" />
<Compile Include="Editor\PartInfoItem.cs" /> <Compile Include="Editor\PartInfoItem.cs" />
<Compile Include="Editor\ResourceInfoItem.cs" /> <Compile Include="Editor\ResourceInfoItem.cs" />
<Compile Include="Extensions\FloatExtensions.cs" /> <Compile Include="Extensions\FloatExtensions.cs" />
<Compile Include="Extensions\OrbitExtensions.cs" /> <Compile Include="Extensions\OrbitExtensions.cs" />
<Compile Include="Flight\ActionMenuGui.cs" /> <Compile Include="Flight\ActionMenuGui.cs" />
<Compile Include="Flight\FlightEngineerPartless.cs" /> <Compile Include="Flight\FlightEngineerPartless.cs" />
<Compile Include="Flight\Presets\Preset.cs" /> <Compile Include="Flight\Presets\Preset.cs" />
  <Compile Include="Flight\Readouts\Miscellaneous\VectoredThrustToggle.cs" />
<Compile Include="Flight\Readouts\Miscellaneous\TimeReference.cs" /> <Compile Include="Flight\Readouts\Miscellaneous\TimeReference.cs" />
<Compile Include="Flight\Readouts\Miscellaneous\Separator.cs" /> <Compile Include="Flight\Readouts\Miscellaneous\Separator.cs" />
<Compile Include="Flight\Readouts\Miscellaneous\GuiSizeAdjustor.cs" /> <Compile Include="Flight\Readouts\Miscellaneous\GuiSizeAdjustor.cs" />
<Compile Include="Flight\Readouts\Orbital\AngleToEquatorialDescendingNode.cs" /> <Compile Include="Flight\Readouts\Orbital\AngleToEquatorialDescendingNode.cs" />
<Compile Include="Flight\Readouts\Orbital\AngleToEquatorialAscendingNode.cs" /> <Compile Include="Flight\Readouts\Orbital\AngleToEquatorialAscendingNode.cs" />
<Compile Include="Flight\Readouts\Orbital\AngleToRetrograde.cs" /> <Compile Include="Flight\Readouts\Orbital\AngleToRetrograde.cs" />
<Compile Include="Flight\Readouts\Orbital\AngleToPrograde.cs" /> <Compile Include="Flight\Readouts\Orbital\AngleToPrograde.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeRadialDeltaV.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeRadialDeltaV.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\ManoeuvreProcessor.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\ManoeuvreProcessor.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeTimeToHalfBurn.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeTimeToHalfBurn.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeTimeToManoeuvre.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeTimeToManoeuvre.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeHalfBurnTime.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeHalfBurnTime.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeBurnTime.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeBurnTime.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeAngleToRetrograde.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeAngleToRetrograde.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeNormalDeltaV.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeNormalDeltaV.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeAngleToPrograde.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeAngleToPrograde.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeTotalDeltaV.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeTotalDeltaV.cs" />
<Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeProgradeDeltaV.cs" /> <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeProgradeDeltaV.cs" />
<Compile Include="Flight\Readouts\Orbital\MeanAnomaly.cs" /> <Compile Include="Flight\Readouts\Orbital\MeanAnomaly.cs" />
<Compile Include="Flight\Readouts\Orbital\EccentricAnomaly.cs" /> <Compile Include="Flight\Readouts\Orbital\EccentricAnomaly.cs" />
<Compile Include="Flight\Readouts\Orbital\ArgumentOfPeriapsis.cs" /> <Compile Include="Flight\Readouts\Orbital\ArgumentOfPeriapsis.cs" />
<Compile Include="Flight\Readouts\Orbital\CurrentSoi.cs" /> <Compile Include="Flight\Readouts\Orbital\CurrentSoi.cs" />
<Compile Include="Flight\Readouts\Orbital\TrueAnomaly.cs" /> <Compile Include="Flight\Readouts\Orbital\TrueAnomaly.cs" />
<Compile Include="Flight\Readouts\Orbital\TimeToEquatorialAscendingNode.cs" /> <Compile Include="Flight\Readouts\Orbital\TimeToEquatorialAscendingNode.cs" />
<Compile Include="Flight\Readouts\Orbital\TimeToEquatorialDescendingNode.cs" /> <Compile Include="Flight\Readouts\Orbital\TimeToEquatorialDescendingNode.cs" />
<Compile Include="Flight\Readouts\Rendezvous\RelativeSpeed.cs" /> <Compile Include="Flight\Readouts\Rendezvous\RelativeSpeed.cs" />
<Compile Include="Flight\Readouts\Rendezvous\RelativeVelocity.cs" /> <Compile Include="Flight\Readouts\Rendezvous\RelativeVelocity.cs" />
<Compile Include="Flight\Readouts\Rendezvous\SemiMinorAxis.cs" /> <Compile Include="Flight\Readouts\Rendezvous\SemiMinorAxis.cs" />
<Compile Include="Flight\Readouts\Rendezvous\SemiMajorAxis.cs" /> <Compile Include="Flight\Readouts\Rendezvous\SemiMajorAxis.cs" />
<Compile Include="Flight\Readouts\Rendezvous\TimeToRelativeDescendingNode.cs" /> <Compile Include="Flight\Readouts\Rendezvous\TimeToRelativeDescendingNode.cs" />
<Compile Include="Flight\Readouts\Rendezvous\TimeToRelativeAscendingNode.cs" /> <Compile Include="Flight\Readouts\Rendezvous\TimeToRelativeAscendingNode.cs" />
<Compile Include="Flight\Readouts\Surface\ImpactBiome.cs" /> <Compile Include="Flight\Readouts\Surface\ImpactBiome.cs" />
<Compile Include="Flight\Readouts\Surface\Slope.cs" /> <Compile Include="Flight\Readouts\Surface\Slope.cs" />
<Compile Include="Flight\Readouts\Surface\Biome.cs" /> <Compile Include="Flight\Readouts\Surface\Biome.cs" />
<Compile Include="Flight\Readouts\Surface\HorizontalAcceleration.cs" /> <Compile Include="Flight\Readouts\Surface\HorizontalAcceleration.cs" />
<Compile Include="Flight\Readouts\Surface\VerticalAcceleration.cs" /> <Compile Include="Flight\Readouts\Surface\VerticalAcceleration.cs" />
  <Compile Include="Flight\Readouts\Vessel\AttitudeProcessor.cs" />
<Compile Include="Flight\Readouts\Vessel\DeltaVCurrentTotal.cs" /> <Compile Include="Flight\Readouts\Vessel\DeltaVCurrentTotal.cs" />
  <Compile Include="Flight\Readouts\Vessel\PitchRate.cs" />
  <Compile Include="Flight\Readouts\Vessel\HeadingRate.cs" />
  <Compile Include="Flight\Readouts\Vessel\RollRate.cs" />
  <Compile Include="Flight\Readouts\Vessel\Roll.cs" />
  <Compile Include="Flight\Readouts\Vessel\Pitch.cs" />
  <Compile Include="Flight\Readouts\Vessel\Heading.cs" />
  <Compile Include="Flight\Readouts\Vessel\PartCount.cs" />
<Compile Include="Flight\Readouts\Vessel\SuicideBurnDeltaV.cs" /> <Compile Include="Flight\Readouts\Vessel\SuicideBurnDeltaV.cs" />
<Compile Include="Flight\Readouts\Vessel\SuicideBurnAltitude.cs" /> <Compile Include="Flight\Readouts\Vessel\SuicideBurnAltitude.cs" />
<Compile Include="Flight\Readouts\Vessel\SuicideBurnDistance.cs" /> <Compile Include="Flight\Readouts\Vessel\SuicideBurnDistance.cs" />
<Compile Include="Flight\Readouts\Vessel\DeltaVCurrent.cs" /> <Compile Include="Flight\Readouts\Vessel\DeltaVCurrent.cs" />
<Compile Include="Flight\Readouts\Vessel\IntakeAirUsage.cs" /> <Compile Include="Flight\Readouts\Vessel\IntakeAirUsage.cs" />
<Compile Include="Flight\Readouts\Vessel\IntakeAirDemandSupply.cs" /> <Compile Include="Flight\Readouts\Vessel\IntakeAirDemandSupply.cs" />
<Compile Include="Flight\Readouts\Vessel\IntakeAirSupply.cs" /> <Compile Include="Flight\Readouts\Vessel\IntakeAirSupply.cs" />
<Compile Include="Flight\Readouts\Vessel\IntakeAirDemand.cs" /> <Compile Include="Flight\Readouts\Vessel\IntakeAirDemand.cs" />
<Compile Include="Flight\Readouts\Miscellaneous\SimulationDelay.cs" /> <Compile Include="Flight\Readouts\Miscellaneous\SimulationDelay.cs" />
<Compile Include="Flight\Readouts\Vessel\SimulationProcessor.cs" /> <Compile Include="Flight\Readouts\Vessel\SimulationProcessor.cs" />
<Compile Include="Flight\Readouts\Vessel\Acceleration.cs" /> <Compile Include="Flight\Readouts\Vessel\Acceleration.cs" />
<Compile Include="Flight\Presets\PresetLibrary.cs" /> <Compile Include="Flight\Presets\PresetLibrary.cs" />
<Compile Include="Flight\Readouts\Vessel\SuicideBurnProcessor.cs" /> <Compile Include="Flight\Readouts\Vessel\SuicideBurnProcessor.cs" />
<Compile Include="Flight\Readouts\Vessel\SurfaceThrustToWeight.cs" /> <Compile Include="Flight\Readouts\Vessel\SurfaceThrustToWeight.cs" />
<Compile Include="Flight\Readouts\Surface\Situation.cs" /> <Compile Include="Flight\Readouts\Surface\Situation.cs" />
  <Compile Include="Flight\Readouts\Vessel\ThrustOffsetAngle.cs" />
  <Compile Include="Flight\Readouts\Vessel\ThrustTorque.cs" />
<Compile Include="GuiDisplaySize.cs" /> <Compile Include="GuiDisplaySize.cs" />
<Compile Include="Helpers\AngleHelper.cs" /> <Compile Include="Helpers\AngleHelper.cs" />
  <Compile Include="Helpers\Averager.cs" />
  <Compile Include="Helpers\ForceAccumulator.cs" />
<Compile Include="Helpers\TextureHelper.cs" /> <Compile Include="Helpers\TextureHelper.cs" />
<Compile Include="Helpers\Units.cs" /> <Compile Include="Helpers\Units.cs" />
<Compile Include="Helpers\TimeFormatter.cs" /> <Compile Include="Helpers\TimeFormatter.cs" />
<Compile Include="KeyBinder.cs" /> <Compile Include="KeyBinder.cs" />
<Compile Include="Control\ControlCentre.cs" /> <Compile Include="Control\ControlCentre.cs" />
<Compile Include="UIControls\DropDown.cs" /> <Compile Include="UIControls\DropDown.cs" />
<Compile Include="Logger.cs" /> <Compile Include="Logger.cs" />
<Compile Include="EngineerGlobals.cs" /> <Compile Include="EngineerGlobals.cs" />
<Compile Include="Extensions\DoubleExtensions.cs" /> <Compile Include="Extensions\DoubleExtensions.cs" />
<Compile Include="Extensions\PartExtensions.cs" /> <Compile Include="Extensions\PartExtensions.cs" />
<Compile Include="Extensions\PartResourceExtensions.cs" /> <Compile Include="Extensions\PartResourceExtensions.cs" />
<Compile Include="Extensions\RectExtensions.cs" /> <Compile Include="Extensions\RectExtensions.cs" />
<Compile Include="Flight\ActionMenu.cs" /> <Compile Include="Flight\ActionMenu.cs" />
<Compile Include="Flight\DisplayStack.cs" /> <Compile Include="Flight\DisplayStack.cs" />
<Compile Include="Flight\FlightEngineerCore.cs" /> <Compile Include="Flight\FlightEngineerCore.cs" />
<Compile Include="Flight\FlightEngineerModule.cs" /> <Compile Include="Flight\FlightEngineerModule.cs" />
<Compile Include="Flight\IUpdatable.cs" /> <Compile Include="Flight\IUpdatable.cs" />
<Compile Include="Flight\IUpdateRequest.cs" /> <Compile Include="Flight\IUpdateRequest.cs" />
<Compile Include="Flight\Readouts\Orbital\ApoapsisHeight.cs" /> <Compile Include="Flight\Readouts\Orbital\ApoapsisHeight.cs" />
<Compile Include="Flight\Readouts\Orbital\Eccentricity.cs" /> <Compile Include="Flight\Readouts\Orbital\Eccentricity.cs" />
<Compile Include="Flight\Readouts\Orbital\Inclination.cs" /> <Compile Include="Flight\Readouts\Orbital\Inclination.cs" />
<Compile Include="Flight\Readouts\Orbital\LongitudeOfAscendingNode.cs" /> <Compile Include="Flight\Readouts\Orbital\LongitudeOfAscendingNode.cs" />
<Compile Include="Flight\Readouts\Orbital\LongitudeOfPeriapsis.cs" /> <Compile Include="Flight\Readouts\Orbital\LongitudeOfPeriapsis.cs" />
<Compile Include="Flight\Readouts\Orbital\OrbitalPeriod.cs" /> <Compile Include="Flight\Readouts\Orbital\OrbitalPeriod.cs" />
<Compile Include="Flight\Readouts\Orbital\OrbitalSpeed.cs" /> <Compile Include="Flight\Readouts\Orbital\OrbitalSpeed.cs" />
<Compile Include="Flight\Readouts\Orbital\PeriapsisHeight.cs" /> <Compile Include="Flight\Readouts\Orbital\PeriapsisHeight.cs" />
<Compile Include="Flight\Readouts\Orbital\SemiMajorAxis.cs" /> <Compile Include="Flight\Readouts\Orbital\SemiMajorAxis.cs" />
<Compile Include="Flight\Readouts\Orbital\SemiMinorAxis.cs" /> <Compile Include="Flight\Readouts\Orbital\SemiMinorAxis.cs" />
<Compile Include="Flight\Readouts\Orbital\TimeToApoapsis.cs" /> <Compile Include="Flight\Readouts\Orbital\TimeToApoapsis.cs" />
<Compile Include="Flight\Readouts\Orbital\TimeToPeriapsis.cs" /> <Compile Include="Flight\Readouts\Orbital\TimeToPeriapsis.cs" />
<Compile Include="Flight\Readouts\ReadoutCategory.cs" /> <Compile Include="Flight\Readouts\ReadoutCategory.cs" />
<Compile Include="Flight\Readouts\ReadoutLibrary.cs" /> <Compile Include="Flight\Readouts\ReadoutLibrary.cs" />
<Compile Include="Flight\Readouts\ReadoutModule.cs" /> <Compile Include="Flight\Readouts\ReadoutModule.cs" />
<Compile Include="Flight\Readouts\Rendezvous\TimeToPeriapsis.cs" /> <Compile Include="Flight\Readouts\Rendezvous\TimeToPeriapsis.cs" />
<Compile Include="Flight\Readouts\Rendezvous\TimeToApoapsis.cs" /> <Compile Include="Flight\Readouts\Rendezvous\TimeToApoapsis.cs" />
<Compile Include="Flight\Readouts\Rendezvous\PeriapsisHeight.cs" /> <Compile Include="Flight\Readouts\Rendezvous\PeriapsisHeight.cs" />
<Compile Include="Flight\Readouts\Rendezvous\ApoapsisHeight.cs" /> <Compile Include="Flight\Readouts\Rendezvous\ApoapsisHeight.cs" />
<Compile Include="Flight\Readouts\Rendezvous\InterceptAngle.cs" /> <Compile Include="Flight\Readouts\Rendezvous\InterceptAngle.cs" />
<Compile Include="Flight\Readouts\Rendezvous\OrbitalPeriod.cs" /> <Compile Include="Flight\Readouts\Rendezvous\OrbitalPeriod.cs" />
<Compile Include="Flight\Readouts\Rendezvous\Distance.cs" /> <Compile Include="Flight\Readouts\Rendezvous\Distance.cs" />
<Compile Include="Flight\Readouts\Rendezvous\AltitudeSeaLevel.cs" /> <Compile Include="Flight\Readouts\Rendezvous\AltitudeSeaLevel.cs" />
<Compile Include="Flight\Readouts\Rendezvous\AngleToRelativeDescendingNode.cs" /> <Compile Include="Flight\Readouts\Rendezvous\AngleToRelativeDescendingNode.cs" />
<Compile Include="Flight\Readouts\Rendezvous\AngleToRelativeAscendingNode.cs" /> <Compile Include="Flight\Readouts\Rendezvous\AngleToRelativeAscendingNode.cs" />
<Compile Include="Flight\Readouts\Rendezvous\PhaseAngle.cs" /> <Compile Include="Flight\Readouts\Rendezvous\PhaseAngle.cs" />
<Compile Include="Flight\Readouts\Rendezvous\RelativeInclination.cs" /> <Compile Include="Flight\Readouts\Rendezvous\RelativeInclination.cs" />
<Compile Include="Flight\Readouts\Rendezvous\RendezvousProcessor.cs" /> <Compile Include="Flight\Readouts\Rendezvous\RendezvousProcessor.cs" />
<Compile Include="Flight\Readouts\Rendezvous\TargetSelector.cs" /> <Compile Include="Flight\Readouts\Rendezvous\TargetSelector.cs" />
<Compile Include="Flight\Readouts\Surface\AltitudeSeaLevel.cs" /> <Compile Include="Flight\Readouts\Surface\AltitudeSeaLevel.cs" />
<Compile Include="Flight\Readouts\Surface\AltitudeTerrain.cs" /> <Compile Include="Flight\Readouts\Surface\AltitudeTerrain.cs" />
<Compile Include="Flight\Readouts\Surface\ImpactLatitude.cs" /> <Compile Include="Flight\Readouts\Surface\ImpactLatitude.cs" />
<Compile Include="Flight\Readouts\Surface\ImpactAltitude.cs" /> <Compile Include="Flight\Readouts\Surface\ImpactAltitude.cs" />
<Compile Include="Flight\Readouts\Surface\ImpactLongitude.cs" /> <Compile Include="Flight\Readouts\Surface\ImpactLongitude.cs" />
<Compile Include="Flight\Readouts\Surface\ImpactTime.cs" /> <Compile Include="Flight\Readouts\Surface\ImpactTime.cs" />
<Compile Include="Flight\Readouts\Surface\AtmosphericProcessor.cs" /> <Compile Include="Flight\Readouts\Surface\AtmosphericProcessor.cs" />
<Compile Include="Flight\Readouts\Surface\AtmosphericEfficiency.cs" /> <Compile Include="Flight\Readouts\Surface\AtmosphericEfficiency.cs" />
<Compile Include="Flight\Readouts\Surface\GeeForce.cs" /> <Compile Include="Flight\Readouts\Surface\GeeForce.cs" />
<Compile Include="Flight\Readouts\Surface\HorizontalSpeed.cs" /> <Compile Include="Flight\Readouts\Surface\HorizontalSpeed.cs" />
<Compile Include="Flight\Readouts\Surface\ImpactProcessor.cs" /> <Compile Include="Flight\Readouts\Surface\ImpactProcessor.cs" />
<Compile Include="Flight\Readouts\Surface\Latitude.cs" /> <Compile Include="Flight\Readouts\Surface\Latitude.cs" />
<Compile Include="Flight\Readouts\Surface\Longitude.cs" /> <Compile Include="Flight\Readouts\Surface\Longitude.cs" />
<Compile Include="Flight\Readouts\Surface\TerminalVelocity.cs" /> <Compile Include="Flight\Readouts\Surface\TerminalVelocity.cs" />
<Compile Include="Flight\Readouts\Surface\VerticalSpeed.cs" /> <Compile Include="Flight\Readouts\Surface\VerticalSpeed.cs" />
<Compile Include="Flight\Readouts\Vessel\DeltaVStaged.cs" /> <Compile Include="Flight\Readouts\Vessel\DeltaVStaged.cs" />
<Compile Include="Flight\Readouts\Vessel\DeltaVTotal.cs" /> <Compile Include="Flight\Readouts\Vessel\DeltaVTotal.cs" />
<Compile Include="Flight\Readouts\Vessel\Mass.cs" /> <Compile Include="Flight\Readouts\Vessel\Mass.cs" />
<Compile Include="Flight\Readouts\Vessel\Thrust.cs" /> <Compile Include="Flight\Readouts\Vessel\Thrust.cs" />
<Compile Include="Flight\Readouts\Vessel\SpecificImpulse.cs" /> <Compile Include="Flight\Readouts\Vessel\SpecificImpulse.cs" />
<Compile Include="Flight\Readouts\Vessel\ThrustToWeight.cs" /> <Compile Include="Flight\Readouts\Vessel\ThrustToWeight.cs" />
<Compile Include="Flight\Sections\SectionEditor.cs" /> <Compile Include="Flight\Sections\SectionEditor.cs" />
<Compile Include="Flight\Sections\SectionLibrary.cs" /> <Compile Include="Flight\Sections\SectionLibrary.cs" />
<Compile Include="Flight\Sections\SectionModule.cs" /> <Compile Include="Flight\Sections\SectionModule.cs" />
<Compile Include="Flight\Sections\SectionWindow.cs" /> <Compile Include="Flight\Sections\SectionWindow.cs" />
<Compile Include="LogMsg.cs" /> <Compile Include="LogMsg.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings\SettingHandler.cs" /> <Compile Include="Settings\SettingHandler.cs" />
<Compile Include="Settings\SettingItem.cs" /> <Compile Include="Settings\SettingItem.cs" />
<Compile Include="TapeDriveAnimator.cs" /> <Compile Include="TapeDriveAnimator.cs" />
<Compile Include="UIControls\WindowObject.cs" /> <Compile Include="UIControls\WindowObject.cs" />
<Compile Include="VesselSimulator\AttachNodeSim.cs" /> <Compile Include="VesselSimulator\AttachNodeSim.cs" />
<Compile Include="VesselSimulator\EngineSim.cs" /> <Compile Include="VesselSimulator\EngineSim.cs" />
<Compile Include="VesselSimulator\PartSim.cs" /> <Compile Include="VesselSimulator\PartSim.cs" />
<Compile Include="VesselSimulator\ResourceContainer.cs" /> <Compile Include="VesselSimulator\ResourceContainer.cs" />
<Compile Include="VesselSimulator\SimManager.cs" /> <Compile Include="VesselSimulator\SimManager.cs" />
<Compile Include="VesselSimulator\Simulation.cs" /> <Compile Include="VesselSimulator\Simulation.cs" />
<Compile Include="VesselSimulator\Stage.cs" /> <Compile Include="VesselSimulator\Stage.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Assembly-CSharp"> <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> <Private>False</Private>
</Reference> </Reference>
<Reference Include="System"> <Reference Include="System">
<HintPath>..\Game\KSP_Data\Managed\System.dll</HintPath> <HintPath>..\Game\KSP_Data\Managed\System.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="System.Xml"> <Reference Include="System.Xml">
<HintPath>..\Game\KSP_Data\Managed\System.Xml.dll</HintPath> <HintPath>..\Game\KSP_Data\Managed\System.Xml.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="UnityEngine"> <Reference Include="UnityEngine">
<HintPath>..\Game\KSP_Data\Managed\UnityEngine.dll</HintPath> <HintPath>..\Game\KSP_Data\Managed\UnityEngine.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="PostBuildMacros"> <Target Name="PostBuildMacros">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)"> <GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="Targets" /> <Output TaskParameter="Assemblies" ItemName="Targets" />
</GetAssemblyIdentity> </GetAssemblyIdentity>
<ItemGroup> <ItemGroup>
<VersionNumber Include="@(Targets->'%(Version)')" /> <VersionNumber Include="@(Targets->'%(Version)')" />
</ItemGroup> </ItemGroup>
</Target> </Target>
<PropertyGroup> <PropertyGroup>
<PostBuildEventDependsOn> <PostBuildEventDependsOn>
$(PostBuildEventDependsOn); $(PostBuildEventDependsOn);
PostBuildMacros; PostBuildMacros;
</PostBuildEventDependsOn> </PostBuildEventDependsOn>
<PostBuildEvent>xcopy "$(SolutionDir)Output\*" "$(SolutionDir)Game\GameData\*" /E /Y <PostBuildEvent>xcopy "$(SolutionDir)Output\*" "$(SolutionDir)Game\GameData\*" /E /Y
del "$(SolutionDir)Release\*" /Q del "$(SolutionDir)Release\*" /Q
xcopy "$(SolutionDir)Documents\*" "$(SolutionDir)Release\Documents\*" /E /Y xcopy "$(SolutionDir)Documents\*" "$(SolutionDir)Release\Documents\*" /E /Y
7z.exe a -tzip -mx3 "$(SolutionDir)Release\$(ProjectName)-@(VersionNumber).zip" "$(SolutionDir)Output\*" 7z.exe a -tzip -mx3 "$(SolutionDir)Release\$(ProjectName)-@(VersionNumber).zip" "$(SolutionDir)Output\*"
7z.exe a -tzip -mx3 "$(SolutionDir)Release\$(ProjectName)-@(VersionNumber).zip" "$(SolutionDir)Documents\*"</PostBuildEvent> 7z.exe a -tzip -mx3 "$(SolutionDir)Release\$(ProjectName)-@(VersionNumber).zip" "$(SolutionDir)Documents\*"</PostBuildEvent>
</PropertyGroup> </PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">
</Target> </Target>
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </Target>
--> -->
</Project> </Project>
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.VesselSimulator namespace KerbalEngineer.VesselSimulator
{ {
public class EngineSim public class EngineSim
{ {
private readonly ResourceContainer resourceConsumptions = new ResourceContainer(); private readonly ResourceContainer resourceConsumptions = new ResourceContainer();
   
public double actualThrust = 0; public double actualThrust = 0;
public bool isActive = false; public bool isActive = false;
public double isp = 0; public double isp = 0;
public PartSim partSim; public PartSim partSim;
  public List<AppliedForce> appliedForces;
   
public double thrust = 0; public double thrust = 0;
   
// Add thrust vector to account for directional losses // Add thrust vector to account for directional losses
public Vector3 thrustVec; public Vector3 thrustVec;
   
public EngineSim(PartSim theEngine, public EngineSim(PartSim theEngine,
double atmosphere, double atmosphere,
double velocity, double velocity,
float maxThrust, float maxThrust,
float minThrust, float minThrust,
float thrustPercentage, float thrustPercentage,
float requestedThrust, float requestedThrust,
Vector3 vecThrust, Vector3 vecThrust,
float realIsp, float realIsp,
FloatCurve atmosphereCurve, FloatCurve atmosphereCurve,
FloatCurve velocityCurve, FloatCurve velocityCurve,
bool throttleLocked, bool throttleLocked,
List<Propellant> propellants, List<Propellant> propellants,
bool active, bool active,
bool correctThrust) bool correctThrust,
  List<Transform> thrustTransforms)
{ {
StringBuilder buffer = null; StringBuilder buffer = null;
//MonoBehaviour.print("Create EngineSim for " + theEngine.name); //MonoBehaviour.print("Create EngineSim for " + theEngine.name);
//MonoBehaviour.print("maxThrust = " + maxThrust); //MonoBehaviour.print("maxThrust = " + maxThrust);
//MonoBehaviour.print("minThrust = " + minThrust); //MonoBehaviour.print("minThrust = " + minThrust);
//MonoBehaviour.print("thrustPercentage = " + thrustPercentage); //MonoBehaviour.print("thrustPercentage = " + thrustPercentage);
//MonoBehaviour.print("requestedThrust = " + requestedThrust); //MonoBehaviour.print("requestedThrust = " + requestedThrust);
//MonoBehaviour.print("velocity = " + velocity); //MonoBehaviour.print("velocity = " + velocity);
   
this.partSim = theEngine; this.partSim = theEngine;
   
this.isActive = active; this.isActive = active;
this.thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust; this.thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust;
//MonoBehaviour.print("thrust = " + thrust); //MonoBehaviour.print("thrust = " + thrust);
   
this.thrustVec = vecThrust; this.thrustVec = vecThrust;
   
double flowRate = 0d; double flowRate = 0d;
if (this.partSim.hasVessel) if (this.partSim.hasVessel)
{ {
//MonoBehaviour.print("hasVessel is true"); //MonoBehaviour.print("hasVessel is true");
this.actualThrust = isActive ? requestedThrust : 0.0; this.actualThrust = isActive ? requestedThrust : 0.0;
if (velocityCurve != null) if (velocityCurve != null)
{ {
this.actualThrust *= velocityCurve.Evaluate((float)velocity); this.actualThrust *= velocityCurve.Evaluate((float)velocity);
//MonoBehaviour.print("actualThrust at velocity = " + actualThrust); //MonoBehaviour.print("actualThrust at velocity = " + actualThrust);
} }
   
this.isp = atmosphereCurve.Evaluate((float)this.partSim.part.staticPressureAtm); this.isp = atmosphereCurve.Evaluate((float)this.partSim.part.staticPressureAtm);
if (this.isp == 0d) if (this.isp == 0d)
{ {
MonoBehaviour.print("Isp at " + this.partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN"); MonoBehaviour.print("Isp at " + this.partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN");
} }
   
if (correctThrust && realIsp == 0) if (correctThrust && realIsp == 0)
{ {
float ispsl = atmosphereCurve.Evaluate(0); float ispsl = atmosphereCurve.Evaluate(0);
if (ispsl != 0) if (ispsl != 0)
{ {
this.thrust = this.thrust * this.isp / ispsl; this.thrust = this.thrust * this.isp / ispsl;
} }
else else
{ {
MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust."); MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
} }
//MonoBehaviour.print("corrected thrust = " + thrust); //MonoBehaviour.print("corrected thrust = " + thrust);
} }
   
if (velocityCurve != null) if (velocityCurve != null)
{ {
this.thrust *= velocityCurve.Evaluate((float)velocity); this.thrust *= velocityCurve.Evaluate((float)velocity);
//MonoBehaviour.print("thrust at velocity = " + thrust); //MonoBehaviour.print("thrust at velocity = " + thrust);
} }
   
if (throttleLocked) if (throttleLocked)
{ {
//MonoBehaviour.print("throttleLocked is true"); //MonoBehaviour.print("throttleLocked is true");
flowRate = this.thrust / (this.isp * 9.81d); flowRate = this.thrust / (this.isp * 9.82);
} }
else else
{ {
if (this.partSim.isLanded) if (this.partSim.isLanded)
{ {
//MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle); //MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle);
flowRate = Math.Max(0.000001d, this.thrust * FlightInputHandler.state.mainThrottle) / (this.isp * 9.81d); flowRate = Math.Max(0.000001d, this.thrust * FlightInputHandler.state.mainThrottle) / (this.isp * 9.82);
} }
else else
{ {
if (requestedThrust > 0) if (requestedThrust > 0)
{ {
if (velocityCurve != null) if (velocityCurve != null)
{ {
requestedThrust *= velocityCurve.Evaluate((float)velocity); requestedThrust *= velocityCurve.Evaluate((float)velocity);
//MonoBehaviour.print("requestedThrust at velocity = " + requestedThrust); //MonoBehaviour.print("requestedThrust at velocity = " + requestedThrust);
} }
   
//MonoBehaviour.print("requestedThrust > 0"); //MonoBehaviour.print("requestedThrust > 0");
flowRate = requestedThrust / (this.isp * 9.81d); flowRate = requestedThrust / (this.isp * 9.82);
} }
else else
{ {
//MonoBehaviour.print("requestedThrust <= 0"); //MonoBehaviour.print("requestedThrust <= 0");
flowRate = this.thrust / (this.isp * 9.81d); flowRate = this.thrust / (this.isp * 9.82);
} }
} }
} }
} }
else else
{ {
//MonoBehaviour.print("hasVessel is false"); //MonoBehaviour.print("hasVessel is false");
this.isp = atmosphereCurve.Evaluate((float)atmosphere); this.isp = atmosphereCurve.Evaluate((float)atmosphere);
if (this.isp == 0d) if (this.isp == 0d)
{ {
MonoBehaviour.print("Isp at " + atmosphere + " is zero. Flow rate will be NaN"); MonoBehaviour.print("Isp at " + atmosphere + " is zero. Flow rate will be NaN");
} }
if (correctThrust) if (correctThrust)
{ {
float ispsl = atmosphereCurve.Evaluate(0); float ispsl = atmosphereCurve.Evaluate(0);
if (ispsl != 0) if (ispsl != 0)
{ {
this.thrust = this.thrust * this.isp / ispsl; this.thrust = this.thrust * this.isp / ispsl;
} }
else else
{ {
MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust."); MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
} }
//MonoBehaviour.print("corrected thrust = " + thrust); //MonoBehaviour.print("corrected thrust = " + thrust);
} }
   
if (velocityCurve != null) if (velocityCurve != null)
{ {
this.thrust *= velocityCurve.Evaluate((float)velocity); this.thrust *= velocityCurve.Evaluate((float)velocity);
//MonoBehaviour.print("thrust at velocity = " + thrust); //MonoBehaviour.print("thrust at velocity = " + thrust);
} }
   
flowRate = this.thrust / (this.isp * 9.81d); flowRate = this.thrust / (this.isp * 9.82);
} }
   
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
buffer = new StringBuilder(1024); buffer = new StringBuilder(1024);
buffer.AppendFormat("flowRate = {0:g6}\n", flowRate); buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);
} }
   
float flowMass = 0f; float flowMass = 0f;
foreach (Propellant propellant in propellants) foreach (Propellant propellant in propellants)
{ {
flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id); flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
} }
   
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
buffer.AppendFormat("flowMass = {0:g6}\n", flowMass); buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);
} }
   
foreach (Propellant propellant in propellants) foreach (Propellant propellant in propellants)
{ {
if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir") if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
{ {
continue; continue;
} }
   
double consumptionRate = propellant.ratio * flowRate / flowMass; double consumptionRate = propellant.ratio * flowRate / flowMass;
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
buffer.AppendFormat("Add consumption({0}, {1}:{2:d}) = {3:g6}\n", ResourceContainer.GetResourceName(propellant.id), theEngine.name, theEngine.partId, consumptionRate); 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); this.resourceConsumptions.Add(propellant.id, consumptionRate);
} }
   
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
MonoBehaviour.print(buffer); MonoBehaviour.print(buffer);
  }
   
  appliedForces = new List<AppliedForce>();
  double thrustPerThrustTransform = thrust / thrustTransforms.Count;
  foreach (Transform thrustTransform in thrustTransforms) {
  Vector3d direction = thrustTransform.forward.normalized;
  Vector3d position = thrustTransform.position;
  appliedForces.Add(new AppliedForce(direction * thrustPerThrustTransform, position));
} }
} }
   
public ResourceContainer ResourceConsumptions public ResourceContainer ResourceConsumptions
{ {
get { return this.resourceConsumptions; } get { return this.resourceConsumptions; }
} }
   
public bool SetResourceDrains(List<PartSim> allParts, List<PartSim> allFuelLines, HashSet<PartSim> drainingParts) public bool SetResourceDrains(List<PartSim> allParts, List<PartSim> allFuelLines, HashSet<PartSim> drainingParts)
{ {
LogMsg log = null; LogMsg log = null;
   
// A dictionary to hold a set of parts for each resource // A dictionary to hold a set of parts for each resource
Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>(); Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>();
   
foreach (int type in this.resourceConsumptions.Types) foreach (int type in this.resourceConsumptions.Types)
{ {
HashSet<PartSim> sourcePartSet = null; HashSet<PartSim> sourcePartSet = null;
switch (ResourceContainer.GetResourceFlowMode(type)) switch (ResourceContainer.GetResourceFlowMode(type))
{ {
case ResourceFlowMode.NO_FLOW: case ResourceFlowMode.NO_FLOW:
if (this.partSim.resources[type] > SimManager.RESOURCE_MIN) if (this.partSim.resources[type] > SimManager.RESOURCE_MIN)
{ {
sourcePartSet = new HashSet<PartSim>(); sourcePartSet = new HashSet<PartSim>();
//MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this"); //MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this");
sourcePartSet.Add(this.partSim); sourcePartSet.Add(this.partSim);
} }
break; break;
   
case ResourceFlowMode.ALL_VESSEL: case ResourceFlowMode.ALL_VESSEL:
foreach (PartSim aPartSim in allParts) foreach (PartSim aPartSim in allParts)
{ {
if (aPartSim.resources[type] > SimManager.RESOURCE_MIN) if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)
{ {
if (sourcePartSet == null) if (sourcePartSet == null)
{ {
sourcePartSet = new HashSet<PartSim>(); sourcePartSet = new HashSet<PartSim>();
} }
   
sourcePartSet.Add(aPartSim); sourcePartSet.Add(aPartSim);
} }
} }
break; break;
   
case ResourceFlowMode.STAGE_PRIORITY_FLOW: case ResourceFlowMode.STAGE_PRIORITY_FLOW:
{ var stagePartSets = new Dictionary<int, HashSet<PartSim>>();
Dictionary<int, HashSet<PartSim>> stagePartSets = new Dictionary<int, HashSet<PartSim>>(); var maxStage = -1;
int maxStage = -1;  
foreach (PartSim aPartSim in allParts) Logger.Log(type);
{ foreach (var aPartSim in allParts)
if (aPartSim.resources[type] > SimManager.RESOURCE_MIN) {
{ if (aPartSim.resources[type] <= SimManager.RESOURCE_MIN) continue;
//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 var stage = aPartSim.DecouplerCount();
if (stage > maxStage) if (stage > maxStage)
{ {
maxStage = stage; maxStage = stage;
} }
if (stagePartSets.ContainsKey(stage))  
{ if (!stagePartSets.TryGetValue(stage, out sourcePartSet))
sourcePartSet = stagePartSets[stage]; {
} sourcePartSet = new HashSet<PartSim>();
else stagePartSets.Add(stage, sourcePartSet);
{ }
sourcePartSet = new HashSet<PartSim>(); sourcePartSet.Add(aPartSim);
stagePartSets.Add(stage, sourcePartSet); }
}  
  for (var i = 0; i <= maxStage; i++)
sourcePartSet.Add(aPartSim); {
} HashSet<PartSim> stagePartSet;
} if (stagePartSets.TryGetValue(i, out stagePartSet) && stagePartSet.Count > 0)
  {
while (maxStage >= 0) sourcePartSet = stagePartSet;
{ }
if (stagePartSets.ContainsKey(maxStage)) }
{  
if (stagePartSets[maxStage].Count() > 0)  
{  
sourcePartSet = stagePartSets[maxStage];  
break;  
}  
}  
maxStage--;  
}  
}  
break; break;
   
case ResourceFlowMode.STACK_PRIORITY_SEARCH: case ResourceFlowMode.STACK_PRIORITY_SEARCH:
HashSet<PartSim> visited = new HashSet<PartSim>(); HashSet<PartSim> visited = new HashSet<PartSim>();
   
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
log = new LogMsg(); log = new LogMsg();
log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + this.partSim.name + ":" + this.partSim.partId); log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + this.partSim.name + ":" + this.partSim.partId);
} }
sourcePartSet = this.partSim.GetSourceSet(type, allParts, visited, log, ""); sourcePartSet = this.partSim.GetSourceSet(type, allParts, visited, log, "");
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
MonoBehaviour.print(log.buf); MonoBehaviour.print(log.buf);
} }
break; break;
   
default: default:
MonoBehaviour.print("SetResourceDrains(" + this.partSim.name + ":" + this.partSim.partId + ") Unexpected flow type for " + ResourceContainer.GetResourceName(type) + ")"); MonoBehaviour.print("SetResourceDrains(" + this.partSim.name + ":" + this.partSim.partId + ") Unexpected flow type for " + ResourceContainer.GetResourceName(type) + ")");
break; break;
} }
   
if (sourcePartSet != null && sourcePartSet.Count > 0) if (sourcePartSet != null && sourcePartSet.Count > 0)
{ {
sourcePartSets[type] = sourcePartSet; sourcePartSets[type] = sourcePartSet;
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
log = new LogMsg(); log = new LogMsg();
log.buf.AppendLine("Source parts for " + ResourceContainer.GetResourceName(type) + ":"); log.buf.AppendLine("Source parts for " + ResourceContainer.GetResourceName(type) + ":");
foreach (PartSim partSim in sourcePartSet) foreach (PartSim partSim in sourcePartSet)
{ {
log.buf.AppendLine(partSim.name + ":" + partSim.partId); log.buf.AppendLine(partSim.name + ":" + partSim.partId);
} }
MonoBehaviour.print(log.buf); MonoBehaviour.print(log.buf);
} }
} }
} }
   
// If we don't have sources for all the needed resources then return false without setting up any drains // 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) foreach (int type in this.resourceConsumptions.Types)
{ {
if (!sourcePartSets.ContainsKey(type)) if (!sourcePartSets.ContainsKey(type))
{ {
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
MonoBehaviour.print("No source of " + ResourceContainer.GetResourceName(type)); MonoBehaviour.print("No source of " + ResourceContainer.GetResourceName(type));
} }
   
this.isActive = false; this.isActive = false;
return false; return false;
} }
} }
   
// Now we set the drains on the members of the sets and update the draining parts set // Now we set the drains on the members of the sets and update the draining parts set
foreach (int type in this.resourceConsumptions.Types) foreach (int type in this.resourceConsumptions.Types)
{ {
HashSet<PartSim> sourcePartSet = sourcePartSets[type]; HashSet<PartSim> sourcePartSet = sourcePartSets[type];
// Loop through the members of the set // Loop through the members of the set
double amount = this.resourceConsumptions[type] / sourcePartSet.Count; double amount = this.resourceConsumptions[type] / sourcePartSet.Count;
foreach (PartSim partSim in sourcePartSet) foreach (PartSim partSim in sourcePartSet)
{ {
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
MonoBehaviour.print("Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" + partSim.partId); MonoBehaviour.print("Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" + partSim.partId);
} }
   
partSim.resourceDrains.Add(type, amount); partSim.resourceDrains.Add(type, amount);
drainingParts.Add(partSim); drainingParts.Add(partSim);
} }
} }
   
return true; return true;
} }
   
public void DumpEngineToBuffer(StringBuilder buffer, String prefix) public void DumpEngineToBuffer(StringBuilder buffer, String prefix)
{ {
buffer.Append(prefix); buffer.Append(prefix);
buffer.AppendFormat("[thrust = {0:g6}, actual = {1:g6}, isp = {2:g6}\n", this.thrust, this.actualThrust, this.isp); buffer.AppendFormat("[thrust = {0:g6}, actual = {1:g6}, isp = {2:g6}\n", this.thrust, this.actualThrust, this.isp);
} }
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2014 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives #region Using Directives
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
   
using KerbalEngineer.Extensions; using KerbalEngineer.Extensions;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.VesselSimulator namespace KerbalEngineer.VesselSimulator
{ {
public class PartSim public class PartSim
{ {
private readonly List<AttachNodeSim> attachNodes = new List<AttachNodeSim>(); private readonly List<AttachNodeSim> attachNodes = new List<AttachNodeSim>();
  public Vector3d centerOfMass;
public double baseMass = 0d; public double baseMass = 0d;
public double cost; public double cost;
public int decoupledInStage; public int decoupledInStage;
public bool fuelCrossFeed; public bool fuelCrossFeed;
public List<PartSim> fuelTargets = new List<PartSim>(); public List<PartSim> fuelTargets = new List<PartSim>();
public bool hasModuleEngines; public bool hasModuleEngines;
public bool hasModuleEnginesFX; public bool hasModuleEnginesFX;
public bool hasMultiModeEngine; public bool hasMultiModeEngine;
   
public bool hasVessel; public bool hasVessel;
public String initialVesselName; public String initialVesselName;
public int inverseStage; public int inverseStage;
public bool isDecoupler; public bool isDecoupler;
public bool isEngine; public bool isEngine;
public bool isFuelLine; public bool isFuelLine;
public bool isFuelTank; public bool isFuelTank;
public bool isLanded; public bool isLanded;
public bool isNoPhysics; public bool isNoPhysics;
public bool isSepratron; public bool isSepratron;
public bool localCorrectThrust; public bool localCorrectThrust;
public String name; public String name;
public String noCrossFeedNodeKey; public String noCrossFeedNodeKey;
public PartSim parent; public PartSim parent;
public AttachModes parentAttach; public AttachModes parentAttach;
public Part part; // This is only set while the data structures are being initialised public Part part; // This is only set while the data structures are being initialised
public int partId = 0; public int partId = 0;
public ResourceContainer resourceDrains = new ResourceContainer(); public ResourceContainer resourceDrains = new ResourceContainer();
public ResourceContainer resourceFlowStates = new ResourceContainer(); public ResourceContainer resourceFlowStates = new ResourceContainer();
public ResourceContainer resources = new ResourceContainer(); public ResourceContainer resources = new ResourceContainer();
public double startMass = 0d; public double startMass = 0d;
public String vesselName; public String vesselName;
public VesselType vesselType; public VesselType vesselType;
   
public PartSim(Part thePart, int id, double atmosphere, LogMsg log) public PartSim(Part thePart, int id, double atmosphere, LogMsg log)
{ {
this.part = thePart; this.part = thePart;
  this.centerOfMass = thePart.transform.TransformPoint(thePart.CoMOffset);
this.partId = id; this.partId = id;
this.name = this.part.partInfo.name; this.name = this.part.partInfo.name;
   
if (log != null) if (log != null)
{ {
log.buf.AppendLine("Create PartSim for " + this.name); log.buf.AppendLine("Create PartSim for " + this.name);
} }
   
this.parent = null; this.parent = null;
this.parentAttach = part.attachMode; this.parentAttach = part.attachMode;
this.fuelCrossFeed = this.part.fuelCrossFeed; this.fuelCrossFeed = this.part.fuelCrossFeed;
this.noCrossFeedNodeKey = this.part.NoCrossFeedNodeKey; this.noCrossFeedNodeKey = this.part.NoCrossFeedNodeKey;
this.decoupledInStage = this.DecoupledInStage(this.part); this.decoupledInStage = this.DecoupledInStage(this.part);
this.isFuelLine = this.part is FuelLine; this.isFuelLine = this.part is FuelLine;
this.isFuelTank = this.part is FuelTank; this.isFuelTank = this.part is FuelTank;
this.isSepratron = this.IsSepratron(); this.isSepratron = this.IsSepratron();
this.inverseStage = this.part.inverseStage; this.inverseStage = this.part.inverseStage;
//MonoBehaviour.print("inverseStage = " + inverseStage); //MonoBehaviour.print("inverseStage = " + inverseStage);
   
this.cost = this.part.GetCostWet(); this.cost = this.part.GetCostWet();
   
// Work out if the part should have no physical significance // Work out if the part should have no physical significance
this.isNoPhysics = this.part.HasModule<LaunchClamp>() || this.isNoPhysics = this.part.HasModule<LaunchClamp>() ||
this.part.physicalSignificance == Part.PhysicalSignificance.NONE || this.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
this.part.PhysicsSignificance == 1; this.part.PhysicsSignificance == 1;
   
if (!this.isNoPhysics) if (!this.isNoPhysics)
{ {
this.baseMass = this.part.mass; this.baseMass = this.part.mass;
} }
   
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
MonoBehaviour.print((this.isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + this.part.mass); MonoBehaviour.print((this.isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + this.part.mass);
} }
   
foreach (PartResource resource in this.part.Resources) foreach (PartResource resource in this.part.Resources)
{ {
// Make sure it isn't NaN as this messes up the part mass and hence most of the values // Make sure it isn't NaN as this messes up the part mass and hence most of the values
// This can happen if a resource capacity is 0 and tweakable // This can happen if a resource capacity is 0 and tweakable
if (!Double.IsNaN(resource.amount)) if (!Double.IsNaN(resource.amount))
{ {
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
MonoBehaviour.print(resource.resourceName + " = " + resource.amount); MonoBehaviour.print(resource.resourceName + " = " + resource.amount);
} }
   
this.resources.Add(resource.info.id, resource.amount); this.resources.Add(resource.info.id, resource.amount);
this.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0); this.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
} }
else else
{ {
MonoBehaviour.print(resource.resourceName + " is NaN. Skipping."); MonoBehaviour.print(resource.resourceName + " is NaN. Skipping.");
} }
} }
   
this.startMass = this.GetMass(); this.startMass = this.GetMass();
   
this.hasVessel = (this.part.vessel != null); this.hasVessel = (this.part.vessel != null);
this.isLanded = this.hasVessel && this.part.vessel.Landed; this.isLanded = this.hasVessel && this.part.vessel.Landed;
if (this.hasVessel) if (this.hasVessel)
{ {
this.vesselName = this.part.vessel.vesselName; this.vesselName = this.part.vessel.vesselName;
this.vesselType = this.part.vesselType; this.vesselType = this.part.vesselType;
} }
this.initialVesselName = this.part.initialVesselName; this.initialVesselName = this.part.initialVesselName;
   
this.hasMultiModeEngine = this.part.HasModule<MultiModeEngine>(); this.hasMultiModeEngine = this.part.HasModule<MultiModeEngine>();
this.hasModuleEnginesFX = this.part.HasModule<ModuleEnginesFX>(); this.hasModuleEnginesFX = this.part.HasModule<ModuleEnginesFX>();
this.hasModuleEngines = this.part.HasModule<ModuleEngines>(); this.hasModuleEngines = this.part.HasModule<ModuleEngines>();
   
this.isEngine = this.hasMultiModeEngine || this.hasModuleEnginesFX || this.hasModuleEngines; this.isEngine = this.hasMultiModeEngine || this.hasModuleEnginesFX || this.hasModuleEngines;
   
if (SimManager.logOutput) if (SimManager.logOutput)
{ {
MonoBehaviour.print("Created " + this.name + ". Decoupled in stage " + this.decoupledInStage); MonoBehaviour.print("Created " + this.name + ". Decoupled in stage " + this.decoupledInStage);
} }
} }
   
public ResourceContainer Resources public ResourceContainer Resources
{ {
get { return this.resources; } get { return this.resources; }
} }
   
public ResourceContainer ResourceDrains public ResourceContainer ResourceDrains
{ {
get { return this.resourceDrains; } get { return this.resourceDrains; }
} }
   
public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double velocity, bool vectoredThrust, LogMsg log) public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double velocity, bool vectoredThrust, LogMsg log)
{ {
bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(this.part); bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(this.part);
if (log != null) if (log != null)
{ {
log.buf.AppendLine("CreateEngineSims for " + this.name); log.buf.AppendLine("CreateEngineSims for " + this.name);
   
foreach (PartModule partMod in this.part.Modules) foreach (PartModule partMod in this.part.Modules)
{ {
log.buf.AppendLine("Module: " + partMod.moduleName); log.buf.AppendLine("Module: " + partMod.moduleName);
} }
   
log.buf.AppendLine("correctThrust = " + correctThrust); log.buf.AppendLine("correctThrust = " + correctThrust);
} }
   
if (this.hasMultiModeEngine) if (this.hasMultiModeEngine)
{ {
// A multi-mode engine has multiple ModuleEnginesFX but only one is active at any point // A multi-mode engine has multiple ModuleEnginesFX but only one is active at any point
// The mode of the engine is the engineID of the ModuleEnginesFX that is active // The mode of the engine is the engineID of the ModuleEnginesFX that is active
string mode = this.part.GetModule<MultiModeEngine>().mode; string mode = this.part.GetModule<MultiModeEngine>().mode;
   
foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>()) foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>())
{ {
if (engine.engineID == mode) if (engine.engineID == mode)
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("Module: " + engine.moduleName); log.buf.AppendLine("Module: " + engine.moduleName);
} }
   
Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log); Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
   
EngineSim engineSim = new EngineSim(this, EngineSim engineSim = new EngineSim(this,
atmosphere, atmosphere,
velocity, velocity,
engine.maxThrust, engine.maxThrust,
engine.minThrust, engine.minThrust,
engine.thrustPercentage, engine.thrustPercentage,
engine.requestedThrust, engine.requestedThrust,
thrustvec, thrustvec,
engine.realIsp, engine.realIsp,
engine.atmosphereCurve, engine.atmosphereCurve,
engine.useVelocityCurve ? engine.velocityCurve : null, engine.useVelocityCurve ? engine.velocityCurve : null,
engine.throttleLocked, engine.throttleLocked,
engine.propellants, engine.propellants,
engine.isOperational, engine.isOperational,
correctThrust); correctThrust,
  engine.thrustTransforms);
allEngines.Add(engineSim); allEngines.Add(engineSim);
} }
} }
} }
else else
{ {
if (this.hasModuleEnginesFX) if (this.hasModuleEnginesFX)
{ {
foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>()) foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>())
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("Module: " + engine.moduleName); log.buf.AppendLine("Module: " + engine.moduleName);
} }
   
Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log); Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
   
EngineSim engineSim = new EngineSim(this, EngineSim engineSim = new EngineSim(this,
atmosphere, atmosphere,
velocity, velocity,
engine.maxThrust, engine.maxThrust,
engine.minThrust, engine.minThrust,
engine.thrustPercentage, engine.thrustPercentage,
engine.requestedThrust, engine.requestedThrust,
thrustvec, thrustvec,
engine.realIsp, engine.realIsp,
engine.atmosphereCurve, engine.atmosphereCurve,
engine.useVelocityCurve ? engine.velocityCurve : null, engine.useVelocityCurve ? engine.velocityCurve : null,
engine.throttleLocked, engine.throttleLocked,
engine.propellants, engine.propellants,
engine.isOperational, engine.isOperational,
correctThrust); correctThrust,
  engine.thrustTransforms);
allEngines.Add(engineSim); allEngines.Add(engineSim);
} }
} }
   
if (this.hasModuleEngines) if (this.hasModuleEngines)
{ {
foreach (ModuleEngines engine in this.part.GetModules<ModuleEngines>()) foreach (ModuleEngines engine in this.part.GetModules<ModuleEngines>())
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("Module: " + engine.moduleName); log.buf.AppendLine("Module: " + engine.moduleName);
} }
   
Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log); Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
   
EngineSim engineSim = new EngineSim(this, EngineSim engineSim = new EngineSim(this,
atmosphere, atmosphere,
velocity, velocity,
engine.maxThrust, engine.maxThrust,
engine.minThrust, engine.minThrust,
engine.thrustPercentage, engine.thrustPercentage,
engine.requestedThrust, engine.requestedThrust,
thrustvec, thrustvec,
engine.realIsp, engine.realIsp,
engine.atmosphereCurve, engine.atmosphereCurve,
engine.useVelocityCurve ? engine.velocityCurve : null, engine.useVelocityCurve ? engine.velocityCurve : null,
engine.throttleLocked, engine.throttleLocked,
engine.propellants, engine.propellants,
engine.isOperational, engine.isOperational,
correctThrust); correctThrust,
  engine.thrustTransforms);
allEngines.Add(engineSim); allEngines.Add(engineSim);
} }
} }
} }
   
if (log != null) if (log != null)
{ {
log.Flush(); log.Flush();
} }
} }
   
private Vector3 CalculateThrustVector(List<Transform> thrustTransforms, LogMsg log) private Vector3 CalculateThrustVector(List<Transform> thrustTransforms, LogMsg log)
{ {
if (thrustTransforms == null) if (thrustTransforms == null)
{ {
return Vector3.forward; return Vector3.forward;
} }
   
Vector3 thrustvec = Vector3.zero; Vector3 thrustvec = Vector3.zero;
foreach (Transform trans in thrustTransforms) foreach (Transform trans in thrustTransforms)
{ {
if (log != null) 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); 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; thrustvec -= trans.forward;
} }
   
if (log != null) 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); log.buf.AppendFormat("ThrustVec = ({0:g6}, {1:g6}, {2:g6}) length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
} }
   
thrustvec.Normalize(); thrustvec.Normalize();
   
if (log != null) 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); log.buf.AppendFormat("ThrustVecN = ({0:g6}, {1:g6}, {2:g6}) length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
} }
   
return thrustvec; return thrustvec;
} }
   
public void SetupParent(Dictionary<Part, PartSim> partSimLookup, LogMsg log) public void SetupParent(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
{ {
if (this.part.parent != null) if (this.part.parent != null)
{ {
this.parent = null; this.parent = null;
if (partSimLookup.TryGetValue(this.part.parent, out this.parent)) if (partSimLookup.TryGetValue(this.part.parent, out this.parent))
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("Parent part is " + this.parent.name + ":" + this.parent.partId); log.buf.AppendLine("Parent part is " + this.parent.name + ":" + this.parent.partId);
} }
} }
else else
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("No PartSim for parent part (" + this.part.parent.partInfo.name + ")"); log.buf.AppendLine("No PartSim for parent part (" + this.part.parent.partInfo.name + ")");
} }
} }
} }
} }
   
public void SetupAttachNodes(Dictionary<Part, PartSim> partSimLookup, LogMsg log) public void SetupAttachNodes(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("SetupAttachNodes for " + this.name + ":" + this.partId + ""); log.buf.AppendLine("SetupAttachNodes for " + this.name + ":" + this.partId + "");
} }
   
this.attachNodes.Clear(); this.attachNodes.Clear();
foreach (AttachNode attachNode in this.part.attachNodes) foreach (AttachNode attachNode in this.part.attachNodes)
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("AttachNode " + attachNode.id + " = " + (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null")); log.buf.AppendLine("AttachNode " + attachNode.id + " = " + (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null"));
} }
   
if (attachNode.attachedPart != null && attachNode.id != "Strut") if (attachNode.attachedPart != null && attachNode.id != "Strut")
{ {
PartSim attachedSim; PartSim attachedSim;
if (partSimLookup.TryGetValue(attachNode.attachedPart, out attachedSim)) if (partSimLookup.TryGetValue(attachNode.attachedPart, out attachedSim))
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + ""); log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + "");
} }
   
this.attachNodes.Add(new AttachNodeSim(attachedSim, attachNode.id, attachNode.nodeType)); this.attachNodes.Add(new AttachNodeSim(attachedSim, attachNode.id, attachNode.nodeType));
} }
else else
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("No PartSim for attached part (" + attachNode.attachedPart.partInfo.name + ")"); log.buf.AppendLine("No PartSim for attached part (" + attachNode.attachedPart.partInfo.name + ")");
} }
} }
} }
} }
   
foreach (Part p in this.part.fuelLookupTargets) foreach (Part p in this.part.fuelLookupTargets)
{ {
if (p != null) if (p != null)
{ {
PartSim targetSim; PartSim targetSim;
if (partSimLookup.TryGetValue(p, out targetSim)) if (partSimLookup.TryGetValue(p, out targetSim))
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("Fuel target: " + targetSim.name + ":" + targetSim.partId); log.buf.AppendLine("Fuel target: " + targetSim.name + ":" + targetSim.partId);
} }
   
this.fuelTargets.Add(targetSim); this.fuelTargets.Add(targetSim);
} }
else else
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine("No PartSim for fuel target (" + p.name + ")"); log.buf.AppendLine("No PartSim for fuel target (" + p.name + ")");
} }
} }
} }
} }
} }
   
private int DecoupledInStage(Part thePart, int stage = -1) private int DecoupledInStage(Part thePart, int stage = -1)
{ {
if (this.IsDecoupler(thePart)) if (this.IsDecoupler(thePart))
{ {
if (thePart.inverseStage > stage) if (thePart.inverseStage > stage)
{ {
stage = thePart.inverseStage; stage = thePart.inverseStage;
} }
} }
   
if (thePart.parent != null) if (thePart.parent != null)
{ {
stage = this.DecoupledInStage(thePart.parent, stage); stage = this.DecoupledInStage(thePart.parent, stage);
} }
   
return stage; return stage;
} }
   
private bool IsDecoupler(Part thePart) private bool IsDecoupler(Part thePart)
{ {
return thePart.HasModule<ModuleDecouple>() || return thePart.HasModule<ModuleDecouple>() ||
thePart.HasModule<ModuleAnchoredDecoupler>(); thePart.HasModule<ModuleAnchoredDecoupler>();
} }
   
private bool IsActiveDecoupler(Part thePart) private bool IsActiveDecoupler(Part thePart)
{ {
return thePart.FindModulesImplementing<ModuleDecouple>().Any(mod => !mod.isDecoupled) || return thePart.FindModulesImplementing<ModuleDecouple>().Any(mod => !mod.isDecoupled) ||
thePart.FindModulesImplementing<ModuleAnchoredDecoupler>().Any(mod => !mod.isDecoupled); thePart.FindModulesImplementing<ModuleAnchoredDecoupler>().Any(mod => !mod.isDecoupled);
} }
   
private bool IsSepratron() private bool IsSepratron()
{ {
if (!this.part.ActivatesEvenIfDisconnected) if (!this.part.ActivatesEvenIfDisconnected)
{ {
return false; return false;
} }
   
if (this.part is SolidRocket) if (this.part is SolidRocket)
{ {
return true; return true;
} }
   
var modList = this.part.Modules.OfType<ModuleEngines>(); var modList = this.part.Modules.OfType<ModuleEngines>();
if (modList.Count() == 0) if (modList.Count() == 0)
{ {
return false; return false;
} }
   
if (modList.First().throttleLocked) if (modList.First().throttleLocked)
{ {
return true; return true;
} }
   
return false; return false;
} }
   
public void ReleasePart() public void ReleasePart()
{ {
this.part = null; this.part = null;
} }
   
// All functions below this point must not rely on the part member (it may be null) // All functions below this point must not rely on the part member (it may be null)
// //
   
public HashSet<PartSim> GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, LogMsg log, String indent) public HashSet<PartSim> GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, LogMsg log, String indent)
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine(indent + "GetSourceSet(" + ResourceContainer.GetResourceName(type) + ") for " + this.name + ":" + this.partId); log.buf.AppendLine(indent + "GetSourceSet(" + ResourceContainer.GetResourceName(type) + ") for " + this.name + ":" + this.partId);
indent += " "; indent += " ";
} }
   
HashSet<PartSim> allSources = new HashSet<PartSim>(); HashSet<PartSim> allSources = new HashSet<PartSim>();
HashSet<PartSim> partSources = null; HashSet<PartSim> partSources = null;
   
// Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns empty list. // Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns empty list.
if (visited.Contains(this)) if (visited.Contains(this))
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine(indent + "Returning empty set, already visited (" + this.name + ":" + this.partId + ")"); log.buf.AppendLine(indent + "Returning empty set, already visited (" + this.name + ":" + this.partId + ")");
} }
   
return allSources; return allSources;
} }
   
//if (log != null) //if (log != null)
// log.buf.AppendLine(indent + "Adding this to visited"); // log.buf.AppendLine(indent + "Adding this to visited");
   
visited.Add(this); visited.Add(this);
   
// Rule 2: Part performs scan on start of every fuel pipe ending in it. This scan is done in order in which pipes were installed. // Rule 2: Part performs scan on start of every fuel pipe ending in it. This scan is done in order in which pipes were installed.
// Then it makes an union of fuel tank sets each pipe scan returned. If the resulting list is not empty, it is returned as result. // Then it makes an union of fuel tank sets each pipe scan returned. If the resulting list is not empty, it is returned as result.
//MonoBehaviour.print("foreach fuel line"); //MonoBehaviour.print("foreach fuel line");
   
foreach (PartSim partSim in this.fuelTargets) foreach (PartSim partSim in this.fuelTargets)
{ {
if (visited.Contains(partSim)) if (visited.Contains(partSim))
{ {
//if (log != null) //if (log != null)
// log.buf.AppendLine(indent + "Fuel target already visited, skipping (" + partSim.name + ":" + partSim.partId + ")"); // log.buf.AppendLine(indent + "Fuel target already visited, skipping (" + partSim.name + ":" + partSim.partId + ")");
} }
else else
{ {
//if (log != null) //if (log != null)
// log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")"); // log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
   
partSources = partSim.GetSourceSet(type, allParts, visited, log, indent); partSources = partSim.GetSourceSet(type, allParts, visited, log, indent);
if (partSources.Count > 0) if (partSources.Count > 0)
{ {
allSources.UnionWith(partSources); allSources.UnionWith(partSources);
partSources.Clear(); partSources.Clear();
} }
} }
} }
   
if (allSources.Count > 0) if (allSources.Count > 0)
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine(indent + "Returning " + allSources.Count + " fuel target sources (" + this.name + ":" + this.partId + ")"); log.buf.AppendLine(indent + "Returning " + allSources.Count + " fuel target sources (" + this.name + ":" + this.partId + ")");
} }
   
return allSources; return allSources;
} }
   
// Rule 3: This rule has been removed and merged with rules 4 and 7 to fix issue with fuel tanks with disabled crossfeed // Rule 3: This rule has been removed and merged with rules 4 and 7 to fix issue with fuel tanks with disabled crossfeed
   
// Rule 4: Part performs scan on each of its axially mounted neighbors. // Rule 4: Part performs scan on each of its axially mounted neighbors.
// Couplers (bicoupler, tricoupler, ...) are an exception, they only scan one attach point on the single attachment side, // Couplers (bicoupler, tricoupler, ...) are an exception, they only scan one attach point on the single attachment side,
// skip the points on the side where multiple points are. [Experiment] // skip the points on the side where multiple points are. [Experiment]
// Again, the part creates union of scan lists from each of its neighbor and if it is not empty, returns this list. // Again, the part creates union of scan lists from each of its neighbor and if it is not empty, returns this list.
// The order in which mount points of a part are scanned appears to be fixed and defined by the part specification file. [Experiment] // The order in which mount points of a part are scanned appears to be fixed and defined by the part specification file. [Experiment]
if (this.fuelCrossFeed) if (this.fuelCrossFeed)
{ {
//MonoBehaviour.print("foreach attach node"); //MonoBehaviour.print("foreach attach node");
foreach (AttachNodeSim attachSim in this.attachNodes) foreach (AttachNodeSim attachSim in this.attachNodes)
{ {
if (attachSim.attachedPartSim != null) if (attachSim.attachedPartSim != null)
{ {
if (attachSim.nodeType == AttachNode.NodeType.Stack) if (attachSim.nodeType == AttachNode.NodeType.Stack)
{ {
if (!(this.noCrossFeedNodeKey != null && this.noCrossFeedNodeKey.Length > 0 && attachSim.id.Contains(this.noCrossFeedNodeKey))) if (!(this.noCrossFeedNodeKey != null && this.noCrossFeedNodeKey.Length > 0 && attachSim.id.Contains(this.noCrossFeedNodeKey)))
{ {
if (visited.Contains(attachSim.attachedPartSim)) if (visited.Contains(attachSim.attachedPartSim))
{ {
//if (log != null) //if (log != null)
// log.buf.AppendLine(indent + "Attached part already visited, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")"); // log.buf.AppendLine(indent + "Attached part already visited, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
} }
else else
{ {
//if (log != null) //if (log != null)
// log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")"); // log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
   
partSources = attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, log, indent); partSources = attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, log, indent);
if (partSources.Count > 0) if (partSources.Count > 0)
{ {
allSources.UnionWith(partSources); allSources.UnionWith(partSources);
partSources.Clear(); partSources.Clear();
} }
} }
} }
} }
} }
} }
   
if (allSources.Count > 0) if (allSources.Count > 0)
{ {
if (log != null) if (log != null)
{ {
log.buf.AppendLine(indent + "Returning " + allSources.Count + " attached sources (" + this.name + ":" + this.partId + ")"); log.buf.AppendLine(indent + "Returning " + allSources.Count + " attached sources (" + this.name + ":" + this.partId + ")");
} }
   
return allSources; return allSources;
} }
} }
   
// Rule 5: 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 // Rule 5: 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 [Experiment]) and it contains fuel, it returns itself. // 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 // 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] // type was not disabled) but it does not contain the requested fuel, it returns empty list. [Experiment]
if (this.resources.HasType(type) && this.resourceFlowStates[type] != 0) if (this.resources.HasType(type) && this.resourceFlowStates[type] != 0)
{ {
if (this.resources[type] > SimManager.RESOURCE_MIN) if (this.resources[type] > SimManager.RESOURCE_MIN)
{ {
allSources.Add(this); allSources.Add(this);
   
if (log != null) if (log != null)
{ {
log.buf.AppendLine(indent + "Returning enabled tank as only source (" + this.name + ":" + this.partId + ")"); log.buf.AppendLine(indent + "Returning enabled tank as only source (" + this.name + ":" + this.partId + ")");
} }
} }
   
return allSources; return allSources;
} }
   
// Rule 7: If the part is radially attached to another part and it is child of that part in the ship's tree structure, it scans its // Rule 7: If the part is radially attached to another part and it is child of that part in the ship's tree structure, it scans its
// parent and returns whatever the parent scan returned. [Experiment] [Experiment] // parent and returns whatever the parent scan returned. [Experiment] [Experiment]
if (this.parent != null && this.parentAttach == AttachModes.SRF_ATTACH) if (this.parent != null && this.parentAttach == AttachModes.SRF_ATTACH)
{ {
if (this.fuelCrossFeed) if (this.fuelCrossFeed)
{ {
if (visited.Contains(this.parent)) if (visited.Contains(this.parent))
{ {
//if (log != null) //if (log != null)
// log.buf.AppendLine(indent + "Parent part already visited, skipping (" + parent.name + ":" + parent.partId + ")"); // log.buf.AppendLine(indent + "Parent part already visited, skipping (" + parent.name + ":" + parent.partId + ")");
} }
else else
{ {
allSources = this.parent.GetSourceSet(type, allParts, visited, log, indent); allSources = this.parent.GetSourceSet(type, allParts, visited, log, indent);
if (allSources.Count > 0) if (allSources.Count > 0)