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

  1.0.18.0
  Added: Orbital readouts - "Speed at Periapsis" and "Speed at Apoapsis". (Padishar)
  Added: Manoeuvre readouts - "Post-burn Apoapsis" and "Post-burn Periapsis". (Padishar)
  Fixed: Synched the minimum simulation time sliders and stopped them from snapping back after 999ms. (saybur)
  Fixed: Added workaround for the bug in Vessel.horizontalSrfSpeed (Padishar)
  Fixed: Physically insignificant part masses were not correctly being cascaded down through its parents.
   
  1.0.17.0
  Added: 'Mach Number' readout under the 'Surface' category and included it on the default surface HUD.
  Added: Stock sections in the Flight Engineer can now become HUDs.
  Added 'Thermal' readouts category including:
  Internal Flux
  Convection Flux
  Radiation Flux
  Critical Part Name
  Critical Part Temperature
  Critical Part Skin Temperature
  Critical Part Thermal Percentage of Max Temperature
  Hottest Part Name
  Hottest Part Temperature
  Hottest Part Skin Temperature
  Coldest Part Name
  Coldest Part Temperature
  Coldest Part Skin Temperature
   
  Changed: Mach on the Build Engineer now accurate to 2 decimal places.
  Changed: Max mach in the Build Engineer defaults to 1.00 even when no jet engines are present.
  Changed: Increased eccentricity readout to 5 decimal places.
  Changed: Implemented Sarbian's object pooling.
  Changed: The default selected body is now assigned via 'Planitarium.Home'.
  Changed: HUDs to clamp fully inside the screen instead of allowing them to run off the edge by a certain amount.
  Fixed: Physically insignificant part mass is now associated with the parent part.
  Fixed: Longitude and Latitude readouts now use a KER formatter instead of Squad's incorrect implementation.
  Fixed: Possible null reference in the Rendezvous Processor.
  Fixed: Fairing mass issues introduced with regards to simulation changes.
  Fixed: Use of per-propellant fuel flow mode override.
  Fixed: Burn times calculated for jet engines.
  Fixed: Thrust issues introduced with Sarbian's simulation alterations.
  Fixed: Issue where HUDs positioned close to the top/bottom of the screen could be pushed out of position.
   
  1.0.16.6, 02-05-15
  Fixed: Separately staged fairing mass jettisons are now calculated in the editor.
   
  1.0.16.5, 02-05-2015
  Fixed: Delta-V not being correctly calculated.
  Changed: Editor locking now uses the InputLockManager.
   
1.0.16.4, 01-05-2015 1.0.16.4, 01-05-2015
Fixed: Physically insignificant part mass is now accounted for. Fixed: Physically insignificant part mass is now accounted for.
Changed: Module mass accounted for as it now makes its way onto the launch pad (e.g. fairings). Changed: Module mass accounted for as it now makes its way onto the launch pad (e.g. fairings).
   
Various optimisations: Various optimisations:
Object pooling. Object pooling.
Removed LINQ expressions. Removed LINQ expressions.
Converted foreach to for loops. Converted foreach to for loops.
   
1.0.16.3, 27-04-2015 1.0.16.3, 27-04-2015
Fixed issue with the toolbar icons not being created. Fixed issue with the toolbar icons not being created.
Removed superfluous 'm/s' on the mach slider in the build engineer. Removed superfluous 'm/s' on the mach slider in the build engineer.
   
1.0.16.2, 27-04-2015 1.0.16.2, 27-04-2015
Changed the atmospheric slider on the build engineer to default to 0km when changing bodies. Changed the atmospheric slider on the build engineer to default to 0km when changing bodies.
   
1.0.16.1, 26-04-2015, KSP Build #828 1.0.16.1, 26-04-2015, KSP Build #828
Merged Sarbian's mach adjustments. Merged Sarbian's mach adjustments.
Fixed bugs relating to thrust and atmosphere/velocity curves. Fixed bugs relating to thrust and atmosphere/velocity curves.
Changed the atmospheric slider on the Build Engineer to work based on altitude. Changed the atmospheric slider on the Build Engineer to work based on altitude.
Changed the atmospheric slider to clamp to the maximum altitude for the selected body. Changed the atmospheric slider to clamp to the maximum altitude for the selected body.
Changed the velocity slider to clamp to the maximum usable mach value for the current vessel. Changed the velocity slider to clamp to the maximum usable mach value for the current vessel.
   
1.0.16.0, 25-04-2015, KSP Build #821 1.0.16.0, 25-04-2015, KSP Build #821
Fixed errors relating to KSP 1.0 update. Fixed errors relating to KSP 1.0 update.
Fixed fuel simulation to account for new thrust system. Fixed fuel simulation to account for new thrust system.
Fixed atmospheric engines to use the new velocity curve. Fixed atmospheric engines to use the new velocity curve.
Fixed atmospheric readouts to work with the new atmospheric model. Fixed atmospheric readouts to work with the new atmospheric model.
   
1.0.15.2, 13-02-2015 1.0.15.2, 13-02-2015
Padishar's Fixes: Padishar's Fixes:
Fixed: Calculation of per-stage resource mass. Fixed: Calculation of per-stage resource mass.
   
1.0.15.1, 13-02-2015 1.0.15.1, 13-02-2015
Rebuild Rebuild
   
1.0.15.0, 08-02-2015 1.0.15.0, 08-02-2015
Padishar's Fixes: Padishar's Fixes:
Added: Support KIDS ISP thrust correction. Added: Support KIDS ISP thrust correction.
Fixed: Log spam for stage priority mode. Fixed: Log spam for stage priority mode.
Fixed: Locked tanks preventing simulation from staging. Fixed: Locked tanks preventing simulation from staging.
Fixed: No flow and all vessel modes to respect flow states. Fixed: No flow and all vessel modes to respect flow states.
   
1.0.14.1, 28-12-2014 1.0.14.1, 28-12-2014
Fixed: Missing texture on the ER-7500 model. Fixed: Missing texture on the ER-7500 model.
   
1.0.14.0, 28-12-2014 1.0.14.0, 28-12-2014
Added: Career mode that limits the Flight Engineer by: Added: Career mode that limits the Flight Engineer by:
- Requiring an Engineer Kerbal of any level, or placement of an Engineer Chip or ER-7500 part. - Requiring an Engineer Kerbal of any level, or placement of an Engineer Chip or ER-7500 part.
- Tracking station level 3 enables Flight Engineer everywhere. - Tracking station level 3 enables Flight Engineer everywhere.
   
Added: New readouts to the orbital category: Added: New readouts to the orbital category:
- Mean Anomaly at Epoc - Mean Anomaly at Epoc
   
Added: New readouts to the miscellaneous category: Added: New readouts to the miscellaneous category:
- System Time - System Time
   
Added: Editor Overlay Tab's X position is now changable in the BuildOverlay.xml settings file. Added: Editor Overlay Tab's X position is now changable in the BuildOverlay.xml settings file.
Changed: Editor Overlay Tabs start position moved over as to not overlap the parts menu. Changed: Editor Overlay Tabs start position moved over as to not overlap the parts menu.
Fixed: Bug where STAGE_PRIORITY_FLOW resources would not be corrently disabled/enabled. Fixed: Bug where STAGE_PRIORITY_FLOW resources would not be corrently disabled/enabled.
Fixed: Issue with the formatting large Mass and Cost values. Fixed: Issue with the formatting large Mass and Cost values.
Fixed: Error when loading the Engineer7500 part model. Fixed: Error when loading the Engineer7500 part model.
   
1.0.13.1, 16-12-2014 1.0.13.1, 16-12-2014
Fixed: Issue with manoeuvre node readouts and low tier tracking station. Fixed: Issue with manoeuvre node readouts and low tier tracking station.
   
1.0.13.0, 16-12-2014 1.0.13.0, 16-12-2014
Updated for KSP version 0.90 Updated for KSP version 0.90
   
Added: New readouts to the vessel category: Added: New readouts to the vessel category:
- Heading Rate - Heading Rate
- Pitch Rate - Pitch Rate
- Roll Rate - Roll Rate
   
Changed: Simulation to look for fuel lines that use CModuleFuelLine module. Changed: Simulation to look for fuel lines that use CModuleFuelLine module.
Fixed: Editor Overlay now loads the saved visibility value properly. Fixed: Editor Overlay now loads the saved visibility value properly.
Fixed: Altitude (Terrain) will no longer give a reading below sea level. Fixed: Altitude (Terrain) will no longer give a reading below sea level.
Fixed: Suicide burn now uses radar altitude that clamps to sea level. Fixed: Suicide burn now uses radar altitude that clamps to sea level.
   
1.0.12.0, 01-12-2014 1.0.12.0, 01-12-2014
Added: Setting in Build Engineer to enable/disable vectored thrust calculations. Added: Setting in Build Engineer to enable/disable vectored thrust calculations.
Added: Thrust torque field in Build Engineer (courtesy of mic_e). Added: Thrust torque field in Build Engineer (courtesy of mic_e).
Added: New readouts to the vessel category: Added: New readouts to the vessel category:
- Thrust Offset Angle (courtesy of mic_e) - Thrust Offset Angle (courtesy of mic_e)
- Thrust Torque (courtesy of mic_e) - Thrust Torque (courtesy of mic_e)
- Part Count: stage/total - Part Count: stage/total
- Heading - Heading
- Pitch - Pitch
- Roll - Roll
   
Added: New readouts to the surface category: Added: New readouts to the surface category:
- Situation - Situation
   
Added: New readouts to the miscellaneous category: Added: New readouts to the miscellaneous category:
- Vectored Thrust Toggle - Vectored Thrust Toggle
   
Fixed: The category selection within the section editors now do not always reset back to 'Orbital'. 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 can sometimes permanently freeze.
Fixed: Issue where the vessel simulation would not show updates when the delay was set lower than the frame rate. 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 1.0.11.3, 11-11-2014
Changed: Gravity measurements for Isp to 9.82. Changed: Gravity measurements for Isp to 9.82.
   
1.0.11.2, 10-11-2014 1.0.11.2, 10-11-2014
Changed: Gravity measurements for Isp calculations from 9.81 to 9.8066 for accuracy. Changed: Gravity measurements for Isp calculations from 9.81 to 9.8066 for accuracy.
Changed: Manoeuvre node burn times are now more accurate. 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. Fixed: Bug in the manoeuvre node burn time calculations where it was not averaging acceleration correctly.
   
1.0.11.1, 07-11-2014 1.0.11.1, 07-11-2014
Changed: Build Engineer now shows stage part count as well as total. Changed: Build Engineer now shows stage part count as well as total.
Changed: Build Overlay Vessel tab data: Changed: Build Overlay Vessel tab data:
DeltaV: stage / total DeltaV: stage / total
Mass: stage / total Mass: stage / total
TWR: start (max) <- shows for bottom stage only. TWR: start (max) <- shows for bottom stage only.
Parts: stage / total Parts: stage / total
   
Fixed: Issue with the vessel tab vanishing from the editor. Fixed: Issue with the vessel tab vanishing from the editor.
   
1.0.11.0, 06-11-2014 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/>.
// //
   
namespace KerbalEngineer namespace KerbalEngineer
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
   
/* /*
* *
* With thanks to Nathaniel R. Lewis (aka. Teknoman117) (linux.robotdude@gmail.com) for working out * With thanks to Nathaniel R. Lewis (aka. Teknoman117) (linux.robotdude@gmail.com) for working out
* the best way of getting the celestial body information dynamically using PSystemManager. * the best way of getting the celestial body information dynamically using PSystemManager.
* *
*/ */
   
public static class CelestialBodies public static class CelestialBodies
{ {
static CelestialBodies() static CelestialBodies()
{ {
try try
{ {
SystemBody = new BodyInfo(PSystemManager.Instance.localBodies.Find(b => b.referenceBody == null || b.referenceBody == b)); SystemBody = new BodyInfo(PSystemManager.Instance.localBodies.Find(b => b.referenceBody == null || b.referenceBody == b));
if (!SetSelectedBody("Kerbin")) String homeCBName = Planetarium.fetch.Home.bodyName;
  if (!SetSelectedBody(homeCBName))
{ {
SelectedBody = SystemBody; SelectedBody = SystemBody;
SelectedBody.SetSelected(true); SelectedBody.SetSelected(true);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
public static BodyInfo SelectedBody { get; private set; } public static BodyInfo SelectedBody { get; private set; }
public static BodyInfo SystemBody { get; private set; } public static BodyInfo SystemBody { get; private set; }
   
/// <summary> /// <summary>
/// Gets a body given a supplied body name. /// Gets a body given a supplied body name.
/// </summary> /// </summary>
public static BodyInfo GetBodyInfo(string bodyName) public static BodyInfo GetBodyInfo(string bodyName)
{ {
try try
{ {
return SystemBody.GetBodyInfo(bodyName); return SystemBody.GetBodyInfo(bodyName);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
return null; return null;
} }
   
/// <summary> /// <summary>
/// Sets the selected body to one matching the supplied body name. Returns true if successful. /// Sets the selected body to one matching the supplied body name. Returns true if successful.
/// </summary> /// </summary>
public static bool SetSelectedBody(string bodyName) public static bool SetSelectedBody(string bodyName)
{ {
try try
{ {
BodyInfo body = GetBodyInfo(bodyName); BodyInfo body = GetBodyInfo(bodyName);
if (body != null) if (body != null)
{ {
if (SelectedBody != null) if (SelectedBody != null)
{ {
SelectedBody.SetSelected(false); SelectedBody.SetSelected(false);
} }
SelectedBody = body; SelectedBody = body;
SelectedBody.SetSelected(true); SelectedBody.SetSelected(true);
return true; return true;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
return false; return false;
} }
   
public class BodyInfo public class BodyInfo
{ {
public BodyInfo(CelestialBody body, BodyInfo parent = null) public BodyInfo(CelestialBody body, BodyInfo parent = null)
{ {
try try
{ {
// Set the body information. // Set the body information.
CelestialBody = body; CelestialBody = body;
Name = body.bodyName; Name = body.bodyName;
Gravity = 9.81 * body.GeeASL; Gravity = 9.81 * body.GeeASL;
Parent = parent; Parent = parent;
   
// Set orbiting bodies information. // Set orbiting bodies information.
Children = new List<BodyInfo>(); Children = new List<BodyInfo>();
foreach (CelestialBody orbitingBody in body.orbitingBodies) foreach (CelestialBody orbitingBody in body.orbitingBodies)
{ {
Children.Add(new BodyInfo(orbitingBody, this)); Children.Add(new BodyInfo(orbitingBody, this));
} }
   
SelectedDepth = 0; SelectedDepth = 0;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
public CelestialBody CelestialBody { get; private set; } public CelestialBody CelestialBody { get; private set; }
public List<BodyInfo> Children { get; private set; } public List<BodyInfo> Children { get; private set; }
public double Gravity { get; private set; } public double Gravity { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public BodyInfo Parent { get; private set; } public BodyInfo Parent { get; private set; }
public bool Selected { get; private set; } public bool Selected { get; private set; }
public int SelectedDepth { get; private set; } public int SelectedDepth { get; private set; }
   
public BodyInfo GetBodyInfo(string bodyName) public BodyInfo GetBodyInfo(string bodyName)
{ {
try try
{ {
// This is the searched body. // This is the searched body.
if (String.Equals(Name, bodyName, StringComparison.CurrentCultureIgnoreCase)) if (String.Equals(Name, bodyName, StringComparison.CurrentCultureIgnoreCase))
{ {
return this; return this;
} }
   
// Check to see if any of this bodies children are the searched body. // Check to see if any of this bodies children are the searched body.
foreach (BodyInfo child in Children) foreach (BodyInfo child in Children)
{ {
BodyInfo body = child.GetBodyInfo(bodyName); BodyInfo body = child.GetBodyInfo(bodyName);
if (body != null) if (body != null)
{ {
return body; return body;
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
   
// A body with the specified name was not found. // A body with the specified name was not found.
return null; return null;
} }
   
public double GetDensity(double altitude) public double GetDensity(double altitude)
{ {
return CelestialBody.GetDensity(GetPressure(altitude), GetTemperature(altitude)); return CelestialBody.GetDensity(GetPressure(altitude), GetTemperature(altitude));
} }
   
public double GetPressure(double altitude) public double GetPressure(double altitude)
{ {
return CelestialBody.GetPressure(altitude); return CelestialBody.GetPressure(altitude);
} }
   
public double GetTemperature(double altitude) public double GetTemperature(double altitude)
{ {
return CelestialBody.GetTemperature(altitude); return CelestialBody.GetTemperature(altitude);
} }
   
public double GetAtmospheres(double altitude) public double GetAtmospheres(double altitude)
{ {
return GetPressure(altitude) * PhysicsGlobals.KpaToAtmospheres; return GetPressure(altitude) * PhysicsGlobals.KpaToAtmospheres;
} }
   
public void SetSelected(bool state, int depth = 0) public void SetSelected(bool state, int depth = 0)
{ {
Selected = state; Selected = state;
SelectedDepth = depth; SelectedDepth = depth;
if (Parent != null) if (Parent != null)
{ {
Parent.SetSelected(state, depth + 1); Parent.SetSelected(state, depth + 1);
} }
} }
   
public override string ToString() public override string ToString()
{ {
string log = "\n" + Name + string log = "\n" + Name +
"\n\tGravity: " + Gravity + "\n\tGravity: " + Gravity +
"\n\tSelected: " + Selected; "\n\tSelected: " + Selected;
   
return Children.Aggregate(log, (current, child) => current + "\n" + child); return Children.Aggregate(log, (current, child) => current + "\n" + child);
} }
} }
} }
} }
// //
// 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.Control.Panels; using KerbalEngineer.Control.Panels;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Control namespace KerbalEngineer.Control
{ {
[KSPAddon(KSPAddon.Startup.Instantly, false)] [KSPAddon(KSPAddon.Startup.Instantly, false)]
public class ControlCentre : MonoBehaviour public class ControlCentre : MonoBehaviour
{ {
#region Fields #region Fields
   
private static readonly List<IControlPanel> panels = new List<IControlPanel>(); private static readonly List<IControlPanel> panels = new List<IControlPanel>();
   
private static GUIStyle button; private static GUIStyle button;
private static ControlCentre instance; private static ControlCentre instance;
private static GUIStyle label; private static GUIStyle label;
private static GUIStyle title; private static GUIStyle title;
   
private Vector2 contentsScrollPosition; private Vector2 contentsScrollPosition;
private GUIStyle panelSelectorStyle; private GUIStyle panelSelectorStyle;
private Rect position = new Rect(Screen.width, Screen.height, 900.0f, 500.0f); private Rect position = new Rect(Screen.width, Screen.height, 900.0f, 500.0f);
private IControlPanel selectedPanel; private IControlPanel selectedPanel;
private bool shouldCentre = true; private bool shouldCentre = true;
   
#endregion #endregion
   
#region Properties #region Properties
   
public static GUIStyle Button public static GUIStyle Button
{ {
get get
{ {
return button ?? (button = new GUIStyle(HighLogic.Skin.button) return button ?? (button = new GUIStyle(HighLogic.Skin.button)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
fixedHeight = 30.0f fixedHeight = 30.0f
}); });
} }
} }
   
public static bool Enabled public static bool Enabled
{ {
get { return instance.enabled; } get { return instance.enabled; }
set { instance.enabled = value; } set { instance.enabled = value; }
} }
   
public static GUIStyle Label public static GUIStyle Label
{ {
get get
{ {
return label ?? (label = new GUIStyle(HighLogic.Skin.label) return label ?? (label = new GUIStyle(HighLogic.Skin.label)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
fixedHeight = 30.0f, fixedHeight = 30.0f,
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
stretchWidth = true, stretchWidth = true,
}); });
} }
} }
   
public static List<IControlPanel> Panels public static List<IControlPanel> Panels
{ {
get { return panels; } get { return panels; }
} }
   
public static GUIStyle Title public static GUIStyle Title
{ {
get get
{ {
return title ?? (title = new GUIStyle(HighLogic.Skin.label) return title ?? (title = new GUIStyle(HighLogic.Skin.label)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
fontSize = 26, fontSize = 26,
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
alignment = TextAnchor.UpperCenter, alignment = TextAnchor.UpperCenter,
stretchWidth = true, stretchWidth = true,
}); });
} }
} }
   
#endregion #endregion
   
#region Methods: protected #region Methods: protected
   
protected void Awake() protected void Awake()
{ {
try try
{ {
if (instance == null) if (instance == null)
{ {
DontDestroyOnLoad(this); DontDestroyOnLoad(this);
instance = this; instance = this;
this.enabled = false; this.enabled = false;
return; return;
} }
Destroy(this); Destroy(this);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void OnGUI() protected void OnGUI()
{ {
try try
{ {
GUI.skin = null; GUI.skin = null;
this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion + " - CONTROL CENTRE", HighLogic.Skin.window); this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, "KERBAL ENGINEER REDUX " + EngineerGlobals.ASSEMBLY_VERSION + " - CONTROL CENTRE", HighLogic.Skin.window);
this.CentreWindow(); this.CentreWindow();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void Start() protected void Start()
{ {
try try
{ {
this.InitialiseStyles(); this.InitialiseStyles();
LoadPanels(); LoadPanels();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion #endregion
   
#region Methods: private #region Methods: private
   
private static void LoadPanels() private static void LoadPanels()
{ {
panels.Add(new BuildEngineerPanel()); panels.Add(new BuildEngineerPanel());
panels.Add(new BuildOverlayPanel()); panels.Add(new BuildOverlayPanel());
} }
   
private void CentreWindow() private void CentreWindow()
{ {
if (this.shouldCentre && this.position.width > 0.0f && this.position.height > 0.0f) if (this.shouldCentre && this.position.width > 0.0f && this.position.height > 0.0f)
{ {
this.position.center = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f); this.position.center = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f);
this.shouldCentre = false; this.shouldCentre = false;
} }
} }
   
private void DrawContents() private void DrawContents()
{ {
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
this.contentsScrollPosition = GUILayout.BeginScrollView(this.contentsScrollPosition, false, true); this.contentsScrollPosition = GUILayout.BeginScrollView(this.contentsScrollPosition, false, true);
GUI.skin = null; GUI.skin = null;
   
if (this.selectedPanel != null) if (this.selectedPanel != null)
{ {
this.selectedPanel.Draw(); this.selectedPanel.Draw();
} }
   
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUILayout.EndScrollView(); GUILayout.EndScrollView();
} }
   
private void DrawSelectors() private void DrawSelectors()
{ {
GUILayout.BeginVertical(HighLogic.Skin.box, GUILayout.Width(225.0f)); GUILayout.BeginVertical(HighLogic.Skin.box, GUILayout.Width(225.0f));
foreach (var panel in panels) foreach (var panel in panels)
{ {
if (GUILayout.Toggle(this.selectedPanel == panel, panel.Name, this.panelSelectorStyle)) if (GUILayout.Toggle(this.selectedPanel == panel, panel.Name, this.panelSelectorStyle))
{ {
this.selectedPanel = panel; this.selectedPanel = panel;
} }
} }
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
if (GUILayout.Button("CLOSE", Button)) if (GUILayout.Button("CLOSE", Button))
{ {
this.enabled = false; this.enabled = false;
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
private void InitialiseStyles() private void InitialiseStyles()
{ {
this.panelSelectorStyle = new GUIStyle(Button) this.panelSelectorStyle = new GUIStyle(Button)
{ {
fontSize = 16, fontSize = 16,
fixedHeight = 40.0f fixedHeight = 40.0f
}; };
} }
   
private void Window(int windowId) private void Window(int windowId)
{ {
try try
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
this.DrawSelectors(); this.DrawSelectors();
this.DrawContents(); this.DrawContents();
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/>.
// //
   
namespace KerbalEngineer.Editor namespace KerbalEngineer.Editor
{ {
#region Using Directives #region Using Directives
using System; using System;
using Extensions; using Extensions;
using Flight; using Flight;
using Helpers; using Helpers;
using Settings; using Settings;
using UIControls; using UIControls;
using UnityEngine; using UnityEngine;
using VesselSimulator; using VesselSimulator;
   
#endregion #endregion
   
[KSPAddon(KSPAddon.Startup.EditorAny, false)] [KSPAddon(KSPAddon.Startup.EditorAny, false)]
public class BuildAdvanced : MonoBehaviour public class BuildAdvanced : MonoBehaviour
{ {
#region Fields #region Fields
public static float Altitude = 0.0f; public static float Altitude = 0.0f;
   
private GUIStyle areaSettingStyle; private GUIStyle areaSettingStyle;
private GUIStyle areaStyle; private GUIStyle areaStyle;
private float atmosphericMach; private float atmosphericMach;
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 float maxMach; private float maxMach;
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 get
{ {
return compactMode; return compactMode;
} }
set set
{ {
compactMode = value; 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 get
{ {
return showAllStages; return showAllStages;
} }
set set
{ {
showAllStages = value; 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 get
{ {
return showAtmosphericDetails; return showAtmosphericDetails;
} }
set set
{ {
showAtmosphericDetails = value; 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 get
{ {
return showSettings; return showSettings;
} }
set set
{ {
showSettings = value; 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 get
{ {
return visible; return visible;
} }
set set
{ {
visible = value; visible = value;
} }
} }
#endregion #endregion
   
#region Methods #region Methods
private static Rect compactModeRect = new Rect(0.0f, 5.0f, 0.0f, 20.0f); private static Rect compactModeRect = new Rect(0.0f, 5.0f, 0.0f, 20.0f);
private static Stage stage; private static Stage stage;
private static int stagesCount; private static int stagesCount;
private static int stagesLength; private static int stagesLength;
private static string title; private static string title;
   
protected void Awake() protected void Awake()
{ {
try try
{ {
Instance = this; Instance = this;
bodiesList = gameObject.AddComponent<DropDown>(); bodiesList = gameObject.AddComponent<DropDown>();
bodiesList.DrawCallback = DrawBodiesList; bodiesList.DrawCallback = DrawBodiesList;
Load(); Load();
   
SimManager.UpdateModSettings(); SimManager.UpdateModSettings();
SimManager.OnReady -= GetStageInfo; SimManager.OnReady -= GetStageInfo;
SimManager.OnReady += GetStageInfo; SimManager.OnReady += GetStageInfo;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced.Awake()"); Logger.Exception(ex, "BuildAdvanced.Awake()");
} }
} }
   
/// <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
{ {
SettingHandler handler = new SettingHandler(); SettingHandler handler = new SettingHandler();
handler.Set("visible", visible); handler.Set("visible", visible);
handler.Set("windowPositionX", position.x); handler.Set("windowPositionX", position.x);
handler.Set("windowPositionY", position.y); handler.Set("windowPositionY", position.y);
handler.Set("compactMode", compactMode); handler.Set("compactMode", compactMode);
handler.Set("compactCollapseRight", compactCollapseRight); handler.Set("compactCollapseRight", compactCollapseRight);
handler.Set("showAllStages", showAllStages); handler.Set("showAllStages", showAllStages);
handler.Set("showAtmosphericDetails", showAtmosphericDetails); handler.Set("showAtmosphericDetails", showAtmosphericDetails);
handler.Set("showSettings", showSettings); handler.Set("showSettings", showSettings);
handler.Set("selectedBodyName", CelestialBodies.SelectedBody.Name); handler.Set("selectedBodyName", CelestialBodies.SelectedBody.Name);
handler.Save("BuildAdvanced.xml"); handler.Save("BuildAdvanced.xml");
GuiDisplaySize.OnSizeChanged -= OnSizeChanged; GuiDisplaySize.OnSizeChanged -= OnSizeChanged;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced.OnDestroy()"); Logger.Exception(ex, "BuildAdvanced.OnDestroy()");
} }
} }
   
protected void OnGUI() protected void OnGUI()
{ {
try try
{ {
if (!visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0 || EditorLogic.fetch.editorScreen != EditorScreen.Parts) if (!visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0 || EditorLogic.fetch.editorScreen != EditorScreen.Parts)
{ {
return; return;
} }
   
if (stages == null) if (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.
title = !compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion : "K.E.R. " + EngineerGlobals.AssemblyVersion + (showAtmosphericDetails ? " (ATMOS.)" : String.Empty); title = !compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.ASSEMBLY_VERSION : "K.E.R. " + EngineerGlobals.ASSEMBLY_VERSION;
   
// Reset the window size when the staging or something else has changed. // Reset the window size when the staging or something else has changed.
stagesLength = stages.Length; stagesLength = stages.Length;
if (showAllStages) if (showAllStages)
{ {
stagesCount = stagesLength; stagesCount = stagesLength;
} }
if (showAllStages == false) if (showAllStages == false)
{ {
stagesCount = 0; stagesCount = 0;
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
if (stages[i].deltaV > 0.0f) if (stages[i].deltaV > 0.0f)
{ {
stagesCount = stagesCount + 1; stagesCount = stagesCount + 1;
} }
} }
} }
   
if (hasChanged || stagesCount != numberOfStages) if (hasChanged || stagesCount != numberOfStages)
{ {
hasChanged = false; hasChanged = false;
numberOfStages = stagesCount; numberOfStages = stagesCount;
   
position.width = 0; position.width = 0;
position.height = 0; position.height = 0;
} }
   
GUI.skin = null; GUI.skin = null;
position = GUILayout.Window(GetInstanceID(), position, Window, title, windowStyle).ClampToScreen(); position = GUILayout.Window(GetInstanceID(), position, Window, title, windowStyle).ClampToScreen();
   
if (compactCheck > 0 && compactCollapseRight) if (compactCheck > 0 && compactCollapseRight)
{ {
position.x = compactRight - position.width; position.x = compactRight - position.width;
compactCheck--; compactCheck--;
} }
else if (compactCheck > 0) else if (compactCheck > 0)
{ {
compactCheck = 0; compactCheck = 0;
} }
   
// Check editor lock to manage click-through. // Check editor lock to manage click-through.
CheckEditorLock(); CheckEditorLock();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced.OnGUI()"); Logger.Exception(ex, "BuildAdvanced.OnGUI()");
} }
} }
   
protected void Start() protected void Start()
{ {
try try
{ {
InitialiseStyles(); InitialiseStyles();
GuiDisplaySize.OnSizeChanged += OnSizeChanged; GuiDisplaySize.OnSizeChanged += OnSizeChanged;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced.Start()"); Logger.Exception(ex, "BuildAdvanced.Start()");
} }
} }
   
protected void Update() protected void Update()
{ {
try try
{ {
if (Input.GetKeyDown(KeyBinder.EditorShowHide)) if (Input.GetKeyDown(KeyBinder.EditorShowHide))
{ {
visible = !visible; visible = !visible;
if (!visible) if (!visible)
{ {
EditorLock(false); EditorLock(false);
} }
} }
   
if (!visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0) if (!visible || EditorLogic.fetch == null || EditorLogic.fetch.ship.parts.Count == 0)
{ {
bodiesList.enabled = false; 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 (showAtmosphericDetails) if (showAtmosphericDetails)
{ {
SimManager.Atmosphere = CelestialBodies.SelectedBody.GetAtmospheres(Altitude); SimManager.Atmosphere = CelestialBodies.SelectedBody.GetAtmospheres(Altitude);
} }
else else
{ {
SimManager.Atmosphere = 0; SimManager.Atmosphere = 0;
} }
   
SimManager.Mach = atmosphericMach; SimManager.Mach = atmosphericMach;
   
SimManager.RequestSimulation(); SimManager.RequestSimulation();
SimManager.TryStartSimulation(); SimManager.TryStartSimulation();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced.Update()"); Logger.Exception(ex, "BuildAdvanced.Update()");
} }
} }
   
/// <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 ((position.MouseIsOver() || bodiesList.Position.MouseIsOver()) && !isEditorLocked) if ((position.MouseIsOver() || bodiesList.Position.MouseIsOver()) && !isEditorLocked)
{ {
EditorLock(true); EditorLock(true);
} }
else if (!position.MouseIsOver() && !bodiesList.Position.MouseIsOver() && isEditorLocked) else if (!position.MouseIsOver() && !bodiesList.Position.MouseIsOver() && isEditorLocked)
{ {
EditorLock(false); EditorLock(false);
} }
} }
   
/// <summary> /// <summary>
/// Draws the atmospheric settings. /// Draws the atmospheric settings.
/// </summary> /// </summary>
private void DrawAtmosphericDetails() private void DrawAtmosphericDetails()
{ {
try try
{ {
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.BeginVertical(); GUILayout.BeginVertical();
GUILayout.Label("Altitude: " + (Altitude * 0.001f).ToString("F1") + "km", settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset)); GUILayout.Label("Altitude: " + (Altitude * 0.001f).ToString("F1") + "km", settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
Altitude = GUILayout.HorizontalSlider(Altitude, 0.0f, (float)(CelestialBodies.SelectedBody.CelestialBody.atmosphereDepth)); Altitude = GUILayout.HorizontalSlider(Altitude, 0.0f, (float)(CelestialBodies.SelectedBody.CelestialBody.atmosphereDepth));
GUI.skin = null; GUI.skin = null;
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.Space(5.0f); GUILayout.Space(5.0f);
   
GUILayout.BeginVertical(); GUILayout.BeginVertical();
GUILayout.Label("Mach: " + atmosphericMach.ToString("F1"), settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset)); GUILayout.Label("Mach: " + atmosphericMach.ToString("F2"), settingAtmoStyle, GUILayout.Width(125.0f * GuiDisplaySize.Offset));
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
atmosphericMach = GUILayout.HorizontalSlider(Mathf.Clamp(atmosphericMach, 0.0f, maxMach), 0.0f, maxMach); atmosphericMach = GUILayout.HorizontalSlider(Mathf.Clamp(atmosphericMach, 0.0f, maxMach), 0.0f, maxMach);
GUI.skin = null; GUI.skin = null;
GUILayout.EndVertical(); GUILayout.EndVertical();
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced.DrawAtmosphericDetails()"); Logger.Exception(ex, "BuildAdvanced.DrawAtmosphericDetails()");
} }
} }
   
private void DrawBodiesList() private void DrawBodiesList()
{ {
if (CelestialBodies.SystemBody == CelestialBodies.SelectedBody) if (CelestialBodies.SystemBody == CelestialBodies.SelectedBody)
{ {
DrawBody(CelestialBodies.SystemBody); DrawBody(CelestialBodies.SystemBody);
} }
else else
{ {
foreach (CelestialBodies.BodyInfo body in CelestialBodies.SystemBody.Children) foreach (CelestialBodies.BodyInfo body in CelestialBodies.SystemBody.Children)
{ {
DrawBody(body); 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 ? bodiesButtonActiveStyle : bodiesButtonStyle)) if (GUILayout.Button(bodyInfo.Children.Count > 0 ? bodyInfo.Name + " [" + bodyInfo.Children.Count + "]" : bodyInfo.Name, bodyInfo.Selected && bodyInfo.SelectedDepth == 0 ? bodiesButtonActiveStyle : bodiesButtonStyle))
{ {
CelestialBodies.SetSelectedBody(bodyInfo.Name); CelestialBodies.SetSelectedBody(bodyInfo.Name);
Altitude = 0.0f; Altitude = 0.0f;
bodiesList.Resize = true; bodiesList.Resize = true;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (bodyInfo.Selected) if (bodyInfo.Selected)
{ {
for (int i = 0; i < bodyInfo.Children.Count; ++i) for (int i = 0; i < bodyInfo.Children.Count; ++i)
{ {
DrawBody(bodyInfo.Children[i], depth + 1); DrawBody(bodyInfo.Children[i], 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", titleStyle); GUILayout.Label("BURN", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(TimeFormatter.ConvertToString(stage.time), infoStyle); GUILayout.Label(TimeFormatter.ConvertToString(stage.time), 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", titleStyle); GUILayout.Label("COST", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(Units.Cost(stage.cost, stage.totalCost), infoStyle); GUILayout.Label(Units.Cost(stage.cost, stage.totalCost), 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", titleStyle); GUILayout.Label("DELTA-V", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(stage.deltaV.ToString("N0") + " / " + stage.inverseTotalDeltaV.ToString("N0") + "m/s", infoStyle); GUILayout.Label(stage.deltaV.ToString("N0") + " / " + stage.inverseTotalDeltaV.ToString("N0") + "m/s", 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", titleStyle); GUILayout.Label("ISP", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(stage.isp.ToString("F1") + "s", infoStyle); GUILayout.Label(stage.isp.ToString("F1") + "s", 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", titleStyle); GUILayout.Label("MASS", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(Units.ToMass(stage.mass, stage.totalMass), infoStyle); GUILayout.Label(Units.ToMass(stage.mass, stage.totalMass), 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", titleStyle); GUILayout.Label("PARTS", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(stage.partCount + " / " + stage.totalPartCount, infoStyle); GUILayout.Label(stage.partCount + " / " + stage.totalPartCount, 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:", settingStyle); GUILayout.Label("Compact mode collapses to the:", settingStyle);
compactCollapseRight = !GUILayout.Toggle(!compactCollapseRight, "LEFT", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); compactCollapseRight = !GUILayout.Toggle(!compactCollapseRight, "LEFT", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
compactCollapseRight = GUILayout.Toggle(compactCollapseRight, "RIGHT", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); compactCollapseRight = GUILayout.Toggle(compactCollapseRight, "RIGHT", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Simulate using vectored thrust values:"); GUILayout.Label("Simulate using vectored thrust values:", settingStyle);
SimManager.vectoredThrust = GUILayout.Toggle(SimManager.vectoredThrust, "ENABLED", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); SimManager.vectoredThrust = GUILayout.Toggle(SimManager.vectoredThrust, "ENABLED", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
  GUILayout.EndHorizontal();
   
  GUILayout.BeginHorizontal();
  GUILayout.Label("Verbose Simulation Log:", settingStyle);
  SimManager.logOutput = GUILayout.Toggle(SimManager.logOutput, "ENABLED", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Build Engineer Overlay:", settingStyle); GUILayout.Label("Build Engineer Overlay:", settingStyle);
BuildOverlay.Visible = GUILayout.Toggle(BuildOverlay.Visible, "VISIBLE", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); BuildOverlay.Visible = GUILayout.Toggle(BuildOverlay.Visible, "VISIBLE", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
BuildOverlayPartInfo.NamesOnly = GUILayout.Toggle(BuildOverlayPartInfo.NamesOnly, "NAMES ONLY", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); BuildOverlayPartInfo.NamesOnly = GUILayout.Toggle(BuildOverlayPartInfo.NamesOnly, "NAMES ONLY", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
BuildOverlayPartInfo.ClickToOpen = GUILayout.Toggle(BuildOverlayPartInfo.ClickToOpen, "CLICK TO OPEN", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); BuildOverlayPartInfo.ClickToOpen = GUILayout.Toggle(BuildOverlayPartInfo.ClickToOpen, "CLICK TO OPEN", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Flight Engineer activation mode:", settingStyle); GUILayout.Label("Flight Engineer activation mode:", settingStyle);
FlightEngineerCore.IsCareerMode = GUILayout.Toggle(FlightEngineerCore.IsCareerMode, "CAREER", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); FlightEngineerCore.IsCareerMode = GUILayout.Toggle(FlightEngineerCore.IsCareerMode, "CAREER", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
FlightEngineerCore.IsCareerMode = !GUILayout.Toggle(!FlightEngineerCore.IsCareerMode, "PARTLESS", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); FlightEngineerCore.IsCareerMode = !GUILayout.Toggle(!FlightEngineerCore.IsCareerMode, "PARTLESS", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Flight Engineer Career Limitations:", settingStyle); GUILayout.Label("Flight Engineer Career Limitations:", settingStyle);
FlightEngineerCore.IsKerbalLimited = GUILayout.Toggle(FlightEngineerCore.IsKerbalLimited, "KERBAL", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); FlightEngineerCore.IsKerbalLimited = GUILayout.Toggle(FlightEngineerCore.IsKerbalLimited, "KERBAL", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
FlightEngineerCore.IsTrackingStationLimited = GUILayout.Toggle(FlightEngineerCore.IsTrackingStationLimited, "TRACKING", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)); FlightEngineerCore.IsTrackingStationLimited = GUILayout.Toggle(FlightEngineerCore.IsTrackingStationLimited, "TRACKING", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("GUI Size: " + GuiDisplaySize.Increment, settingStyle); GUILayout.Label("GUI Size: " + GuiDisplaySize.Increment, settingStyle);
if (GUILayout.Button("<", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset))) if (GUILayout.Button("<", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)))
{ {
GuiDisplaySize.Increment--; GuiDisplaySize.Increment--;
} }
if (GUILayout.Button(">", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset))) if (GUILayout.Button(">", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset)))
{ {
GuiDisplaySize.Increment++; GuiDisplaySize.Increment++;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.Milliseconds + "ms", settingStyle); GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.TotalMilliseconds + "ms", settingStyle);
GUI.skin = HighLogic.Skin; GUI.skin = HighLogic.Skin;
SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 2000.0f)); SimManager.minSimTime = TimeSpan.FromMilliseconds(GUILayout.HorizontalSlider((float)SimManager.minSimTime.TotalMilliseconds, 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, titleStyle); GUILayout.Label(string.Empty, titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label("S" + stage.number, titleStyle); GUILayout.Label("S" + stage.number, 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", titleStyle); GUILayout.Label("THRUST", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(stage.thrust.ToForce(), infoStyle); GUILayout.Label(stage.thrust.ToForce(), infoStyle);
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
/// <summary> /// <summary>
/// Draws the torque column. /// Draws the torque column.
/// </summary> /// </summary>
private void DrawTorque() private void DrawTorque()
{ {
GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset)); GUILayout.BeginVertical(GUILayout.Width(75.0f * GuiDisplaySize.Offset));
GUILayout.Label("TORQUE", titleStyle); GUILayout.Label("TORQUE", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(stage.maxThrustTorque.ToTorque(), infoStyle); GUILayout.Label(stage.maxThrustTorque.ToTorque(), 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)", titleStyle); GUILayout.Label("TWR (MAX)", titleStyle);
for (int i = 0; i < stagesLength; ++i) for (int i = 0; i < stagesLength; ++i)
{ {
stage = stages[i]; stage = stages[i];
if (showAllStages || stage.deltaV > 0.0) if (showAllStages || stage.deltaV > 0.0)
{ {
GUILayout.Label(stage.thrustToWeight.ToString("F2") + " (" + stage.maxThrustToWeight.ToString("F2") + ")", infoStyle); GUILayout.Label(stage.thrustToWeight.ToString("F2") + " (" + stage.maxThrustToWeight.ToString("F2") + ")", 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"); InputLockManager.SetControlLock(ControlTypes.All, "KER_BuildAdvanced");
BuildOverlayPartInfo.Hidden = true; BuildOverlayPartInfo.Hidden = true;
isEditorLocked = true; isEditorLocked = true;
} }
else else
{ {
EditorLogic.fetch.Unlock("KER_BuildAdvanced"); InputLockManager.SetControlLock(ControlTypes.None, "KER_BuildAdvanced");
BuildOverlayPartInfo.Hidden = false; BuildOverlayPartInfo.Hidden = false;
isEditorLocked = false; isEditorLocked = false;
} }
} }
   
private void GetStageInfo() private void GetStageInfo()
{ {
stages = SimManager.Stages; stages = SimManager.Stages;
if (stages != null && stages.Length > 0) if (stages != null && stages.Length > 0)
{ {
maxMach = stages[stages.Length - 1].maxMach; maxMach = stages[stages.Length - 1].maxMach;
} }
} }
   
/// <summary> /// <summary>
/// Initialises all the styles that are required. /// Initialises all the styles that are required.
/// </summary> /// </summary>
private void InitialiseStyles() private void InitialiseStyles()
{ {
windowStyle = new GUIStyle(HighLogic.Skin.window) windowStyle = new GUIStyle(HighLogic.Skin.window)
{ {
alignment = TextAnchor.UpperLeft alignment = TextAnchor.UpperLeft
}; };
   
areaStyle = new GUIStyle(HighLogic.Skin.box) areaStyle = new GUIStyle(HighLogic.Skin.box)
{ {
padding = new RectOffset(0, 0, 9, 0) padding = new RectOffset(0, 0, 9, 0)
}; };
   
areaSettingStyle = new GUIStyle(HighLogic.Skin.box) areaSettingStyle = new GUIStyle(HighLogic.Skin.box)
{ {
padding = new RectOffset(10, 10, 10, 10) padding = new RectOffset(10, 10, 10, 10)
}; };
   
buttonStyle = new GUIStyle(HighLogic.Skin.button) 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
}; };
   
titleStyle = new GUIStyle(HighLogic.Skin.label) 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,
}; };
   
infoStyle = new GUIStyle(HighLogic.Skin.label) 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
}; };
   
settingStyle = new GUIStyle(titleStyle) settingStyle = new GUIStyle(titleStyle)
{ {
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
stretchWidth = true, stretchWidth = true,
stretchHeight = true stretchHeight = true
}; };
   
settingAtmoStyle = new GUIStyle(titleStyle) settingAtmoStyle = new GUIStyle(titleStyle)
{ {
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(), padding = new RectOffset(),
alignment = TextAnchor.UpperLeft alignment = TextAnchor.UpperLeft
}; };
   
bodiesButtonStyle = new GUIStyle(HighLogic.Skin.button) 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
}; };
   
bodiesButtonActiveStyle = new GUIStyle(bodiesButtonStyle) bodiesButtonActiveStyle = new GUIStyle(bodiesButtonStyle)
{ {
normal = bodiesButtonStyle.onNormal, normal = bodiesButtonStyle.onNormal,
hover = bodiesButtonStyle.onHover hover = 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
{ {
SettingHandler handler = SettingHandler.Load("BuildAdvanced.xml"); SettingHandler handler = SettingHandler.Load("BuildAdvanced.xml");
handler.Get("visible", ref visible); handler.Get("visible", ref visible);
position.x = handler.Get("windowPositionX", position.x); position.x = handler.Get("windowPositionX", position.x);
position.y = handler.Get("windowPositionY", position.y); position.y = handler.Get("windowPositionY", position.y);
handler.Get("compactMode", ref compactMode); handler.Get("compactMode", ref compactMode);
handler.Get("compactCollapseRight", ref compactCollapseRight); handler.Get("compactCollapseRight", ref compactCollapseRight);
handler.Get("showAllStages", ref showAllStages); handler.Get("showAllStages", ref showAllStages);
handler.Get("showAtmosphericDetails", ref showAtmosphericDetails); handler.Get("showAtmosphericDetails", ref showAtmosphericDetails);
handler.Get("showSettings", ref showSettings); handler.Get("showSettings", ref 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()
{ {
InitialiseStyles(); InitialiseStyles();
hasChanged = true; 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
{ {
compactModeRect = new Rect(position.width - 70.0f * GuiDisplaySize.Offset, 5.0f, 65.0f * GuiDisplaySize.Offset, 20.0f); compactModeRect = new Rect(position.width - 70.0f * GuiDisplaySize.Offset, 5.0f, 65.0f * GuiDisplaySize.Offset, 20.0f);
   
// Draw the compact mode toggle. // Draw the compact mode toggle.
if (GUI.Toggle(compactModeRect, compactMode, "COMPACT", buttonStyle) != compactMode) if (GUI.Toggle(compactModeRect, compactMode, "COMPACT", buttonStyle) != compactMode)
{ {
hasChanged = true; hasChanged = true;
compactCheck = 2; compactCheck = 2;
compactRight = position.xMax; compactRight = position.xMax;
compactMode = !compactMode; compactMode = !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 (!compactMode) if (!compactMode)
{ {
if (GUI.Toggle(new Rect(position.width - 143.0f * GuiDisplaySize.Offset, 5.0f, 70.0f * GuiDisplaySize.Offset, 20.0f), showSettings, "SETTINGS", buttonStyle) != showSettings) if (GUI.Toggle(new Rect(position.width - 143.0f * GuiDisplaySize.Offset, 5.0f, 70.0f * GuiDisplaySize.Offset, 20.0f), showSettings, "SETTINGS", buttonStyle) != showSettings)
{ {
hasChanged = true; hasChanged = true;
showSettings = !showSettings; showSettings = !showSettings;
} }
   
if (GUI.Toggle(new Rect(position.width - 226.0f * GuiDisplaySize.Offset, 5.0f, 80.0f * GuiDisplaySize.Offset, 20.0f), showAllStages, "ALL STAGES", buttonStyle) != showAllStages) if (GUI.Toggle(new Rect(position.width - 226.0f * GuiDisplaySize.Offset, 5.0f, 80.0f * GuiDisplaySize.Offset, 20.0f), showAllStages, "ALL STAGES", buttonStyle) != showAllStages)
{ {
hasChanged = true; hasChanged = true;
showAllStages = !showAllStages; showAllStages = !showAllStages;
} }
   
if (GUI.Toggle(new Rect(position.width - 324.0f * GuiDisplaySize.Offset, 5.0f, 95.0f * GuiDisplaySize.Offset, 20.0f), showAtmosphericDetails, "ATMOSPHERIC", buttonStyle) != showAtmosphericDetails) if (GUI.Toggle(new Rect(position.width - 324.0f * GuiDisplaySize.Offset, 5.0f, 95.0f * GuiDisplaySize.Offset, 20.0f), showAtmosphericDetails, "ATMOSPHERIC", buttonStyle) != showAtmosphericDetails)
{ {
hasChanged = true; hasChanged = true;
showAtmosphericDetails = !showAtmosphericDetails; showAtmosphericDetails = !showAtmosphericDetails;
} }
   
bodiesListPosition = new Rect(position.width - 452.0f * GuiDisplaySize.Offset, 5.0f, 125.0f * GuiDisplaySize.Offset, 20.0f); bodiesListPosition = new Rect(position.width - 452.0f * GuiDisplaySize.Offset, 5.0f, 125.0f * GuiDisplaySize.Offset, 20.0f);
bodiesList.enabled = GUI.Toggle(bodiesListPosition, bodiesList.enabled, "BODY: " + CelestialBodies.SelectedBody.Name.ToUpper(), buttonStyle); bodiesList.enabled = GUI.Toggle(bodiesListPosition, bodiesList.enabled, "BODY: " + CelestialBodies.SelectedBody.Name.ToUpper(), buttonStyle);
bodiesList.SetPosition(bodiesListPosition.Translate(position)); bodiesList.SetPosition(bodiesListPosition.Translate(position));
  }
  else
  {
  if (GUI.Toggle(new Rect(position.width - 133.0f * GuiDisplaySize.Offset, 5.0f, 60.0f * GuiDisplaySize.Offset, 20.0f), showAtmosphericDetails, "ATMO", buttonStyle) != showAtmosphericDetails)
  {
  hasChanged = true;
  showAtmosphericDetails = !showAtmosphericDetails;
  }
} }
   
// Draw the main informational display box. // Draw the main informational display box.
if (!compactMode) if (!compactMode)
{ {
GUILayout.BeginHorizontal(areaStyle); GUILayout.BeginHorizontal(areaStyle);
DrawStageNumbers(); DrawStageNumbers();
DrawPartCount(); DrawPartCount();
DrawCost(); DrawCost();
DrawMass(); DrawMass();
DrawIsp(); DrawIsp();
DrawThrust(); DrawThrust();
DrawTorque(); DrawTorque();
DrawTwr(); DrawTwr();
DrawDeltaV(); DrawDeltaV();
DrawBurnTime(); DrawBurnTime();
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (showAtmosphericDetails) if (showAtmosphericDetails && !compactMode)
{ {
GUILayout.BeginVertical(areaSettingStyle); GUILayout.BeginVertical(areaSettingStyle);
DrawAtmosphericDetails(); DrawAtmosphericDetails();
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
   
if (showSettings) if (showSettings)
{ {
GUILayout.BeginVertical(areaSettingStyle); GUILayout.BeginVertical(areaSettingStyle);
DrawSettings(); 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(areaStyle); GUILayout.BeginHorizontal(areaStyle);
DrawStageNumbers(); DrawStageNumbers();
DrawTwr(); DrawTwr();
DrawDeltaV(); DrawDeltaV();
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
GUI.DragWindow(); GUI.DragWindow();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "BuildAdvanced.Window()"); Logger.Exception(ex, "BuildAdvanced.Window()");
} }
} }
#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/>.
// //
   
namespace KerbalEngineer.Editor namespace KerbalEngineer.Editor
{ {
  using System.Collections.Generic;
using VesselSimulator; using VesselSimulator;
   
public class PartInfoItem : Pool<PartInfoItem> public class PartInfoItem
{ {
  private static readonly Pool<PartInfoItem> pool = new Pool<PartInfoItem>(Create, Reset);
   
public string Name { get; set; } public string Name { get; set; }
   
public string Value { get; set; } public string Value { get; set; }
   
  private static PartInfoItem Create()
  {
  return new PartInfoItem();
  }
   
  public void Release()
  {
  pool.Release(this);
  }
   
  public static void Release(List<PartInfoItem> objList)
  {
  for (int i = 0; i < objList.Count; ++i)
  {
  objList[i].Release();
  }
  }
   
  private static void Reset(PartInfoItem obj)
  {
  obj.Name = string.Empty;
  obj.Value = string.Empty;
  }
   
public static PartInfoItem Create(string name) public static PartInfoItem Create(string name)
{ {
return GetPoolObject().Initialise(name); return New(name);
} }
   
public static PartInfoItem Create(string name, string value) public static PartInfoItem Create(string name, string value)
{ {
return GetPoolObject().Initialise(name, value); return New(name, value);
} }
   
public PartInfoItem Initialise(string name) public static PartInfoItem New(string name)
{ {
Name = name; PartInfoItem obj = pool.Borrow();
Value = string.Empty;  
  obj.Name = name;
  obj.Value = string.Empty;
   
return this; return obj;
} }
   
public PartInfoItem Initialise(string name, string value) public static PartInfoItem New(string name, string value)
{ {
Name = name; PartInfoItem obj = pool.Borrow();
Value = value;  
   
return this; obj.Name = name;
  obj.Value = value;
   
  return obj;
} }
} }
} }
// //
// Kerbal Engineer Redux // Copyright (C) 2015 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.IO;  
using System.Reflection;  
   
#endregion  
   
namespace KerbalEngineer namespace KerbalEngineer
{ {
public class EngineerGlobals using System.IO;
  using System.Reflection;
   
  public static class EngineerGlobals
{ {
#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.16.4"; public const string ASSEMBLY_VERSION = "1.0.18.0";
   
#endregion  
   
#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  
   
#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  
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2015 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 KerbalEngineer.Helpers;  
   
#endregion  
   
namespace KerbalEngineer.Extensions namespace KerbalEngineer.Extensions
{ {
  using Helpers;
   
public static class DoubleExtensions public static class DoubleExtensions
{ {
#region Methods: public  
   
public static double Clamp(this double value, double lower, double higher) public static double Clamp(this double value, double lower, double higher)
{ {
return value < lower ? lower : value > higher ? higher : value; 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) public static string ToFlux(this double value)
{ {
return Units.ToTorque(value); return Units.ToFlux(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 ToMach(this double value)
  {
  return Units.ToMach(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 public static string ToTemperature(this double value)
  {
  return Units.ToTemperature(value);
  }
   
  public static string ToTorque(this double value)
  {
  return Units.ToTorque(value);
  }
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2015 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 KerbalEngineer.Helpers;  
   
#endregion  
   
namespace KerbalEngineer.Extensions namespace KerbalEngineer.Extensions
{ {
  using Helpers;
   
public static class FloatExtensions public static class FloatExtensions
{ {
#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 ToFlux(this float value)
  {
  return Units.ToFlux(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) public static string ToMach(this float value)
{ {
return Units.ToTorque(value); return Units.ToMach(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 public static string ToTemperature(this float value)
  {
  return Units.ToTemperature(value);
  }
   
  public static string ToTorque(this float value)
  {
  return Units.ToTorque(value);
  }
} }
} }
// //
// 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/>.
// //
   
namespace KerbalEngineer.Extensions namespace KerbalEngineer.Extensions
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using CompoundParts; using CompoundParts;
   
public static class PartExtensions public static class PartExtensions
{ {
private static Part cachePart; //private static Part cachePart;
private static PartModule cachePartModule; //private static PartModule cachePartModule;
private static PartResource cachePartResource; //private static PartResource cachePartResource;
   
/// <summary> /// <summary>
/// Gets whether the part contains a specific resource. /// Gets whether the part contains a specific resource.
/// </summary> /// </summary>
public static bool ContainsResource(this Part part, int resourceId) public static bool ContainsResource(this Part part, int resourceId)
{ {
return part.Resources.Contains(resourceId); return part.Resources.Contains(resourceId);
} }
   
/// <summary> /// <summary>
/// Gets whether the part contains resources. /// Gets whether the part contains resources.
/// </summary> /// </summary>
public static bool ContainsResources(this Part part) public static bool ContainsResources(this Part part)
{ {
for (int i = 0; i < part.Resources.list.Count; ++i) for (int i = 0; i < part.Resources.list.Count; ++i)
{ {
if (part.Resources.list[i].amount > 0.0) if (part.Resources.list[i].amount > 0.0)
{ {
return true; return true;
} }
} }
return false; return false;
} }
   
/// <summary> /// <summary>
/// Gets whether the part has fuel. /// Gets whether the part has fuel.
/// </summary> /// </summary>
  /* not used
public static bool EngineHasFuel(this Part part) public static bool EngineHasFuel(this Part part)
{ {
cachePartModule = GetModule<ModuleEngines>(part); PartModule cachePartModule = GetModule<ModuleEngines>(part);
if (cachePartModule != null) if (cachePartModule != null)
{ {
return (cachePartModule as ModuleEngines).getFlameoutState; return (cachePartModule as ModuleEngines).getFlameoutState;
} }
   
cachePartModule = GetModuleMultiModeEngine(part); cachePartModule = GetModuleMultiModeEngine(part);
if (cachePartModule != null) if (cachePartModule != null)
{ {
return (cachePartModule as ModuleEnginesFX).getFlameoutState; return (cachePartModule as ModuleEnginesFX).getFlameoutState;
} }
   
return false; return false;
} }
  */
/// <summary> /// <summary>
/// Gets the cost of the part excluding resources. /// Gets the cost of the part excluding resources.
/// </summary> /// </summary>
public static double GetCostDry(this Part part) public static double GetCostDry(this Part part)
{ {
return part.partInfo.cost - GetResourceCostMax(part) + part.GetModuleCosts(0.0f); return part.partInfo.cost - GetResourceCostMax(part) + part.GetModuleCosts(0.0f);
} }
   
/// <summary> /// <summary>
/// Gets the cost of the part including maximum resources. /// Gets the cost of the part including maximum resources.
/// </summary> /// </summary>
public static double GetCostMax(this Part part) public static double GetCostMax(this Part part)
{ {
return part.partInfo.cost + part.GetModuleCosts(0.0f); return part.partInfo.cost + part.GetModuleCosts(0.0f);
} }
   
/// <summary> /// <summary>
  /// Gets the cost of the part modules
  /// Same as stock but without mem allocation
  /// </summary>
  public static double GetModuleCostsNoAlloc(this Part part, float defaultCost)
  {
  float cost = 0f;
  for (int i = 0; i < part.Modules.Count; i++)
  {
  PartModule pm = part.Modules[i];
  if (pm is IPartCostModifier)
  cost += (pm as IPartCostModifier).GetModuleCost(defaultCost);
  }
  return cost;
  }
   
  /// <summary>
/// Gets the cost of the part including resources. /// Gets the cost of the part including resources.
/// </summary> /// </summary>
public static double GetCostWet(this Part part) public static double GetCostWet(this Part part)
{ {
return part.partInfo.cost - GetResourceCostInverted(part) + part.GetModuleCosts(0.0f); return part.partInfo.cost - GetResourceCostInverted(part) + part.GetModuleCostsNoAlloc(0.0f); // part.GetModuleCosts allocate 44B per call.
} }
   
/// <summary> /// <summary>
/// Gets the dry mass of the part. /// Gets the dry mass of the part.
/// </summary> /// </summary>
public static double GetDryMass(this Part part) public static double GetDryMass(this Part part)
{ {
return (part.physicalSignificance == Part.PhysicalSignificance.FULL) ? part.mass : 0d; return (part.physicalSignificance == Part.PhysicalSignificance.FULL) ? part.mass : 0d;
} }
   
/// <summary> /// <summary>
/// Gets the maximum thrust of the part if it's an engine. /// Gets the maximum thrust of the part if it's an engine.
/// </summary> /// </summary>
  /* not used
public static double GetMaxThrust(this Part part) public static double GetMaxThrust(this Part part)
{ {
cachePartModule = GetModule<ModuleEngines>(part); PartModule cachePartModule = GetModule<ModuleEngines>(part);
if (cachePartModule != null) if (cachePartModule != null)
{ {
return (cachePartModule as ModuleEngines).maxThrust; return (cachePartModule as ModuleEngines).maxThrust;
} }
   
cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part); cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part);
if (cachePartModule != null) if (cachePartModule != null)
{ {
return (cachePartModule as ModuleEnginesFX).maxThrust; return (cachePartModule as ModuleEnginesFX).maxThrust;
} }
   
return 0.0; return 0.0;
} }
  */
   
/// <summary> /// <summary>
/// Gets the first typed PartModule in the part's module list. /// Gets the first typed PartModule in the part's module list.
/// </summary> /// </summary>
public static T GetModule<T>(this Part part) where T : PartModule public static T GetModule<T>(this Part part) where T : PartModule
{ {
PartModule partModule; for (int i = 0; i < part.Modules.Count; i++)
for (int i = 0; i < part.Modules.Count; ++i) {
{ PartModule pm = part.Modules[i];
partModule = part.Modules[i]; if (pm is T)
if (partModule is T) return (T)pm;
{  
return partModule as T;  
}  
} }
return null; return null;
} }
   
/// <summary> /// <summary>
/// Gets a typed PartModule. /// Gets a typed PartModule.
/// </summary> /// </summary>
public static T GetModule<T>(this Part part, string className) where T : PartModule public static T GetModule<T>(this Part part, string className) where T : PartModule
{ {
return part.Modules[className] as T; return part.Modules[className] as T;
} }
   
/// <summary> /// <summary>
/// Gets a typed PartModule. /// Gets a typed PartModule.
/// </summary> /// </summary>
public static T GetModule<T>(this Part part, int classId) where T : PartModule public static T GetModule<T>(this Part part, int classId) where T : PartModule
{ {
return part.Modules[classId] as T; return part.Modules[classId] as T;
} }
   
/// <summary> /// <summary>
/// Gets a ModuleAlternator typed PartModule. /// Gets a ModuleAlternator typed PartModule.
/// </summary> /// </summary>
public static ModuleAlternator GetModuleAlternator(this Part part) public static ModuleAlternator GetModuleAlternator(this Part part)
{ {
return GetModule<ModuleAlternator>(part); return GetModule<ModuleAlternator>(part);
} }
   
/// <summary> /// <summary>
/// Gets a ModuleDeployableSolarPanel typed PartModule. /// Gets a ModuleDeployableSolarPanel typed PartModule.
/// </summary> /// </summary>
public static ModuleDeployableSolarPanel GetModuleDeployableSolarPanel(this Part part) public static ModuleDeployableSolarPanel GetModuleDeployableSolarPanel(this Part part)
{ {
return GetModule<ModuleDeployableSolarPanel>(part); return GetModule<ModuleDeployableSolarPanel>(part);
} }
   
/// <summary> /// <summary>
/// Gets a ModuleEngines typed PartModule. /// Gets a ModuleEngines typed PartModule.
/// </summary> /// </summary>
public static ModuleEngines GetModuleEngines(this Part part) public static ModuleEngines GetModuleEngines(this Part part)
{ {
return GetModule<ModuleEngines>(part); return GetModule<ModuleEngines>(part);
} }
   
public static ModuleEnginesFX GetModuleEnginesFx(this Part part) /* public static ModuleEnginesFX GetModuleEnginesFx(this Part part)
{ {
return GetModule<ModuleEnginesFX>(part); return GetModule<ModuleEnginesFX>(part);
} }*/
   
/// <summary> /// <summary>
/// Gets a ModuleGenerator typed PartModule. /// Gets a ModuleGenerator typed PartModule.
/// </summary> /// </summary>
public static ModuleGenerator GetModuleGenerator(this Part part) public static ModuleGenerator GetModuleGenerator(this Part part)
{ {
return GetModule<ModuleGenerator>(part); return GetModule<ModuleGenerator>(part);
} }
   
/// <summary> /// <summary>
/// Gets a ModuleGimbal typed PartModule. /// Gets a ModuleGimbal typed PartModule.
/// </summary> /// </summary>
public static ModuleGimbal GetModuleGimbal(this Part part) public static ModuleGimbal GetModuleGimbal(this Part part)
{ {
return GetModule<ModuleGimbal>(part); return GetModule<ModuleGimbal>(part);
} }
   
/// <summary> /// <summary>
/// Gets the current selected ModuleEnginesFX. /// Gets the current selected ModuleEnginesFX.
/// </summary> /// </summary>
public static ModuleEnginesFX GetModuleMultiModeEngine(this Part part) public static ModuleEngines GetModuleMultiModeEngine(this Part part)
{ {
ModuleEnginesFX moduleEngineFx; ModuleEngines moduleEngines;
string mode = GetModule<MultiModeEngine>(part).mode; MultiModeEngine multiMod = GetModule<MultiModeEngine>(part);
for (int i = 0; i < part.Modules.Count; ++i) if (multiMod != null)
{ {
moduleEngineFx = part.Modules[i] as ModuleEnginesFX; string mode = multiMod.mode;
if (moduleEngineFx != null && moduleEngineFx.engineID == mode) for (int i = 0; i < part.Modules.Count; ++i)
{ {
return moduleEngineFx; moduleEngines = part.Modules[i] as ModuleEngines;
  if (moduleEngines != null && moduleEngines.engineID == mode)
  {
  return moduleEngines;
  }
} }
} }
return null; return null;
} }
   
/// <summary> /// <summary>
/// Gets a ModuleParachute typed PartModule. /// Gets a ModuleParachute typed PartModule.
/// </summary> /// </summary>
public static ModuleParachute GetModuleParachute(this Part part) public static ModuleParachute GetModuleParachute(this Part part)
{ {
return GetModule<ModuleParachute>(part); return GetModule<ModuleParachute>(part);
} }
   
public static ModuleRCS GetModuleRcs(this Part part) public static ModuleRCS GetModuleRcs(this Part part)
{ {
return GetModule<ModuleRCS>(part); return GetModule<ModuleRCS>(part);
} }
   
/// <summary> /// <summary>
/// Gets a typed list of PartModules. /// Gets a typed list of PartModules.
/// </summary> /// </summary>
public static List<T> GetModules<T>(this Part part) where T : PartModule public static List<T> GetModules<T>(this Part part) where T : PartModule
{ {
List<T> list = new List<T>(); List<T> list = new List<T>();
for (int i = 0; i < part.Modules.Count; ++i) for (int i = 0; i < part.Modules.Count; ++i)
{ {
T module = part.Modules[i] as T; T module = part.Modules[i] as T;
if (module != null) if (module != null)
{ {
list.Add(module); list.Add(module);
} }
} }
return list; return list;
} }
   
public static ProtoModuleDecoupler GetProtoModuleDecoupler(this Part part) public static ProtoModuleDecoupler GetProtoModuleDecoupler(this Part part)
{ {
cachePartModule = GetModule<ModuleDecouple>(part); PartModule cachePartModule = GetModule<ModuleDecouple>(part);
if (cachePartModule == null) if (cachePartModule == null)
{ {
cachePartModule = GetModule<ModuleAnchoredDecoupler>(part); cachePartModule = GetModule<ModuleAnchoredDecoupler>(part);
} }
if (cachePartModule != null) if (cachePartModule != null)
{ {
return new ProtoModuleDecoupler(cachePartModule); return new ProtoModuleDecoupler(cachePartModule);
} }
   
return null; return null;
} }
   
/// <summary> /// <summary>
/// Gets a generic proto engine for the current engine module attached to the part. /// Gets a generic proto engine for the current engine module attached to the part.
/// </summary> /// </summary>
public static ProtoModuleEngine GetProtoModuleEngine(this Part part) public static ProtoModuleEngine GetProtoModuleEngine(this Part part)
{ {
cachePartModule = GetModule<ModuleEngines>(part); PartModule cachePartModule = GetModule<ModuleEngines>(part);
if (cachePartModule != null) if (cachePartModule != null)
{ {
return new ProtoModuleEngine(cachePartModule); return new ProtoModuleEngine(cachePartModule);
} }
   
cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part); cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part);
if (cachePartModule != null) if (cachePartModule != null)
{ {
return new ProtoModuleEngine(cachePartModule); return new ProtoModuleEngine(cachePartModule);
} }
   
return null; return null;
} }
   
/// <summary> /// <summary>
/// Gets the cost of the part's contained resources. /// Gets the cost of the part's contained resources.
/// </summary> /// </summary>
public static double GetResourceCost(this Part part) public static double GetResourceCost(this Part part)
{ {
double cost = 0.0; double cost = 0.0;
for (int i = 0; i < part.Resources.list.Count; ++i) for (int i = 0; i < part.Resources.list.Count; ++i)
{ {
cachePartResource = part.Resources.list[i]; PartResource cachePartResource = part.Resources.list[i];
cost = cost + (cachePartResource.amount * cachePartResource.info.unitCost); cost = cost + (cachePartResource.amount * cachePartResource.info.unitCost);
} }
return cost; return cost;
} }
   
/// <summary> /// <summary>
/// Gets the cost of the part's contained resources, inverted. /// Gets the cost of the part's contained resources, inverted.
/// </summary> /// </summary>
public static double GetResourceCostInverted(this Part part) public static double GetResourceCostInverted(this Part part)
  {
  double sum = 0;
  for (int i = 0; i < part.Resources.list.Count; i++)
  {
  PartResource r = part.Resources.list[i];
  sum += (r.maxAmount - r.amount) * r.info.unitCost;
  }
  return sum;
  }
   
  /// <summary>
  /// Gets the cost of the part's maximum contained resources.
  /// </summary>
  public static double GetResourceCostMax(this Part part)
{ {
double cost = 0.0; double cost = 0.0;
for (int i = 0; i < part.Resources.list.Count; ++i) for (int i = 0; i < part.Resources.list.Count; ++i)
{ {
cachePartResource = part.Resources.list[i]; PartResource cachePartResource = part.Resources.list[i];
cost = cost + ((cachePartResource.maxAmount - cachePartResource.amount) * cachePartResource.info.unitCost); cost = cost + (cachePartResource.maxAmount * cachePartResource.info.unitCost);
} }
return cost; return cost;
} }
   
/// <summary> /// <summary>
/// Gets the cost of the part's maximum contained resources.  
/// </summary>  
public static double GetResourceCostMax(this Part part)  
{  
double cost = 0.0;  
for (int i = 0; i < part.Resources.list.Count; ++i)  
{  
cachePartResource = part.Resources.list[i];  
cost = cost + (cachePartResource.maxAmount * cachePartResource.info.unitCost);  
}  
return cost;  
}  
   
/// <summary>  
/// Gets the current specific impulse for the engine. /// Gets the current specific impulse for the engine.
/// </summary> /// </summary>
  /* not used
public static double GetSpecificImpulse(this Part part, float atmosphere) public static double GetSpecificImpulse(this Part part, float atmosphere)
{ {
cachePartModule = GetModule<ModuleEngines>(part); PartModule cachePartModule = GetModule<ModuleEngines>(part);
if (cachePartModule != null) if (cachePartModule != null)
{ {
return (cachePartModule as ModuleEngines).atmosphereCurve.Evaluate(atmosphere); return (cachePartModule as ModuleEngines).atmosphereCurve.Evaluate(atmosphere);
} }
   
cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part); cachePartModule = GetModuleMultiModeEngine(part) ?? GetModule<ModuleEnginesFX>(part);
if (cachePartModule != null) if (cachePartModule != null)
{ {
return (cachePartModule as ModuleEnginesFX).atmosphereCurve.Evaluate(atmosphere); return (cachePartModule as ModuleEnginesFX).atmosphereCurve.Evaluate(atmosphere);
} }
   
return 0.0; return 0.0;
} }
  */
   
/// <summary> /// <summary>
/// Gets the total mass of the part including resources. /// Gets the total mass of the part including resources.
/// </summary> /// </summary>
public static double GetWetMass(this Part part) public static double GetWetMass(this Part part)
{ {
return (part.physicalSignificance == Part.PhysicalSignificance.FULL) ? part.mass + part.GetResourceMass() : part.GetResourceMass(); return (part.physicalSignificance == Part.PhysicalSignificance.FULL) ? part.mass + part.GetResourceMass() : part.GetResourceMass();
} }
   
/// <summary> /// <summary>
/// Gets whether the part contains a PartModule. /// Gets whether the part contains a PartModule.
/// </summary> /// </summary>
public static bool HasModule<T>(this Part part) where T : PartModule public static bool HasModule<T>(this Part part) where T : PartModule
{ {
for (int i = 0; i < part.Modules.Count; ++i) for (int i = 0; i < part.Modules.Count; i++)
{ {
if (part.Modules[i] is T) if (part.Modules[i] is T)
{  
return true; return true;
}  
} }
return false; return false;
} }
   
/// <summary> /// <summary>
/// Gets whether the part contains a PartModule conforming to the supplied predicate. /// Gets whether the part contains a PartModule conforming to the supplied predicate.
/// </summary> /// </summary>
public static bool HasModule<T>(this Part part, Func<T, bool> predicate) where T : PartModule public static bool HasModule<T>(this Part part, Func<T, bool> predicate) where T : PartModule
{ {
for (int i = 0; i < part.Modules.Count; ++i) for (int i = 0; i < part.Modules.Count; i++)
{ {
cachePartModule = part.Modules[i] as T; PartModule pm = part.Modules[i];
if (cachePartModule != null && predicate(cachePartModule as T)) if (pm is T && predicate(pm as T))
{  
return true; return true;
}  
} }
return false; return false;
} }
   
/// <summary> /// <summary>
/// Gets whether the part contains a PartModule. /// Gets whether the part contains a PartModule.
/// </summary> /// </summary>
public static bool HasModule(this Part part, string className) public static bool HasModule(this Part part, string className)
{ {
return part.Modules.Contains(className); return part.Modules.Contains(className);
} }
   
/// <summary> /// <summary>
/// Gets whether the part contains a PartModule. /// Gets whether the part contains a PartModule.
/// </summary> /// </summary>
public static bool HasModule(this Part part, int moduleId) public static bool HasModule(this Part part, int moduleId)
{ {
return part.Modules.Contains(moduleId); return part.Modules.Contains(moduleId);
} }
   
/// <summary> /// <summary>
/// Gets whether the part has a one shot animation. /// Gets whether the part has a one shot animation.
/// </summary> /// </summary>
public static bool HasOneShotAnimation(this Part part) public static bool HasOneShotAnimation(this Part part)
{ {
cachePartModule = GetModule<ModuleAnimateGeneric>(part); PartModule cachePartModule = GetModule<ModuleAnimateGeneric>(part);
return cachePartModule != null && (cachePartModule as ModuleAnimateGeneric).isOneShot; return cachePartModule != null && (cachePartModule as ModuleAnimateGeneric).isOneShot;
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a command module. /// Gets whether the part is a command module.
/// </summary> /// </summary>
public static bool IsCommandModule(this Part part) public static bool IsCommandModule(this Part part)
{ {
return HasModule<ModuleCommand>(part); return HasModule<ModuleCommand>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is decoupled in a specified stage. /// Gets whether the part is decoupled in a specified stage.
/// </summary> /// </summary>
public static bool IsDecoupledInStage(this Part part, int stage) public static bool IsDecoupledInStage(this Part part, int stage)
{ {
if ((IsDecoupler(part) || IsLaunchClamp(part)) && part.inverseStage == stage) if ((IsDecoupler(part) || IsLaunchClamp(part)) && part.inverseStage == stage)
{ {
return true; return true;
} }
if (part.parent == null) if (part.parent == null)
{ {
return false; return false;
} }
return IsDecoupledInStage(part.parent, stage); return IsDecoupledInStage(part.parent, stage);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a decoupler. /// Gets whether the part is a decoupler.
/// </summary> /// </summary>
public static bool IsDecoupler(this Part part) public static bool IsDecoupler(this Part part)
{ {
return HasModule<ModuleDecouple>(part) || HasModule<ModuleAnchoredDecoupler>(part); return HasModule<ModuleDecouple>(part) || HasModule<ModuleAnchoredDecoupler>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is an active engine. /// Gets whether the part is an active engine.
/// </summary> /// </summary>
public static bool IsEngine(this Part part) public static bool IsEngine(this Part part)
{ {
return HasModule<ModuleEngines>(part) || HasModule<ModuleEnginesFX>(part); return HasModule<ModuleEngines>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a fuel line. /// Gets whether the part is a fuel line.
/// </summary> /// </summary>
public static bool IsFuelLine(this Part part) public static bool IsFuelLine(this Part part)
{ {
return HasModule<CModuleFuelLine>(part); return HasModule<CModuleFuelLine>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a generator. /// Gets whether the part is a generator.
/// </summary> /// </summary>
public static bool IsGenerator(this Part part) public static bool IsGenerator(this Part part)
{ {
return HasModule<ModuleGenerator>(part); return HasModule<ModuleGenerator>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a launch clamp. /// Gets whether the part is a launch clamp.
/// </summary> /// </summary>
public static bool IsLaunchClamp(this Part part) public static bool IsLaunchClamp(this Part part)
{ {
return HasModule<LaunchClamp>(part); return HasModule<LaunchClamp>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a parachute. /// Gets whether the part is a parachute.
/// </summary> /// </summary>
public static bool IsParachute(this Part part) public static bool IsParachute(this Part part)
{ {
return HasModule<ModuleParachute>(part); return HasModule<ModuleParachute>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is considered a primary part on the vessel. /// Gets whether the part is considered a primary part on the vessel.
/// </summary> /// </summary>
public static bool IsPrimary(this Part part, List<Part> partsList, PartModule module) public static bool IsPrimary(this Part part, List<Part> partsList, PartModule module)
{ {
for (int i = 0; i < partsList.Count; ++i) for (int i = 0; i < partsList.Count; i++)
{ {
cachePart = partsList[i]; var vesselPart = partsList[i];
  if (!vesselPart.HasModule(module.ClassID))
if (HasModule(cachePart, module.ClassID) == false)  
{ {
continue; continue;
} }
if (cachePart == part) if (vesselPart == part)
{ {
return true; return true;
} }
break; break;
} }
   
return false; return false;
} }
   
public static bool IsRcsModule(this Part part) public static bool IsRcsModule(this Part part)
{ {
return HasModule<ModuleRCS>(part); return HasModule<ModuleRCS>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a sepratron. /// Gets whether the part is a sepratron.
/// </summary> /// </summary>
public static bool IsSepratron(this Part part) public static bool IsSepratron(this Part part)
{ {
return IsSolidRocket(part) && part.ActivatesEvenIfDisconnected && IsDecoupledInStage(part, part.inverseStage); return IsSolidRocket(part) && part.ActivatesEvenIfDisconnected && IsDecoupledInStage(part, part.inverseStage);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a deployable solar panel. /// Gets whether the part is a deployable solar panel.
/// </summary> /// </summary>
public static bool IsSolarPanel(this Part part) public static bool IsSolarPanel(this Part part)
{ {
return HasModule<ModuleDeployableSolarPanel>(part); return HasModule<ModuleDeployableSolarPanel>(part);
} }
   
/// <summary> /// <summary>
/// Gets whether the part is a solid rocket motor. /// Gets whether the part is a solid rocket motor.
/// </summary> /// </summary>
public static bool IsSolidRocket(this Part part) public static bool IsSolidRocket(this Part part)
{ {
return (HasModule<ModuleEngines>(part) && GetModuleEngines(part).throttleLocked) || (HasModule<ModuleEnginesFX>(part) && GetModuleEnginesFx(part).throttleLocked); return (part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked);
} }
   
public class ProtoModuleDecoupler public class ProtoModuleDecoupler
{ {
private readonly PartModule module; private readonly PartModule module;
   
public ProtoModuleDecoupler(PartModule module) public ProtoModuleDecoupler(PartModule module)
{ {
this.module = module; this.module = module;
   
if (this.module is ModuleDecouple) if (this.module is ModuleDecouple)
{ {
SetModuleDecouple(); SetModuleDecouple();
} }
else if (this.module is ModuleAnchoredDecoupler) else if (this.module is ModuleAnchoredDecoupler)
{ {
SetModuleAnchoredDecoupler(); SetModuleAnchoredDecoupler();
} }
} }
   
public double EjectionForce { get; private set; } public double EjectionForce { get; private set; }
public bool IsOmniDecoupler { get; private set; } public bool IsOmniDecoupler { get; private set; }
   
private void SetModuleAnchoredDecoupler() private void SetModuleAnchoredDecoupler()
{ {
ModuleAnchoredDecoupler decoupler = module as ModuleAnchoredDecoupler; ModuleAnchoredDecoupler decoupler = module as ModuleAnchoredDecoupler;
if (decoupler == null) if (decoupler == null)
{ {
return; return;
} }
   
EjectionForce = decoupler.ejectionForce; EjectionForce = decoupler.ejectionForce;
} }
   
private void SetModuleDecouple() private void SetModuleDecouple()
{ {
ModuleDecouple decoupler = module as ModuleDecouple; ModuleDecouple decoupler = module as ModuleDecouple;
if (decoupler == null) if (decoupler == null)
{ {
return; return;
} }
   
EjectionForce = decoupler.ejectionForce; EjectionForce = decoupler.ejectionForce;
IsOmniDecoupler = decoupler.isOmniDecoupler; IsOmniDecoupler = decoupler.isOmniDecoupler;
} }
} }
   
  // This needs updating to handle multi-mode engines and engines with multiple ModuleEngines correctly.
  // It currently just shows the stats of the currently active module for multi-mode engines and just
  // the first ModuleEngines for engines with multiple modules.
  // It should really show all the modes for multi-mode engines as separate sections.
  // For other engines with multiple ModuleEngines it should combine the separate modules into a single set of data
  // The constructor should be changed to take the Part itself. It can be called if HasModule<ModuleEngines>() is true.
public class ProtoModuleEngine public class ProtoModuleEngine
{ {
private readonly PartModule module; private readonly PartModule module;
   
public ProtoModuleEngine(PartModule module) public ProtoModuleEngine(PartModule module)
{ {
this.module = module; this.module = module;
   
if (module is ModuleEngines) if (module is ModuleEngines)
{ {
SetModuleEngines(); SetModuleEngines();
} }
} }
   
public double MaximumThrust { get; private set; } public double MaximumThrust { get; private set; }
public double MinimumThrust { get; private set; } public double MinimumThrust { get; private set; }
public List<Propellant> Propellants { get; private set; } public List<Propellant> Propellants { get; private set; }
   
public float GetSpecificImpulse(float atmosphere) public float GetSpecificImpulse(float atmosphere)
{ {
if (module is ModuleEngines) if (module is ModuleEngines)
{ {
return (module as ModuleEngines).atmosphereCurve.Evaluate(atmosphere); return (module as ModuleEngines).atmosphereCurve.Evaluate(atmosphere);
} }
return 0.0f; return 0.0f;
} }
   
private void SetModuleEngines() private void SetModuleEngines()
{ {
ModuleEngines engine = module as ModuleEngines; ModuleEngines engine = module as ModuleEngines;
if (engine == null) if (engine == null)
{ {
return; return;
} }
   
MaximumThrust = engine.maxThrust * (engine.thrustPercentage * 0.01); MaximumThrust = engine.maxThrust * (engine.thrustPercentage * 0.01);
MinimumThrust = engine.minThrust; MinimumThrust = engine.minThrust;
Propellants = engine.propellants; Propellants = engine.propellants;
} }
   
private void SetModuleEnginesFx()  
{  
ModuleEnginesFX engine = module as ModuleEnginesFX;  
if (engine == null)  
{  
return;  
}  
   
MaximumThrust = engine.maxThrust * (engine.thrustPercentage * 0.01);  
MinimumThrust = engine.minThrust;  
Propellants = engine.propellants;  
}  
} }
} }
} }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Extensions
  {
  public static class StringExtensions
  {
  public static string ToLength(this string value, int length)
  {
  if (value != null && value.Length > length)
  {
  value = value.Substring(0, length) + "...";
  }
  return value;
  }
  }
  }
// //
// 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.Flight.Sections; using KerbalEngineer.Flight.Sections;
using KerbalEngineer.Settings; using KerbalEngineer.Settings;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight namespace KerbalEngineer.Flight
{ {
using Upgradeables; using Upgradeables;
   
/// <summary> /// <summary>
/// Graphical controller for displaying stacked sections. /// Graphical controller for displaying stacked sections.
/// </summary> /// </summary>
[KSPAddon(KSPAddon.Startup.Flight, false)] [KSPAddon(KSPAddon.Startup.Flight, false)]
public class DisplayStack : MonoBehaviour public class DisplayStack : MonoBehaviour
{ {
#region Fields #region Fields
   
private GUIStyle buttonStyle; private GUIStyle buttonStyle;
private int numberOfStackSections; private int numberOfStackSections;
private bool resizeRequested; private bool resizeRequested;
private bool showControlBar = true; private bool showControlBar = true;
private GUIStyle titleStyle; private GUIStyle titleStyle;
private int windowId; private int windowId;
private Rect windowPosition; private Rect windowPosition;
private GUIStyle windowStyle; private GUIStyle windowStyle;
   
#endregion #endregion
   
#region Properties #region Properties
   
/// <summary> /// <summary>
/// Gets the current instance of the DisplayStack. /// Gets the current instance of the DisplayStack.
/// </summary> /// </summary>
public static DisplayStack Instance { get; private set; } public static DisplayStack Instance { get; private set; }
   
public bool Hidden { get; set; } public bool Hidden { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets the visibility of the control bar. /// Gets and sets the visibility of the control bar.
/// </summary> /// </summary>
public bool ShowControlBar public bool ShowControlBar
{ {
get { return this.showControlBar; } get { return this.showControlBar; }
set { this.showControlBar = value; } set { this.showControlBar = value; }
} }
   
#endregion #endregion
   
#region Methods: public #region Methods: public
   
/// <summary> /// <summary>
/// Request that the display stack's size is reset in the next draw call. /// Request that the display stack's size is reset in the next draw call.
/// </summary> /// </summary>
public void RequestResize() public void RequestResize()
{ {
this.resizeRequested = true; this.resizeRequested = true;
} }
   
#endregion #endregion
   
#region Methods: protected #region Methods: protected
   
/// <summary> /// <summary>
/// Sets the instance to this object. /// Sets the instance to this object.
/// </summary> /// </summary>
protected void Awake() protected void Awake()
{ {
try try
{ {
if (Instance == null) if (Instance == null)
{ {
Instance = this; Instance = this;
GuiDisplaySize.OnSizeChanged += this.OnSizeChanged; GuiDisplaySize.OnSizeChanged += this.OnSizeChanged;
Logger.Log("ActionMenu->Awake"); Logger.Log("ActionMenu->Awake");
} }
else else
{ {
Destroy(this); Destroy(this);
} }
} }
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
{ {
this.Save(); this.Save();
RenderingManager.RemoveFromPostDrawQueue(0, this.Draw); RenderingManager.RemoveFromPostDrawQueue(0, this.Draw);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
Logger.Log("ActionMenu->OnDestroy"); Logger.Log("ActionMenu->OnDestroy");
} }
   
/// <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.windowId = this.GetHashCode(); this.windowId = this.GetHashCode();
this.InitialiseStyles(); this.InitialiseStyles();
this.Load(); this.Load();
RenderingManager.AddToPostDrawQueue(0, this.Draw); RenderingManager.AddToPostDrawQueue(0, this.Draw);
Logger.Log("ActionMenu->Start"); Logger.Log("ActionMenu->Start");
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
protected void Update() protected void Update()
{ {
try try
{ {
if (!FlightEngineerCore.IsDisplayable) if (!FlightEngineerCore.IsDisplayable)
{ {
return; return;
} }
   
if (Input.GetKeyDown(KeyBinder.FlightShowHide)) if (Input.GetKeyDown(KeyBinder.FlightShowHide))
{ {
this.Hidden = !this.Hidden; this.Hidden = !this.Hidden;
} }
} }
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 display stack when the UI is enabled. /// Called to draw the display stack when the UI is enabled.
/// </summary> /// </summary>
private void Draw() private void Draw()
{ {
try try
{ {
if (!FlightEngineerCore.IsDisplayable) if (!FlightEngineerCore.IsDisplayable)
{ {
return; return;
} }
   
if (this.resizeRequested || this.numberOfStackSections != SectionLibrary.NumberOfStackSections) if (this.resizeRequested || this.numberOfStackSections != SectionLibrary.NumberOfStackSections)
{ {
this.numberOfStackSections = SectionLibrary.NumberOfStackSections; this.numberOfStackSections = SectionLibrary.NumberOfStackSections;
this.windowPosition.width = 0; this.windowPosition.width = 0;
this.windowPosition.height = 0; this.windowPosition.height = 0;
this.resizeRequested = false; this.resizeRequested = false;
} }
   
if (!this.Hidden && (SectionLibrary.NumberOfStackSections > 0 || this.ShowControlBar)) if (!this.Hidden && (SectionLibrary.NumberOfStackSections > 0 || this.ShowControlBar))
{ {
var shouldCentre = this.windowPosition.min == Vector2.zero; var shouldCentre = this.windowPosition.min == Vector2.zero;
GUI.skin = null; GUI.skin = null;
this.windowPosition = GUILayout.Window(this.windowId, this.windowPosition, this.Window, string.Empty, this.windowStyle).ClampToScreen(); this.windowPosition = GUILayout.Window(this.windowId, this.windowPosition, this.Window, string.Empty, this.windowStyle).ClampToScreen();
if (shouldCentre) if (shouldCentre)
{ {
this.windowPosition.center = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f); this.windowPosition.center = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f);
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
/// <summary> /// <summary>
/// Draws the control bar. /// Draws the control bar.
/// </summary> /// </summary>
private void DrawControlBar() private void DrawControlBar()
{ {
GUILayout.Label("FLIGHT ENGINEER " + EngineerGlobals.AssemblyVersion, this.titleStyle); GUILayout.Label("FLIGHT ENGINEER " + EngineerGlobals.ASSEMBLY_VERSION, this.titleStyle);
   
this.DrawControlBarButtons(SectionLibrary.StockSections); this.DrawControlBarButtons(SectionLibrary.StockSections);
this.DrawControlBarButtons(SectionLibrary.CustomSections); this.DrawControlBarButtons(SectionLibrary.CustomSections);
} }
   
/// <summary> /// <summary>
/// Draws a button list for a set of sections. /// Draws a button list for a set of sections.
/// </summary> /// </summary>
private void DrawControlBarButtons(IEnumerable<SectionModule> sections) private void DrawControlBarButtons(IEnumerable<SectionModule> sections)
{ {
var index = 0; var index = 0;
foreach (var section in sections.Where(s => !string.IsNullOrEmpty(s.Abbreviation) || !s.IsCustom)) foreach (var section in sections.Where(s => !string.IsNullOrEmpty(s.Abbreviation) || !s.IsCustom))
{ {
if (index % 4 == 0) if (index % 4 == 0)
{ {
if (index > 0) if (index > 0)
{ {
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
} }
section.IsVisible = GUILayout.Toggle(section.IsVisible, section.Abbreviation.ToUpper(), this.buttonStyle); section.IsVisible = GUILayout.Toggle(section.IsVisible, section.Abbreviation.ToUpper(), this.buttonStyle);
index++; index++;
} }
if (index > 0) if (index > 0)
{ {
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
} }
   
/// <summary> /// <summary>
/// Draws a list of sections. /// Draws a list of sections.
/// </summary> /// </summary>
private void DrawSections(IEnumerable<SectionModule> sections) private void DrawSections(IEnumerable<SectionModule> sections)
{ {
foreach (var section in sections) foreach (var section in sections)
{ {
if (!section.IsFloating) if (!section.IsFloating)
{ {
section.Draw(); section.Draw();
} }
} }
} }
   
/// <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)
{ {
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(5, 5, 0, 5) padding = new RectOffset(5, 5, 0, 5)
}; };
   
this.titleStyle = new GUIStyle(HighLogic.Skin.label) this.titleStyle = new GUIStyle(HighLogic.Skin.label)
{ {
margin = new RectOffset(0, 0, 5, 3), margin = new RectOffset(0, 0, 5, 3),
padding = new RectOffset(), padding = new RectOffset(),
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
fontSize = (int)(13 * GuiDisplaySize.Offset), fontSize = (int)(13 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
stretchWidth = true stretchWidth = true
}; };
   
this.buttonStyle = new GUIStyle(HighLogic.Skin.button) this.buttonStyle = new GUIStyle(HighLogic.Skin.button)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(), padding = new RectOffset(),
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
fixedWidth = 60.0f * GuiDisplaySize.Offset, fixedWidth = 60.0f * GuiDisplaySize.Offset,
fixedHeight = 25.0f * GuiDisplaySize.Offset, fixedHeight = 25.0f * GuiDisplaySize.Offset,
}; };
} }
   
/// <summary> /// <summary>
/// Load the stack's state. /// Load the stack's state.
/// </summary> /// </summary>
private void Load() private void Load()
{ {
try try
{ {
var handler = SettingHandler.Load("DisplayStack.xml"); var handler = SettingHandler.Load("DisplayStack.xml");
this.Hidden = handler.Get("hidden", this.Hidden); this.Hidden = handler.Get("hidden", this.Hidden);
this.ShowControlBar = handler.Get("showControlBar", this.ShowControlBar); this.ShowControlBar = handler.Get("showControlBar", this.ShowControlBar);
this.windowPosition.x = handler.Get("windowPositionX", this.windowPosition.x); this.windowPosition.x = handler.Get("windowPositionX", this.windowPosition.x);
this.windowPosition.y = handler.Get("windowPositionY", this.windowPosition.y); this.windowPosition.y = handler.Get("windowPositionY", this.windowPosition.y);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "DisplayStack->Load"); Logger.Exception(ex, "DisplayStack->Load");
} }
} }
   
private void OnSizeChanged() private void OnSizeChanged()
{ {
this.InitialiseStyles(); this.InitialiseStyles();
this.RequestResize(); this.RequestResize();
} }
   
/// <summary> /// <summary>
/// Saves the stack's state. /// Saves the stack's state.
/// </summary> /// </summary>
private void Save() private void Save()
{ {
try try
{ {
var handler = new SettingHandler(); var handler = new SettingHandler();
handler.Set("hidden", this.Hidden); handler.Set("hidden", this.Hidden);
handler.Set("showControlBar", this.ShowControlBar); handler.Set("showControlBar", this.ShowControlBar);
handler.Set("windowPositionX", this.windowPosition.x); handler.Set("windowPositionX", this.windowPosition.x);
handler.Set("windowPositionY", this.windowPosition.y); handler.Set("windowPositionY", this.windowPosition.y);
handler.Save("DisplayStack.xml"); handler.Save("DisplayStack.xml");
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "DisplayStack->Save"); Logger.Exception(ex, "DisplayStack->Save");
} }
} }
   
/// <summary> /// <summary>
/// Draws the display stack window. /// Draws the display stack window.
/// </summary> /// </summary>
private void Window(int windowId) private void Window(int windowId)
{ {
try try
{ {
if (this.ShowControlBar) if (this.ShowControlBar)
{ {
this.DrawControlBar(); this.DrawControlBar();
} }
   
if (SectionLibrary.NumberOfStackSections > 0) if (SectionLibrary.NumberOfStackSections > 0)
{ {
this.DrawSections(SectionLibrary.StockSections); this.DrawSections(SectionLibrary.StockSections);
this.DrawSections(SectionLibrary.CustomSections); this.DrawSections(SectionLibrary.CustomSections);
} }
   
GUI.DragWindow(); GUI.DragWindow();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex, "DisplayStack->Widnow"); Logger.Exception(ex, "DisplayStack->Widnow");
} }
} }
   
#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; 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 = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 1000.0f)); SimManager.minSimTime = TimeSpan.FromMilliseconds(GUILayout.HorizontalSlider((float)SimManager.minSimTime.TotalMilliseconds, 0, 2000.0f));
GUI.skin = null; GUI.skin = null;
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
#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;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Orbital namespace KerbalEngineer.Flight.Readouts.Orbital
{ {
public class Eccentricity : ReadoutModule public class Eccentricity : ReadoutModule
{ {
#region Constructors #region Constructors
   
public Eccentricity() public Eccentricity()
{ {
this.Name = "Eccentricity"; this.Name = "Eccentricity";
this.Category = ReadoutCategory.GetCategory("Orbital"); this.Category = ReadoutCategory.GetCategory("Orbital");
this.HelpString = "Shows the vessel's orbital eccentricity."; this.HelpString = "Shows the vessel's orbital eccentricity.";
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)
{ {
this.DrawLine(FlightGlobals.ship_orbit.eccentricity.ToString("F3"), section.IsHud); this.DrawLine(FlightGlobals.ship_orbit.eccentricity.ToString("F5"), section.IsHud);
} }
   
#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.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
{ {
  using Helpers;
   
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 PostBurnAp { get; private set; }
   
  public static double PostBurnPe { 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()
{ {
// Extra tests for low level tracking station not supporting patched conics and maneuver nodes // Extra tests for low level tracking station not supporting patched conics and maneuver nodes
if (FlightGlobals.ActiveVessel.patchedConicSolver == null || if (FlightGlobals.ActiveVessel.patchedConicSolver == null ||
FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes == null || FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes == null ||
FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0 || FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0 ||
!SimulationProcessor.ShowDetails) !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;
  PostBurnAp = node.nextPatch != null ? node.nextPatch.ApA : 0;
  PostBurnPe = node.nextPatch != null ? node.nextPatch.PeA : 0;
   
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(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(double 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.5; var deltaVMidPoint = deltaV * 0.5;
   
for (var i = SimulationProcessor.Stages.Length - 1; i > -1; i--) for (var i = SimulationProcessor.Stages.Length - 1; i > -1; i--)
{ {
var stage = SimulationProcessor.Stages[i]; var stage = SimulationProcessor.Stages[i];
var stageDeltaV = stage.deltaV; var stageDeltaV = stage.deltaV;
var startMass = stage.totalMass; var startMass = stage.totalMass;
   
ProcessStageDrain: ProcessStageDrain:
if (deltaV <= Double.Epsilon) if (deltaV <= Double.Epsilon)
{ {
break; break;
} }
if (stageDeltaV <= Double.Epsilon) if (stageDeltaV <= Double.Epsilon)
{ {
continue; continue;
} }
   
FinalStage = i; FinalStage = i;
   
double deltaVDrain; double deltaVDrain;
if (deltaVMidPoint > 0.0) if (deltaVMidPoint > 0.0)
{ {
deltaVDrain = deltaV.Clamp(0.0, stageDeltaV.Clamp(0.0, deltaVMidPoint)); deltaVDrain = deltaV.Clamp(0.0, stageDeltaV.Clamp(0.0, deltaVMidPoint));
deltaVMidPoint -= deltaVDrain; deltaVMidPoint -= deltaVDrain;
setMidPoint = deltaVMidPoint <= Double.Epsilon; setMidPoint = deltaVMidPoint <= Double.Epsilon;
} }
else else
{ {
deltaVDrain = deltaV.Clamp(0.0, stageDeltaV); deltaVDrain = deltaV.Clamp(0.0, stageDeltaV);
} }
   
var exhaustVelocity = stage.isp * 9.82; var exhaustVelocity = stage.isp * Units.GRAVITY;
var flowRate = stage.thrust / exhaustVelocity; var flowRate = stage.thrust / exhaustVelocity;
var endMass = Math.Exp(Math.Log(startMass) - deltaVDrain / exhaustVelocity); var endMass = Math.Exp(Math.Log(startMass) - deltaVDrain / exhaustVelocity);
var deltaMass = (startMass - endMass) * Math.Exp(-(deltaVDrain * 0.001) / exhaustVelocity); var deltaMass = (startMass - endMass) * Math.Exp(-(deltaVDrain * 0.001) / exhaustVelocity);
burnTime += deltaMass / flowRate; burnTime += deltaMass / flowRate;
   
deltaV -= deltaVDrain; deltaV -= deltaVDrain;
stageDeltaV -= deltaVDrain; stageDeltaV -= deltaVDrain;
startMass -= deltaMass; startMass -= deltaMass;
   
if (setMidPoint) if (setMidPoint)
{ {
midPointTime = burnTime; midPointTime = burnTime;
setMidPoint = false; setMidPoint = false;
goto ProcessStageDrain; goto ProcessStageDrain;
} }
} }
return deltaV <= Double.Epsilon; return deltaV <= Double.Epsilon;
} }
   
#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 System;
 
  using KerbalEngineer.Extensions;
  using KerbalEngineer.Flight.Sections;
 
  #endregion
 
  namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
  {
  public class PostBurnApoapsis : ReadoutModule
  {
  #region Constructors
 
  public PostBurnApoapsis()
  {
  this.Name = "Post-burn Apoapsis";
  this.Category = ReadoutCategory.GetCategory("Orbital");
  this.HelpString = String.Empty;
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods: public
 
  public override void Draw(SectionModule section)
  {
  if (!ManoeuvreProcessor.ShowDetails)
  {
  return;
  }
 
  this.DrawLine("Post-burn Apoapsis", ManoeuvreProcessor.PostBurnAp.ToDistance(), section.IsHud);
  }
 
  public override void Reset()
  {
  ManoeuvreProcessor.Reset();
  }
 
  public override void Update()
  {
  ManoeuvreProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  #region Using Directives
 
  using System;
 
  using KerbalEngineer.Extensions;
  using KerbalEngineer.Flight.Sections;
 
  #endregion
 
  namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
  {
  public class PostBurnPeriapsis : ReadoutModule
  {
  #region Constructors
 
  public PostBurnPeriapsis()
  {
  this.Name = "Post-burn Periapsis";
  this.Category = ReadoutCategory.GetCategory("Orbital");
  this.HelpString = String.Empty;
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods: public
 
  public override void Draw(SectionModule section)
  {
  if (!ManoeuvreProcessor.ShowDetails)
  {
  return;
  }
 
  this.DrawLine("Post-burn Periapsis", ManoeuvreProcessor.PostBurnPe.ToDistance(), section.IsHud);
  }
 
  public override void Reset()
  {
  ManoeuvreProcessor.Reset();
  }
 
  public override void Update()
  {
  ManoeuvreProcessor.RequestUpdate();
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  #region Using Directives
 
  using System;
  using KerbalEngineer.Flight.Sections;
  using KerbalEngineer.Helpers;
  using KerbalEngineer.Extensions;
 
  #endregion
 
  namespace KerbalEngineer.Flight.Readouts.Orbital
  {
  public class SpeedAtApoapsis : ReadoutModule
  {
  #region Constructors
 
  public SpeedAtApoapsis()
  {
  this.Name = "Speed at Apoapsis";
  this.Category = ReadoutCategory.GetCategory("Orbital");
  this.HelpString = "Shows the orbital speed of the vessel when at apoapsis, the highest point of the orbit.";
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods: public
 
  public override void Draw(SectionModule section)
  {
  // Vis-viva: v^2 = GM(2/r - 1/a)
  // All this is easily got from the ships orbit (and reference body)
  String str;
  Orbit orbit = FlightGlobals.ship_orbit;
  if (orbit.eccentricity > 1.0)
  str = "---m/s";
  else
  {
  double speedsqr = orbit.referenceBody.gravParameter * ((2 / orbit.ApR) - (1 / orbit.semiMajorAxis));
  if (Double.IsNaN(speedsqr) || speedsqr < 0)
  str = "---m/s"; // Don't think this is possible barring bugs in the Orbit class
  else
  str = Math.Sqrt(speedsqr).ToSpeed();
  }
  this.DrawLine(str, section.IsHud);
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  #region Using Directives
 
  using System;
  using KerbalEngineer.Flight.Sections;
  using KerbalEngineer.Helpers;
  using KerbalEngineer.Extensions;
 
  #endregion
 
  namespace KerbalEngineer.Flight.Readouts.Orbital
  {
  public class SpeedAtPeriapsis : ReadoutModule
  {
  #region Constructors
 
  public SpeedAtPeriapsis()
  {
  this.Name = "Speed at Periapsis";
  this.Category = ReadoutCategory.GetCategory("Orbital");
  this.HelpString = "Shows the orbital speed of the vessel when at periapsis, the lowest point of the orbit.";
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods: public
 
  public override void Draw(SectionModule section)
  {
  // Vis-viva: v^2 = GM(2/r - 1/a)
  // All this is easily got from the ships orbit (and reference body)
  String str;
  Orbit orbit = FlightGlobals.ship_orbit;
  double oneovera = (orbit.eccentricity == 1) ? 0 : (1 / orbit.semiMajorAxis);
  double speedsqr = orbit.referenceBody.gravParameter * ((2 / orbit.PeR) - oneovera);
  if (Double.IsNaN(speedsqr) || speedsqr < 0)
  str = "---m/s";
  else
  str = Math.Sqrt(speedsqr).ToSpeed();
  this.DrawLine(str, section.IsHud);
  }
 
  #endregion
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2014 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  #region Using Directives
 
  using System;
  using KerbalEngineer.Flight.Sections;
  using KerbalEngineer.Helpers;
 
  #endregion
 
  namespace KerbalEngineer.Flight.Readouts.Orbital
  {
  public class TimeToAtmosphere : ReadoutModule
  {
  //private LogMsg log = new LogMsg();
 
  #region Constructors
 
  public TimeToAtmosphere()
  {
  this.Name = "Time to Atmosphere";
  this.Category = ReadoutCategory.GetCategory("Orbital");
  this.HelpString = "Shows the time until the vessel enters or leaves atmosphere.";
  this.IsDefault = false;
  }
 
  #endregion
 
  #region Methods: public
 
  public override void Draw(SectionModule section)
  {
  String str;
  Orbit orbit = FlightGlobals.ship_orbit;
 
  if (orbit.referenceBody.atmosphere && orbit.PeA < orbit.referenceBody.atmosphereDepth)
  {
  double tA = orbit.TrueAnomalyAtRadius(orbit.referenceBody.atmosphereDepth + orbit.referenceBody.Radius);
  //log.buf.AppendFormat("tA = {0}\n", tA);
  double utTime = Planetarium.GetUniversalTime();
  //log.buf.AppendFormat("utTime = {0}\n", utTime);
  double timeAtRad1 = orbit.GetUTforTrueAnomaly(tA, orbit.period * 0.5);
  //log.buf.AppendFormat("timeAtRad1 = {0}\n", timeAtRad1);
  if (timeAtRad1 < utTime)
  {
  timeAtRad1 += orbit.period;
  //log.buf.AppendFormat("timeAtRad1 = {0}\n", timeAtRad1);
  }
  double timeAtRad2 = orbit.GetUTforTrueAnomaly(-tA, orbit.period * 0.5);
  //log.buf.AppendFormat("timeAtRad2 = {0}\n", timeAtRad2);
  if (timeAtRad2 < utTime)
  {
  timeAtRad2 += orbit.period;
  //log.buf.AppendFormat("timeAtRad2 = {0}\n", timeAtRad2);
  }
  double time = Math.Min(timeAtRad1, timeAtRad2) - utTime;
  //log.buf.AppendFormat("time = {0}\n", time);
 
  if (Double.IsNaN(time))
  {
  str = "---s";
  //log.buf.AppendLine("time is NaN");
  }
  else
  {
  str = TimeFormatter.ConvertToString(time);
  //log.buf.AppendFormat("str = {0}\n", str);
  }
  }
  else
  {
  str = "---s";
  //log.buf.AppendLine("no atmosphere or pe > atmosphere");
  }
 
  //log.Flush();
  this.DrawLine(str, section.IsHud);
  }
 
  #endregion
  }
  }
// //
// Kerbal Engineer Redux // Copyright (C) 2015 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/>.
// //
   
namespace KerbalEngineer.Flight.Readouts namespace KerbalEngineer.Flight.Readouts
{ {
#region Using Directives  
   
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Miscellaneous; using Miscellaneous;
using Orbital; using Orbital;
using Orbital.ManoeuvreNode; using Orbital.ManoeuvreNode;
using Rendezvous; using Rendezvous;
using Settings; using Settings;
using Surface; using Surface;
  using Thermal;
using Vessel; using Vessel;
using AltitudeSeaLevel = Surface.AltitudeSeaLevel; using AltitudeSeaLevel = Surface.AltitudeSeaLevel;
using ApoapsisHeight = Orbital.ApoapsisHeight; using ApoapsisHeight = Orbital.ApoapsisHeight;
using OrbitalPeriod = Orbital.OrbitalPeriod; using OrbitalPeriod = Orbital.OrbitalPeriod;
using PeriapsisHeight = Orbital.PeriapsisHeight; using PeriapsisHeight = Orbital.PeriapsisHeight;
using SemiMajorAxis = Orbital.SemiMajorAxis; using SemiMajorAxis = Orbital.SemiMajorAxis;
using SemiMinorAxis = Orbital.SemiMinorAxis; using SemiMinorAxis = Orbital.SemiMinorAxis;
using TimeToApoapsis = Orbital.TimeToApoapsis; using TimeToApoapsis = Orbital.TimeToApoapsis;
using TimeToPeriapsis = Orbital.TimeToPeriapsis; using TimeToPeriapsis = Orbital.TimeToPeriapsis;
   
#endregion  
   
public static class ReadoutLibrary public static class ReadoutLibrary
{ {
#region Fields  
   
private static List<ReadoutModule> readouts = new List<ReadoutModule>(); private static List<ReadoutModule> readouts = new List<ReadoutModule>();
   
#endregion  
   
#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("Thermal", "Thermal characteristics readouts.");
ReadoutCategory.SetCategory("Miscellaneous", "Miscellaneous readouts."); ReadoutCategory.SetCategory("Miscellaneous", "Miscellaneous readouts.");
ReadoutCategory.Selected = ReadoutCategory.GetCategory("Orbital"); 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 MeanAnomalyAtEpoc()); readouts.Add(new MeanAnomalyAtEpoc());
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());
  readouts.Add(new PostBurnApoapsis());
  readouts.Add(new PostBurnPeriapsis());
  readouts.Add(new SpeedAtApoapsis());
  readouts.Add(new SpeedAtPeriapsis());
  readouts.Add(new TimeToAtmosphere());
   
// 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 MachNumber());
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 ThrustOffsetAngle());
readouts.Add(new ThrustTorque()); 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 PartCount());
readouts.Add(new Heading()); readouts.Add(new Heading());
readouts.Add(new Pitch()); readouts.Add(new Pitch());
readouts.Add(new Roll()); readouts.Add(new Roll());
readouts.Add(new HeadingRate()); readouts.Add(new HeadingRate());
readouts.Add(new PitchRate()); readouts.Add(new PitchRate());
readouts.Add(new RollRate()); 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());
   
  // Thermal
  readouts.Add(new InternalFlux());
  readouts.Add(new ConvectionFlux());
  readouts.Add(new RadiationFlux());
  readouts.Add(new CriticalPart());
  readouts.Add(new CriticalTemperature());
  readouts.Add(new CriticalSkinTemperature());
  readouts.Add(new CriticalThermalPercentage());
  readouts.Add(new HottestPart());
  readouts.Add(new HottestTemperature());
  readouts.Add(new HottestSkinTemperature());
  readouts.Add(new CoolestPart());
  readouts.Add(new CoolestTemperature());
  readouts.Add(new CoolestSkinTemperature());
   
// Misc // 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()); readouts.Add(new VectoredThrustToggle());
readouts.Add(new SystemTime()); readouts.Add(new SystemTime());
   
LoadHelpStrings(); LoadHelpStrings();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Exception(ex); Logger.Exception(ex);
} }
} }
   
#endregion  
   
#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
set { readouts = value; } {
} return readouts;
  }
#endregion set
  {
#region Methods readouts = value;
  }
  }
   
/// <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 (ReadoutModule readout in readouts)
{ {
readout.Reset(); readout.Reset();
} }
} }
   
/// <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"); SettingHandler handler = SettingHandler.Load("HelpStrings.xml");
foreach (var readout in readouts) foreach (ReadoutModule 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  
} }
} }
// //
// 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.Flight.Sections; using KerbalEngineer.Flight.Sections;
   
using UnityEngine; using UnityEngine;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts namespace KerbalEngineer.Flight.Readouts
{ {
  using Extensions;
   
public abstract class ReadoutModule public abstract class ReadoutModule
{ {
#region Fields #region Fields
   
private int lineCountEnd; private int lineCountEnd;
private int lineCountStart; private int lineCountStart;
   
#endregion #endregion
   
#region Constructors #region Constructors
   
protected ReadoutModule() protected ReadoutModule()
{ {
this.InitialiseStyles(); this.InitialiseStyles();
GuiDisplaySize.OnSizeChanged += this.OnSizeChanged; GuiDisplaySize.OnSizeChanged += this.OnSizeChanged;
} }
   
#endregion #endregion
   
#region Properties #region Properties
   
/// <summary> /// <summary>
/// Gets and sets the button style. /// Gets and sets the button style.
/// </summary> /// </summary>
public GUIStyle ButtonStyle { get; set; } public GUIStyle ButtonStyle { get; set; }
   
/// <summary> /// <summary>
/// Gets ans sets the readout category. /// Gets ans sets the readout category.
/// </summary> /// </summary>
public ReadoutCategory Category { get; set; } public ReadoutCategory Category { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets whether the readout can be added to a section multiple times. /// Gets and sets whether the readout can be added to a section multiple times.
/// </summary> /// </summary>
public bool Cloneable { get; set; } public bool Cloneable { get; set; }
   
/// <summary> /// <summary>
/// Gets the width of the content. (Sum of NameStyle + ValueStyle widths.) /// Gets the width of the content. (Sum of NameStyle + ValueStyle widths.)
/// </summary> /// </summary>
public float ContentWidth public float ContentWidth
{ {
get { return 230.0f * GuiDisplaySize.Offset; } get { return 230.0f * GuiDisplaySize.Offset; }
} }
   
/// <summary> /// <summary>
/// Gets and sets the flexible label style. /// Gets and sets the flexible label style.
/// </summary> /// </summary>
public GUIStyle FlexiLabelStyle { get; set; } public GUIStyle FlexiLabelStyle { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets the help string which is shown in the editor. /// Gets and sets the help string which is shown in the editor.
/// </summary> /// </summary>
public string HelpString { get; set; } public string HelpString { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets whether the readout should be shown on new installs. /// Gets and sets whether the readout should be shown on new installs.
/// </summary> /// </summary>
public bool IsDefault { get; set; } public bool IsDefault { get; set; }
   
/// <summary> /// <summary>
/// Gets the number of drawn lines. /// Gets the number of drawn lines.
/// </summary> /// </summary>
public int LineCount { get; private set; } public int LineCount { get; private set; }
   
/// <summary> /// <summary>
/// Gets and sets the message style. /// Gets and sets the message style.
/// </summary> /// </summary>
public GUIStyle MessageStyle { get; set; } public GUIStyle MessageStyle { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets the readout name. /// Gets and sets the readout name.
/// </summary> /// </summary>
public string Name { get; set; } public string Name { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets the name style. /// Gets and sets the name style.
/// </summary> /// </summary>
public GUIStyle NameStyle { get; set; } public GUIStyle NameStyle { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets whether the readout has requested a section resize. /// Gets and sets whether the readout has requested a section resize.
/// </summary> /// </summary>
public bool ResizeRequested { get; set; } public bool ResizeRequested { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets whether the help string is being shown in the editor. /// Gets and sets whether the help string is being shown in the editor.
/// </summary> /// </summary>
public bool ShowHelp { get; set; } public bool ShowHelp { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets the text field style. /// Gets and sets the text field style.
/// </summary> /// </summary>
public GUIStyle TextFieldStyle { get; set; } public GUIStyle TextFieldStyle { get; set; }
   
/// <summary> /// <summary>
/// Gets and sets the value style. /// Gets and sets the value style.
/// </summary> /// </summary>
public GUIStyle ValueStyle { get; set; } public GUIStyle ValueStyle { get; set; }
   
#endregion #endregion
   
#region Methods: public #region Methods: public
   
/// <summary> /// <summary>
/// Called when a readout is asked to draw its self. /// Called when a readout is asked to draw its self.
/// </summary> /// </summary>
public virtual void Draw(SectionModule section) { } public virtual void Draw(SectionModule section) { }
   
/// <summary> /// <summary>
/// Called on each fixed update frame where the readout is visible. /// Called on each fixed update frame where the readout is visible.
/// </summary> /// </summary>
public virtual void FixedUpdate() { } public virtual void FixedUpdate() { }
   
public void LineCountEnd() public void LineCountEnd()
{ {
this.LineCount = this.lineCountEnd; this.LineCount = this.lineCountEnd;
if (this.lineCountEnd.CompareTo(this.lineCountStart) < 0) if (this.lineCountEnd.CompareTo(this.lineCountStart) < 0)
{ {
this.ResizeRequested = true; this.ResizeRequested = true;
} }
} }
   
public void LineCountStart() public void LineCountStart()
{ {
this.lineCountStart = this.lineCountEnd; this.lineCountStart = this.lineCountEnd;
this.lineCountEnd = 0; this.lineCountEnd = 0;
} }
   
/// <summary> /// <summary>
/// Called when FlightEngineerCore is started. /// Called when FlightEngineerCore is started.
/// </summary> /// </summary>
public virtual void Reset() { } public virtual void Reset() { }
   
/// <summary> /// <summary>
/// Called on each update frame when the readout is visible. /// Called on each update frame when the readout is visible.
/// </summary> /// </summary>
public virtual void Update() { } public virtual void Update() { }
   
#endregion #endregion
   
#region Methods: protected #region Methods: protected
   
protected void DrawLine(string value, bool compact = false) protected void DrawLine(string value, bool compact = false)
{ {
GUILayout.BeginHorizontal(GUILayout.Width(this.ContentWidth)); GUILayout.BeginHorizontal(GUILayout.Width(this.ContentWidth));
if (!compact) if (!compact)
{ {
GUILayout.Label(this.Name, this.NameStyle); GUILayout.Label(this.Name, this.NameStyle);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUILayout.Label(value, this.ValueStyle); GUILayout.Label(value.ToLength(20), this.ValueStyle);
} }
else else
{ {
GUILayout.Label(this.Name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f)); GUILayout.Label(this.Name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f));
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUILayout.Label(value, this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f)); GUILayout.Label(value.ToLength(20), this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
this.lineCountEnd++; this.lineCountEnd++;
} }
   
protected void DrawLine(string name, string value, bool compact = false) protected void DrawLine(string name, string value, bool compact = false)
{ {
GUILayout.BeginHorizontal(GUILayout.Width(this.ContentWidth)); GUILayout.BeginHorizontal(GUILayout.Width(this.ContentWidth));
if (!compact) if (!compact)
{ {
GUILayout.Label(name, this.NameStyle); GUILayout.Label(name, this.NameStyle);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUILayout.Label(value, this.ValueStyle); GUILayout.Label(value.ToLength(20), this.ValueStyle);
} }
else else
{ {
GUILayout.Label(name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f)); GUILayout.Label(name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f));
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUILayout.Label(value, this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f)); GUILayout.Label(value.ToLength(20), this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
this.lineCountEnd++; this.lineCountEnd++;
} }
   
protected void DrawLine(Action drawAction, bool showName = true, bool compact = false) protected void DrawLine(Action drawAction, bool showName = true, bool compact = false)
{ {
GUILayout.BeginHorizontal(GUILayout.Width(this.ContentWidth)); GUILayout.BeginHorizontal(GUILayout.Width(this.ContentWidth));
if (showName) if (showName)
{ {
if (!compact) if (!compact)
{ {
GUILayout.Label(this.Name, this.NameStyle); GUILayout.Label(this.Name, this.NameStyle);
} }
else else
{ {
GUILayout.Label(this.Name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f)); GUILayout.Label(this.Name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f));
} }
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
} }
drawAction(); drawAction();
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
this.lineCountEnd++; this.lineCountEnd++;
} }
   
protected void DrawMessageLine(string value, bool compact = false) protected void DrawMessageLine(string value, bool compact = false)
{ {
GUILayout.BeginHorizontal(GUILayout.Width(this.ContentWidth)); GUILayout.BeginHorizontal(GUILayout.Width(this.ContentWidth));
if (!compact) if (!compact)
{ {
GUILayout.Label(value, this.MessageStyle); GUILayout.Label(value, this.MessageStyle);
} }
else else
{ {
GUILayout.Label(value, this.MessageStyle, GUILayout.Height(this.MessageStyle.fontSize * 1.2f)); GUILayout.Label(value, this.MessageStyle, GUILayout.Height(this.MessageStyle.fontSize * 1.2f));
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
this.lineCountEnd++; this.lineCountEnd++;
} }
   
#endregion #endregion
   
#region Methods: private #region Methods: private
   
/// <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.NameStyle = new GUIStyle(HighLogic.Skin.label) this.NameStyle = new GUIStyle(HighLogic.Skin.label)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(5, 0, 0, 0), padding = new RectOffset(5, 0, 0, 0),
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Bold, fontStyle = FontStyle.Bold,
fixedHeight = 20.0f * GuiDisplaySize.Offset fixedHeight = 20.0f * GuiDisplaySize.Offset
}; };
   
this.ValueStyle = new GUIStyle(HighLogic.Skin.label) this.ValueStyle = new GUIStyle(HighLogic.Skin.label)
{ {
margin = new RectOffset(), margin = new RectOffset(),
padding = new RectOffset(0, 5, 0, 0), padding = new RectOffset(0, 5, 0, 0),
alignment = TextAnchor.MiddleRight, alignment = TextAnchor.MiddleRight,
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Normal, fontStyle = FontStyle.Normal,
fixedHeight = 20.0f * GuiDisplaySize.Offset fixedHeight = 20.0f * GuiDisplaySize.Offset
}; };
   
this.MessageStyle = new GUIStyle(HighLogic.Skin.label) this.MessageStyle = 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.MiddleCenter, alignment = TextAnchor.MiddleCenter,
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fontStyle = FontStyle.Normal, fontStyle = FontStyle.Normal,
fixedHeight = 20.0f * GuiDisplaySize.Offset, fixedHeight = 20.0f * GuiDisplaySize.Offset,
stretchWidth = true stretchWidth = true
}; };
   
this.FlexiLabelStyle = new GUIStyle(this.NameStyle) this.FlexiLabelStyle = new GUIStyle(this.NameStyle)
{ {
fixedWidth = 0, fixedWidth = 0,
stretchWidth = true stretchWidth = true
}; };
   
this.ButtonStyle = new GUIStyle(HighLogic.Skin.button) this.ButtonStyle = new GUIStyle(HighLogic.Skin.button)
{ {
normal = normal =
{ {
textColor = Color.white textColor = Color.white
}, },
margin = new RectOffset(0, 0, 1, 1), margin = new RectOffset(0, 0, 1, 1),
padding = new RectOffset(), padding = new RectOffset(),
alignment = TextAnchor.MiddleCenter, alignment = TextAnchor.MiddleCenter,
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fixedHeight = 18.0f * GuiDisplaySize.Offset fixedHeight = 18.0f * GuiDisplaySize.Offset
}; };
   
this.TextFieldStyle = new GUIStyle(HighLogic.Skin.textField) this.TextFieldStyle = new GUIStyle(HighLogic.Skin.textField)
{ {
margin = new RectOffset(0, 0, 1, 1), margin = new RectOffset(0, 0, 1, 1),
padding = new RectOffset(5, 5, 0, 0), padding = new RectOffset(5, 5, 0, 0),
alignment = TextAnchor.MiddleLeft, alignment = TextAnchor.MiddleLeft,
fontSize = (int)(11 * GuiDisplaySize.Offset), fontSize = (int)(11 * GuiDisplaySize.Offset),
fixedHeight = 18.0f * GuiDisplaySize.Offset fixedHeight = 18.0f * GuiDisplaySize.Offset
}; };
} }
   
private void OnSizeChanged() private void OnSizeChanged()
{ {
this.InitialiseStyles(); this.InitialiseStyles();
this.ResizeRequested = true; this.ResizeRequested = true;
} }
   
#endregion #endregion
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2015 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 KerbalEngineer.Extensions;  
using KerbalEngineer.Helpers;  
   
#endregion  
   
namespace KerbalEngineer.Flight.Readouts.Rendezvous namespace KerbalEngineer.Flight.Readouts.Rendezvous
{ {
  using System;
  using Extensions;
  using Helpers;
   
public class RendezvousProcessor : IUpdatable, IUpdateRequest public class RendezvousProcessor : IUpdatable, IUpdateRequest
{ {
#region Fields  
   
private static readonly RendezvousProcessor instance = new RendezvousProcessor(); private static readonly RendezvousProcessor instance = new RendezvousProcessor();
   
private Orbit originOrbit; private Orbit originOrbit;
private Orbit targetOrbit; private Orbit targetOrbit;
   
#endregion  
   
#region Properties  
   
/// <summary> /// <summary>
/// Gets the target's altitude above its reference body. /// Gets the target's altitude above its reference body.
/// </summary> /// </summary>
public static double AltitudeSeaLevel { get; private set; } public static double AltitudeSeaLevel { get; private set; }
   
/// <summary> /// <summary>
/// Gets the angle from the origin position to the ascending node. /// Gets the angle from the origin position to the ascending node.
/// </summary> /// </summary>
public static double AngleToAscendingNode { get; private set; } public static double AngleToAscendingNode { get; private set; }
   
/// <summary> /// <summary>
/// Gets the angle from the origin position to the descending node. /// Gets the angle from the origin position to the descending node.
/// </summary> /// </summary>
public static double AngleToDescendingNode { get; private set; } public static double AngleToDescendingNode { get; private set; }
   
/// <summary> /// <summary>
/// Gets the target's apoapsis above its reference body. /// Gets the target's apoapsis above its reference body.
/// </summary> /// </summary>
public static double ApoapsisHeight { get; private set; } public static double ApoapsisHeight { get; private set; }
   
/// <summary> /// <summary>
/// Gets the distance from the origin position to the target position. /// Gets the distance from the origin position to the target position.
/// </summary> /// </summary>
public static double Distance { get; private set; } public static double Distance { get; private set; }
   
/// <summary> /// <summary>
/// Gets the current instance of the rendezvous processor. /// Gets the current instance of the rendezvous processor.
/// </summary> /// </summary>
public static RendezvousProcessor Instance public static RendezvousProcessor Instance
{ {
get { return instance; } get
  {
  return instance;
  }
} }
   
/// <summary> /// <summary>
/// Gets the difference in angle from the origin position to where it is most efficient to burn for an encounter. /// Gets the difference in angle from the origin position to where it is most efficient to burn for an encounter.
/// </summary> /// </summary>
public static double InterceptAngle { get; private set; } public static double InterceptAngle { get; private set; }
   
/// <summary> /// <summary>
/// Gets the orbital period of the target orbit. /// Gets the orbital period of the target orbit.
/// </summary> /// </summary>
public static double OrbitalPeriod { get; private set; } public static double OrbitalPeriod { get; private set; }
   
/// <summary> /// <summary>
/// Gets the target's periapsis above its reference body. /// Gets the target's periapsis above its reference body.
/// </summary> /// </summary>
public static double PeriapsisHeight { get; private set; } public static double PeriapsisHeight { get; private set; }
   
/// <summary> /// <summary>
/// Gets the difference in angle from the origin position to the target position based on a common reference. /// Gets the difference in angle from the origin position to the target position based on a common reference.
/// </summary> /// </summary>
public static double PhaseAngle { get; private set; } public static double PhaseAngle { get; private set; }
   
/// <summary> /// <summary>
/// Gets the angular difference between the origin and target orbits. /// Gets the angular difference between the origin and target orbits.
/// </summary> /// </summary>
public static double RelativeInclination { get; private set; } public static double RelativeInclination { get; private set; }
   
/// <summary> /// <summary>
/// Gets the relative orbital speed between the vessel and target. /// Gets the relative orbital speed between the vessel and target.
/// </summary> /// </summary>
public static double RelativeSpeed { get; private set; } public static double RelativeSpeed { get; private set; }
   
/// <summary> /// <summary>
/// Gets the relative orbital velocity between the vessel and target. /// Gets the relative orbital velocity between the vessel and target.
/// </summary> /// </summary>
public static double RelativeVelocity { get; private set; } public static double RelativeVelocity { get; private set; }
   
/// <summary> /// <summary>
/// Gets the semi-major axis of the target orbit. /// Gets the semi-major axis of the target orbit.
/// </summary> /// </summary>
public static double SemiMajorAxis { get; private set; } public static double SemiMajorAxis { get; private set; }
   
/// <summary> /// <summary>
/// Gets the semi-minor axis of the target orbit. /// Gets the semi-minor axis of the target orbit.
/// </summary> /// </summary>
public static double SemiMinorAxis { get; private set; } public static double SemiMinorAxis { 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 the target's time to apoapsis. /// Gets the target's time to apoapsis.
/// </summary> /// </summary>
public static double TimeToApoapsis { get; private set; } public static double TimeToApoapsis { get; private set; }
   
/// <summary> /// <summary>
/// Gets the time it will take to reach the ascending node. /// Gets the time it will take to reach the ascending node.
/// </summary> /// </summary>
public static double TimeToAscendingNode { get; private set; } public static double TimeToAscendingNode { get; private set; }
   
/// <summary> /// <summary>
/// Gets the time it will take to reach the descending node. /// Gets the time it will take to reach the descending node.
/// </summary> /// </summary>
public static double TimeToDescendingNode { get; private set; } public static double TimeToDescendingNode { get; private set; }
   
/// <summary> /// <summary>
/// Gets the target's time to periapsis. /// Gets the target's time to periapsis.
/// </summary> /// </summary>
public static double TimeToPeriapsis { get; private set; } public static double TimeToPeriapsis { get; private set; }
   
/// <summary> /// <summary>
/// Gets and sets whether the updatable object should be updated. /// Gets and sets whether the updatable object should be updated.
/// </summary> /// </summary>
public bool UpdateRequested { get; set; } public bool UpdateRequested { get; set; }
   
#endregion  
   
#region Methods: public  
   
/// <summary> /// <summary>
/// Request and update to calculate the details. /// Request and update to calculate the details.
/// </summary> /// </summary>
public static void RequestUpdate() public static void RequestUpdate()
{ {
instance.UpdateRequested = true; instance.UpdateRequested = true;
} }
   
/// <summary> /// <summary>
/// Updates the details by recalculating if requested. /// Updates the details by recalculating if requested.
/// </summary> /// </summary>
public void Update() public void Update()
{ {
if (FlightGlobals.fetch.VesselTarget == null) if (FlightGlobals.fetch == null ||
  FlightGlobals.fetch.VesselTarget == null ||
  FlightGlobals.ActiveVessel == null ||
  FlightGlobals.ActiveVessel.targetObject == null ||
  FlightGlobals.ActiveVessel.targetObject.GetOrbit() == null ||
  FlightGlobals.ship_orbit == null ||
  FlightGlobals.ship_orbit.referenceBody == null)
{ {
ShowDetails = false; ShowDetails = false;
return; return;
} }
   
ShowDetails = true; ShowDetails = true;
   
this.targetOrbit = FlightGlobals.fetch.VesselTarget.GetOrbit(); targetOrbit = FlightGlobals.fetch.VesselTarget.GetOrbit();
this.originOrbit = (FlightGlobals.ship_orbit.referenceBody == Planetarium.fetch.Sun || FlightGlobals.ship_orbit.referenceBody == FlightGlobals.ActiveVessel.targetObject.GetOrbit().referenceBody) originOrbit = (FlightGlobals.ship_orbit.referenceBody == Planetarium.fetch.Sun ||
  FlightGlobals.ship_orbit.referenceBody == FlightGlobals.ActiveVessel.targetObject.GetOrbit().referenceBody)
? FlightGlobals.ship_orbit ? FlightGlobals.ship_orbit
: FlightGlobals.ship_orbit.referenceBody.orbit; : FlightGlobals.ship_orbit.referenceBody.orbit;
   
RelativeInclination = this.originOrbit.GetRelativeInclination(this.targetOrbit); RelativeInclination = originOrbit.GetRelativeInclination(targetOrbit);
RelativeVelocity = FlightGlobals.ship_tgtSpeed; RelativeVelocity = FlightGlobals.ship_tgtSpeed;
RelativeSpeed = FlightGlobals.ship_obtSpeed - this.targetOrbit.orbitalSpeed; RelativeSpeed = FlightGlobals.ship_obtSpeed - targetOrbit.orbitalSpeed;
PhaseAngle = this.originOrbit.GetPhaseAngle(this.targetOrbit); PhaseAngle = originOrbit.GetPhaseAngle(targetOrbit);
InterceptAngle = this.CalcInterceptAngle(); InterceptAngle = CalcInterceptAngle();
TimeToAscendingNode = this.originOrbit.GetTimeToVector(this.GetAscendingNode()); TimeToAscendingNode = originOrbit.GetTimeToVector(GetAscendingNode());
TimeToDescendingNode = this.originOrbit.GetTimeToVector(this.GetDescendingNode()); TimeToDescendingNode = originOrbit.GetTimeToVector(GetDescendingNode());
AngleToAscendingNode = this.originOrbit.GetAngleToVector(this.GetAscendingNode()); AngleToAscendingNode = originOrbit.GetAngleToVector(GetAscendingNode());
AngleToDescendingNode = this.originOrbit.GetAngleToVector(this.GetDescendingNode()); AngleToDescendingNode = originOrbit.GetAngleToVector(GetDescendingNode());
AltitudeSeaLevel = this.targetOrbit.altitude; AltitudeSeaLevel = targetOrbit.altitude;
ApoapsisHeight = this.targetOrbit.ApA; ApoapsisHeight = targetOrbit.ApA;
PeriapsisHeight = this.targetOrbit.PeA; PeriapsisHeight = targetOrbit.PeA;
TimeToApoapsis = this.targetOrbit.timeToAp; TimeToApoapsis = targetOrbit.timeToAp;
TimeToPeriapsis = this.targetOrbit.timeToPe; TimeToPeriapsis = targetOrbit.timeToPe;
SemiMajorAxis = this.targetOrbit.semiMajorAxis; SemiMajorAxis = targetOrbit.semiMajorAxis;
SemiMinorAxis = this.targetOrbit.semiMinorAxis; SemiMinorAxis = targetOrbit.semiMinorAxis;
   
Distance = Vector3d.Distance(this.targetOrbit.pos, this.originOrbit.pos); Distance = Vector3d.Distance(targetOrbit.pos, originOrbit.pos);
OrbitalPeriod = this.targetOrbit.period; OrbitalPeriod = targetOrbit.period;
} }
   
#endregion  
   
#region Methods: private  
   
private double CalcInterceptAngle() private double CalcInterceptAngle()
{ {
var originRadius = (this.originOrbit.semiMinorAxis + this.originOrbit.semiMajorAxis) * 0.5; double originRadius = (originOrbit.semiMinorAxis + originOrbit.semiMajorAxis) * 0.5;
var targetRadius = (this.targetOrbit.semiMinorAxis + this.targetOrbit.semiMajorAxis) * 0.5; double targetRadius = (targetOrbit.semiMinorAxis + targetOrbit.semiMajorAxis) * 0.5;
var angle = 180.0 * (1.0 - Math.Pow((originRadius + targetRadius) / (2.0 * targetRadius), 1.5)); double angle = 180.0 * (1.0 - Math.Pow((originRadius + targetRadius) / (2.0 * targetRadius), 1.5));
angle = PhaseAngle - angle; angle = PhaseAngle - angle;
return RelativeInclination < 90.0 ? AngleHelper.Clamp360(angle) : AngleHelper.Clamp360(360.0 - (180.0 - angle)); return RelativeInclination < 90.0 ? AngleHelper.Clamp360(angle) : AngleHelper.Clamp360(360.0 - (180.0 - angle));
} }
   
private Vector3d GetAscendingNode() private Vector3d GetAscendingNode()
{ {
return Vector3d.Cross(this.targetOrbit.GetOrbitNormal(), this.originOrbit.GetOrbitNormal()); return Vector3d.Cross(targetOrbit.GetOrbitNormal(), originOrbit.GetOrbitNormal());
} }
   
private Vector3d GetDescendingNode() private Vector3d GetDescendingNode()
{ {
return Vector3d.Cross(this.originOrbit.GetOrbitNormal(), this.targetOrbit.GetOrbitNormal()); return Vector3d.Cross(originOrbit.GetOrbitNormal(), targetOrbit.GetOrbitNormal());
} }
   
#endregion  
} }
} }
// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2015 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 KerbalEngineer.Extensions;  
using KerbalEngineer.Flight.Sections;  
   
#endregion  
   
namespace KerbalEngineer.Flight.Readouts.Surface namespace KerbalEngineer.Flight.Readouts.Surface
{ {
  using Extensions;
  using Sections;
   
public class AtmosphericEfficiency : ReadoutModule public class AtmosphericEfficiency : ReadoutModule
{ {
#region Constructors  
   
public AtmosphericEfficiency() public AtmosphericEfficiency()
{ {
this.Name = "Atmos. Efficiency"; Name = "Atmos. Efficiency";
this.Category = ReadoutCategory.GetCategory("Surface"); Category = ReadoutCategory.GetCategory("Surface");
this.HelpString = "Shows you vessel's efficiency as a ratio of the current velocity and terminal velocity. Less than 1 means that you are losing efficiency due to gravity and greater than 1 is due to drag."; HelpString = "Shows you vessel's efficiency as a ratio of the current velocity and terminal velocity. Less than 100% means that you are losing efficiency due to gravity and greater than 100% is due to drag.";
this.IsDefault = true; IsDefault = false;
} }
   
#endregion  
   
#region Methods: public  
   
public override void Draw(SectionModule section) public override void Draw(SectionModule section)
{ {
if (AtmosphericProcessor.ShowDetails) if (AtmosphericProcessor.ShowDetails)
{ {
this.DrawLine(AtmosphericProcessor.Efficiency.ToPercent(), section.IsHud); DrawLine(AtmosphericProcessor.Efficiency.ToPercent(), section.IsHud);
} }
} }
   
public override void Reset() public override void Reset()
{ {
FlightEngineerCore.Instance.AddUpdatable(AtmosphericProcessor.Instance); FlightEngineerCore.Instance.AddUpdatable(AtmosphericProcessor.Instance);
} }
   
public override void Update() public override void Update()
{ {
AtmosphericProcessor.RequestUpdate(); AtmosphericProcessor.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 KerbalEngineer.Extensions; using KerbalEngineer.Extensions;
using KerbalEngineer.Flight.Sections; using KerbalEngineer.Flight.Sections;
  using System;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Surface namespace KerbalEngineer.Flight.Readouts.Surface
{ {
public class HorizontalSpeed : ReadoutModule public class HorizontalSpeed : ReadoutModule
{ {
#region Constructors #region Constructors
   
public HorizontalSpeed() public HorizontalSpeed()
{ {
this.Name = "Horizontal Speed"; this.Name = "Horizontal Speed";
this.Category = ReadoutCategory.GetCategory("Surface"); this.Category = ReadoutCategory.GetCategory("Surface");
this.HelpString = "Shows the vessel's horizontal speed across a celestial body's surface."; this.HelpString = "Shows the vessel's horizontal speed across a celestial body's surface.";
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)
{ {
this.DrawLine(FlightGlobals.ActiveVessel.horizontalSrfSpeed.ToSpeed(), section.IsHud); // Used to do this but the bug-fix to horizontalSrfSpeed in KSP 1.0.3 actually made it worse so workaround
  //this.DrawLine(FlightGlobals.ActiveVessel.horizontalSrfSpeed.ToSpeed(), section.IsHud);
  var ves = FlightGlobals.ActiveVessel;
  double horizSpeed = Math.Sqrt(ves.srfSpeed * ves.srfSpeed - ves.verticalSpeed * ves.verticalSpeed);
  this.DrawLine(horizSpeed.ToSpeed(), section.IsHud);
} }
   
#endregion #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.Helpers;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Surface namespace KerbalEngineer.Flight.Readouts.Surface
{ {
public class Latitude : ReadoutModule public class Latitude : ReadoutModule
{ {
#region Constructors #region Constructors
   
public Latitude() public Latitude()
{ {
this.Name = "Latitude"; this.Name = "Latitude";
this.Category = ReadoutCategory.GetCategory("Surface"); this.Category = ReadoutCategory.GetCategory("Surface");
this.HelpString = "Shows the vessel's latitude position around the celestial body. Latitude is the angle from the equator to poles."; this.HelpString = "Shows the vessel's latitude position around the celestial body. Latitude is the angle from the equator to poles.";
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)
{ {
this.DrawLine(KSPUtil.PrintLatitude(FlightGlobals.ship_latitude), section.IsHud); this.DrawLine(Units.ToAngleDMS(FlightGlobals.ship_latitude) + (FlightGlobals.ship_latitude < 0 ? " S" : " N"), section.IsHud);
} }
   
#endregion #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 KerbalEngineer.Flight.Sections;  
   
#endregion  
   
namespace KerbalEngineer.Flight.Readouts.Surface namespace KerbalEngineer.Flight.Readouts.Surface
{ {
  using Helpers;
  using Sections;
   
public class Longitude : ReadoutModule public class Longitude : ReadoutModule
{ {
#region Constructors  
   
public Longitude() public Longitude()
{ {
this.Name = "Longitude"; Name = "Longitude";
this.Category = ReadoutCategory.GetCategory("Surface"); Category = ReadoutCategory.GetCategory("Surface");
this.HelpString = "Shows the vessel's longitude around a celestial body. Longitude is the angle from the bodies prime meridian."; HelpString = "Shows the vessel's longitude around a celestial body. Longitude is the angle from the bodies prime meridian.";
this.IsDefault = true; IsDefault = true;
} }
   
#endregion  
   
#region Methods: public  
   
public override void Draw(SectionModule section) public override void Draw(SectionModule section)
{ {
this.DrawLine(KSPUtil.PrintLongitude(FlightGlobals.ship_longitude), section.IsHud); double angle = AngleHelper.Clamp180(FlightGlobals.ship_longitude);
  DrawLine(Units.ToAngleDMS(angle) + (angle < 0.0 ? "W" : " E"), section.IsHud);
} }
   
#endregion  
} }
} }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Surface
  {
  using Extensions;
  using Sections;
 
  public class MachNumber : ReadoutModule
  {
  public MachNumber()
  {
  Name = "Mach Number";
  Category = ReadoutCategory.GetCategory("Surface");
  HelpString = "Shows the vessel's mach number.";
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (FlightGlobals.ActiveVessel.atmDensity > 0.0)
  {
  DrawLine(FlightGlobals.ActiveVessel.mach.ToMach(), section.IsHud);
  }
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Extensions;
  using Sections;
 
  public class ConvectionFlux : ReadoutModule
  {
  public ConvectionFlux()
  {
  Name = "Convection Flux";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails && FlightGlobals.ActiveVessel.atmDensity > 0.0)
  {
  DrawLine(ThermalProcessor.ConvectionFlux.ToFlux(), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Sections;
 
  public class CoolestPart : ReadoutModule
  {
  public CoolestPart()
  {
  Name = "Coolest Part";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(ThermalProcessor.CoolestPartName, section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Helpers;
  using Sections;
 
  public class CoolestSkinTemperature : ReadoutModule
  {
  public CoolestSkinTemperature()
  {
  Name = "Coolest Skin Temperature";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(Units.ToTemperature(ThermalProcessor.CoolestSkinTemperature, ThermalProcessor.CoolestSkinTemperatureMax), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Helpers;
  using Sections;
 
  public class CoolestTemperature : ReadoutModule
  {
  public CoolestTemperature()
  {
  Name = "Coolest Temperature";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(Units.ToTemperature(ThermalProcessor.CoolestTemperature, ThermalProcessor.CoolestTemperatureMax), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Sections;
 
  public class CriticalPart : ReadoutModule
  {
  public CriticalPart()
  {
  Name = "Critical Part";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(ThermalProcessor.CriticalPartName, section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Helpers;
  using Sections;
 
  public class CriticalSkinTemperature : ReadoutModule
  {
  public CriticalSkinTemperature()
  {
  Name = "Critical Skin Temperature";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(Units.ToTemperature(ThermalProcessor.CriticalSkinTemperature, ThermalProcessor.CriticalSkinTemperatureMax), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Helpers;
  using Sections;
 
  public class CriticalTemperature : ReadoutModule
  {
  public CriticalTemperature()
  {
  Name = "Critical Temperature";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(Units.ToTemperature(ThermalProcessor.CriticalTemperature, ThermalProcessor.CriticalTemperatureMax), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Extensions;
  using Sections;
 
  public class CriticalThermalPercentage : ReadoutModule
  {
  public CriticalThermalPercentage()
  {
  Name = "Critical Thermal Percentage";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(ThermalProcessor.CriticalTemperaturePercentage.ToPercent(), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Sections;
 
  public class HottestPart : ReadoutModule
  {
  public HottestPart()
  {
  Name = "Hottest Part";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(ThermalProcessor.HottestPartName, section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Helpers;
  using Sections;
 
  public class HottestSkinTemperature : ReadoutModule
  {
  public HottestSkinTemperature()
  {
  Name = "Hottest Skin Temperature";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(Units.ToTemperature(ThermalProcessor.HottestSkinTemperature, ThermalProcessor.HottestSkinTemperatureMax), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Helpers;
  using Sections;
 
  public class HottestTemperature : ReadoutModule
  {
  public HottestTemperature()
  {
  Name = "Hottest Temperature";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(Units.ToTemperature(ThermalProcessor.HottestTemperature, ThermalProcessor.HottestTemperatureMax), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Extensions;
  using Sections;
 
  public class InternalFlux : ReadoutModule
  {
  public InternalFlux()
  {
  Name = "Internal Flux";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(ThermalProcessor.InternalFlux.ToFlux(), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Kerbal Engineer Redux
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using Extensions;
  using Sections;
 
  public class RadiationFlux : ReadoutModule
  {
  public RadiationFlux()
  {
  Name = "Radiation Flux";
  Category = ReadoutCategory.GetCategory("Thermal");
  HelpString = string.Empty;
  IsDefault = true;
  }
 
  public override void Draw(SectionModule section)
  {
  if (ThermalProcessor.ShowDetails)
  {
  DrawLine(ThermalProcessor.RadiationFlux.ToFlux(), section.IsHud);
  }
  }
 
  public override void Reset()
  {
  FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
  }
 
  public override void Update()
  {
  ThermalProcessor.RequestUpdate();
  }
  }
  }
  //
  // Copyright (C) 2015 CYBUTEK
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
 
  namespace KerbalEngineer.Flight.Readouts.Thermal
  {
  using System;
 
  public class ThermalProcessor : IUpdatable, IUpdateRequest
  {
  private static readonly ThermalProcessor instance = new ThermalProcessor();
 
  static ThermalProcessor()
  {
  HottestTemperature = 0.0;
  HottestTemperatureMax = 0.0;
  HottestSkinTemperature = 0.0;
  HottestSkinTemperatureMax = 0.0;
  CoolestTemperature = 0.0;
  CoolestTemperatureMax = 0.0;
  CoolestSkinTemperature = 0.0;
  CoolestSkinTemperatureMax = 0.0;
  CriticalTemperature = 0.0;
  CriticalTemperatureMax = 0.0;
  CriticalSkinTemperature = 0.0;
  CriticalSkinTemperatureMax = 0.0;
  HottestPartName = string.Empty;
  CoolestPartName = string.Empty;
  CriticalPartName = string.Empty;
  }
 
  public static double ConvectionFlux { get; private set; }
 
  public static string CoolestPartName { get; private set; }
 
  public static double CoolestSkinTemperature { get; private set; }
 
  public static double CoolestSkinTemperatureMax { get; private set; }
 
  public static double CoolestTemperature { get; private set; }
 
  public static double CoolestTemperatureMax { get; private set; }
 
  public static string CriticalPartName { get; private set; }
 
  public static double CriticalSkinTemperature { get; private set; }
 
  public static double CriticalSkinTemperatureMax { get; private set; }
 
  public static double CriticalTemperature { get; private set; }
 
  public static double CriticalTemperatureMax { get; private set; }
 
  public static double CriticalTemperaturePercentage { get; private set; }
 
  public static string HottestPartName { get; private set; }
 
  public static double HottestSkinTemperature { get; private set; }
 
  public static double HottestSkinTemperatureMax { get; private set; }
 
  public static double HottestTemperature { get; private set; }
 
  public static double HottestTemperatureMax { get; private set; }
 
  public static ThermalProcessor Instance
  {
  get
  {
  return instance;
  }
  }
 
  public static double InternalFlux { get; private set; }
 
  public static double RadiationFlux { get; private set; }
 
  public static bool ShowDetails { get; private set; }
 
  public void Update()
  {
  if (FlightGlobals.ActiveVessel.parts.Count == 0)
  {
  ShowDetails = false;
  return;
  }
 
  ShowDetails = true;
 
  ConvectionFlux = 0.0;
  RadiationFlux = 0.0;
  InternalFlux = 0.0;
  HottestTemperature = 0.0;
  HottestSkinTemperature = 0.0;
  CoolestTemperature = double.MaxValue;
  CoolestSkinTemperature = double.MaxValue;
  CriticalTemperature = double.MaxValue;
  CriticalSkinTemperature = double.MaxValue;
  CriticalTemperaturePercentage = 0.0;
  HottestPartName = string.Empty;
  CoolestPartName = string.Empty;
  CriticalPartName = string.Empty;
 
  for (int i = 0; i < FlightGlobals.ActiveVessel.parts.Count; ++i)
  {
  Part part = FlightGlobals.ActiveVessel.parts[i];
 
  ConvectionFlux = ConvectionFlux + part.thermalConvectionFlux;
  RadiationFlux = RadiationFlux + part.thermalRadiationFlux;
  InternalFlux = InternalFlux + part.thermalInternalFluxPrevious;
 
  if (part.temperature > HottestTemperature || part.skinTemperature > HottestSkinTemperature)
  {
  HottestTemperature = part.temperature;
  HottestTemperatureMax = part.maxTemp;
  HottestSkinTemperature = part.skinTemperature;
  HottestSkinTemperatureMax = part.skinMaxTemp;
  HottestPartName = part.partInfo.title;
  }
  if (part.temperature < CoolestTemperature || part.skinTemperature < CoolestSkinTemperature)
  {
  CoolestTemperature = part.temperature;
  CoolestTemperatureMax = part.maxTemp;
  CoolestSkinTemperature = part.skinTemperature;
  CoolestSkinTemperatureMax = part.skinMaxTemp;
  CoolestPartName = part.partInfo.title;
  }
 
  if (part.temperature / part.maxTemp > CriticalTemperaturePercentage || part.skinTemperature / part.skinMaxTemp > CriticalTemperaturePercentage)
  {
  CriticalTemperature = part.temperature;
  CriticalTemperatureMax = part.maxTemp;
  CriticalSkinTemperature = part.skinTemperature;
  CriticalSkinTemperatureMax = part.skinMaxTemp;
  CriticalTemperaturePercentage = Math.Max(part.temperature / part.maxTemp, part.skinTemperature / part.skinMaxTemp);
  CriticalPartName = part.partInfo.title;
  }
  }
  }
 
  public bool UpdateRequested { get; set; }
 
  public static void RequestUpdate()
  {
  instance.UpdateRequested = true;
  }
  }
  }
// //
// 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.Linq; using System.Linq;
   
using KerbalEngineer.Flight.Sections; using KerbalEngineer.Flight.Sections;
using KerbalEngineer.Helpers; using KerbalEngineer.Helpers;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Vessel namespace KerbalEngineer.Flight.Readouts.Vessel
{ {
public class DeltaVStaged : ReadoutModule public class DeltaVStaged : ReadoutModule
{ {
#region Fields  
   
private int numberOfStages;  
private bool showing;  
   
#endregion  
   
#region Constructors #region Constructors
   
public DeltaVStaged() public DeltaVStaged()
{ {
this.Name = "DeltaV Staged"; this.Name = "DeltaV Staged";
this.Category = ReadoutCategory.GetCategory("Vessel"); this.Category = ReadoutCategory.GetCategory("Vessel");
this.HelpString = "Shows the vessel's delta velocity for each stage."; this.HelpString = "Shows the vessel's delta velocity for each stage.";
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)
{ {
if (!SimulationProcessor.ShowDetails) if (!SimulationProcessor.ShowDetails)
{ {
return; return;
} }
   
foreach (var stage in SimulationProcessor.Stages.Where(stage => stage.deltaV > 0 || stage.number == Staging.CurrentStage)) foreach (var stage in SimulationProcessor.Stages.Where(stage => stage.deltaV > 0 || stage.number == Staging.CurrentStage))
{ {
this.DrawLine("DeltaV (S" + stage.number + ")", stage.deltaV.ToString("N0") + "m/s (" + TimeFormatter.ConvertToString(stage.time) + ")", section.IsHud); this.DrawLine("DeltaV (S" + stage.number + ")", stage.deltaV.ToString("N0") + "m/s (" + TimeFormatter.ConvertToString(stage.time) + ")", section.IsHud);
} }
} }
   
public override void Reset() public override void Reset()
{ {
FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance); FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance);
} }
   
public override void Update() public override void Update()
{ {
SimulationProcessor.RequestUpdate(); SimulationProcessor.RequestUpdate();
} }
   
#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.Linq; using System.Linq;
   
using KerbalEngineer.Flight.Sections; using KerbalEngineer.Flight.Sections;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Vessel namespace KerbalEngineer.Flight.Readouts.Vessel
{ {
public class IntakeAirDemandSupply : ReadoutModule public class IntakeAirDemandSupply : ReadoutModule
{ {
#region Fields #region Fields
   
private double demand; private double demand;
private double supply; private double supply;
   
#endregion #endregion
   
#region Constructors #region Constructors
   
public IntakeAirDemandSupply() public IntakeAirDemandSupply()
{ {
this.Name = "Intake Air (D/S)"; this.Name = "Intake Air (D/S)";
this.Category = ReadoutCategory.GetCategory("Vessel"); this.Category = ReadoutCategory.GetCategory("Vessel");
this.HelpString = string.Empty; this.HelpString = string.Empty;
this.IsDefault = false; this.IsDefault = false;
} }
   
#endregion #endregion
   
#region Methods: public #region Methods: public
   
public static double GetDemand() public static double GetDemand()
{ {
var demand = 0.0; var demand = 0.0;
foreach (var part in FlightGlobals.ActiveVessel.Parts) foreach (var part in FlightGlobals.ActiveVessel.Parts)
{ {
if (part.Modules.Contains("ModuleEngines")) for (int i = 0; i < part.Modules.Count; i++)
{ {
var engine = part.Modules["ModuleEngines"] as ModuleEngines; PartModule partmod = part.Modules[i];
if (engine.isOperational) var engine = partmod as ModuleEngines;
{ if (engine != null && engine.isOperational)
demand += engine.propellants  
.Where(p => p.name == "IntakeAir")  
.Sum(p => p.currentRequirement);  
}  
}  
if (part.Modules.Contains("ModuleEnginesFX"))  
{  
var engine = part.Modules["ModuleEnginesFX"] as ModuleEnginesFX;  
if (engine.isOperational)  
{ {
demand += engine.propellants demand += engine.propellants
.Where(p => p.name == "IntakeAir") .Where(p => p.name == "IntakeAir")
.Sum(p => p.currentRequirement); .Sum(p => p.currentRequirement);
} }
} }
} }
return demand; return demand;
} }
   
public static double GetSupply() public static double GetSupply()
{ {
return FlightGlobals.ActiveVessel.Parts return FlightGlobals.ActiveVessel.Parts
.Where(p => p.Resources.Contains("IntakeAir")) .Where(p => p.Resources.Contains("IntakeAir"))
.Sum(p => p.Resources["IntakeAir"].amount); .Sum(p => p.Resources["IntakeAir"].amount);
} }
   
public override void Draw(SectionModule section) public override void Draw(SectionModule section)
{ {
this.DrawLine(this.demand.ToString("F4") + " / " + this.supply.ToString("F4"), section.IsHud); this.DrawLine(this.demand.ToString("F4") + " / " + this.supply.ToString("F4"), section.IsHud);
} }
   
public override void Update() public override void Update()
{ {
this.demand = GetDemand(); this.demand = GetDemand();
this.supply = GetSupply(); this.supply = GetSupply();
} }
   
#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.Helpers; using KerbalEngineer.Helpers;
   
#endregion #endregion
   
namespace KerbalEngineer.Flight.Readouts.Vessel namespace KerbalEngineer.Flight.Readouts.Vessel
{ {
public class Mass : ReadoutModule public class Mass : ReadoutModule
{ {
#region Fields  
   
private bool showing;  
   
#endregion  
   
#region Constructors #region Constructors
   
public Mass() public Mass()
{ {
this.Name = "Mass"; this.Name = "Mass";
this.Category = ReadoutCategory.GetCategory("Vessel"); this.Category = ReadoutCategory.GetCategory("Vessel");
this.HelpString = string.Empty; this.HelpString = string.Empty;
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)
{ {
if (SimulationProcessor.ShowDetails) if (SimulationProcessor.ShowDetails)
{ {
this.DrawLine(Units.ToMass(SimulationProcessor.LastStage.mass, SimulationProcessor.LastStage.totalMass), section.IsHud); this.DrawLine(Units.ToMass(SimulationProcessor.LastStage.mass, SimulationProcessor.LastStage.totalMass), section.IsHud);
} }
} }
   
public override void Reset() public override void Reset()
{ {
FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance); FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance);
} }
   
public override void Update() public override void Update()
{ {
SimulationProcessor.RequestUpdate(); SimulationProcessor.RequestUpdate();
} }
   
#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/>.
// //
   
namespace KerbalEngineer.Flight.Readouts.Vessel namespace KerbalEngineer.Flight.Readouts.Vessel
{ {
#region Using Directives #region Using Directives
   
using Helpers; using Helpers;
using Sections; using Sections;
   
#endregion #endregion
   
public class PartCount : ReadoutModule public class PartCount : ReadoutModule
{ {
#region Constructors #region Constructors
   
public PartCount() public PartCount()
{ {
this.Name = "Part Count"; this.Name = "Part Count";
this.Category = ReadoutCategory.GetCategory("Vessel"); this.Category = ReadoutCategory.GetCategory("Vessel");
this.HelpString = string.Empty; this.HelpString = string.Empty;
this.IsDefault = true; this.IsDefault = true;
} }
   
#endregion #endregion
   
#region Methods #region Methods
   
public override void Draw(SectionModule section) public override void Draw(SectionModule section)
{ {
if (SimulationProcessor.ShowDetails) if (SimulationProcessor.ShowDetails)
{ {
this.DrawLine(Units.ConcatF(SimulationProcessor.LastStage.partCount, SimulationProcessor.LastStage.totalPartCount), section.IsHud); this.DrawLine(Units.ConcatF(SimulationProcessor.LastStage.partCount, SimulationProcessor.LastStage.totalPartCount, 0), section.IsHud);
} }
} }
   
public override void Reset() public override void Reset()
{ {
FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance); FlightEngineerCore.Instance.AddUpdatable(SimulationProcessor.Instance);
} }
   
public override void Update() public override void Update()
{ {
SimulationProcessor.RequestUpdate(); SimulationProcessor.RequestUpdate();
} }
   
#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.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));
   
  ParentSection.IsHud = GUILayout.Toggle(this.ParentSection.IsHud, "HUD", this.readoutButtonStyle, GUILayout.Width(50.0f));
  if (ParentSection.IsHud)
  {
  this.ParentSection.IsHudBackground = GUILayout.Toggle(this.ParentSection.IsHudBackground, "BG", this.readoutButtonStyle, GUILayout.Width(50.0f));
  }
   
if (this.ParentSection.IsCustom) if (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)))  
{  
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.H