Use ToadicusTools again now that the compat features are gone.
Use ToadicusTools again now that the compat features are gone.

// VOID // VOID
// //
// VOIDCore_Generic.cs // VOIDCore_Generic.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KerbalEngineer.Editor; using KerbalEngineer.Editor;
using KerbalEngineer.Helpers; using KerbalEngineer.Helpers;
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
  using ToadicusTools;
using ToadicusTools.DebugTools; using ToadicusTools.DebugTools;
using ToadicusTools.Extensions; using ToadicusTools.Extensions;
using ToadicusTools.GUIUtils; using ToadicusTools.GUIUtils;
using ToadicusTools.Wrappers; using ToadicusTools.Wrappers;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public abstract class VOIDCore_Generic<T> : VOID_SingletonCore<T>, IVOID_Module, IDisposable public abstract class VOIDCore_Generic<T> : VOID_SingletonCore<T>, IVOID_Module, IDisposable
where T : VOID_Module, new() where T : VOID_Module, new()
{ {
/* /*
* Fields * Fields
* */ * */
protected string VoidName = "VOID"; protected string VoidName = "VOID";
protected string VoidVersion; protected string VoidVersion;
   
[AVOID_SaveValue("configValue")] [AVOID_SaveValue("configValue")]
protected VOID_SaveValue<int> configVersion = (VOID_SaveValue<int>)VOIDCore.CONFIG_VERSION; protected VOID_SaveValue<int> configVersion = (VOID_SaveValue<int>)VOIDCore.CONFIG_VERSION;
   
protected List<IVOID_Module> modules = new List<IVOID_Module>(); protected List<IVOID_Module> modules = new List<IVOID_Module>();
protected bool modulesLoaded = false; protected bool modulesLoaded = false;
   
protected Texture2D VOIDIconTexture; protected Texture2D VOIDIconTexture;
protected string VOIDIconOnActivePath; protected string VOIDIconOnActivePath;
protected string VOIDIconOnInactivePath; protected string VOIDIconOnInactivePath;
protected string VOIDIconOffActivePath; protected string VOIDIconOffActivePath;
protected string VOIDIconOffInactivePath; protected string VOIDIconOffInactivePath;
   
[AVOID_SaveValue("useToolbarManager")] [AVOID_SaveValue("useToolbarManager")]
protected VOID_SaveValue<bool> useToolbarManager; protected VOID_SaveValue<bool> useToolbarManager;
   
protected GUIStyle iconStyle; protected GUIStyle iconStyle;
   
protected int windowBaseID = -96518722; protected int windowBaseID = -96518722;
protected int windowID = 0; protected int windowID = 0;
   
protected bool GUIStylesLoaded = false; protected bool GUIStylesLoaded = false;
   
protected CelestialBody homeBody; protected CelestialBody homeBody;
   
[AVOID_SaveValue("togglePower")] [AVOID_SaveValue("togglePower")]
public VOID_SaveValue<bool> togglePower = (VOID_SaveValue<bool>)true; public VOID_SaveValue<bool> togglePower = (VOID_SaveValue<bool>)true;
   
public override bool powerAvailable { get; protected set; } public override bool powerAvailable { get; protected set; }
   
[AVOID_SaveValue("consumeResource")] [AVOID_SaveValue("consumeResource")]
protected VOID_SaveValue<bool> consumeResource = (VOID_SaveValue<bool>)false; protected VOID_SaveValue<bool> consumeResource = (VOID_SaveValue<bool>)false;
   
[AVOID_SaveValue("resourceName")] [AVOID_SaveValue("resourceName")]
protected VOID_SaveValue<string> resourceName = (VOID_SaveValue<string>)"ElectricCharge"; protected VOID_SaveValue<string> resourceName = (VOID_SaveValue<string>)"ElectricCharge";
   
[AVOID_SaveValue("resourceRate")] [AVOID_SaveValue("resourceRate")]
protected VOID_SaveValue<float> resourceRate = (VOID_SaveValue<float>)0.2f; protected VOID_SaveValue<float> resourceRate = (VOID_SaveValue<float>)0.2f;
   
[AVOID_SaveValue("updatePeriod")] [AVOID_SaveValue("updatePeriod")]
protected VOID_SaveValue<double> updatePeriod = (VOID_SaveValue<double>)(1001f / 15000f); protected VOID_SaveValue<double> updatePeriod = (VOID_SaveValue<double>)(1001f / 15000f);
protected string stringFrequency; protected string stringFrequency;
   
[AVOID_SaveValue("vesselSimActive")] [AVOID_SaveValue("vesselSimActive")]
protected VOID_SaveValue<bool> vesselSimActive; protected VOID_SaveValue<bool> vesselSimActive;
   
[AVOID_SaveValue("timeScaleFlags")] [AVOID_SaveValue("timeScaleFlags")]
protected VOID_SaveValue<UInt32> timeScaleFlags; protected VOID_SaveValue<UInt32> timeScaleFlags;
   
// Load-up housekeeping // Load-up housekeeping
protected bool vesselTypesLoaded = false; protected bool vesselTypesLoaded = false;
protected bool simManagerLoaded = false; protected bool simManagerLoaded = false;
   
protected string defaultSkin = "KSP window 2"; protected string defaultSkin = "KSP window 2";
   
[AVOID_SaveValue("defaultSkin")] [AVOID_SaveValue("defaultSkin")]
protected VOID_SaveValue<string> skinName; protected VOID_SaveValue<string> skinName;
protected int skinIdx; protected int skinIdx;
   
protected Dictionary<string, GUISkin> validSkins; protected Dictionary<string, GUISkin> validSkins;
protected List<string> skinNames; protected List<string> skinNames;
protected string[] forbiddenSkins = protected string[] forbiddenSkins =
{ {
"PlaqueDialogSkin", "PlaqueDialogSkin",
"FlagBrowserSkin", "FlagBrowserSkin",
"SSUITextAreaDefault", "SSUITextAreaDefault",
"ExperimentsDialogSkin", "ExperimentsDialogSkin",
"ExpRecoveryDialogSkin", "ExpRecoveryDialogSkin",
"KSP window 1", "KSP window 1",
"KSP window 3", "KSP window 3",
"KSP window 5", "KSP window 5",
"KSP window 6", "KSP window 6",
"PartTooltipSkin", "PartTooltipSkin",
"KSCContextMenuSkin" "KSCContextMenuSkin"
}; };
protected bool skinsLoaded = false; protected bool skinsLoaded = false;
   
public override bool configDirty { get; set; } public override bool configDirty { get; set; }
   
protected IButton ToolbarButton; protected IButton ToolbarButton;
protected ApplicationLauncherButton AppLauncherButton; protected ApplicationLauncherButton AppLauncherButton;
protected IconState iconState; protected IconState iconState;
   
/* /*
* Properties * Properties
* */ * */
public override bool Active public override bool Active
{ {
get get
{ {
return base.Active; return base.Active;
} }
set set
{ {
if (value != base.Active) if (value != base.Active)
{ {
this.SetIconTexture(this.powerState | this.activeState); this.SetIconTexture(this.powerState | this.activeState);
} }
   
base.Active = value; base.Active = value;
} }
} }
   
public override VesselType[] AllVesselTypes public override VesselType[] AllVesselTypes
{ {
get; get;
protected set; protected set;
} }
   
public override int ConfigVersion public override int ConfigVersion
{ {
get get
{ {
return this.configVersion; return this.configVersion;
} }
} }
   
public bool FactoryReset public bool FactoryReset
{ {
get; get;
protected set; protected set;
} }
   
public override CelestialBody HomeBody public override CelestialBody HomeBody
{ {
get get
{ {
if (this.homeBody == null) if (this.homeBody == null)
{ {
if (Planetarium.fetch != null) if (Planetarium.fetch != null)
{ {
this.homeBody = Planetarium.fetch.Home; this.homeBody = Planetarium.fetch.Home;
} }
} }
   
return this.homeBody; return this.homeBody;
} }
} }
   
public override IList<IVOID_Module> Modules public override IList<IVOID_Module> Modules
{ {
get get
{ {
return this.modules.AsReadOnly(); return this.modules.AsReadOnly();
} }
} }
   
public override GUISkin Skin public override GUISkin Skin
{ {
get get
{ {
if (this.skinsLoaded) if (this.skinsLoaded)
{ {
try try
{ {
return this.validSkins[this.skinName]; return this.validSkins[this.skinName];
} }
catch catch
{ {
} }
} }
   
return AssetBase.GetGUISkin(this.defaultSkin); return AssetBase.GetGUISkin(this.defaultSkin);
} }
} }
   
public override List<CelestialBody> SortedBodyList public override List<CelestialBody> SortedBodyList
{ {
get; get;
protected set; protected set;
} }
   
public override double UpdatePeriod public override double UpdatePeriod
{ {
get get
{ {
return this.updatePeriod; return this.updatePeriod;
} }
} }
   
public override float UpdateTimer public override float UpdateTimer
{ {
get; get;
protected set; protected set;
} }
   
public override int WindowID public override int WindowID
{ {
get get
{ {
if (this.windowID == 0) if (this.windowID == 0)
{ {
this.windowID = this.windowBaseID; this.windowID = this.windowBaseID;
} }
return this.windowID++; return this.windowID++;
} }
} }
   
public override Stage[] Stages public override Stage[] Stages
{ {
get; get;
protected set; protected set;
} }
   
public override Stage LastStage public override Stage LastStage
{ {
get; get;
protected set; protected set;
} }
   
public override VOID_TimeScale TimeScale public override VOID_TimeScale TimeScale
{ {
get get
{ {
return (VOID_TimeScale)this.timeScaleFlags.value; return (VOID_TimeScale)this.timeScaleFlags.value;
} }
protected set protected set
{ {
this.timeScaleFlags.value = (UInt32)value; this.timeScaleFlags.value = (UInt32)value;
} }
} }
   
protected IconState activeState protected IconState activeState
{ {
get get
{ {
if (this.Active) if (this.Active)
{ {
return IconState.Inactive; return IconState.Inactive;
} }
else else
{ {
return IconState.Active; return IconState.Active;
} }
   
} }
} }
   
protected IconState powerState protected IconState powerState
{ {
get get
{ {
if (this.togglePower && this.powerAvailable) if (this.togglePower && this.powerAvailable)
{ {
return IconState.PowerOn; return IconState.PowerOn;
} }
else else
{ {
return IconState.PowerOff; return IconState.PowerOff;
} }
   
} }
} }
   
protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes
{ {
get get
{ {
return HighLogic.LoadedScene.ToAppScenes(); return HighLogic.LoadedScene.ToAppScenes();
} }
} }
   
/* /*
* Events * Events
* */ * */
// public // public
public override event VOIDEventHandler onApplicationQuit; public override event VOIDEventHandler onApplicationQuit;
public override event VOIDEventHandler onSkinChanged; public override event VOIDEventHandler onSkinChanged;
public override event VOIDEventHandler onUpdate; public override event VOIDEventHandler onUpdate;
   
/* /*
* Methods * Methods
* */ * */
public override void DrawGUI() public override void DrawGUI()
{ {
this.windowID = this.windowBaseID; this.windowID = this.windowBaseID;
   
if (!this.modulesLoaded) if (!this.modulesLoaded)
{ {
this.LoadModulesOfType<IVOID_Module>(); this.LoadModulesOfType<IVOID_Module>();
} }
   
if (!this.skinsLoaded) if (!this.skinsLoaded)
{ {
this.LoadSkins(); this.LoadSkins();
} }
   
GUI.skin = this.Skin; GUI.skin = this.Skin;
   
if (!this.GUIStylesLoaded) if (!this.GUIStylesLoaded)
{ {
this.LoadGUIStyles(); this.LoadGUIStyles();
   
ToadicusTools.Logging.PostDebugMessage( Logging.PostDebugMessage(
this, this,
"ToolbarAvailable: {0}, UseToobarManager: {1}", "ToolbarAvailable: {0}, UseToobarManager: {1}",
ToolbarManager.ToolbarAvailable, ToolbarManager.ToolbarAvailable,
this.useToolbarManager); this.useToolbarManager);
} }
   
if ( if (
this.iconState != (this.powerState | this.activeState) || this.iconState != (this.powerState | this.activeState) ||
(this.VOIDIconTexture == null && this.AppLauncherButton != null) (this.VOIDIconTexture == null && this.AppLauncherButton != null)
) )
{ {
this.iconState = this.powerState | this.activeState; this.iconState = this.powerState | this.activeState;
   
this.SetIconTexture(this.iconState); this.SetIconTexture(this.iconState);
} }
   
if (this.Active) if (this.Active)
{ {
base.DrawGUI(); base.DrawGUI();
} }
} }
   
public virtual void Update() public virtual void Update()
{ {
this.LoadBeforeUpdate(); this.LoadBeforeUpdate();
   
if ( if (
this.vesselSimActive && this.vesselSimActive &&
( (
this.Vessel != null || this.Vessel != null ||
( (
HighLogic.LoadedSceneIsEditor && HighLogic.LoadedSceneIsEditor &&
EditorLogic.RootPart != null && EditorLogic.RootPart != null &&
EditorLogic.SortedShipList.Count > 0 EditorLogic.SortedShipList.Count > 0
) )
) )
) )
{ {
ToadicusTools.Logging.PostDebugMessage(this, "Updating SimManager."); Logging.PostDebugMessage(this, "Updating SimManager.");
this.UpdateSimManager(); this.UpdateSimManager();
} }
   
if (!this.GUIRunning) if (!this.GUIRunning)
{ {
this.StartGUI(); this.StartGUI();
} }
   
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.modules.Count; idx++) for (int idx = 0; idx < this.modules.Count; idx++)
{ {
module = this.modules[idx]; module = this.modules[idx];
   
if ( if (
!module.GUIRunning && !module.GUIRunning &&
module.Active && module.Active &&
module.InValidScene && module.InValidScene &&
( (
!HighLogic.LoadedSceneIsEditor || !HighLogic.LoadedSceneIsEditor ||
(EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0) (EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0)
) )
) )
{ {
module.StartGUI(); module.StartGUI();
} }
if ( if (
module.GUIRunning && module.GUIRunning &&
( (
!module.Active || !module.Active ||
!this.togglePower || !this.togglePower ||
!module.InValidScene || !module.InValidScene ||
this.FactoryReset || this.FactoryReset ||
( (
HighLogic.LoadedSceneIsEditor && HighLogic.LoadedSceneIsEditor &&
(EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0) (EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0)
) )
) )
) )
{ {
module.StopGUI(); module.StopGUI();
} }
   
if (module is IVOID_BehaviorModule) if (module is IVOID_BehaviorModule)
{ {
((IVOID_BehaviorModule)module).Update(); ((IVOID_BehaviorModule)module).Update();
} }
} }
   
if (this.useToolbarManager) if (this.useToolbarManager)
{ {
if (this.AppLauncherButton != null) if (this.AppLauncherButton != null)
{ {
ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
this.AppLauncherButton = null; this.AppLauncherButton = null;
} }
   
if (this.ToolbarButton == null) if (this.ToolbarButton == null)
{ {
this.InitializeToolbarButton(); this.InitializeToolbarButton();
} }
} }
else else
{ {
if (this.ToolbarButton != null) if (this.ToolbarButton != null)
{ {
this.ToolbarButton.Destroy(); this.ToolbarButton.Destroy();
this.ToolbarButton = null; this.ToolbarButton = null;
} }
   
if (this.AppLauncherButton == null) if (this.AppLauncherButton == null)
{ {
this.InitializeAppLauncherButton(); this.InitializeAppLauncherButton();
} }
   
} }
   
this.saveTimer += Time.deltaTime; this.saveTimer += Time.deltaTime;
   
if (this.modulesLoaded && this.saveTimer > 2f) if (this.modulesLoaded && this.saveTimer > 2f)
{ {
if (this.configDirty) if (this.configDirty)
{ {
   
ToadicusTools.Logging.PostDebugMessage(string.Format( Logging.PostDebugMessage(string.Format(
"{0}: Time to save, checking if configDirty: {1}", "{0}: Time to save, checking if configDirty: {1}",
this.GetType().Name, this.GetType().Name,
this.configDirty this.configDirty
)); ));
   
this.SaveConfig(); this.SaveConfig();
this.saveTimer = 0; this.saveTimer = 0;
} }
} }
   
this.UpdateTimer += Time.deltaTime; this.UpdateTimer += Time.deltaTime;
   
if (this.onUpdate != null) if (this.onUpdate != null)
{ {
this.onUpdate(this); this.onUpdate(this);
} }
} }
   
public virtual void FixedUpdate() public virtual void FixedUpdate()
{ {
bool newPowerState = this.powerAvailable; bool newPowerState = this.powerAvailable;
   
if (this.togglePower && this.consumeResource && if (this.togglePower && this.consumeResource &&
this.Vessel.vesselType != VesselType.EVA && this.Vessel.vesselType != VesselType.EVA &&
TimeWarp.deltaTime != 0) TimeWarp.deltaTime != 0)
{ {
float powerReceived = this.Vessel.rootPart.RequestResource( float powerReceived = this.Vessel.rootPart.RequestResource(
this.resourceName, this.resourceName,
this.resourceRate * TimeWarp.fixedDeltaTime this.resourceRate * TimeWarp.fixedDeltaTime
); );
   
if (powerReceived > 0) if (powerReceived > 0)
{ {
newPowerState = true; newPowerState = true;
} }
else else
{ {
newPowerState = false; newPowerState = false;
} }
   
if (this.powerAvailable != newPowerState) if (this.powerAvailable != newPowerState)
{ {
this.powerAvailable = newPowerState; this.powerAvailable = newPowerState;
} }
} }
   
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.modules.Count; idx++) for (int idx = 0; idx < this.modules.Count; idx++)
{ {
module = this.modules[idx]; module = this.modules[idx];
   
if (module is IVOID_BehaviorModule) if (module is IVOID_BehaviorModule)
{ {
((IVOID_BehaviorModule)module).FixedUpdate(); ((IVOID_BehaviorModule)module).FixedUpdate();
} }
} }
} }
   
public void OnDestroy() public void OnDestroy()
{ {
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.modules.Count; idx++) for (int idx = 0; idx < this.modules.Count; idx++)
{ {
module = this.modules[idx]; module = this.modules[idx];
   
if (module is IVOID_BehaviorModule) if (module is IVOID_BehaviorModule)
{ {
((IVOID_BehaviorModule)module).OnDestroy(); ((IVOID_BehaviorModule)module).OnDestroy();
} }
} }
   
this.Dispose(); this.Dispose();
} }
   
public virtual void OnApplicationQuit() public virtual void OnApplicationQuit()
{ {
if (this.onApplicationQuit != null) if (this.onApplicationQuit != null)
{ {
this.onApplicationQuit(this); this.onApplicationQuit(this);
} }
   
this.OnDestroy(); this.OnDestroy();
} }
   
public override void StartGUI() public override void StartGUI()
{ {
if (!this.GUIRunning) if (!this.GUIRunning)
{ {
RenderingManager.AddToPostDrawQueue(3, this.DrawGUI); RenderingManager.AddToPostDrawQueue(3, this.DrawGUI);
} }
} }
   
public void ResetGUI() public void ResetGUI()
{ {
this.StopGUI(); this.StopGUI();
   
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.modules.Count; idx++) for (int idx = 0; idx < this.modules.Count; idx++)
{ {
module = this.modules[idx]; module = this.modules[idx];
   
module.StopGUI(); module.StopGUI();
module.StartGUI(); module.StartGUI();
} }
   
this.StartGUI(); this.StartGUI();
} }
   
public override void ModuleWindow(int id) public override void ModuleWindow(int id)
{ {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
if (this.powerAvailable || !HighLogic.LoadedSceneIsFlight) if (this.powerAvailable || !HighLogic.LoadedSceneIsFlight)
{ {
if (!HighLogic.LoadedSceneIsEditor) if (!HighLogic.LoadedSceneIsEditor)
{ {
string str = string.Intern("ON"); string str = string.Intern("ON");
if (togglePower) if (togglePower)
str = string.Intern("OFF"); str = string.Intern("OFF");
if (GUILayout.Button("Power " + str)) if (GUILayout.Button("Power " + str))
{ {
togglePower.value = !togglePower; togglePower.value = !togglePower;
} }
} }
   
if (togglePower || !HighLogic.LoadedSceneIsFlight) if (togglePower || !HighLogic.LoadedSceneIsFlight)
{ {
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.modules.Count; idx++) for (int idx = 0; idx < this.modules.Count; idx++)
{ {
module = this.modules[idx]; module = this.modules[idx];
   
if (module is VOID_ConfigWindow) if (module is VOID_ConfigWindow)
{ {
continue; continue;
} }
   
module.Active = Layout.Toggle(module.Active, module.Name); module.Active = Layout.Toggle(module.Active, module.Name);
} }
} }
} }
else else
{ {
GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed); GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed);
} }
   
VOID_ConfigWindow.Instance.Active = Layout.Toggle( VOID_ConfigWindow.Instance.Active = Layout.Toggle(
VOID_ConfigWindow.Instance.Active, VOID_ConfigWindow.Instance.Active,
"Configuration" "Configuration"
); );
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
base.ModuleWindow(id); base.ModuleWindow(id);
} }
   
public override void DrawConfigurables() public override void DrawConfigurables()
{ {
GUIContent _content; GUIContent _content;
   
this.useToolbarManager.value = Layout.Toggle(this.useToolbarManager, "Use Blizzy's Toolbar If Available"); this.useToolbarManager.value = Layout.Toggle(this.useToolbarManager, "Use Blizzy's Toolbar If Available");
   
this.vesselSimActive.value = Layout.Toggle(this.vesselSimActive.value, this.vesselSimActive.value = Layout.Toggle(this.vesselSimActive.value,
"Enable Engineering Calculations"); "Enable Engineering Calculations");
   
bool useEarthTime = (this.TimeScale & VOID_TimeScale.KERBIN_TIME) == 0u; bool useEarthTime = (this.TimeScale & VOID_TimeScale.KERBIN_TIME) == 0u;
bool useSiderealTime = (this.TimeScale & VOID_TimeScale.SOLAR_DAY) == 0u; bool useSiderealTime = (this.TimeScale & VOID_TimeScale.SOLAR_DAY) == 0u;
bool useRoundedScale = (this.TimeScale & VOID_TimeScale.ROUNDED_SCALE) != 0u; bool useRoundedScale = (this.TimeScale & VOID_TimeScale.ROUNDED_SCALE) != 0u;
   
useEarthTime = Layout.Toggle(useEarthTime, "Use Earth Time (changes KSP option)"); useEarthTime = Layout.Toggle(useEarthTime, "Use Earth Time (changes KSP option)");
   
GameSettings.KERBIN_TIME = !useEarthTime; GameSettings.KERBIN_TIME = !useEarthTime;
   
useSiderealTime = Layout.Toggle( useSiderealTime = Layout.Toggle(
useSiderealTime, useSiderealTime,
string.Format( string.Format(
"Time Scale: {0}", "Time Scale: {0}",
useSiderealTime ? "Sidereal" : "Solar" useSiderealTime ? "Sidereal" : "Solar"
) )
); );
   
useRoundedScale = Layout.Toggle( useRoundedScale = Layout.Toggle(
useRoundedScale, useRoundedScale,
string.Format( string.Format(
"Time Scale: {0}", "Time Scale: {0}",
useRoundedScale ? "Rounded" : "True" useRoundedScale ? "Rounded" : "True"
) )
); );
   
if (useEarthTime) if (useEarthTime)
{ {
this.TimeScale &= ~VOID_TimeScale.KERBIN_TIME; this.TimeScale &= ~VOID_TimeScale.KERBIN_TIME;
} }
else else
{ {
this.TimeScale |= VOID_TimeScale.KERBIN_TIME; this.TimeScale |= VOID_TimeScale.KERBIN_TIME;
} }
   
if (useSiderealTime) if (useSiderealTime)
{ {
this.TimeScale &= ~VOID_TimeScale.SOLAR_DAY; this.TimeScale &= ~VOID_TimeScale.SOLAR_DAY;
} }
else else
{ {
this.TimeScale |= VOID_TimeScale.SOLAR_DAY; this.TimeScale |= VOID_TimeScale.SOLAR_DAY;
} }
   
if (useRoundedScale) if (useRoundedScale)
{ {
this.TimeScale |= VOID_TimeScale.ROUNDED_SCALE; this.TimeScale |= VOID_TimeScale.ROUNDED_SCALE;
} }
else else
{ {
this.TimeScale &= ~VOID_TimeScale.ROUNDED_SCALE; this.TimeScale &= ~VOID_TimeScale.ROUNDED_SCALE;
} }
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
GUILayout.Label("Skin:", GUILayout.ExpandWidth(false)); GUILayout.Label("Skin:", GUILayout.ExpandWidth(false));
   
_content = new GUIContent(); _content = new GUIContent();
   
_content.text = "◄"; _content.text = "◄";
_content.tooltip = "Select previous skin"; _content.tooltip = "Select previous skin";
if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
{ {
this.skinIdx--; this.skinIdx--;
ToadicusTools.Logging.PostDebugMessage(string.Format( Logging.PostDebugMessage(string.Format(
"{0}: new this.skinIdx = {1} :: skin_list.Count = {2}", "{0}: new this.skinIdx = {1} :: skin_list.Count = {2}",
this.GetType().Name, this.GetType().Name,
this.skinName, this.skinName,
this.validSkins.Count this.validSkins.Count
)); ));
} }
   
_content.text = this.Skin.name; _content.text = this.Skin.name;
_content.tooltip = "Current skin"; _content.tooltip = "Current skin";
GUILayout.Label(_content, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true)); GUILayout.Label(_content, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true));
   
_content.text = "►"; _content.text = "►";
_content.tooltip = "Select next skin"; _content.tooltip = "Select next skin";
if (GUILayout.Button(_content, GUILayout.ExpandWidth(true))) if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
{ {
this.skinIdx++; this.skinIdx++;
ToadicusTools.Logging.PostDebugMessage(string.Format( Logging.PostDebugMessage(string.Format(
"{0}: new this.skinIdx = {1} :: skin_list.Count = {2}", "{0}: new this.skinIdx = {1} :: skin_list.Count = {2}",
this.GetType().Name, this.GetType().Name,
this.skinName, this.skinName,
this.validSkins.Count this.validSkins.Count
)); ));
} }
   
this.skinIdx %= this.skinNames.Count; this.skinIdx %= this.skinNames.Count;
if (this.skinIdx < 0) if (this.skinIdx < 0)
{ {
this.skinIdx += this.skinNames.Count; this.skinIdx += this.skinNames.Count;
} }
   
if (this.skinName != skinNames[this.skinIdx]) if (this.skinName != skinNames[this.skinIdx])
{ {
this.skinName.value = skinNames[this.skinIdx]; this.skinName.value = skinNames[this.skinIdx];
this.GUIStylesLoaded = false; this.GUIStylesLoaded = false;
} }
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("Update Rate (Hz):"); GUILayout.Label("Update Rate (Hz):");
if (this.stringFrequency == null) if (this.stringFrequency == null)
{ {
this.stringFrequency = (1f / this.UpdatePeriod).ToString(); this.stringFrequency = (1f / this.UpdatePeriod).ToString();
} }
this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true)); this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true));
   
if (GUILayout.Button("Apply")) if (GUILayout.Button("Apply"))
{ {
double updateFreq = 1f / this.UpdatePeriod; double updateFreq = 1f / this.UpdatePeriod;
double.TryParse(stringFrequency, out updateFreq); double.TryParse(stringFrequency, out updateFreq);
this.updatePeriod.value = 1 / updateFreq; this.updatePeriod.value = 1 / updateFreq;
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.modules.Count; idx++) for (int idx = 0; idx < this.modules.Count; idx++)
{ {
module = this.modules[idx]; module = this.modules[idx];
   
module.DrawConfigurables(); module.DrawConfigurables();
} }
   
this.FactoryReset = Layout.Toggle(this.FactoryReset, "Factory Reset"); this.FactoryReset = Layout.Toggle(this.FactoryReset, "Factory Reset");
} }
   
protected void UpdateSimManager() protected void UpdateSimManager()
{ {
if (HighLogic.LoadedSceneIsFlight) if (HighLogic.LoadedSceneIsFlight)
{ {
double radius = this.Vessel.Radius(); double radius = this.Vessel.Radius();
SimManager.Gravity = this.Vessel.mainBody.gravParameter / (radius * radius); SimManager.Gravity = this.Vessel.mainBody.gravParameter / (radius * radius);
SimManager.Atmosphere = this.Vessel.staticPressurekPa * PhysicsGlobals.KpaToAtmospheres; SimManager.Atmosphere = this.Vessel.staticPressurekPa * PhysicsGlobals.KpaToAtmospheres;
SimManager.Mach = this.Vessel.mach; SimManager.Mach = this.Vessel.mach;
BuildAdvanced.Altitude = this.Vessel.altitude; BuildAdvanced.Altitude = this.Vessel.altitude;
CelestialBodies.SelectedBody = this.Vessel.mainBody; CelestialBodies.SelectedBody = this.Vessel.mainBody;
} }
   
#if DEBUG #if DEBUG
SimManager.logOutput = true; SimManager.logOutput = true;
#endif #endif
   
SimManager.TryStartSimulation(); SimManager.TryStartSimulation();
   
ToadicusTools.Logging.PostDebugMessage(this, "Started Engineer simulation with Atmosphere={0} atm and Gravity={1} m/s²", Logging.PostDebugMessage(this, "Started Engineer simulation with Atmosphere={0} atm and Gravity={1} m/s²",
SimManager.Atmosphere, SimManager.Atmosphere,
SimManager.Gravity SimManager.Gravity
); );
} }
   
protected void GetSimManagerResults() protected void GetSimManagerResults()
{ {
ToadicusTools.Logging.PostDebugMessage(this, "VesselSimulator results ready, setting Stages."); Logging.PostDebugMessage(this, "VesselSimulator results ready, setting Stages.");
   
this.Stages = SimManager.Stages; this.Stages = SimManager.Stages;
   
if (this.Stages != null && this.Stages.Length > 0) if (this.Stages != null && this.Stages.Length > 0)
{ {
this.LastStage = this.Stages[this.Stages.Length - 1]; this.LastStage = this.Stages[this.Stages.Length - 1];
} }
} }
   
protected void LoadModulesOfType<U>() protected void LoadModulesOfType<U>()
{ {
using (PooledDebugLogger sb = PooledDebugLogger.New(this)) using (PooledDebugLogger sb = PooledDebugLogger.New(this))
{ {
sb.AppendLine("Loading modules..."); sb.AppendLine("Loading modules...");
   
AssemblyLoader.LoadedAssembly assy; AssemblyLoader.LoadedAssembly assy;
for (int aIdx = 0; aIdx < AssemblyLoader.loadedAssemblies.Count; aIdx++) for (int aIdx = 0; aIdx < AssemblyLoader.loadedAssemblies.Count; aIdx++)
{ {
assy = AssemblyLoader.loadedAssemblies[aIdx]; assy = AssemblyLoader.loadedAssemblies[aIdx];
   
Type[] loadedTypes = assy.assembly.GetExportedTypes(); Type[] loadedTypes = assy.assembly.GetExportedTypes();
Type loadedType; Type loadedType;
for (int tIdx = 0; tIdx < loadedTypes.Length; tIdx++) for (int tIdx = 0; tIdx < loadedTypes.Length; tIdx++)
{ {
loadedType = loadedTypes[tIdx]; loadedType = loadedTypes[tIdx];
   
if ( if (
loadedType.IsInterface || loadedType.IsInterface ||
loadedType.IsAbstract || loadedType.IsAbstract ||
!typeof(U).IsAssignableFrom(loadedType) || !typeof(U).IsAssignableFrom(loadedType) ||
typeof(VOIDCore).IsAssignableFrom(loadedType)) typeof(VOIDCore).IsAssignableFrom(loadedType))
{ {
continue; continue;
} }
   
sb.AppendFormat("Checking IVOID_Module type {0}...", loadedType.Name); sb.AppendFormat("Checking IVOID_Module type {0}...", loadedType.Name);
   
try try
{ {
this.LoadModule(loadedType); this.LoadModule(loadedType);
sb.AppendLine("Success."); sb.AppendLine("Success.");
} }
catch (Exception ex) catch (Exception ex)
{ {
sb.AppendFormat("Failed, caught {0}\n", ex.GetType().Name); sb.AppendFormat("Failed, caught {0}\n", ex.GetType().Name);
   
#if DEBUG #if DEBUG
Debug.LogException(ex); Debug.LogException(ex);
#endif #endif
} }
} }
} }
   
this.LoadConfig(); this.LoadConfig();
   
this.modulesLoaded = true; this.modulesLoaded = true;
   
sb.AppendFormat("Loaded {0} modules.\n", this.Modules.Count); sb.AppendFormat("Loaded {0} modules.\n", this.Modules.Count);
   
sb.Print(); sb.Print();
} }
} }
   
protected void LoadModule(Type T) protected void LoadModule(Type T)
{ {
/*var existingModules = this.modules.Where(mod => mod.GetType().Name == T.Name); /*var existingModules = this.modules.Where(mod => mod.GetType().Name == T.Name);
if (existingModules.Any())*/ if (existingModules.Any())*/
for (int mIdx = 0; mIdx < this.modules.Count; mIdx++) for (int mIdx = 0; mIdx < this.modules.Count; mIdx++)
{ {
if (this.modules[mIdx].Name == T.Name) if (this.modules[mIdx].Name == T.Name)
{ {
ToadicusTools.Logging.PostErrorMessage("{0}: refusing to load {1}: already loaded", this.GetType().Name, T.Name); Logging.PostErrorMessage("{0}: refusing to load {1}: already loaded", this.GetType().Name, T.Name);
return; return;
} }
} }
   
var InstanceProperty = T.GetProperty( var InstanceProperty = T.GetProperty(
"Instance", "Instance",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.FlattenHierarchy System.Reflection.BindingFlags.FlattenHierarchy
); );
   
object modInstance = null; object modInstance = null;
IVOID_Module module; IVOID_Module module;
   
if (InstanceProperty != null) if (InstanceProperty != null)
{ {
modInstance = InstanceProperty.GetValue(null, null); modInstance = InstanceProperty.GetValue(null, null);
} }
   
if (modInstance != null) if (modInstance != null)
{ {
module = modInstance as IVOID_Module; module = modInstance as IVOID_Module;
} }
else else
{ {
module = Activator.CreateInstance(T) as IVOID_Module; module = Activator.CreateInstance(T) as IVOID_Module;
} }
   
if (module.InValidGame && module.InValidScene) if (module.InValidGame && module.InValidScene)
{ {
this.modules.Add(module); this.modules.Add(module);
   
ToadicusTools.Logging.PostDebugMessage(string.Format( Logging.PostDebugMessage(string.Format(
"{0}: loaded module {1}.", "{0}: loaded module {1}.",
this.GetType().Name, this.GetType().Name,
T.Name T.Name
)); ));
} }
else else
{ {
if (module is IDisposable) if (module is IDisposable)
{ {
(module as IDisposable).Dispose(); (module as IDisposable).Dispose();
} }
} }
} }
   
protected void LoadSkins() protected void LoadSkins()
{ {
this.validSkins = new Dictionary<string, GUISkin>(); this.validSkins = new Dictionary<string, GUISkin>();
this.skinNames = new List<string>(); this.skinNames = new List<string>();
   
UnityEngine.Object[] skins = Resources.FindObjectsOfTypeAll(typeof(GUISkin)); UnityEngine.Object[] skins = Resources.FindObjectsOfTypeAll(typeof(GUISkin));
GUISkin skin; GUISkin skin;
for (int sIdx = 0; sIdx < skins.Length; sIdx++) for (int sIdx = 0; sIdx < skins.Length; sIdx++)
{ {
skin = (GUISkin)skins[sIdx]; skin = (GUISkin)skins[sIdx];
   
if (!this.forbiddenSkins.Contains(skin.name)) if (!this.forbiddenSkins.Contains(skin.name))
{ {
this.validSkins[skin.name] = skin; this.validSkins[skin.name] = skin;
this.skinNames.Add(skin.name); this.skinNames.Add(skin.name);
} }
} }
   
ToadicusTools.Logging.PostDebugMessage(string.Format( Logging.PostDebugMessage(string.Format(
"{0}: loaded {1} GUISkins.", "{0}: loaded {1} GUISkins.",
this.GetType().Name, this.GetType().Name,
this.validSkins.Count this.validSkins.Count
)); ));
   
this.skinNames.Sort(); this.skinNames.Sort();
   
int defaultIdx = int.MinValue; int defaultIdx = int.MinValue;
   
for (int i = 0; i < this.skinNames.Count; i++) for (int i = 0; i < this.skinNames.Count; i++)
{ {
if (this.skinNames[i] == this.skinName) if (this.skinNames[i] == this.skinName)
{ {
this.skinIdx = i; this.skinIdx = i;
} }
if (this.skinNames[i] == this.defaultSkin) if (this.skinNames[i] == this.defaultSkin)
{ {
defaultIdx = i; defaultIdx = i;
} }
if (this.skinIdx != int.MinValue && defaultIdx != int.MinValue) if (this.skinIdx != int.MinValue && defaultIdx != int.MinValue)
{ {
break; break;
} }
} }
   
if (this.skinIdx == int.MinValue) if (this.skinIdx == int.MinValue)
{ {
this.skinIdx = defaultIdx; this.skinIdx = defaultIdx;
} }
   
ToadicusTools.Logging.PostDebugMessage(string.Format( Logging.PostDebugMessage(string.Format(
"{0}: _skinIdx = {1}.", "{0}: _skinIdx = {1}.",
this.GetType().Name, this.GetType().Name,
this.skinName.ToString() this.skinName.ToString()
)); ));
   
this.skinsLoaded = true; this.skinsLoaded = true;
} }
   
protected void LoadGUIStyles() protected void LoadGUIStyles()
{ {
VOID_Styles.OnSkinChanged(); VOID_Styles.OnSkinChanged();
   
if (this.onSkinChanged != null) if (this.onSkinChanged != null)
{ {
this.onSkinChanged(this); this.onSkinChanged(this);
} }
   
this.GUIStylesLoaded = true; this.GUIStylesLoaded = true;
} }
   
protected void LoadBeforeUpdate() protected void LoadBeforeUpdate()
{ {
if (!this.vesselTypesLoaded) if (!this.vesselTypesLoaded)
{ {
Array typeObjs = Enum.GetValues(typeof(VesselType)); Array typeObjs = Enum.GetValues(typeof(VesselType));
this.AllVesselTypes = new VesselType[typeObjs.Length]; this.AllVesselTypes = new VesselType[typeObjs.Length];
   
for (int idx = 0; idx < typeObjs.Length; idx++) for (int idx = 0; idx < typeObjs.Length; idx++)
{ {
this.AllVesselTypes[idx] = (VesselType)typeObjs.GetValue(idx); this.AllVesselTypes[idx] = (VesselType)typeObjs.GetValue(idx);
} }
   
this.vesselTypesLoaded = true; this.vesselTypesLoaded = true;
} }
   
if (this.SortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0) if (this.SortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
{ {
this.SortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies); this.SortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
this.SortedBodyList.Sort(new CBListComparer()); this.SortedBodyList.Sort(new CBListComparer());
this.SortedBodyList.Reverse(); this.SortedBodyList.Reverse();
} }
   
// SimManager initialization that we don't necessarily want to repeat every Update. // SimManager initialization that we don't necessarily want to repeat every Update.
if (!this.simManagerLoaded && this.HomeBody != null) if (!this.simManagerLoaded && this.HomeBody != null)
{ {
SimManager.Gravity = VOID_Data.KerbinGee; SimManager.Gravity = VOID_Data.KerbinGee;
SimManager.Atmosphere = 0d; SimManager.Atmosphere = 0d;
SimManager.Mach = 1d; SimManager.Mach = 1d;
CelestialBodies.SelectedBody = this.HomeBody; CelestialBodies.SelectedBody = this.HomeBody;
BuildAdvanced.Altitude = 0d; BuildAdvanced.Altitude = 0d;
SimManager.OnReady += this.GetSimManagerResults; SimManager.OnReady += this.GetSimManagerResults;
   
this.simManagerLoaded = true; this.simManagerLoaded = true;
} }
} }
   
protected void InitializeToolbarButton() protected void InitializeToolbarButton()
{ {
// Do nothing if (the Toolbar is not available. // Do nothing if (the Toolbar is not available.
if (!ToolbarManager.ToolbarAvailable) if (!ToolbarManager.ToolbarAvailable)
{ {
ToadicusTools.Logging.PostDebugMessage(this, "Refusing to make a ToolbarButton: ToolbarAvailable = false"); Logging.PostDebugMessage(this, "Refusing to make a ToolbarButton: ToolbarAvailable = false");
return; return;
} }
   
this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle"); this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle");
this.ToolbarButton.Text = this.VoidName; this.ToolbarButton.Text = this.VoidName;
this.SetIconTexture(this.powerState | this.activeState); this.SetIconTexture(this.powerState | this.activeState);
   
this.ToolbarButton.Visible = true; this.ToolbarButton.Visible = true;
   
this.ToolbarButton.OnClick += this.ToolbarButton.OnClick +=
(e) => (e) =>
{ {
this.ToggleMainWindow(); this.ToggleMainWindow();
}; };
   
ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name)); Logging.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name));
} }
   
protected void InitializeAppLauncherButton() protected void InitializeAppLauncherButton()
{ {
if (ApplicationLauncher.Ready) if (ApplicationLauncher.Ready)
{ {
this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication( this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication(
this.ToggleMainWindow, this.ToggleMainWindow, this.ToggleMainWindow, this.ToggleMainWindow,
this.appIconVisibleScenes, this.appIconVisibleScenes,
this.VOIDIconTexture this.VOIDIconTexture
); );
   
ToadicusTools.Logging.PostDebugMessage( Logging.PostDebugMessage(
this, this,
"AppLauncherButton initialized in {0}", "AppLauncherButton initialized in {0}",
Enum.GetName( Enum.GetName(
typeof(GameScenes), typeof(GameScenes),
HighLogic.LoadedScene HighLogic.LoadedScene
) )
); );
} }
} }
   
protected void ToggleMainWindow() protected void ToggleMainWindow()
{ {
this.Active = !this.Active; this.Active = !this.Active;
} }
   
protected void SetIconTexture(IconState state) protected void SetIconTexture(IconState state)
{ {
switch (state) switch (state)
{ {
case (IconState.PowerOff | IconState.Inactive): case (IconState.PowerOff | IconState.Inactive):
this.SetIconTexture(this.VOIDIconOffInactivePath); this.SetIconTexture(this.VOIDIconOffInactivePath);
break; break;
case (IconState.PowerOff | IconState.Active): case (IconState.PowerOff | IconState.Active):
this.SetIconTexture(this.VOIDIconOffActivePath); this.SetIconTexture(this.VOIDIconOffActivePath);
break; break;
case (IconState.PowerOn | IconState.Inactive): case (IconState.PowerOn | IconState.Inactive):
this.SetIconTexture(this.VOIDIconOnInactivePath); this.SetIconTexture(this.VOIDIconOnInactivePath);
break; break;
case (IconState.PowerOn | IconState.Active): case (IconState.PowerOn | IconState.Active):
this.SetIconTexture(this.VOIDIconOnActivePath); this.SetIconTexture(this.VOIDIconOnActivePath);
break; break;
default: default:
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }
   
protected void SetIconTexture(string texturePath) protected void SetIconTexture(string texturePath)
{ {
if (texturePath == null) if (texturePath == null)
{ {
return; return;
} }
   
if (this.ToolbarButton != null) if (this.ToolbarButton != null)
{ {
this.ToolbarButton.TexturePath = texturePath; this.ToolbarButton.TexturePath = texturePath;
} }
   
if (this.AppLauncherButton != null) if (this.AppLauncherButton != null)
{ {
this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false); this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false);
   
this.AppLauncherButton.SetTexture(VOIDIconTexture); this.AppLauncherButton.SetTexture(VOIDIconTexture);
} }
} }
   
public void LoadConfig() public void LoadConfig()
{ {
   
if (!System.IO.File.Exists(this.VOIDSettingsPath) && KSP.IO.File.Exists<VOID_Module>("config.xml")) if (!System.IO.File.Exists(this.VOIDSettingsPath) && KSP.IO.File.Exists<VOID_Module>("config.xml"))
{ {
ToadicusTools.Logging.PostLogMessage( Logging.PostLogMessage(
"VOID: No per-save config file but old file detected; copying from old file." "VOID: No per-save config file but old file detected; copying from old file."
); );
   
System.IO.File.Copy( System.IO.File.Copy(
KSP.IO.IOUtils.GetFilePathFor(typeof(VOID_Module), "config.xml"), KSP.IO.IOUtils.GetFilePathFor(typeof(VOID_Module), "config.xml"),
this.VOIDSettingsPath this.VOIDSettingsPath
); );
} }
   
this.LoadConfig(new ToadicusTools.PluginConfiguration(this.VOIDSettingsPath)); this.LoadConfig(new PluginConfiguration(this.VOIDSettingsPath));
} }
   
public override void LoadConfig(KSP.IO.PluginConfiguration config) public override void LoadConfig(KSP.IO.PluginConfiguration config)
{ {
base.LoadConfig(config); base.LoadConfig(config);
   
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.modules.Count; idx++) for (int idx = 0; idx < this.modules.Count; idx++)
{ {
module = this.modules[idx]; module = this.modules[idx];
   
module.LoadConfig(config); module.LoadConfig(config);
} }
   
this.TimeScale |= GameSettings.KERBIN_TIME ? VOID_TimeScale.KERBIN_TIME : 0u; this.TimeScale |= GameSettings.KERBIN_TIME ? VOID_TimeScale.KERBIN_TIME : 0u;
} }
   
public override void SaveConfig() public override void SaveConfig()
{ {
if (this.configNeedsUpdate && this is VOIDCore_Flight) if (this.configNeedsUpdate && this is VOIDCore_Flight)
{ {
KSP.IO.File.Delete<T>("config.xml"); KSP.IO.File.Delete<T>("config.xml");
System.IO.File.Delete(this.VOIDSettingsPath); System.IO.File.Delete(this.VOIDSettingsPath);
} }
   
KSP.IO.PluginConfiguration config = new ToadicusTools.PluginConfiguration(this.VOIDSettingsPath); KSP.IO.PluginConfiguration config = new PluginConfiguration(this.VOIDSettingsPath);
   
config.load(); config.load();
   
this.Save(config, this.SceneKey); this.Save(config, this.SceneKey);
   
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.modules.Count; idx++) for (int idx = 0; idx < this.modules.Count; idx++)
{ {
module = this.modules[idx]; module = this.modules[idx];
   
module.Save(config, this.SceneKey); module.Save(config, this.SceneKey);
} }
   
config.save(); config.save();
   
this.configDirty = false; this.configDirty = false;
} }
   
public VOIDCore_Generic() public VOIDCore_Generic()
{ {
System.Version version = this.GetType().Assembly.GetName().Version; System.Version version = this.GetType().Assembly.GetName().Version;
   
this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision); this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision);
   
this.Name = string.Format("VOID {0}", this.VoidVersion.ToString()); this.Name = string.Format("VOID {0}", this.VoidVersion.ToString());
   
this.powerAvailable = true; this.powerAvailable = true;
   
this.Active = true; this.Active = true;
   
this.skinName = (VOID_SaveValue<string>)this.defaultSkin; this.skinName = (VOID_SaveValue<string>)this.defaultSkin;
this.skinIdx = int.MinValue; this.skinIdx = int.MinValue;
   
this.VOIDIconOnActivePath = "VOID/Textures/void_icon_light_glow"; this.VOIDIconOnActivePath = "VOID/Textures/void_icon_light_glow";
this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_dark_glow"; this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_dark_glow";
this.VOIDIconOffActivePath = "VOID/Textures/void_icon_light"; this.VOIDIconOffActivePath = "VOID/Textures/void_icon_light";
this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_dark"; this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_dark";
   
this.saveTimer = 0f; this.saveTimer = 0f;
this.UpdateTimer = 0f; this.UpdateTimer = 0f;
   
this.vesselSimActive = (VOID_SaveValue<bool>)true; this.vesselSimActive = (VOID_SaveValue<bool>)true;
   
this.useToolbarManager = (VOID_SaveValue<bool>)ToolbarManager.ToolbarAvailable; this.useToolbarManager = (VOID_SaveValue<bool>)ToolbarManager.ToolbarAvailable;
   
this.SaveGamePath = string.Format("{0}saves/{1}", ToadicusTools.IOTools.KSPRootPath, HighLogic.SaveFolder); this.SaveGamePath = string.Format("{0}saves/{1}", IOTools.KSPRootPath, HighLogic.SaveFolder);
this.VOIDSettingsPath = string.Format("{0}/VOIDConfig.xml", this.SaveGamePath); this.VOIDSettingsPath = string.Format("{0}/VOIDConfig.xml", this.SaveGamePath);
   
this.FactoryReset = false; this.FactoryReset = false;
} }
   
public override void Dispose() public override void Dispose()
{ {
this.StopGUI(); this.StopGUI();
   
this.onSkinChanged(this); this.onSkinChanged(this);
   
if (this.AppLauncherButton != null) if (this.AppLauncherButton != null)
{ {
ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton); ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
this.AppLauncherButton = null; this.AppLauncherButton = null;
} }
if (this.ToolbarButton != null) if (this.ToolbarButton != null)
{ {
this.ToolbarButton.Destroy(); this.ToolbarButton.Destroy();
this.ToolbarButton = null; this.ToolbarButton = null;
} }
   
_instance = null; _instance = null;
_initialized = false; _initialized = false;
} }
} }
} }
   
// VOID // VOID
// //
// VOID_CareerStatus.cs // VOID_CareerStatus.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KSP; using KSP;
using System; using System;
using System.Text; using System.Text;
  using ToadicusTools;
using ToadicusTools.Text; using ToadicusTools.Text;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
[VOID_Scenes(GameScenes.FLIGHT, GameScenes.EDITOR, GameScenes.SPACECENTER)] [VOID_Scenes(GameScenes.FLIGHT, GameScenes.EDITOR, GameScenes.SPACECENTER)]
[VOID_GameModes(Game.Modes.CAREER, Game.Modes.SCIENCE_SANDBOX)] [VOID_GameModes(Game.Modes.CAREER, Game.Modes.SCIENCE_SANDBOX)]
public class VOID_CareerStatus : VOID_SingletonWindow<VOID_CareerStatus> public class VOID_CareerStatus : VOID_SingletonWindow<VOID_CareerStatus>
{ {
public static string formatDelta(double delta, string numberFormat) public static string formatDelta(double delta, string numberFormat)
{ {
if (delta > 0) if (delta > 0)
{ {
return string.Format("<color='lime'>{0}↑</color>", delta.ToString(numberFormat, SIFormatProvider.SIFormatter)); return string.Format("<color='lime'>{0}↑</color>", delta.ToString(numberFormat, SIFormatProvider.SIFormatter));
} }
else if (delta < 0) else if (delta < 0)
{ {
return string.Format("<color='red'>{0}↓</color>", delta.ToString(numberFormat, SIFormatProvider.SIFormatter)); return string.Format("<color='red'>{0}↓</color>", delta.ToString(numberFormat, SIFormatProvider.SIFormatter));
} }
else else
{ {
return "0"; return "0";
} }
} }
   
public static string formatDelta(double delta) public static string formatDelta(double delta)
{ {
return formatDelta(delta, "#,##0.##"); return formatDelta(delta, "#,##0.##");
} }
   
public static string formatDelta(float delta) public static string formatDelta(float delta)
{ {
return formatDelta((double)delta); return formatDelta((double)delta);
} }
   
private GUIContent fundsContent; private GUIContent fundsContent;
private GUIContent repContent; private GUIContent repContent;
private GUIContent scienceContent; private GUIContent scienceContent;
   
#pragma warning disable 0414 #pragma warning disable 0414
private Texture2D fundsIconGreen; private Texture2D fundsIconGreen;
private Texture2D fundsIconRed; private Texture2D fundsIconRed;
private Texture2D reputationIconGreen; private Texture2D reputationIconGreen;
private Texture2D reputationIconRed; private Texture2D reputationIconRed;
private Texture2D scienceIcon; private Texture2D scienceIcon;
#pragma warning restore 0414 #pragma warning restore 0414
   
public double lastFundsChange public double lastFundsChange
{ {
get; get;
private set; private set;
} }
   
public float lastRepChange public float lastRepChange
{ {
get; get;
private set; private set;
} }
   
public float lastScienceChange public float lastScienceChange
{ {
get; get;
private set; private set;
} }
   
public double currentFunds public double currentFunds
{ {
get; get;
private set; private set;
} }
   
public float currentReputation public float currentReputation
{ {
get; get;
private set; private set;
} }
   
public float currentScience public float currentScience
{ {
get; get;
private set; private set;
} }
   
private bool currenciesInitialized private bool currenciesInitialized
{ {
get get
{ {
ToadicusTools.Logging.PostDebugMessage( Logging.PostDebugMessage(
this, this,
"Checking init state:" + "Checking init state:" +
"\n\tcurrentFunds={0}" + "\n\tcurrentFunds={0}" +
"\n\tcurrentScience={1}" + "\n\tcurrentScience={1}" +
"\n\tcurrentReputation={2}", "\n\tcurrentReputation={2}",
this.currentFunds, this.currentFunds,
this.currentScience, this.currentScience,
this.currentReputation this.currentReputation
); );
   
return !( return !(
double.IsNaN(this.currentFunds) || double.IsNaN(this.currentFunds) ||
float.IsNaN(this.currentScience) || float.IsNaN(this.currentScience) ||
float.IsNaN(this.currentReputation) float.IsNaN(this.currentReputation)
); );
} }
} }
   
public override void DrawGUI() public override void DrawGUI()
{ {
if (Event.current.type != EventType.Layout && !this.currenciesInitialized) if (Event.current.type != EventType.Layout && !this.currenciesInitialized)
{ {
this.initCurrencies(); this.initCurrencies();
} }
   
base.DrawGUI(); base.DrawGUI();
} }
   
public override void ModuleWindow(int id) public override void ModuleWindow(int id)
{ {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.fundingStatus.Label); GUILayout.Label(VOID_Data.fundingStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.fundsContent.text = VOID_Data.fundingStatus.Value; this.fundsContent.text = VOID_Data.fundingStatus.Value;
GUILayout.Label(this.fundsContent, GUILayout.ExpandWidth(true)); GUILayout.Label(this.fundsContent, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.reputationStatus.Label); GUILayout.Label(VOID_Data.reputationStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.repContent.text = VOID_Data.reputationStatus.Value; this.repContent.text = VOID_Data.reputationStatus.Value;
GUILayout.Label(this.repContent, GUILayout.ExpandWidth(true)); GUILayout.Label(this.repContent, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(VOID_Data.scienceStatus.Label); GUILayout.Label(VOID_Data.scienceStatus.Label);
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
this.scienceContent.text = VOID_Data.scienceStatus.Value; this.scienceContent.text = VOID_Data.scienceStatus.Value;
GUILayout.Label(this.scienceContent, GUILayout.ExpandWidth(true)); GUILayout.Label(this.scienceContent, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
base.ModuleWindow(id); base.ModuleWindow(id);
} }
   
// TODO: Update event handlers to do something useful with the new "reasons" parameter. // TODO: Update event handlers to do something useful with the new "reasons" parameter.
private void onFundsChange(double newValue, TransactionReasons reasons) private void onFundsChange(double newValue, TransactionReasons reasons)
{ {
this.lastFundsChange = newValue - this.currentFunds; this.lastFundsChange = newValue - this.currentFunds;
this.currentFunds = newValue; this.currentFunds = newValue;
} }
   
private void onRepChange(float newValue, TransactionReasons reasons) private void onRepChange(float newValue, TransactionReasons reasons)
{ {
this.lastRepChange = newValue - this.currentReputation; this.lastRepChange = newValue - this.currentReputation;
this.currentReputation = newValue; this.currentReputation = newValue;
} }
   
private void onScienceChange(float newValue, TransactionReasons reasons) private void onScienceChange(float newValue, TransactionReasons reasons)
{ {
this.lastScienceChange = newValue - this.currentScience; this.lastScienceChange = newValue - this.currentScience;
this.currentScience = newValue; this.currentScience = newValue;
} }
   
private void onGameStateLoad(ConfigNode node) private void onGameStateLoad(ConfigNode node)
{ {
this.initCurrencies(); this.initCurrencies();
} }
   
private void initCurrencies() private void initCurrencies()
{ {
ToadicusTools.Logging.PostDebugMessage( Logging.PostDebugMessage(
this, this,
"Initializing currencies." + "Initializing currencies." +
"\n\tFunding.Instance={0}" + "\n\tFunding.Instance={0}" +
"ResearchAndDevelopment.Instance={1}" + "ResearchAndDevelopment.Instance={1}" +
"Reputation.Instance={2}", "Reputation.Instance={2}",
Funding.Instance == null ? "NULL" : Funding.Instance.ToString(), Funding.Instance == null ? "NULL" : Funding.Instance.ToString(),
ResearchAndDevelopment.Instance == null ? "NULL" : ResearchAndDevelopment.Instance.ToString(), ResearchAndDevelopment.Instance == null ? "NULL" : ResearchAndDevelopment.Instance.ToString(),
Reputation.Instance == null ? "NULL" : Reputation.Instance.ToString() Reputation.Instance == null ? "NULL" : Reputation.Instance.ToString()
); );
   
this.currentFunds = Funding.Instance != null ? Funding.Instance.Funds : double.NaN; this.currentFunds = Funding.Instance != null ? Funding.Instance.Funds : double.NaN;
this.currentReputation = Reputation.Instance != null ? Reputation.Instance.reputation : float.NaN; this.currentReputation = Reputation.Instance != null ? Reputation.Instance.reputation : float.NaN;
this.currentScience = ResearchAndDevelopment.Instance != null ? this.currentScience = ResearchAndDevelopment.Instance != null ?
ResearchAndDevelopment.Instance.Science : float.NaN; ResearchAndDevelopment.Instance.Science : float.NaN;
} }
   
/* /*
* MissionRecoveryDialog::fundsIconGreen.name: UiElements_05 * MissionRecoveryDialog::fundsIconGreen.name: UiElements_05
* MissionRecoveryDialog::fundsIconRed.name: UiElements_06 * MissionRecoveryDialog::fundsIconRed.name: UiElements_06
* MissionRecoveryDialog::reputationIconGreen.name: UiElements_07 * MissionRecoveryDialog::reputationIconGreen.name: UiElements_07
* MissionRecoveryDialog::reputationIconRed.name: UiElements_08 * MissionRecoveryDialog::reputationIconRed.name: UiElements_08
* MissionRecoveryDialog::scienceIcon.name: UiElements_12 * MissionRecoveryDialog::scienceIcon.name: UiElements_12
* */ * */
public VOID_CareerStatus() : base() public VOID_CareerStatus() : base()
{ {
this.Name = "Career Status"; this.Name = "Career Status";
   
GameEvents.OnFundsChanged.Add(this.onFundsChange); GameEvents.OnFundsChanged.Add(this.onFundsChange);
GameEvents.OnReputationChanged.Add(this.onRepChange); GameEvents.OnReputationChanged.Add(this.onRepChange);
GameEvents.OnScienceChanged.Add(this.onScienceChange); GameEvents.OnScienceChanged.Add(this.onScienceChange);
GameEvents.onGameStateLoad.Add(this.onGameStateLoad); GameEvents.onGameStateLoad.Add(this.onGameStateLoad);
   
bool texturesLoaded; bool texturesLoaded;
   
texturesLoaded = ToadicusTools.IOTools.LoadTexture(out this.fundsIconGreen, "VOID/Textures/fundsgreen.png", 10, 18); texturesLoaded = IOTools.LoadTexture(out this.fundsIconGreen, "VOID/Textures/fundsgreen.png", 10, 18);
texturesLoaded &= ToadicusTools.IOTools.LoadTexture(out this.fundsIconRed, "VOID/Textures/fundsred.png", 10, 18); texturesLoaded &= IOTools.LoadTexture(out this.fundsIconRed, "VOID/Textures/fundsred.png", 10, 18);
texturesLoaded &= ToadicusTools.IOTools.LoadTexture(out this.reputationIconGreen, "VOID/Textures/repgreen.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.reputationIconGreen, "VOID/Textures/repgreen.png", 16, 18);
texturesLoaded &= ToadicusTools.IOTools.LoadTexture(out this.reputationIconRed, "VOID/Textures/repred.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.reputationIconRed, "VOID/Textures/repred.png", 16, 18);
texturesLoaded &= ToadicusTools.IOTools.LoadTexture(out this.scienceIcon, "VOID/Textures/science.png", 16, 18); texturesLoaded &= IOTools.LoadTexture(out this.scienceIcon, "VOID/Textures/science.png", 16, 18);
   
this.fundsContent = new GUIContent(); this.fundsContent = new GUIContent();
this.repContent = new GUIContent(); this.repContent = new GUIContent();
this.scienceContent = new GUIContent(); this.scienceContent = new GUIContent();
   
if (texturesLoaded) if (texturesLoaded)
{ {
this.fundsContent.image = this.fundsIconGreen; this.fundsContent.image = this.fundsIconGreen;
this.repContent.image = this.reputationIconGreen; this.repContent.image = this.reputationIconGreen;
this.scienceContent.image = this.scienceIcon; this.scienceContent.image = this.scienceIcon;
} }
   
this.currentFunds = double.NaN; this.currentFunds = double.NaN;
this.currentScience = float.NaN; this.currentScience = float.NaN;
this.currentReputation = float.NaN; this.currentReputation = float.NaN;
} }
   
public override void Dispose() public override void Dispose()
{ {
GameEvents.OnFundsChanged.Remove(this.onFundsChange); GameEvents.OnFundsChanged.Remove(this.onFundsChange);
GameEvents.OnReputationChanged.Remove(this.onRepChange); GameEvents.OnReputationChanged.Remove(this.onRepChange);
GameEvents.OnScienceChanged.Remove(this.onScienceChange); GameEvents.OnScienceChanged.Remove(this.onScienceChange);
GameEvents.onGameStateLoad.Remove(this.onGameStateLoad); GameEvents.onGameStateLoad.Remove(this.onGameStateLoad);
   
base.Dispose(); base.Dispose();
} }
   
~VOID_CareerStatus() ~VOID_CareerStatus()
{ {
this.Dispose(); this.Dispose();
} }
} }
} }
   
   
// VOID // VOID
// //
// VOID_Data.cs // VOID_Data.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
  using ToadicusTools;
using ToadicusTools.Extensions; using ToadicusTools.Extensions;
using ToadicusTools.MuMechTools; using ToadicusTools.MuMechTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public static class VOID_Data public static class VOID_Data
{ {
private static Dictionary<int, IVOID_DataValue> dataValues = new Dictionary<int, IVOID_DataValue>(); private static Dictionary<int, IVOID_DataValue> dataValues = new Dictionary<int, IVOID_DataValue>();
   
public static Dictionary<int, IVOID_DataValue> DataValues public static Dictionary<int, IVOID_DataValue> DataValues
{ {
get get
{ {
return dataValues; return dataValues;
} }
} }
   
#region Constants #region Constants
   
private static double kerbinGee; private static double kerbinGee;
   
public static double KerbinGee public static double KerbinGee
{ {
get get
{ {
if (kerbinGee == default(double)) if (kerbinGee == default(double))
{ {
kerbinGee = Core.HomeBody.gravParameter / (Core.HomeBody.Radius * Core.HomeBody.Radius); kerbinGee = Core.HomeBody.gravParameter / (Core.HomeBody.Radius * Core.HomeBody.Radius);
} }
   
return kerbinGee; return kerbinGee;
} }
} }
   
#endregion #endregion
   
#region Core Data #region Core Data
   
public static VOIDCore Core public static VOIDCore Core
{ {
get get
{ {
if (!CoreInitialized) if (!CoreInitialized)
{ {
return null; return null;
} }
   
switch (HighLogic.LoadedScene) switch (HighLogic.LoadedScene)
{ {
case GameScenes.EDITOR: case GameScenes.EDITOR:
return (VOIDCore)VOIDCore_Editor.Instance; return (VOIDCore)VOIDCore_Editor.Instance;
case GameScenes.FLIGHT: case GameScenes.FLIGHT:
return (VOIDCore)VOIDCore_Flight.Instance; return (VOIDCore)VOIDCore_Flight.Instance;
case GameScenes.SPACECENTER: case GameScenes.SPACECENTER:
return (VOIDCore)VOIDCore_SpaceCentre.Instance; return (VOIDCore)VOIDCore_SpaceCentre.Instance;
default: default:
return null; return null;
} }
} }
} }
   
public static bool CoreInitialized public static bool CoreInitialized
{ {
get get
{ {
switch (HighLogic.LoadedScene) switch (HighLogic.LoadedScene)
{ {
case GameScenes.EDITOR: case GameScenes.EDITOR:
return VOIDCore_Editor.Initialized; return VOIDCore_Editor.Initialized;
case GameScenes.FLIGHT: case GameScenes.FLIGHT:
return VOIDCore_Flight.Initialized; return VOIDCore_Flight.Initialized;
case GameScenes.SPACECENTER: case GameScenes.SPACECENTER:
return VOIDCore_SpaceCentre.Initialized; return VOIDCore_SpaceCentre.Initialized;
default: default:
return false; return false;
} }
} }
} }
   
#endregion #endregion
   
#region Atmosphere #region Atmosphere
   
public static readonly VOID_DoubleValue atmDensity = public static readonly VOID_DoubleValue atmDensity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Atmosphere Density", "Atmosphere Density",
new Func<double>(() => Core.Vessel.atmDensity * 1000d), new Func<double>(() => Core.Vessel.atmDensity * 1000d),
"g/m³" "g/m³"
); );
   
public static readonly VOID_DoubleValue atmLimit = public static readonly VOID_DoubleValue atmLimit =
new VOID_DoubleValue( new VOID_DoubleValue(
"Atmosphere Depth", "Atmosphere Depth",
new Func<double>(() => Core.Vessel.mainBody.atmosphereDepth), new Func<double>(() => Core.Vessel.mainBody.atmosphereDepth),
"m" "m"
); );
   
public static readonly VOID_DoubleValue atmPressure = public static readonly VOID_DoubleValue atmPressure =
new VOID_DoubleValue( new VOID_DoubleValue(
"Static Pressure", "Static Pressure",
new Func<double>(() => Core.Vessel.staticPressurekPa * 1000d), new Func<double>(() => Core.Vessel.staticPressurekPa * 1000d),
"Pa" "Pa"
); );
   
public static readonly VOID_DoubleValue temperature = public static readonly VOID_DoubleValue temperature =
new VOID_DoubleValue( new VOID_DoubleValue(
"Temperature", "Temperature",
new Func<double>(() => Core.Vessel.atmosphericTemperature), new Func<double>(() => Core.Vessel.atmosphericTemperature),
"K" "K"
); );
   
#endregion #endregion
   
#region Attitude #region Attitude
   
public static readonly VOID_StrValue vesselHeading = public static readonly VOID_StrValue vesselHeading =
new VOID_StrValue( new VOID_StrValue(
"Heading", "Heading",
delegate() delegate()
{ {
double heading = Core.Vessel.getSurfaceHeading(); double heading = Core.Vessel.getSurfaceHeading();
string cardinal = VOID_Tools.get_heading_text(heading); string cardinal = VOID_Tools.get_heading_text(heading);
   
return string.Format( return string.Format(
"{0}° {1}", "{0}° {1}",
heading.ToString("F2"), heading.ToString("F2"),
cardinal cardinal
); );
} }
); );
   
public static readonly VOID_DoubleValue vesselPitch = public static readonly VOID_DoubleValue vesselPitch =
new VOID_DoubleValue( new VOID_DoubleValue(
"Pitch", "Pitch",
() => Core.Vessel.getSurfacePitch(), () => Core.Vessel.getSurfacePitch(),
"°" "°"
); );
   
#endregion #endregion
   
#region Career #region Career
   
public static readonly VOID_StrValue fundingStatus = public static readonly VOID_StrValue fundingStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Funds"), string.Intern("Funds"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"), VOID_CareerStatus.Instance.currentFunds.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastFundsChange)
); );
} }
); );
   
public static readonly VOID_StrValue reputationStatus = public static readonly VOID_StrValue reputationStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Reputation"), string.Intern("Reputation"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"), VOID_CareerStatus.Instance.currentReputation.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastRepChange)
); );
} }
); );
   
public static readonly VOID_StrValue scienceStatus = public static readonly VOID_StrValue scienceStatus =
new VOID_StrValue( new VOID_StrValue(
string.Intern("Science"), string.Intern("Science"),
delegate() delegate()
{ {
if (VOID_CareerStatus.Instance == null) if (VOID_CareerStatus.Instance == null)
{ {
return string.Empty; return string.Empty;
} }
   
return string.Format("{0} ({1})", return string.Format("{0} ({1})",
VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"), VOID_CareerStatus.Instance.currentScience.ToString("#,#.##"),
VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange) VOID_CareerStatus.formatDelta(VOID_CareerStatus.Instance.lastScienceChange)
); );
} }
); );
   
#endregion #endregion
   
#region Control #region Control
   
public static readonly VOID_FloatValue mainThrottle = public static readonly VOID_FloatValue mainThrottle =
new VOID_FloatValue( new VOID_FloatValue(
"Throttle", "Throttle",
new Func<float>(() => Core.Vessel.ctrlState.mainThrottle), new Func<float>(() => Core.Vessel.ctrlState.mainThrottle),
"" ""
); );
   
#endregion #endregion
   
#region Engineering #region Engineering
   
public static readonly VOID_IntValue partCount = public static readonly VOID_IntValue partCount =
new VOID_IntValue( new VOID_IntValue(
"Parts", "Parts",
new Func<int>(() => Core.Vessel.Parts.Count), new Func<int>(() => Core.Vessel.Parts.Count),
"" ""
); );
   
#region Mass #region Mass
   
public static readonly VOID_StrValue comboResourceMass = public static readonly VOID_StrValue comboResourceMass =
new VOID_StrValue( new VOID_StrValue(
"Resource Mass (curr / total)", "Resource Mass (curr / total)",
delegate() delegate()
{ {
return string.Format("{0} / {1}", return string.Format("{0} / {1}",
stageResourceMass.ValueUnitString("F3"), stageResourceMass.ValueUnitString("F3"),
resourceMass.ValueUnitString("F3") resourceMass.ValueUnitString("F3")
); );
} }
); );
   
public static readonly VOID_DoubleValue resourceMass = public static readonly VOID_DoubleValue resourceMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Resource Mass", "Resource Mass",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.totalResourceMass; return Core.LastStage.totalResourceMass;
}, },
"tons" "tons"
); );
   
public static readonly VOID_DoubleValue stageResourceMass = public static readonly VOID_DoubleValue stageResourceMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Resource Mass (Stage)", "Resource Mass (Stage)",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.resourceMass; return Core.LastStage.resourceMass;
}, },
"tons" "tons"
); );
   
public static readonly VOID_DoubleValue totalMass = public static readonly VOID_DoubleValue totalMass =
new VOID_DoubleValue( new VOID_DoubleValue(
"Total Mass", "Total Mass",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.totalMass; return Core.LastStage.totalMass;
}, },
"tons" "tons"
); );
   
#endregion #endregion
   
#region DeltaV #region DeltaV
   
public static readonly VOID_DoubleValue stageDeltaV = public static readonly VOID_DoubleValue stageDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"DeltaV (Current Stage)", "DeltaV (Current Stage)",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
return Core.LastStage.deltaV; return Core.LastStage.deltaV;
}, },
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue totalDeltaV = public static readonly VOID_DoubleValue totalDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"DeltaV (Total)", "DeltaV (Total)",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
return Core.LastStage.totalDeltaV; return Core.LastStage.totalDeltaV;
}, },
"m/s" "m/s"
); );
   
#endregion #endregion
   
#region Propulsion #region Propulsion
   
public static readonly VOID_StrValue currmaxThrustWeight = public static readonly VOID_StrValue currmaxThrustWeight =
new VOID_StrValue( new VOID_StrValue(
"T:W (curr/max)", "T:W (curr/max)",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return "N/A"; return "N/A";
   
return string.Format( return string.Format(
"{0} / {1}", "{0} / {1}",
(VOID_Data.currThrustWeight.Value).ToString("F2"), (VOID_Data.currThrustWeight.Value).ToString("F2"),
(VOID_Data.maxThrustWeight.Value).ToString("F2") (VOID_Data.maxThrustWeight.Value).ToString("F2")
); );
} }
); );
   
public static readonly VOID_DoubleValue currThrust = public static readonly VOID_DoubleValue currThrust =
new VOID_DoubleValue( new VOID_DoubleValue(
"Current Thrust", "Current Thrust",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
   
return Core.LastStage.actualThrust; return Core.LastStage.actualThrust;
}, },
"kN" "kN"
); );
   
public static readonly VOID_StrValue currmaxThrust = public static readonly VOID_StrValue currmaxThrust =
new VOID_StrValue( new VOID_StrValue(
"Thrust (curr/max)", "Thrust (curr/max)",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return "N/A"; return "N/A";
   
double currThrust = Core.LastStage.actualThrust; double currThrust = Core.LastStage.actualThrust;
double maxThrust = Core.LastStage.thrust; double maxThrust = Core.LastStage.thrust;
   
return string.Format( return string.Format(
"{0} / {1}", "{0} / {1}",
currThrust.ToString("F1"), currThrust.ToString("F1"),
maxThrust.ToString("F1") maxThrust.ToString("F1")
); );
} }
); );
   
public static readonly VOID_DoubleValue stageMassFlow = public static readonly VOID_DoubleValue stageMassFlow =
new VOID_DoubleValue( new VOID_DoubleValue(
"Stage Mass Flow", "Stage Mass Flow",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.MassFlow(); return Core.LastStage.MassFlow();
}, },
"Mg/s" "Mg/s"
); );
   
public static readonly VOID_DoubleValue stageNominalThrust = public static readonly VOID_DoubleValue stageNominalThrust =
new VOID_DoubleValue( new VOID_DoubleValue(
"Nominal Stage Thrust", "Nominal Stage Thrust",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.NominalThrust(); return Core.LastStage.NominalThrust();
}, },
"kN" "kN"
); );
   
#endregion #endregion
   
#region Kinetics #region Kinetics
   
public static readonly VOID_DoubleValue currThrustWeight = public static readonly VOID_DoubleValue currThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"T:W Ratio", "T:W Ratio",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.actualThrustToWeight; return Core.LastStage.actualThrustToWeight;
}, },
"" ""
); );
   
   
   
public static readonly VOID_DoubleValue maxThrustWeight = public static readonly VOID_DoubleValue maxThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"T:W Ratio", "T:W Ratio",
delegate() delegate()
{ {
if (Core.LastStage == null) if (Core.LastStage == null)
{ {
return double.NaN; return double.NaN;
} }
   
return Core.LastStage.thrustToWeight; return Core.LastStage.thrustToWeight;
}, },
"" ""
); );
   
public static readonly VOID_DoubleValue nominalThrustWeight = public static readonly VOID_DoubleValue nominalThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"Thrust-to-Weight Ratio", "Thrust-to-Weight Ratio",
delegate() delegate()
{ {
if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d) if (HighLogic.LoadedSceneIsEditor || currThrustWeight.Value == 0d)
{ {
return maxThrustWeight.Value; return maxThrustWeight.Value;
} }
   
return currThrustWeight.Value; return currThrustWeight.Value;
}, },
"" ""
); );
   
public static readonly VOID_DoubleValue surfaceThrustWeight = public static readonly VOID_DoubleValue surfaceThrustWeight =
new VOID_DoubleValue( new VOID_DoubleValue(
"Max T:W @ surface", "Max T:W @ surface",
delegate() delegate()
{ {
if (Core.Stages == null || Core.LastStage == null) if (Core.Stages == null || Core.LastStage == null)
return double.NaN; return double.NaN;
   
double maxThrust = Core.LastStage.thrust; double maxThrust = Core.LastStage.thrust;
double mass = Core.LastStage.totalMass; double mass = Core.LastStage.totalMass;
double gravity = (VOIDCore.Constant_G * Core.Vessel.mainBody.Mass) / double gravity = (VOIDCore.Constant_G * Core.Vessel.mainBody.Mass) /
(Core.Vessel.mainBody.Radius * Core.Vessel.mainBody.Radius); (Core.Vessel.mainBody.Radius * Core.Vessel.mainBody.Radius);
double weight = mass * gravity; double weight = mass * gravity;
   
return maxThrust / weight; return maxThrust / weight;
}, },
"" ""
); );
   
public static readonly VOID_Vector3dValue vesselThrustOffset = public static readonly VOID_Vector3dValue vesselThrustOffset =
new VOID_Vector3dValue( new VOID_Vector3dValue(
"Thrust Offset", "Thrust Offset",
delegate() delegate()
{ {
if (Core.Vessel == null) if (Core.Vessel == null)
{ {
return Vector3d.zero; return Vector3d.zero;
} }
   
IList<PartModule> engineModules = Core.Vessel.getModulesOfType<PartModule>(); IList<PartModule> engineModules = Core.Vessel.getModulesOfType<PartModule>();
   
Vector3d thrustPos = Vector3d.zero; Vector3d thrustPos = Vector3d.zero;
Vector3d thrustDir = Vector3d.zero; Vector3d thrustDir = Vector3d.zero;
float thrust = 0; float thrust = 0;
   
PartModule engine; PartModule engine;
for (int idx = 0; idx < engineModules.Count; idx++) for (int idx = 0; idx < engineModules.Count; idx++)
{ {
engine = engineModules[idx]; engine = engineModules[idx];
float moduleThrust = 0; float moduleThrust = 0;
   
switch (engine.moduleName) switch (engine.moduleName)
{ {
case "ModuleEngines": case "ModuleEngines":
case "ModuleEnginesFX": case "ModuleEnginesFX":
break; break;
default: default:
continue; continue;
} }
   
if (!engine.isEnabled) if (!engine.isEnabled)
{ {
continue; continue;
} }
   
CenterOfThrustQuery cotQuery = new CenterOfThrustQuery(); CenterOfThrustQuery cotQuery = new CenterOfThrustQuery();
   
if (engine is ModuleEngines) if (engine is ModuleEngines)
{ {
ModuleEngines engineModule = engine as ModuleEngines; ModuleEngines engineModule = engine as ModuleEngines;
   
moduleThrust = engineModule.finalThrust; moduleThrust = engineModule.finalThrust;
   
engineModule.OnCenterOfThrustQuery(cotQuery); engineModule.OnCenterOfThrustQuery(cotQuery);
} }
else // engine is ModuleEnginesFX else // engine is ModuleEnginesFX
{ {
ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX; ModuleEnginesFX engineFXModule = engine as ModuleEnginesFX;
   
moduleThrust = engineFXModule.finalThrust; moduleThrust = engineFXModule.finalThrust;
   
engineFXModule.OnCenterOfThrustQuery(cotQuery); engineFXModule.OnCenterOfThrustQuery(cotQuery);
} }
   
if (moduleThrust != 0d) if (moduleThrust != 0d)
{ {
cotQuery.thrust = moduleThrust; cotQuery.thrust = moduleThrust;
} }
   
thrustPos += cotQuery.pos * cotQuery.thrust; thrustPos += cotQuery.pos * cotQuery.thrust;
thrustDir += cotQuery.dir * cotQuery.thrust; thrustDir += cotQuery.dir * cotQuery.thrust;
thrust += cotQuery.thrust; thrust += cotQuery.thrust;
} }
   
if (thrust != 0) if (thrust != 0)
{ {
thrustPos /= thrust; thrustPos /= thrust;
thrustDir /= thrust; thrustDir /= thrust;
} }
   
Transform vesselTransform = Core.Vessel.transform; Transform vesselTransform = Core.Vessel.transform;
   
thrustPos = vesselTransform.InverseTransformPoint(thrustPos); thrustPos = vesselTransform.InverseTransformPoint(thrustPos);
thrustDir = vesselTransform.InverseTransformDirection(thrustDir); thrustDir = vesselTransform.InverseTransformDirection(thrustDir);
   
Vector3d thrustOffset = ToadicusTools.VectorTools.PointDistanceToLine( Vector3d thrustOffset = VectorTools.PointDistanceToLine(
thrustPos, thrustDir.normalized, Core.Vessel.findLocalCenterOfMass()); thrustPos, thrustDir.normalized, Core.Vessel.findLocalCenterOfMass());
   
ToadicusTools.Logging.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" + Logging.PostDebugMessage(typeof(VOID_Data), "vesselThrustOffset:\n" +
"\tthrustPos: {0}\n" + "\tthrustPos: {0}\n" +
"\tthrustDir: {1}\n" + "\tthrustDir: {1}\n" +
"\tthrustOffset: {2}\n" + "\tthrustOffset: {2}\n" +
"\tvessel.CoM: {3}", "\tvessel.CoM: {3}",
thrustPos, thrustPos,
thrustDir.normalized, thrustDir.normalized,
thrustOffset, thrustOffset,
Core.Vessel.findWorldCenterOfMass() Core.Vessel.findWorldCenterOfMass()
); );
   
return thrustOffset; return thrustOffset;
}, },
"m" "m"
); );
   
#endregion #endregion
   
#region Air Breathing #region Air Breathing
   
public static readonly VOID_StrValue intakeAirStatus = public static readonly VOID_StrValue intakeAirStatus =
new VOID_StrValue( new VOID_StrValue(
"Intake Air (Curr / Req)", "Intake Air (Curr / Req)",
delegate() delegate()
{ {
double currentAmount; double currentAmount;
double currentRequirement; double currentRequirement;
   
currentAmount = 0d; currentAmount = 0d;
currentRequirement = 0d; currentRequirement = 0d;
   
Part part; Part part;
for (int idx = 0; idx < Core.Vessel.Parts.Count; idx++) for (int idx = 0; idx < Core.Vessel.Parts.Count; idx++)
{ {
part = Core.Vessel.Parts[idx]; part = Core.Vessel.Parts[idx];
   
if (part.enabled) if (part.enabled)
{ {
ModuleEngines engineModule; ModuleEngines engineModule;
ModuleEnginesFX enginesFXModule; ModuleEnginesFX enginesFXModule;
List<Propellant> propellantList = null; List<Propellant> propellantList = null;
   
if (part.tryGetFirstModuleOfType<ModuleEngines>(out engineModule)) if (part.tryGetFirstModuleOfType<ModuleEngines>(out engineModule))
{ {
propellantList = engineModule.propellants; propellantList = engineModule.propellants;
} }
else if (part.tryGetFirstModuleOfType<ModuleEnginesFX>(out enginesFXModule)) else if (part.tryGetFirstModuleOfType<ModuleEnginesFX>(out enginesFXModule))
{ {
propellantList = enginesFXModule.propellants; propellantList = enginesFXModule.propellants;
} }
   
if (propellantList != null) if (propellantList != null)
{ {
Propellant propellant; Propellant propellant;
for (int propIdx = 0; propIdx < propellantList.Count; propIdx++) for (int propIdx = 0; propIdx < propellantList.Count; propIdx++)
{ {
propellant = propellantList[propIdx]; propellant = propellantList[propIdx];
   
if (propellant.name == "IntakeAir") if (propellant.name == "IntakeAir")
{ {
currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime; currentRequirement += propellant.currentRequirement / TimeWarp.fixedDeltaTime;
break; break;
} }
} }
} }
} }
   
ModuleResourceIntake intakeModule; ModuleResourceIntake intakeModule;
   
if (part.enabled && part.tryGetFirstModuleOfType<ModuleResourceIntake>(out intakeModule)) if (part.enabled && part.tryGetFirstModuleOfType<ModuleResourceIntake>(out intakeModule))
{ {
if (intakeModule.resourceName == "IntakeAir") if (intakeModule.resourceName == "IntakeAir")
{ {
currentAmount += intakeModule.airFlow; currentAmount += intakeModule.airFlow;
} }
} }
} }
   
if (currentAmount == 0 && currentRequirement == 0) if (currentAmount == 0 && currentRequirement == 0)
{ {
return "N/A"; return "N/A";
} }
   
return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement); return string.Format("{0:F3} / {1:F3}", currentAmount, currentRequirement);
} }
); );
   
#endregion #endregion
   
#region Crew #region Crew
   
public static readonly VOID_IntValue vesselCrewCount = public static readonly VOID_IntValue vesselCrewCount =
new VOID_IntValue( new VOID_IntValue(
"Crew Onboard", "Crew Onboard",
delegate() delegate()
{ {
if (Core.Vessel != null) if (Core.Vessel != null)
{ {
return Core.Vessel.GetCrewCount(); return Core.Vessel.GetCrewCount();
} }
else else
{ {
return 0; return 0;
} }
}, },
"" ""
); );
   
public static readonly VOID_IntValue vesselCrewCapacity = public static readonly VOID_IntValue vesselCrewCapacity =
new VOID_IntValue( new VOID_IntValue(
"Crew Capacity", "Crew Capacity",
delegate() delegate()
{ {
if (Core.Vessel != null) if (Core.Vessel != null)
{ {
return Core.Vessel.GetCrewCapacity(); return Core.Vessel.GetCrewCapacity();
} }
else else
{ {
return 0; return 0;
} }
}, },
"" ""
); );
   
#endregion #endregion
   
#endregion #endregion
   
#region Location #region Location
   
public const double kscLongitude = 285.442323427289 * Math.PI / 180d; public const double kscLongitude = 285.442323427289 * Math.PI / 180d;
public const double kscLatitude = -0.0972112860655246 * Math.PI / 180d; public const double kscLatitude = -0.0972112860655246 * Math.PI / 180d;
   
public static readonly VOID_DoubleValue downrangeDistance = public static readonly VOID_DoubleValue downrangeDistance =
new VOID_DoubleValue( new VOID_DoubleValue(
"Downrange Distance", "Downrange Distance",
delegate() delegate()
{ {
   
if (Core.Vessel == null || if (Core.Vessel == null ||
Planetarium.fetch == null || Planetarium.fetch == null ||
Core.Vessel.mainBody != Planetarium.fetch.Home) Core.Vessel.mainBody != Planetarium.fetch.Home)
{ {
return double.NaN; return double.NaN;
} }
   
double vesselLongitude = Core.Vessel.longitude * Math.PI / 180d; double vesselLongitude = Core.Vessel.longitude * Math.PI / 180d;
double vesselLatitude = Core.Vessel.latitude * Math.PI / 180d; double vesselLatitude = Core.Vessel.latitude * Math.PI / 180d;
   
double diffLon = Math.Abs(vesselLongitude - kscLongitude); double diffLon = Math.Abs(vesselLongitude - kscLongitude);
   
double cosVesselLatitude = Math.Cos(vesselLatitude); double cosVesselLatitude = Math.Cos(vesselLatitude);
double sinDiffLon = Math.Sin(diffLon); double sinDiffLon = Math.Sin(diffLon);
   
double term1 = cosVesselLatitude * sinDiffLon; double term1 = cosVesselLatitude * sinDiffLon;
   
double cosKSCLatitude = Math.Cos(kscLatitude); double cosKSCLatitude = Math.Cos(kscLatitude);
double sinVesselLatitude = Math.Sin(vesselLatitude); double sinVesselLatitude = Math.Sin(vesselLatitude);
double sinKSCLatitude = Math.Sin(kscLatitude); double sinKSCLatitude = Math.Sin(kscLatitude);
double cosDiffLon = Math.Cos(diffLon); double cosDiffLon = Math.Cos(diffLon);
   
double term2 = cosKSCLatitude * sinVesselLatitude - sinKSCLatitude * cosVesselLatitude * cosDiffLon; double term2 = cosKSCLatitude * sinVesselLatitude - sinKSCLatitude * cosVesselLatitude * cosDiffLon;
   
double term3 = sinKSCLatitude * sinVesselLatitude + cosKSCLatitude * cosVesselLatitude * cosDiffLon; double term3 = sinKSCLatitude * sinVesselLatitude + cosKSCLatitude * cosVesselLatitude * cosDiffLon;
   
double arc = Math.Atan2(Math.Sqrt(term1 * term1 + term2 * term2), term3); double arc = Math.Atan2(Math.Sqrt(term1 * term1 + term2 * term2), term3);
   
return arc * Core.Vessel.mainBody.Radius; return arc * Core.Vessel.mainBody.Radius;
}, },
"m" "m"
); );
   
public static readonly VOID_StrValue surfLatitudeString = public static readonly VOID_StrValue surfLatitudeString =
new VOID_StrValue( new VOID_StrValue(
"Latitude", "Latitude",
new Func<string>(() => VOID_Tools.GetLatitudeString(Core.Vessel)) new Func<string>(() => VOID_Tools.GetLatitudeString(Core.Vessel))
); );
   
public static readonly VOID_DoubleValue surfLatitude = public static readonly VOID_DoubleValue surfLatitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Latitude", "Latitude",
delegate() delegate()
{ {
if (CoreInitialized && Core.Vessel != null) if (CoreInitialized && Core.Vessel != null)
{ {
return Core.Vessel.latitude; return Core.Vessel.latitude;
} }
return double.NaN; return double.NaN;
}, },
"°" "°"
); );
   
public static readonly VOID_StrValue surfLongitudeString = public static readonly VOID_StrValue surfLongitudeString =
new VOID_StrValue( new VOID_StrValue(
"Longitude", "Longitude",
new Func<string>(() => VOID_Tools.GetLongitudeString(Core.Vessel)) new Func<string>(() => VOID_Tools.GetLongitudeString(Core.Vessel))
); );
   
public static readonly VOID_DoubleValue surfLongitude = public static readonly VOID_DoubleValue surfLongitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Longitude", "Longitude",
delegate() delegate()
{ {
if (CoreInitialized && Core.Vessel != null) if (CoreInitialized && Core.Vessel != null)
{ {
double longitude = Core.Vessel.longitude; double longitude = Core.Vessel.longitude;
   
longitude = VOID_Tools.FixDegreeDomain(longitude); longitude = VOID_Tools.FixDegreeDomain(longitude);
   
if (longitude < -180d) if (longitude < -180d)
{ {
longitude += 360d; longitude += 360d;
} }
if (longitude >= 180) if (longitude >= 180)
{ {
longitude -= 360d; longitude -= 360d;
} }
   
return longitude; return longitude;
} }
return double.NaN; return double.NaN;
}, },
"°" "°"
); );
   
public static readonly VOID_DoubleValue trueAltitude = public static readonly VOID_DoubleValue trueAltitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Altitude (true)", "Altitude (true)",
delegate() delegate()
{ {
double alt_true = Core.Vessel.orbit.altitude - Core.Vessel.terrainAltitude; double alt_true = Core.Vessel.orbit.altitude - Core.Vessel.terrainAltitude;
// HACK: This assumes that on worlds with oceans, all water is fixed at 0 m, // HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,
// and water covers the whole surface at 0 m. // and water covers the whole surface at 0 m.
if (Core.Vessel.terrainAltitude < 0 && Core.Vessel.mainBody.ocean) if (Core.Vessel.terrainAltitude < 0 && Core.Vessel.mainBody.ocean)
alt_true = Core.Vessel.orbit.altitude; alt_true = Core.Vessel.orbit.altitude;
return alt_true; return alt_true;
}, },
"m" "m"
); );
   
#endregion #endregion
   
#region Kinematics #region Kinematics
   
public static readonly VOID_DoubleValue geeForce = public static readonly VOID_DoubleValue geeForce =
new VOID_DoubleValue( new VOID_DoubleValue(
"G-force", "G-force",
new Func<double>(() => Core.Vessel.geeForce), new Func<double>(() => Core.Vessel.geeForce),
"gees" "gees"
); );
   
public static readonly VOID_DoubleValue horzVelocity = public static readonly VOID_DoubleValue horzVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Horizontal speed", "Horizontal speed",
delegate delegate
{ {
return Core.Vessel.horizontalSrfSpeed; return Core.Vessel.horizontalSrfSpeed;
}, },
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue surfVelocity = public static readonly VOID_DoubleValue surfVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Surface velocity", "Surface velocity",
new Func<double>(() => Core.Vessel.srf_velocity.magnitude), new Func<double>(() => Core.Vessel.srf_velocity.magnitude),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue vertVelocity = public static readonly VOID_DoubleValue vertVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Vertical speed", "Vertical speed",
new Func<double>(() => Core.Vessel.verticalSpeed), new Func<double>(() => Core.Vessel.verticalSpeed),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue vesselAccel = public static readonly VOID_DoubleValue vesselAccel =
new VOID_DoubleValue( new VOID_DoubleValue(
"Acceleration", "Acceleration",
() => geeForce * KerbinGee, () => geeForce * KerbinGee,
"m/s²" "m/s²"
); );
   
public static readonly VOID_DoubleValue vesselAngularVelocity = public static readonly VOID_DoubleValue vesselAngularVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Angular Velocity", "Angular Velocity",
delegate() delegate()
{ {
if (Core.Vessel != null) if (Core.Vessel != null)
{ {
return Core.Vessel.angularVelocity.magnitude; return Core.Vessel.angularVelocity.magnitude;
} }
else else
{ {
return double.NaN; return double.NaN;
} }
}, },
"rad/s" "rad/s"
); );
   
#endregion #endregion
   
#region Navigation #region Navigation
   
public static int upcomingManeuverNodes public static int upcomingManeuverNodes
{ {
get get
{ {
if (Core.Vessel == null || if (Core.Vessel == null ||
Core.Vessel.patchedConicSolver == null || Core.Vessel.patchedConicSolver == null ||
Core.Vessel.patchedConicSolver.maneuverNodes == null) Core.Vessel.patchedConicSolver.maneuverNodes == null)
{ {
return 0; return 0;
} }
   
return Core.Vessel.patchedConicSolver.maneuverNodes.Count; return Core.Vessel.patchedConicSolver.maneuverNodes.Count;
} }
} }
   
public static readonly VOID_StrValue burnTimeDoneAtNode = public static readonly VOID_StrValue burnTimeDoneAtNode =
new VOID_StrValue( new VOID_StrValue(
"Full burn time to be half done at node", "Full burn time to be half done at node",
delegate() delegate()
{ {
if (Core.LastStage == null && upcomingManeuverNodes < 1) if (Core.LastStage == null && upcomingManeuverNodes < 1)
{ {
return "N/A"; return "N/A";
} }
   
ManeuverNode node = Core.Vessel.patchedConicSolver.maneuverNodes[0]; ManeuverNode node = Core.Vessel.patchedConicSolver.maneuverNodes[0];
   
if ((node.UT - Planetarium.GetUniversalTime()) < 0) if ((node.UT - Planetarium.GetUniversalTime()) < 0)
{ {
return string.Empty; return string.Empty;
} }
   
double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime(); double interval = (node.UT - currentNodeBurnDuration) - Planetarium.GetUniversalTime();
   
if (double.IsNaN(interval)) if (double.IsNaN(interval))
{ {
return string.Intern("NaN"); return string.Intern("NaN");
} }
   
int sign = Math.Sign(interval); int sign = Math.Sign(interval);
interval = Math.Abs(interval); interval = Math.Abs(interval);
   
string format; string format;
   
if (sign >= 0) if (sign >= 0)
{ {
format = string.Intern("T - {0}"); format = string.Intern("T - {0}");
} }
else else
{ {
format = string.Intern("T + {0}"); format = string.Intern("T + {0}");
} }
   
return string.Format(format, VOID_Tools.FormatInterval(interval)); return string.Format(format, VOID_Tools.FormatInterval(interval));
} }
); );
   
public static readonly VOID_StrValue burnTimeHalfDoneAtNode = public static readonly VOID_StrValue burnTimeHalfDoneAtNode =
new VOID_StrValue( new VOID_StrValue(
"Full burn time to be half done at node", "Full burn time to be half done at node",
delegate() delegate()
{ {
if (Core.LastStage == null && upcomingManeuverNodes < 1) if (Core.LastStage == null && upcomingManeuverNodes < 1)
{ {
return "N/A"; return "N/A";
} }
   
ManeuverNode node = Core.Vessel.patchedConicSolver.maneuverNodes[0]; ManeuverNode node = Core.Vessel.patchedConicSolver.maneuverNodes[0];
   
if ((node.UT - Planetarium.GetUniversalTime()) < 0) if ((node.UT - Planetarium.GetUniversalTime()) < 0)
{ {
return string.Empty; return string.Empty;
} }
   
double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime(); double interval = (node.UT - currentNodeHalfBurnDuration) - Planetarium.GetUniversalTime();
   
if (double.IsNaN(interval)) if (double.IsNaN(interval))
{ {
return string.Intern("NaN"); return string.Intern("NaN");
} }
   
int sign = Math.Sign(interval); int sign = Math.Sign(interval);
interval = Math.Abs(interval); interval = Math.Abs(interval);
   
string format; string format;
   
if (sign >= 0) if (sign >= 0)
{ {
format = string.Intern("T - {0}"); format = string.Intern("T - {0}");
} }
else else
{ {
format = string.Intern("T + {0}"); format = string.Intern("T + {0}");
} }
   
return string.Format(format, VOID_Tools.FormatInterval(interval)); return string.Format(format, VOID_Tools.FormatInterval(interval));
} }
); );
   
public static readonly VOID_DoubleValue currManeuverDeltaV = public static readonly VOID_DoubleValue currManeuverDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"Current Maneuver Delta-V", "Current Maneuver Delta-V",
delegate() delegate()
{ {
if (upcomingManeuverNodes > 0) if (upcomingManeuverNodes > 0)
{ {
return Core.Vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude; return Core.Vessel.patchedConicSolver.maneuverNodes[0].DeltaV.magnitude;
} }
else else
{ {
return double.NaN; return double.NaN;
} }
}, },
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue currManeuverDVRemaining = public static readonly VOID_DoubleValue currManeuverDVRemaining =
new VOID_DoubleValue( new VOID_DoubleValue(
"Remaining Maneuver Delta-V", "Remaining Maneuver Delta-V",
delegate() delegate()
{ {
if (upcomingManeuverNodes > 0) if (upcomingManeuverNodes > 0)
{ {
return Core.Vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(Core.Vessel.orbit).magnitude; return Core.Vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(Core.Vessel.orbit).magnitude;
} }
else else
{ {
return double.NaN; return double.NaN;
} }
}, },
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue currentNodeBurnDuration = public static readonly VOID_DoubleValue currentNodeBurnDuration =
new VOID_DoubleValue( new VOID_DoubleValue(
"Total Burn Time", "Total Burn Time",
delegate() delegate()
{ {
if (currManeuverDeltaV.Value == double.NaN) if (currManeuverDeltaV.Value == double.NaN)
{ {
return double.NaN; return double.NaN;
} }
   
return realVesselBurnTime(currManeuverDeltaV.Value); return realVesselBurnTime(currManeuverDeltaV.Value);
}, },
"s" "s"
); );
   
public static readonly VOID_DoubleValue currentNodeBurnRemaining = public static readonly VOID_DoubleValue currentNodeBurnRemaining =
new VOID_DoubleValue( new VOID_DoubleValue(
"Burn Time Remaining", "Burn Time Remaining",
delegate() delegate()
{ {
if (currManeuverDVRemaining.Value == double.NaN) if (currManeuverDVRemaining.Value == double.NaN)
{ {
return double.NaN; return double.NaN;
} }
   
return realVesselBurnTime(currManeuverDVRemaining.Value); return realVesselBurnTime(currManeuverDVRemaining.Value);
}, },
"s" "s"
); );
   
public static readonly VOID_DoubleValue currentNodeHalfBurnDuration = public static readonly VOID_DoubleValue currentNodeHalfBurnDuration =
new VOID_DoubleValue( new VOID_DoubleValue(
"Half Burn Time", "Half Burn Time",
delegate() delegate()
{ {
if (currManeuverDeltaV.Value == double.NaN) if (currManeuverDeltaV.Value == double.NaN)
{ {
return double.NaN; return double.NaN;
} }
   
return realVesselBurnTime(currManeuverDeltaV.Value / 2d); return realVesselBurnTime(currManeuverDeltaV.Value / 2d);
}, },
"s" "s"
); );
   
public static readonly VOID_DoubleValue nextManeuverDeltaV = public static readonly VOID_DoubleValue nextManeuverDeltaV =
new VOID_DoubleValue( new VOID_DoubleValue(
"Current Maneuver Delta-V", "Current Maneuver Delta-V",
delegate() delegate()
{ {
if (upcomingManeuverNodes > 1) if (upcomingManeuverNodes > 1)
{ {
return Core.Vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude; return Core.Vessel.patchedConicSolver.maneuverNodes[1].DeltaV.magnitude;
} }
else else
{ {
return double.NaN; return double.NaN;
} }
}, },
"m/s" "m/s"
); );
   
#endregion #endregion
   
#region Orbits #region Orbits
   
public static readonly VOID_StrValue primaryName = public static readonly VOID_StrValue primaryName =
new VOID_StrValue( new VOID_StrValue(
VOID_Localization.void_primary, VOID_Localization.void_primary,
delegate() delegate()
{ {
if (Core.Vessel == null) if (Core.Vessel == null)
{ {
return string.Empty; return string.Empty;
} }
return Core.Vessel.mainBody.name; return Core.Vessel.mainBody.name;
} }
); );
   
public static readonly VOID_DoubleValue orbitAltitude = public static readonly VOID_DoubleValue orbitAltitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Altitude (ASL)", "Altitude (ASL)",
new Func<double>(() => Core.Vessel.orbit.altitude), new Func<double>(() => Core.Vessel.orbit.altitude),
"m" "m"
); );
   
public static readonly VOID_DoubleValue orbitVelocity = public static readonly VOID_DoubleValue orbitVelocity =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_velocity, VOID_Localization.void_velocity,
new Func<double>(() => Core.Vessel.orbit.vel.magnitude), new Func<double>(() => Core.Vessel.orbit.vel.magnitude),
"m/s" "m/s"
); );
   
public static readonly VOID_DoubleValue orbitApoAlt = public static readonly VOID_DoubleValue orbitApoAlt =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_apoapsis, VOID_Localization.void_apoapsis,
new Func<double>(() => Core.Vessel.orbit.ApA), new Func<double>(() => Core.Vessel.orbit.ApA),
"m" "m"
); );
   
public static readonly VOID_DoubleValue oribtPeriAlt = public static readonly VOID_DoubleValue oribtPeriAlt =
new VOID_DoubleValue( new VOID_DoubleValue(
VOID_Localization.void_periapsis, VOID_Localization.void_periapsis,
new Func<double>(() => Core.Vessel.orbit.PeA), new Func<double>(() => Core.Vessel.orbit.PeA),
"m" "m"
); );
   
public static readonly VOID_StrValue timeToApo = public static readonly VOID_StrValue timeToApo =
new VOID_StrValue( new VOID_StrValue(
"Time to Apoapsis", "Time to Apoapsis",
new Func<string>(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.timeToAp)) new Func<string>(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.timeToAp))
); );
   
public static readonly VOID_StrValue timeToPeri = public static readonly VOID_StrValue timeToPeri =
new VOID_StrValue( new VOID_StrValue(
"Time to Periapsis", "Time to Periapsis",
new Func<string>(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.timeToPe)) new Func<string>(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.timeToPe))
); );
   
public static readonly VOID_DoubleValue orbitInclination = public static readonly VOID_DoubleValue orbitInclination =
new VOID_DoubleValue( new VOID_DoubleValue(
"Inclination", "Inclination",
new Func<double>(() => Core.Vessel.orbit.inclination), new Func<double>(() => Core.Vessel.orbit.inclination),
"°" "°"
); );
   
public static readonly VOID_DoubleValue gravityAccel = public static readonly VOID_DoubleValue gravityAccel =
new VOID_DoubleValue( new VOID_DoubleValue(
"Gravity", "Gravity",
delegate() delegate()
{ {
double orbitRadius = Core.Vessel.mainBody.Radius + double orbitRadius = Core.Vessel.mainBody.Radius +
Core.Vessel.mainBody.GetAltitude(Core.Vessel.findWorldCenterOfMass()); Core.Vessel.mainBody.GetAltitude(Core.Vessel.findWorldCenterOfMass());
return (VOIDCore.Constant_G * Core.Vessel.mainBody.Mass) / return (VOIDCore.Constant_G * Core.Vessel.mainBody.Mass) /
(orbitRadius * orbitRadius); (orbitRadius * orbitRadius);
}, },
"m/s²" "m/s²"
); );
   
public static readonly VOID_StrValue orbitPeriod = public static readonly VOID_StrValue orbitPeriod =
new VOID_StrValue( new VOID_StrValue(
"Period", "Period",
new Func<string>(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.period)) new Func<string>(() => VOID_Tools.FormatInterval(Core.Vessel.orbit.period))
); );
   
public static readonly VOID_DoubleValue semiMajorAxis = public static readonly VOID_DoubleValue semiMajorAxis =
new VOID_DoubleValue( new VOID_DoubleValue(
"Semi-Major Axis", "Semi-Major Axis",
new Func<double>(() => Core.Vessel.orbit.semiMajorAxis), new Func<double>(() => Core.Vessel.orbit.semiMajorAxis),
"m" "m"
); );
   
public static readonly VOID_DoubleValue eccentricity = public static readonly VOID_DoubleValue eccentricity =
new VOID_DoubleValue( new VOID_DoubleValue(
"Eccentricity", "Eccentricity",
new Func<double>(() => Core.Vessel.orbit.eccentricity), new Func<double>(() => Core.Vessel.orbit.eccentricity),
"" ""
); );
   
public static readonly VOID_DoubleValue meanAnomaly = public static readonly VOID_DoubleValue meanAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"Mean Anomaly", "Mean Anomaly",
new Func<double>(() => Core.Vessel.orbit.meanAnomaly * 180d / Math.PI), new Func<double>(() => Core.Vessel.orbit.meanAnomaly * 180d / Math.PI),
"°" "°"
); );
   
public static readonly VOID_DoubleValue trueAnomaly = public static readonly VOID_DoubleValue trueAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"True Anomaly", "True Anomaly",
new Func<double>(() => Core.Vessel.orbit.trueAnomaly), new Func<double>(() => Core.Vessel.orbit.trueAnomaly),
"°" "°"
); );
   
public static readonly VOID_DoubleValue eccAnomaly = public static readonly VOID_DoubleValue eccAnomaly =
new VOID_DoubleValue( new VOID_DoubleValue(
"Eccentric Anomaly", "Eccentric Anomaly",
new Func<double>(() => Core.Vessel.orbit.eccentricAnomaly * 180d / Math.PI), new Func<double>(() => Core.Vessel.orbit.eccentricAnomaly * 180d / Math.PI),
"°" "°"
); );
   
public static readonly VOID_DoubleValue longitudeAscNode = public static readonly VOID_DoubleValue longitudeAscNode =
new VOID_DoubleValue( new VOID_DoubleValue(
"Long. Ascending Node", "Long. Ascending Node",
new Func<double>(() => Core.Vessel.orbit.LAN), new Func<double>(() => Core.Vessel.orbit.LAN),
"°" "°"
); );
   
public static readonly VOID_DoubleValue argumentPeriapsis = public static readonly VOID_DoubleValue argumentPeriapsis =
new VOID_DoubleValue( new VOID_DoubleValue(
"Argument of Periapsis", "Argument of Periapsis",
new Func<double>(() => Core.Vessel.orbit.argumentOfPeriapsis), new Func<double>(() => Core.Vessel.orbit.argumentOfPeriapsis),
"°" "°"
); );
   
public static readonly VOID_StrValue timeToAscendingNode = public static readonly VOID_StrValue timeToAscendingNode =
new VOID_StrValue( new VOID_StrValue(
"Time to Ascending Node", "Time to Ascending Node",
delegate() delegate()
{ {
double trueAnomalyAscNode = 360d - argumentPeriapsis; double trueAnomalyAscNode = 360d - argumentPeriapsis;
double dTAscNode = Core.Vessel.orbit.GetDTforTrueAnomaly( double dTAscNode = Core.Vessel.orbit.GetDTforTrueAnomaly(
trueAnomalyAscNode * Mathf.Deg2Rad, trueAnomalyAscNode * Mathf.Deg2Rad,
Core.Vessel.orbit.period Core.Vessel.orbit.period
); );
   
dTAscNode %= Core.Vessel.orbit.period; dTAscNode %= Core.Vessel.orbit.period;
   
if (dTAscNode < 0d) if (dTAscNode < 0d)
{ {
dTAscNode += Core.Vessel.orbit.period; dTAscNode += Core.Vessel.orbit.period;
} }
   
return VOID_Tools.FormatInterval(dTAscNode); return VOID_Tools.FormatInterval(dTAscNode);
} }
); );
   
public static readonly VOID_StrValue timeToDescendingNode = public static readonly VOID_StrValue timeToDescendingNode =
new VOID_StrValue( new VOID_StrValue(
"Time to Descending Node", "Time to Descending Node",
delegate() delegate()
{ {
double trueAnomalyAscNode = 180d - argumentPeriapsis; double trueAnomalyAscNode = 180d - argumentPeriapsis;
double dTDescNode = Core.Vessel.orbit.GetDTforTrueAnomaly( double dTDescNode = Core.Vessel.orbit.GetDTforTrueAnomaly(
trueAnomalyAscNode * Mathf.Deg2Rad, trueAnomalyAscNode * Mathf.Deg2Rad,
Core.Vessel.orbit.period Core.Vessel.orbit.period
); );
   
dTDescNode %= Core.Vessel.orbit.period; dTDescNode %= Core.Vessel.orbit.period;
   
if (dTDescNode < 0d) if (dTDescNode < 0d)
{ {
dTDescNode += Core.Vessel.orbit.period; dTDescNode += Core.Vessel.orbit.period;
} }
   
return VOID_Tools.FormatInterval(dTDescNode); return VOID_Tools.FormatInterval(dTDescNode);
} }
); );
   
public static readonly VOID_DoubleValue localSiderealLongitude = public static readonly VOID_DoubleValue localSiderealLongitude =
new VOID_DoubleValue( new VOID_DoubleValue(
"Local Sidereal Longitude", "Local Sidereal Longitude",
new Func<double>(() => VOID_Tools.FixDegreeDomain( new Func<double>(() => VOID_Tools.FixDegreeDomain(
Core.Vessel.longitude + Core.Vessel.orbit.referenceBody.rotationAngle)), Core.Vessel.longitude + Core.Vessel.orbit.referenceBody.rotationAngle)),
"°" "°"
); );
   
#endregion #endregion
   
#region Science #region Science
   
public static readonly VOID_StrValue expSituation = public static readonly VOID_StrValue expSituation =
new VOID_StrValue( new VOID_StrValue(
"Situation", "Situation",
new Func<string>(() => Core.Vessel.GetExperimentSituation().HumanString()) new Func<string>(() => Core.Vessel.GetExperimentSituation().HumanString())
); );
   
public static readonly VOID_StrValue currBiome = public static readonly VOID_StrValue currBiome =
new VOID_StrValue( new VOID_StrValue(
"Biome", "Biome",
delegate() delegate()
{ {
if (Core.Vessel.landedAt == string.Empty) if (Core.Vessel.landedAt == string.Empty)
{ {
return VOID_Tools.GetBiome(Core.Vessel).name; return VOID_Tools.GetBiome(Core.Vessel).name;
} }
else else
{ {
return Core.Vessel.landedAt; return Core.Vessel.landedAt;
} }
} }
); );
   
#endregion #endregion
   
#region Surface #region Surface
   
public static readonly VOID_DoubleValue terrainElevation = public static readonly VOID_DoubleValue terrainElevation =
new VOID_DoubleValue( new VOID_DoubleValue(
"Terrain elevation", "Terrain elevation",
new Func<double>(() => Core.Vessel.terrainAltitude), new Func<double>(() => Core.Vessel.terrainAltitude),
"m" "m"
); );
   
#endregion #endregion
   
private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust) private static double burnTime(double deltaV, double initialMass, double massFlow, double thrust)
{ {
ToadicusTools.Logging.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" + Logging.PostDebugMessage(typeof(VOID_Data), "calculating burnTime from:\n" +
"\tdeltaV: {0}\n" + "\tdeltaV: {0}\n" +
"\tinitialMass: {1}\n" + "\tinitialMass: {1}\n" +
"\tmassFlow: {2}\n" + "\tmassFlow: {2}\n" +
"\tthrust: {3}\n", "\tthrust: {3}\n",
deltaV, deltaV,
initialMass, initialMass,
massFlow, massFlow,
thrust thrust
); );
return initialMass / massFlow * (1d - Math.Exp(-deltaV * massFlow / thrust)); return initialMass / massFlow * (1d - Math.Exp(-deltaV * massFlow / thrust));
} }
   
private static double dVfromBurnTime(double time, double initialMass, double massFlow, double thrust) private static double dVfromBurnTime(double time, double initialMass, double massFlow, double thrust)
{ {
return -thrust / massFlow * Math.Log(1d - time * massFlow / initialMass); return -thrust / massFlow * Math.Log(1d - time * massFlow / initialMass);
} }
   
private static double realVesselBurnTime(double deltaV) private static double realVesselBurnTime(double deltaV)
{ {
if (Core.Stages == null || Core.Stages.Length < 1) if (Core.Stages == null || Core.Stages.Length < 1)
{ {
return double.NaN; return double.NaN;
} }
   
double burntime = 0d; double burntime = 0d;
double dVRemaining = deltaV; double dVRemaining = deltaV;
   
int stageIdx = Core.Stages.Length - 1; int stageIdx = Core.Stages.Length - 1;
   
while (dVRemaining > double.Epsilon) while (dVRemaining > double.Epsilon)
{ {
if (stageIdx < 0) if (stageIdx < 0)
{ {
return double.PositiveInfinity; return double.PositiveInfinity;
} }
   
Stage stage = Core.Stages[stageIdx]; Stage stage = Core.Stages[stageIdx];
   
if (stage.deltaV > 0) if (stage.deltaV > 0)
{ {
double stageDVUsed = Math.Min(stage.deltaV, dVRemaining); double stageDVUsed = Math.Min(stage.deltaV, dVRemaining);
   
burntime += burnTime(stageDVUsed, stage.totalMass, stage.MassFlow(), stage.NominalThrust()); burntime += burnTime(stageDVUsed, stage.totalMass, stage.MassFlow(), stage.NominalThrust());
dVRemaining -= stageDVUsed; dVRemaining -= stageDVUsed;
} }
   
stageIdx--; stageIdx--;
} }
   
return burntime; return burntime;
} }
} }
} }
   
// VOID // VOID
// //
// VOID_DataLogger.cs // VOID_DataLogger.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
  using ToadicusTools;
using ToadicusTools.DebugTools; using ToadicusTools.DebugTools;
using ToadicusTools.GUIUtils; using ToadicusTools.GUIUtils;
using ToadicusTools.Text; using ToadicusTools.Text;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_DataLogger : VOID_WindowModule, IVOID_BehaviorModule public class VOID_DataLogger : VOID_WindowModule, IVOID_BehaviorModule
{ {
/* /*
* Fields * Fields
* */ * */
#region Fields #region Fields
   
protected bool _loggingActive; protected bool _loggingActive;
protected bool firstWrite; protected bool firstWrite;
   
[AVOID_SaveValue("waitForLaunch")] [AVOID_SaveValue("waitForLaunch")]
protected VOID_SaveValue<bool> waitForLaunch; protected VOID_SaveValue<bool> waitForLaunch;
   
[AVOID_SaveValue("logInterval")] [AVOID_SaveValue("logInterval")]
protected VOID_SaveValue<float> logInterval; protected VOID_SaveValue<float> logInterval;
protected string logIntervalStr; protected string logIntervalStr;
   
protected float csvCollectTimer; protected float csvCollectTimer;
   
protected List<byte> csvBytes; protected List<byte> csvBytes;
   
protected string _fileName; protected string _fileName;
protected FileStream _outputFile; protected FileStream _outputFile;
   
protected uint outstandingWrites; protected uint outstandingWrites;
   
protected System.Text.UTF8Encoding _utf8Encoding; protected System.Text.UTF8Encoding _utf8Encoding;
   
#endregion #endregion
   
/* /*
* Properties * Properties
* */ * */
   
#region Properties #region Properties
   
// TODO: Add configurable or incremental file names. // TODO: Add configurable or incremental file names.
protected bool loggingActive protected bool loggingActive
{ {
get get
{ {
return this._loggingActive; return this._loggingActive;
} }
set set
{ {
if (value != this._loggingActive) if (value != this._loggingActive)
{ {
if (value) if (value)
{ {
this.csvCollectTimer = 0f; this.csvCollectTimer = 0f;
} }
else else
{ {
this.CloseFileIfOpen(); this.CloseFileIfOpen();
} }
   
this._loggingActive = value; this._loggingActive = value;
} }
} }
} }
   
protected string fileName protected string fileName
{ {
get get
{ {
if (this._fileName == null || this._fileName == string.Empty) if (this._fileName == null || this._fileName == string.Empty)
{ {
this._fileName = string.Format( this._fileName = string.Format(
"{0}/{1}_{2}", "{0}/{1}_{2}",
this.core.SaveGamePath, this.core.SaveGamePath,
this.Vessel.vesselName, this.Vessel.vesselName,
"data.csv" "data.csv"
); );
} }
   
return this._fileName; return this._fileName;
} }
} }
   
protected FileStream outputFile protected FileStream outputFile
{ {
get get
{ {
if (this._outputFile == null) if (this._outputFile == null)
{ {
using (PooledDebugLogger logger = PooledDebugLogger.New(this)) using (PooledDebugLogger logger = PooledDebugLogger.New(this))
{ {
logger.AppendFormat("Initializing output file '{0}' with mode ", this.fileName); logger.AppendFormat("Initializing output file '{0}' with mode ", this.fileName);
   
if (File.Exists(this.fileName)) if (File.Exists(this.fileName))
{ {
logger.Append("append"); logger.Append("append");
this._outputFile = new FileStream( this._outputFile = new FileStream(
this.fileName, this.fileName,
FileMode.Append, FileMode.Append,
FileAccess.Write, FileAccess.Write,
FileShare.Read, FileShare.Read,
512, 512,
true true
); );
} }
else else
{ {
logger.Append("create"); logger.Append("create");
this._outputFile = new FileStream( this._outputFile = new FileStream(
this.fileName, this.fileName,
FileMode.Create, FileMode.Create,
FileAccess.Write, FileAccess.Write,
FileShare.Read, FileShare.Read,
512, 512,
true true
); );
   
byte[] byteOrderMark = utf8Encoding.GetPreamble(); byte[] byteOrderMark = utf8Encoding.GetPreamble();
   
logger.Append(" and writing preamble"); logger.Append(" and writing preamble");
this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length); this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length);
} }
   
logger.Append('.'); logger.Append('.');
   
logger.AppendFormat(" File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not "); logger.AppendFormat(" File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not ");
   
logger.Print(); logger.Print();
} }
} }
   
return this._outputFile; return this._outputFile;
} }
} }
   
public UTF8Encoding utf8Encoding public UTF8Encoding utf8Encoding
{ {
get get
{ {
if (this._utf8Encoding == null) if (this._utf8Encoding == null)
{ {
this._utf8Encoding = new UTF8Encoding(true); this._utf8Encoding = new UTF8Encoding(true);
} }
   
return this._utf8Encoding; return this._utf8Encoding;
} }
} }
   
#endregion #endregion
   
/* /*
* Methods * Methods
* */ * */
#region Monobehaviour Lifecycle #region Monobehaviour Lifecycle
public void Update() public void Update()
{ {
if (this.csvBytes != null && this.csvBytes.Count > 0) if (this.csvBytes != null && this.csvBytes.Count > 0)
{ {
// csvList is not empty, write it // csvList is not empty, write it
this.AsyncWriteData(); this.AsyncWriteData();
} }
   
// CSV Logging // CSV Logging
// from ISA MapSat // from ISA MapSat
if (loggingActive && (!waitForLaunch || this.Vessel.situation != Vessel.Situations.PRELAUNCH)) if (loggingActive && (!waitForLaunch || this.Vessel.situation != Vessel.Situations.PRELAUNCH))
{ {
//data logging is on //data logging is on
//increment timers //increment timers
this.csvCollectTimer += Time.deltaTime; this.csvCollectTimer += Time.deltaTime;
   
if (this.csvCollectTimer >= this.logInterval) if (this.csvCollectTimer >= this.logInterval)
{ {
//data logging is on, vessel is not prelaunch, and interval has passed //data logging is on, vessel is not prelaunch, and interval has passed
//write a line to the list //write a line to the list
this.CollectLogData(); this.CollectLogData();
} }
} }
} }
   
public void FixedUpdate() {} public void FixedUpdate() {}
   
public void OnDestroy() public void OnDestroy()
{ {
using (PooledDebugLogger logger = PooledDebugLogger.New(this)) using (PooledDebugLogger logger = PooledDebugLogger.New(this))
{ {
logger.Append("Destroying..."); logger.Append("Destroying...");
   
this.CloseFileIfOpen(); this.CloseFileIfOpen();
   
logger.Append(" Done."); logger.Append(" Done.");
logger.Print(false); logger.Print(false);
} }
} }
   
#endregion #endregion
   
#region VOID_Module Overrides #region VOID_Module Overrides
   
public override void LoadConfig(KSP.IO.PluginConfiguration config) public override void LoadConfig(KSP.IO.PluginConfiguration config)
{ {
base.LoadConfig(config); base.LoadConfig(config);
   
this.logIntervalStr = this.logInterval.value.ToString("#.0##"); this.logIntervalStr = this.logInterval.value.ToString("#.0##");
} }
   
public override void ModuleWindow(int id) public override void ModuleWindow(int id)
{ {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
GUILayout.Label( GUILayout.Label(
string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")), string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")),
GUILayout.ExpandWidth(true) GUILayout.ExpandWidth(true)
); );
GUILayout.Label( GUILayout.Label(
string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())), string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())),
GUILayout.ExpandWidth(true) GUILayout.ExpandWidth(true)
); );
   
GUIStyle activeLabelStyle = VOID_Styles.labelRed; GUIStyle activeLabelStyle = VOID_Styles.labelRed;
string activeLabelText = "Inactive"; string activeLabelText = "Inactive";
if (loggingActive) if (loggingActive)
{ {
activeLabelText = "Active"; activeLabelText = "Active";
activeLabelStyle = VOID_Styles.labelGreen; activeLabelStyle = VOID_Styles.labelGreen;
} }
   
this.loggingActive = Layout.Toggle( this.loggingActive = Layout.Toggle(
loggingActive, loggingActive,
string.Format("Data logging: {0}", activeLabelText), string.Format("Data logging: {0}", activeLabelText),
null, null,
activeLabelStyle activeLabelStyle
); );
   
this.waitForLaunch.value = Layout.Toggle( this.waitForLaunch.value = Layout.Toggle(
this.waitForLaunch, this.waitForLaunch,
"Wait for launch" "Wait for launch"
); );
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false)); GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false));
   
logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true)); logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true));
GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.Label("s", GUILayout.ExpandWidth(false));
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
float newLogInterval; float newLogInterval;
if (float.TryParse(logIntervalStr, out newLogInterval)) if (float.TryParse(logIntervalStr, out newLogInterval))
{ {
logInterval.value = newLogInterval; logInterval.value = newLogInterval;
this.logIntervalStr = this.logInterval.value.ToString("#.0##"); this.logIntervalStr = this.logInterval.value.ToString("#.0##");
} }
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
base.ModuleWindow(id); base.ModuleWindow(id);
} }
   
#endregion #endregion
   
#region Data Collection #region Data Collection
   
private void CollectLogData() private void CollectLogData()
{ {
if (this.csvBytes == null) if (this.csvBytes == null)
{ {
this.csvBytes = new List<byte>(); this.csvBytes = new List<byte>();
} }
   
//called if logging is on and interval has passed //called if logging is on and interval has passed
//writes one line to the csvList //writes one line to the csvList
   
using (PooledStringBuilder line = PooledStringBuilder.Get()) using (PooledStringBuilder line = PooledStringBuilder.Get())
{ {
if (firstWrite) if (firstWrite)
{ {
firstWrite = false; firstWrite = false;
line.Append( line.Append(
"\"Kerbin Universal Time (s)\"," + "\"Kerbin Universal Time (s)\"," +
"\"Mission Elapsed Time (s)\t\"," + "\"Mission Elapsed Time (s)\t\"," +
"\"Altitude ASL (m)\"," + "\"Altitude ASL (m)\"," +
"\"Altitude above terrain (m)\"," + "\"Altitude above terrain (m)\"," +
"\"Surface Latitude (°)\"," + "\"Surface Latitude (°)\"," +
"\"Surface Longitude (°)\"," + "\"Surface Longitude (°)\"," +
"\"Apoapsis Altitude (m)\"," + "\"Apoapsis Altitude (m)\"," +
"\"Periapsis Altitude (m)\"," + "\"Periapsis Altitude (m)\"," +
"\"Orbital Inclination (°)\"," + "\"Orbital Inclination (°)\"," +
"\"Orbital Velocity (m/s)\"," + "\"Orbital Velocity (m/s)\"," +
"\"Surface Velocity (m/s)\"," + "\"Surface Velocity (m/s)\"," +
"\"Vertical Speed (m/s)\"," + "\"Vertical Speed (m/s)\"," +
"\"Horizontal Speed (m/s)\"," + "\"Horizontal Speed (m/s)\"," +
"\"Current Thrust (kN)\"," + "\"Current Thrust (kN)\"," +
"\"Gee Force (gees)\"," + "\"Gee Force (gees)\"," +
"\"Temperature (°C)\"," + "\"Temperature (°C)\"," +
"\"Gravity (m/s²)\"," + "\"Gravity (m/s²)\"," +
"\"Atmosphere Density (g/m³)\"," + "\"Atmosphere Density (g/m³)\"," +
"\"Downrange Distance (m)\"," + "\"Downrange Distance (m)\"," +
"\"Main Throttle\"," + "\"Main Throttle\"," +
"\n" "\n"
); );
} }
   
// Universal time // Universal time
line.Append(Planetarium.GetUniversalTime().ToString("F2")); line.Append(Planetarium.GetUniversalTime().ToString("F2"));
line.Append(','); line.Append(',');
   
//Mission time //Mission time
line.Append(Vessel.missionTime.ToString("F3")); line.Append(Vessel.missionTime.ToString("F3"));
line.Append(','); line.Append(',');
   
//Altitude ASL //Altitude ASL
line.Append(VOID_Data.orbitAltitude.Value.ToString("G9")); line.Append(VOID_Data.orbitAltitude.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
//Altitude (true) //Altitude (true)
line.Append(VOID_Data.trueAltitude.Value.ToString("G9")); line.Append(VOID_Data.trueAltitude.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
// Surface Latitude // Surface Latitude
line.Append('"'); line.Append('"');
line.Append(VOID_Data.surfLatitude.Value.ToString("F3")); line.Append(VOID_Data.surfLatitude.Value.ToString("F3"));
line.Append('"'); line.Append('"');
line.Append(','); line.Append(',');
   
// Surface Longitude // Surface Longitude
line.Append('"'); line.Append('"');
line.Append(VOID_Data.surfLongitude.Value.ToString("F3")); line.Append(VOID_Data.surfLongitude.Value.ToString("F3"));
line.Append('"'); line.Append('"');
line.Append(','); line.Append(',');
   
// Apoapsis Altitude // Apoapsis Altitude
line.Append(VOID_Data.orbitApoAlt.Value.ToString("G9")); line.Append(VOID_Data.orbitApoAlt.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
// Periapsis Altitude // Periapsis Altitude
line.Append(VOID_Data.oribtPeriAlt.Value.ToString("G9")); line.Append(VOID_Data.oribtPeriAlt.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
// Orbital Inclination // Orbital Inclination
line.Append(VOID_Data.orbitInclination.Value.ToString("F2")); line.Append(VOID_Data.orbitInclination.Value.ToString("F2"));
line.Append(','); line.Append(',');
   
//Orbital velocity //Orbital velocity
line.Append(VOID_Data.orbitVelocity.Value.ToString("G9")); line.Append(VOID_Data.orbitVelocity.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
//surface velocity //surface velocity
line.Append(VOID_Data.surfVelocity.Value.ToString("G9")); line.Append(VOID_Data.surfVelocity.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
//vertical speed //vertical speed
line.Append(VOID_Data.vertVelocity.Value.ToString("G9")); line.Append(VOID_Data.vertVelocity.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
//horizontal speed //horizontal speed
line.Append(VOID_Data.horzVelocity.Value.ToString("G9")); line.Append(VOID_Data.horzVelocity.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
// Current Thrust // Current Thrust
line.Append(VOID_Data.currThrust.Value.ToString("G9")); line.Append(VOID_Data.currThrust.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
//gee force //gee force
line.Append(VOID_Data.geeForce.Value.ToString("G9")); line.Append(VOID_Data.geeForce.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
//temperature //temperature
line.Append(VOID_Data.temperature.Value.ToString("F3")); line.Append(VOID_Data.temperature.Value.ToString("F3"));
line.Append(','); line.Append(',');
   
//gravity //gravity
line.Append(VOID_Data.gravityAccel.Value.ToString("G9")); line.Append(VOID_Data.gravityAccel.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
//atm density //atm density
line.Append(VOID_Data.atmDensity.Value.ToString("G9")); line.Append(VOID_Data.atmDensity.Value.ToString("G9"));
line.Append(','); line.Append(',');
   
// Downrange Distance // Downrange Distance
line.Append((VOID_Data.downrangeDistance.Value.ToString("G9"))); line.Append((VOID_Data.downrangeDistance.Value.ToString("G9")));
line.Append(','); line.Append(',');
   
// Main Throttle // Main Throttle
line.Append(VOID_Data.mainThrottle.Value.ToString("P2")); line.Append(VOID_Data.mainThrottle.Value.ToString("P2"));
   
line.Append('\n'); line.Append('\n');
   
csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString())); csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString()));
   
this.csvCollectTimer = 0f; this.csvCollectTimer = 0f;
} }
} }
   
#endregion #endregion
   
#region File IO Methods #region File IO Methods
   
protected void AsyncWriteCallback(IAsyncResult result) protected void AsyncWriteCallback(IAsyncResult result)
{ {
ToadicusTools.Logging.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted); Logging.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted);
   
this.outputFile.EndWrite(result); this.outputFile.EndWrite(result);
this.outstandingWrites--; this.outstandingWrites--;
} }
   
private void AsyncWriteData() private void AsyncWriteData()
{ {
WriteState state = new WriteState(); WriteState state = new WriteState();
   
state.bytes = this.csvBytes.ToArray(); state.bytes = this.csvBytes.ToArray();
state.stream = this.outputFile; state.stream = this.outputFile;
   
this.outstandingWrites++; this.outstandingWrites++;
var writeCallback = new AsyncCallback(this.AsyncWriteCallback); var writeCallback = new AsyncCallback(this.AsyncWriteCallback);
   
this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state); this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state);
   
this.csvBytes.Clear(); this.csvBytes.Clear();
} }
   
private void CloseFileIfOpen() private void CloseFileIfOpen()
{ {
using (PooledDebugLogger logger = PooledDebugLogger.New(this)) using (PooledDebugLogger logger = PooledDebugLogger.New(this))
{ {
logger.AppendFormat("Cleaning up file {0}...", this.fileName); logger.AppendFormat("Cleaning up file {0}...", this.fileName);
   
if (this.csvBytes != null && this.csvBytes.Count > 0) if (this.csvBytes != null && this.csvBytes.Count > 0)
{ {
logger.Append(" Writing remaining data..."); logger.Append(" Writing remaining data...");
this.AsyncWriteData(); this.AsyncWriteData();
} }
   
logger.Append(" Waiting for writes to finish."); logger.Append(" Waiting for writes to finish.");
while (this.outstandingWrites > 0) while (this.outstandingWrites > 0)
{ {
logger.Append('.'); logger.Append('.');
System.Threading.Thread.Sleep(10); System.Threading.Thread.Sleep(10);
} }
   
if (this._outputFile != null) if (this._outputFile != null)
{ {
this._outputFile.Close(); this._outputFile.Close();
this._outputFile = null; this._outputFile = null;
logger.Append(" File closed."); logger.Append(" File closed.");
} }
   
logger.Print(false); logger.Print(false);
} }
} }
   
#endregion #endregion
   
#region Constructors & Destructors #region Constructors & Destructors
   
public VOID_DataLogger() public VOID_DataLogger()
{ {
this.Name = "CSV Data Logger"; this.Name = "CSV Data Logger";
   
this.loggingActive = false; this.loggingActive = false;
this.firstWrite = true; this.firstWrite = true;
   
this.waitForLaunch = (VOID_SaveValue<bool>)true; this.waitForLaunch = (VOID_SaveValue<bool>)true;
   
this.logInterval = (VOID_SaveValue<float>)0.5f; this.logInterval = (VOID_SaveValue<float>)0.5f;
this.csvCollectTimer = (VOID_SaveValue<float>)0f; this.csvCollectTimer = (VOID_SaveValue<float>)0f;
   
this.outstandingWrites = 0; this.outstandingWrites = 0;
   
this.WindowPos.x = Screen.width - 520f; this.WindowPos.x = Screen.width - 520f;
this.WindowPos.y = 85f; this.WindowPos.y = 85f;
   
this.core.onApplicationQuit += delegate(object sender) this.core.onApplicationQuit += delegate(object sender)
{ {
this.CloseFileIfOpen(); this.CloseFileIfOpen();
}; };
} }
   
~VOID_DataLogger() ~VOID_DataLogger()
{ {
this.OnDestroy(); this.OnDestroy();
} }
   
#endregion #endregion
   
#region Subclasses #region Subclasses
   
private class WriteState private class WriteState
{ {
public byte[] bytes; public byte[] bytes;
public FileStream stream; public FileStream stream;
} }
   
#endregion #endregion
} }
} }
   
   
// VOID // VOID
// //
// VOID_EditorHUD.cs // VOID_EditorHUD.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
  using ToadicusTools;
using ToadicusTools.Text; using ToadicusTools.Text;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
[VOID_Scenes(GameScenes.EDITOR)] [VOID_Scenes(GameScenes.EDITOR)]
public class VOID_EditorHUD : VOID_HUDModule public class VOID_EditorHUD : VOID_HUDModule
{ {
/* /*
* Fields * Fields
* */ * */
protected HUDWindow ehudWindow; protected HUDWindow ehudWindow;
protected EditorVesselOverlays _vesselOverlays; protected EditorVesselOverlays _vesselOverlays;
   
[AVOID_SaveValue("snapToLeft")] [AVOID_SaveValue("snapToLeft")]
protected VOID_SaveValue<bool> snapToLeft; protected VOID_SaveValue<bool> snapToLeft;
   
/* /*
* Properties * Properties
* */ * */
protected EditorVesselOverlays vesselOverlays protected EditorVesselOverlays vesselOverlays
{ {
get get
{ {
if (this._vesselOverlays == null) if (this._vesselOverlays == null)
{ {
UnityEngine.Object[] overlayObjs = Resources.FindObjectsOfTypeAll(typeof(EditorVesselOverlays)); UnityEngine.Object[] overlayObjs = Resources.FindObjectsOfTypeAll(typeof(EditorVesselOverlays));
   
if (overlayObjs.Length > 0) if (overlayObjs.Length > 0)
{ {
this._vesselOverlays = (EditorVesselOverlays)overlayObjs[0]; this._vesselOverlays = (EditorVesselOverlays)overlayObjs[0];
} }
} }
   
return this._vesselOverlays; return this._vesselOverlays;
} }
} }
   
protected EditorMarker_CoM CoMmarker protected EditorMarker_CoM CoMmarker
{ {
get get
{ {
if (this.vesselOverlays == null) if (this.vesselOverlays == null)
{ {
return null; return null;
} }
   
return this.vesselOverlays.CoMmarker; return this.vesselOverlays.CoMmarker;
} }
} }
   
protected EditorMarker_CoT CoTmarker protected EditorMarker_CoT CoTmarker
{ {
get get
{ {
if (this.vesselOverlays == null) if (this.vesselOverlays == null)
{ {
return null; return null;
} }
   
return this.vesselOverlays.CoTmarker; return this.vesselOverlays.CoTmarker;
} }
} }
   
/* /*
* Methods * Methods
* */ * */
public VOID_EditorHUD() : base() public VOID_EditorHUD() : base()
{ {
this.Name = "Heads-Up Display"; this.Name = "Heads-Up Display";
   
this.Active = true; this.Active = true;
   
this.snapToLeft.value = true; this.snapToLeft.value = true;
   
this.ehudWindow = new HUDWindow( this.ehudWindow = new HUDWindow(
"editorHUD", "editorHUD",
this.ehudWindowFunc, this.ehudWindowFunc,
new Rect(EditorPanels.Instance.partsPanelWidth + 10f, 125f, 300f, 64f) new Rect(EditorPanels.Instance.partsPanelWidth + 10f, 125f, 300f, 64f)
); );
this.Windows.Add(this.ehudWindow); this.Windows.Add(this.ehudWindow);
   
ToadicusTools.Logging.PostDebugMessage (this.GetType().Name + ": Constructed."); Logging.PostDebugMessage (this.GetType().Name + ": Constructed.");
} }
   
public void ehudWindowFunc(int id) public void ehudWindowFunc(int id)
{ {
using (PooledStringBuilder hudString = PooledStringBuilder.Get()) using (PooledStringBuilder hudString = PooledStringBuilder.Get())
{ {
if (this.core.LastStage == null) if (this.core.LastStage == null)
{ {
return; return;
} }
   
VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft;
   
hudString.Append("Total Mass: "); hudString.Append("Total Mass: ");
hudString.Append(this.core.LastStage.totalMass.ToString("F3")); hudString.Append(this.core.LastStage.totalMass.ToString("F3"));
hudString.Append('t'); hudString.Append('t');
   
hudString.Append(' '); hudString.Append(' ');
   
hudString.Append("Part Count: "); hudString.Append("Part Count: ");
hudString.Append(EditorLogic.SortedShipList.Count); hudString.Append(EditorLogic.SortedShipList.Count);
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Total Delta-V: "); hudString.Append("Total Delta-V: ");
hudString.Append(SIFormatProvider.ToSI(this.core.LastStage.totalDeltaV)); hudString.Append(SIFormatProvider.ToSI(this.core.LastStage.totalDeltaV));
hudString.Append("m/s"); hudString.Append("m/s");
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Bottom Stage Delta-V"); hudString.Append("Bottom Stage Delta-V");
hudString.Append(SIFormatProvider.ToSI(this.core.LastStage.deltaV)); hudString.Append(SIFormatProvider.ToSI(this.core.LastStage.deltaV));
hudString.Append("m/s"); hudString.Append("m/s");
   
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Bottom Stage T/W Ratio: "); hudString.Append("Bottom Stage T/W Ratio: ");
hudString.Append(this.core.LastStage.thrustToWeight.ToString("F3")); hudString.Append(this.core.LastStage.thrustToWeight.ToString("F3"));
   
ToadicusTools.Logging.PostDebugMessage(this, Logging.PostDebugMessage(this,
"CoMmarker.gameObject.activeInHierarchy: {0};" + "CoMmarker.gameObject.activeInHierarchy: {0};" +
"CoTmarker.gameObject.activeInHierarchy: {1}", "CoTmarker.gameObject.activeInHierarchy: {1}",
this.CoMmarker.gameObject.activeInHierarchy, this.CoMmarker.gameObject.activeInHierarchy,
this.CoTmarker.gameObject.activeInHierarchy this.CoTmarker.gameObject.activeInHierarchy
); );
   
if (this.CoMmarker.gameObject.activeInHierarchy && this.CoTmarker.gameObject.activeInHierarchy) if (this.CoMmarker.gameObject.activeInHierarchy && this.CoTmarker.gameObject.activeInHierarchy)
{ {
ToadicusTools.Logging.PostDebugMessage(this, "CoM and CoT markers are active, doing thrust offset."); Logging.PostDebugMessage(this, "CoM and CoT markers are active, doing thrust offset.");
hudString.Append('\n'); hudString.Append('\n');
   
hudString.Append("Thrust Offset: "); hudString.Append("Thrust Offset: ");
hudString.Append( hudString.Append(
Vector3.Cross( Vector3.Cross(
this.CoTmarker.dirMarkerObject.transform.forward, this.CoTmarker.dirMarkerObject.transform.forward,
this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position this.CoMmarker.posMarkerObject.transform.position - this.CoTmarker.posMarkerObject.transform.position
).ToString("F3")); ).ToString("F3"));
} }
#if DEBUG #if DEBUG
else else
{ {
ToadicusTools.Logging.PostDebugMessage(this, "CoM and CoT markers are not active, thrust offset skipped."); Logging.PostDebugMessage(this, "CoM and CoT markers are not active, thrust offset skipped.");
} }
#endif #endif
   
GUILayout.Label( GUILayout.Label(
hudString.ToString(), hudString.ToString(),
VOID_Styles.labelHud, VOID_Styles.labelHud,
GUILayout.ExpandWidth(true), GUILayout.ExpandWidth(true),
GUILayout.ExpandHeight(true) GUILayout.ExpandHeight(true)
); );
   
if (!this.positionsLocked) if (!this.positionsLocked)
{ {
GUI.DragWindow(); GUI.DragWindow();
} }
   
GUI.BringWindowToBack(id); GUI.BringWindowToBack(id);
} }
} }
   
public override void DrawGUI() public override void DrawGUI()
{ {
float hudLeft; float hudLeft;
   
if (EditorLogic.fetch.editorScreen == EditorScreen.Parts) if (EditorLogic.fetch.editorScreen == EditorScreen.Parts)
{ {
hudLeft = EditorPanels.Instance.partsPanelWidth + 10f; hudLeft = EditorPanels.Instance.partsPanelWidth + 10f;
hudLeft += EditorPartList.Instance.transformTopLeft.position.x - hudLeft += EditorPartList.Instance.transformTopLeft.position.x -
EditorPartList.Instance.transformTopLeft.parent.parent.position.x - EditorPartList.Instance.transformTopLeft.parent.parent.position.x -
72f; 72f;
} }
else if (EditorLogic.fetch.editorScreen == EditorScreen.Actions) else if (EditorLogic.fetch.editorScreen == EditorScreen.Actions)
{ {
hudLeft = EditorPanels.Instance.actionsPanelWidth + 10f; hudLeft = EditorPanels.Instance.actionsPanelWidth + 10f;
} }
else else
{ {
return; return;
} }
   
ToadicusTools.Logging.PostDebugMessage(this, Logging.PostDebugMessage(this,
"EditorPartList topLeft.parent.parent.position: {0}\n" + "EditorPartList topLeft.parent.parent.position: {0}\n" +
"EditorPartList topLeft.parent.position: {1}\n" + "EditorPartList topLeft.parent.position: {1}\n" +
"EditorPartList topLeft.position: {2}\n" + "EditorPartList topLeft.position: {2}\n" +
"snapToEdge: {3} (pos.Xmin: {4}; hudLeft: {5})", "snapToEdge: {3} (pos.Xmin: {4}; hudLeft: {5})",
EditorPartList.Instance.transformTopLeft.parent.parent.position, EditorPartList.Instance.transformTopLeft.parent.parent.position,
EditorPartList.Instance.transformTopLeft.parent.position, EditorPartList.Instance.transformTopLeft.parent.position,
EditorPartList.Instance.transformTopLeft.position, EditorPartList.Instance.transformTopLeft.position,
this.snapToLeft, this.ehudWindow.WindowPos.xMin, hudLeft this.snapToLeft, this.ehudWindow.WindowPos.xMin, hudLeft
); );
   
base.DrawGUI(); base.DrawGUI();
   
Rect hudPos = this.ehudWindow.WindowPos; Rect hudPos = this.ehudWindow.WindowPos;
   
if (this.snapToLeft && this.positionsLocked) if (this.snapToLeft && this.positionsLocked)
{ {
hudPos.xMin = hudLeft; hudPos.xMin = hudLeft;
} }
else else
{ {
hudPos.xMin = Mathf.Max(hudLeft, hudPos.xMin); hudPos.xMin = Mathf.Max(hudLeft, hudPos.xMin);
} }
   
hudPos.width = this.ehudWindow.defaultWindowPos.width; hudPos.width = this.ehudWindow.defaultWindowPos.width;
   
this.ehudWindow.WindowPos = hudPos; this.ehudWindow.WindowPos = hudPos;
   
this.snapToLeft.value = Mathf.Abs(this.ehudWindow.WindowPos.xMin - hudLeft) < 15f; this.snapToLeft.value = Mathf.Abs(this.ehudWindow.WindowPos.xMin - hudLeft) < 15f;
} }
} }
} }
   
// VOID // VOID
// //
// VOID_HUD.cs // VOID_HUD.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
  using ToadicusTools;
using ToadicusTools.Text; using ToadicusTools.Text;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_HUD : VOID_HUDModule, IVOID_Module public class VOID_HUD : VOID_HUDModule, IVOID_Module
{ {
/* /*
* Fields * Fields
* */ * */
protected HUDWindow leftHUD; protected HUDWindow leftHUD;
protected HUDWindow rightHUD; protected HUDWindow rightHUD;
   
/* /*
* Properties * Properties
* */ * */
   
/* /*
* Methods * Methods
* */ * */
public VOID_HUD() : base() public VOID_HUD() : base()
{ {
this.Name = "Heads-Up Display"; this.Name = "Heads-Up Display";
   
this.Active = true; this.Active = true;
   
this.leftHUD = new HUDWindow("leftHUD", this.leftHUDWindow, new Rect(Screen.width * .375f - 300f, 0f, 300f, 90f)); this.leftHUD = new HUDWindow("leftHUD", this.leftHUDWindow, new Rect(Screen.width * .375f - 300f, 0f, 300f, 90f));
this.Windows.Add(this.leftHUD); this.Windows.Add(this.leftHUD);
   
this.rightHUD = new HUDWindow("rightHUD", this.rightHUDWindow, new Rect(Screen.width * .625f, 0f, 300f, 90f)); this.rightHUD = new HUDWindow("rightHUD", this.rightHUDWindow, new Rect(Screen.width * .625f, 0f, 300f, 90f));
this.Windows.Add(this.rightHUD); this.Windows.Add(this.rightHUD);
   
ToadicusTools.Logging.PostDebugMessage ("VOID_HUD: Constructed."); Logging.PostDebugMessage ("VOID_HUD: Constructed.");
} }
   
protected void leftHUDWindow(int id) protected void leftHUDWindow(int id)
{ {
using (PooledStringBuilder leftHUD = PooledStringBuilder.Get()) using (PooledStringBuilder leftHUD = PooledStringBuilder.Get())
{ {
VOID_Styles.labelHud.alignment = TextAnchor.UpperRight; VOID_Styles.labelHud.alignment = TextAnchor.UpperRight;
   
if (this.core.powerAvailable) if (this.core.powerAvailable)
{ {
leftHUD.AppendFormat("Primary: {0} Inc: {1}", leftHUD.AppendFormat("Primary: {0} Inc: {1}",
VOID_Data.primaryName.ValueUnitString(), VOID_Data.primaryName.ValueUnitString(),
VOID_Data.orbitInclination.ValueUnitString("F3") VOID_Data.orbitInclination.ValueUnitString("F3")
); );
leftHUD.AppendFormat("\nObt Alt: {0} Obt Vel: {1}", leftHUD.AppendFormat("\nObt Alt: {0} Obt Vel: {1}",
VOID_Data.orbitAltitude.ToSIString(), VOID_Data.orbitAltitude.ToSIString(),
VOID_Data.orbitVelocity.ToSIString() VOID_Data.orbitVelocity.ToSIString()
); );
leftHUD.AppendFormat("\nAp: {0} ETA {1}", leftHUD.AppendFormat("\nAp: {0} ETA {1}",
VOID_Data.orbitApoAlt.ToSIString(), VOID_Data.orbitApoAlt.ToSIString(),
VOID_Data.timeToApo.ValueUnitString() VOID_Data.timeToApo.ValueUnitString()
); );
leftHUD.AppendFormat("\nPe: {0} ETA {1}", leftHUD.AppendFormat("\nPe: {0} ETA {1}",
VOID_Data.oribtPeriAlt.ToSIString(), VOID_Data.oribtPeriAlt.ToSIString(),
VOID_Data.timeToPeri.ValueUnitString() VOID_Data.timeToPeri.ValueUnitString()
); );
leftHUD.AppendFormat("\nTot Δv: {0} Stg Δv: {1}", leftHUD.AppendFormat("\nTot Δv: {0} Stg Δv: {1}",
VOID_Data.totalDeltaV.ToSIString(2), VOID_Data.totalDeltaV.ToSIString(2),
VOID_Data.stageDeltaV.ToSIString(2) VOID_Data.stageDeltaV.ToSIString(2)
); );
} }
else else
{ {
VOID_Styles.labelHud.normal.textColor = Color.red; VOID_Styles.labelHud.normal.textColor = Color.red;
leftHUD.Append(string.Intern("-- POWER LOST --")); leftHUD.Append(string.Intern("-- POWER LOST --"));
} }
   
GUILayout.Label( GUILayout.Label(
leftHUD.ToString(), leftHUD.ToString(),
VOID_Styles.labelHud, VOID_Styles.labelHud,
GUILayout.ExpandWidth(true), GUILayout.ExpandWidth(true),
GUILayout.ExpandHeight(true) GUILayout.ExpandHeight(true)
); );
   
if (!this.positionsLocked) if (!this.positionsLocked)
{ {
GUI.DragWindow(); GUI.DragWindow();
} }
   
GUI.BringWindowToBack(id); GUI.BringWindowToBack(id);
} }
} }
   
protected void rightHUDWindow(int id) protected void rightHUDWindow(int id)
{ {
using (PooledStringBuilder rightHUD = PooledStringBuilder.Get()) using (PooledStringBuilder rightHUD = PooledStringBuilder.Get())
{ {
VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft;
   
if (this.core.powerAvailable) if (this.core.powerAvailable)
{ {
rightHUD.AppendFormat("Biome: {0} Sit: {1}", rightHUD.AppendFormat("Biome: {0} Sit: {1}",
VOID_Data.currBiome.ValueUnitString(), VOID_Data.currBiome.ValueUnitString(),
VOID_Data.expSituation.ValueUnitString() VOID_Data.expSituation.ValueUnitString()
); );
rightHUD.AppendFormat("\nSrf Alt: {0} Srf Vel: {1}", rightHUD.AppendFormat("\nSrf Alt: {0} Srf Vel: {1}",
VOID_Data.trueAltitude.ToSIString(), VOID_Data.trueAltitude.ToSIString(),
VOID_Data.surfVelocity.ToSIString() VOID_Data.surfVelocity.ToSIString()
); );
rightHUD.AppendFormat("\nVer: {0} Hor: {1}", rightHUD.AppendFormat("\nVer: {0} Hor: {1}",
VOID_Data.vertVelocity.ToSIString(), VOID_Data.vertVelocity.ToSIString(),
VOID_Data.horzVelocity.ToSIString() VOID_Data.horzVelocity.ToSIString()
); );
rightHUD.AppendFormat("\nLat: {0} Lon: {1}", rightHUD.AppendFormat("\nLat: {0} Lon: {1}",
VOID_Data.surfLatitudeString.ValueUnitString(), VOID_Data.surfLatitudeString.ValueUnitString(),
VOID_Data.surfLongitudeString.ValueUnitString() VOID_Data.surfLongitudeString.ValueUnitString()
); );
rightHUD.AppendFormat("\nHdg: {0} Pit: {1}", rightHUD.AppendFormat("\nHdg: {0} Pit: {1}",
VOID_Data.vesselHeading.ValueUnitString(), VOID_Data.vesselHeading.ValueUnitString(),
VOID_Data.vesselPitch.ToSIString(2) VOID_Data.vesselPitch.ToSIString(2)
); );
   
if ( if (
this.core.Vessel.mainBody == this.core.HomeBody && this.core.Vessel.mainBody == this.core.HomeBody &&
( (
this.core.Vessel.situation == Vessel.Situations.FLYING || this.core.Vessel.situation == Vessel.Situations.FLYING ||
this.core.Vessel.situation == Vessel.Situations.SUB_ORBITAL || this.core.Vessel.situation == Vessel.Situations.SUB_ORBITAL ||
this.core.Vessel.situation == Vessel.Situations.LANDED || this.core.Vessel.situation == Vessel.Situations.LANDED ||
this.core.Vessel.situation == Vessel.Situations.SPLASHED this.core.Vessel.situation == Vessel.Situations.SPLASHED
)) ))
{ {
rightHUD.AppendFormat("\nRange to KSC: {0}", VOID_Data.downrangeDistance.ValueUnitString(2)); rightHUD.AppendFormat("\nRange to KSC: {0}", VOID_Data.downrangeDistance.ValueUnitString(2));
} }
} }
else else
{ {
VOID_Styles.labelHud.normal.textColor = Color.red; VOID_Styles.labelHud.normal.textColor = Color.red;
rightHUD.Append(string.Intern("-- POWER LOST --")); rightHUD.Append(string.Intern("-- POWER LOST --"));
} }
   
   
GUILayout.Label( GUILayout.Label(
rightHUD.ToString(), rightHUD.ToString(),
VOID_Styles.labelHud, VOID_Styles.labelHud,
GUILayout.ExpandWidth(true), GUILayout.ExpandWidth(true),
GUILayout.ExpandHeight(true) GUILayout.ExpandHeight(true)
); );
   
if (!this.positionsLocked) if (!this.positionsLocked)
{ {
GUI.DragWindow(); GUI.DragWindow();
} }
   
GUI.BringWindowToBack(id); GUI.BringWindowToBack(id);
} }
} }
} }
} }
   
// VOID // VOID
// //
// VOID_HUD.cs // VOID_HUD.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KerbalEngineer.VesselSimulator; using KerbalEngineer.VesselSimulator;
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
  using ToadicusTools;
using ToadicusTools.GUIUtils; using ToadicusTools.GUIUtils;
using ToadicusTools.Text; using ToadicusTools.Text;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_HUDAdvanced : VOID_HUDModule, IVOID_Module public class VOID_HUDAdvanced : VOID_HUDModule, IVOID_Module
{ {
/* /*
* Fields * Fields
* */ * */
protected VOID_HUD primaryHUD; protected VOID_HUD primaryHUD;
   
protected HUDWindow leftHUD; protected HUDWindow leftHUD;
protected HUDWindow rightHUD; protected HUDWindow rightHUD;
   
/* /*
* Properties * Properties
* */ * */
public override int ColorIndex public override int ColorIndex
{ {
get get
{ {
if (this.primaryHUD != null) if (this.primaryHUD != null)
{ {
return this.primaryHUD.ColorIndex; return this.primaryHUD.ColorIndex;
} }
   
return base.ColorIndex; return base.ColorIndex;
} }
set set
{ {
base.ColorIndex = value; base.ColorIndex = value;
} }
} }
   
/* /*
* Methods * Methods
* */ * */
public VOID_HUDAdvanced() : base() public VOID_HUDAdvanced() : base()
{ {
this.Name = "Advanced Heads-Up Display"; this.Name = "Advanced Heads-Up Display";
   
this.Active = true; this.Active = true;
   
this.leftHUD = new HUDWindow("leftHUD", this.leftHUD = new HUDWindow("leftHUD",
this.leftHUDWindow, this.leftHUDWindow,
new Rect( new Rect(
Screen.width * .5f - (float)GameSettings.UI_SIZE * .25f - 300f, Screen.width * .5f - (float)GameSettings.UI_SIZE * .25f - 300f,
Screen.height - 200f, Screen.height - 200f,
300f, 90f) 300f, 90f)
); );
this.Windows.Add(this.leftHUD); this.Windows.Add(this.leftHUD);
   
this.rightHUD = new HUDWindow( this.rightHUD = new HUDWindow(
"rightHUD", "rightHUD",
this.rightHUDWindow, this.rightHUDWindow,
new Rect( new Rect(
Screen.width * .5f + (float)GameSettings.UI_SIZE * .25f, Screen.width * .5f + (float)GameSettings.UI_SIZE * .25f,
Screen.height - 200f, Screen.height - 200f,
300f, 90f) 300f, 90f)
); );
this.Windows.Add(this.rightHUD); this.Windows.Add(this.rightHUD);
   
this.positionsLocked.value = true; this.positionsLocked.value = true;
   
ToadicusTools.Logging.PostDebugMessage (this, "Constructed."); Logging.PostDebugMessage (this, "Constructed.");
} }
   
protected void leftHUDWindow(int id) protected void leftHUDWindow(int id)
{ {
using (PooledStringBuilder leftHUD = PooledStringBuilder.Get()) using (PooledStringBuilder leftHUD = PooledStringBuilder.Get())
{ {
VOID_Styles.labelHud.alignment = TextAnchor.UpperRight; VOID_Styles.labelHud.alignment = TextAnchor.UpperRight;
   
if (this.core.powerAvailable) if (this.core.powerAvailable)
{ {
leftHUD.AppendFormat( leftHUD.AppendFormat(
string.Intern("Mass: {0}\n"), string.Intern("Mass: {0}\n"),
VOID_Data.totalMass.ToSIString(2) VOID_Data.totalMass.ToSIString(2)
); );
   
if (VOID_Data.vesselCrewCapacity > 0) if (VOID_Data.vesselCrewCapacity > 0)
{ {
leftHUD.AppendFormat( leftHUD.AppendFormat(
string.Intern("Crew: {0} / {1}\n"), string.Intern("Crew: {0} / {1}\n"),
VOID_Data.vesselCrewCount.Value, VOID_Data.vesselCrewCount.Value,
VOID_Data.vesselCrewCapacity.Value VOID_Data.vesselCrewCapacity.Value
); );
} }
   
leftHUD.AppendFormat( leftHUD.AppendFormat(
string.Intern("Acc: {0} T:W: {1}\n"), string.Intern("Acc: {0} T:W: {1}\n"),
VOID_Data.vesselAccel.ToSIString(2), VOID_Data.vesselAccel.ToSIString(2),
VOID_Data.currThrustWeight.Value.ToString("f2") VOID_Data.currThrustWeight.Value.ToString("f2")
); );
   
leftHUD.AppendFormat( leftHUD.AppendFormat(
string.Intern("Ang Vel: {0}\n"), string.Intern("Ang Vel: {0}\n"),
VOID_Data.vesselAngularVelocity.ToSIString(2) VOID_Data.vesselAngularVelocity.ToSIString(2)
); );
   
if (VOID_Data.stageNominalThrust != 0d) if (VOID_Data.stageNominalThrust != 0d)
{ {
leftHUD.AppendFormat( leftHUD.AppendFormat(
string.Intern("Thrust Offset: {0}\n"), string.Intern("Thrust Offset: {0}\n"),
VOID_Data.vesselThrustOffset.Value.ToString("F1") VOID_Data.vesselThrustOffset.Value.ToString("F1")
); );
} }
} }
else else
{ {
VOID_Styles.labelHud.normal.textColor = Color.red; VOID_Styles.labelHud.normal.textColor = Color.red;
leftHUD.Append(string.Intern("-- POWER LOST --")); leftHUD.Append(string.Intern("-- POWER LOST --"));
} }
   
GUILayout.Label( GUILayout.Label(
leftHUD.ToString(), leftHUD.ToString(),
VOID_Styles.labelHud, VOID_Styles.labelHud,
GUILayout.ExpandWidth(true), GUILayout.ExpandWidth(true),
GUILayout.ExpandHeight(true) GUILayout.ExpandHeight(true)
); );
   
if (!this.positionsLocked) if (!this.positionsLocked)
{ {
GUI.DragWindow(); GUI.DragWindow();
} }
   
GUI.BringWindowToBack(id); GUI.BringWindowToBack(id);
} }
} }
   
protected void rightHUDWindow(int id) protected void rightHUDWindow(int id)
{ {
using (PooledStringBuilder rightHUD = PooledStringBuilder.Get()) using (PooledStringBuilder rightHUD = PooledStringBuilder.Get())
{ {
VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft; VOID_Styles.labelHud.alignment = TextAnchor.UpperLeft;
   
if (this.core.powerAvailable) if (this.core.powerAvailable)
{ {
rightHUD.AppendFormat( rightHUD.AppendFormat(
"Burn Δv (Rem/Tot): {0} / {1}\n", "Burn Δv (Rem/Tot): {0} / {1}\n",
VOID_Data.currManeuverDVRemaining.ValueUnitString("f2"), VOID_Data.currManeuverDVRemaining.ValueUnitString("f2"),
VOID_Data.currManeuverDeltaV.ValueUnitString("f2") VOID_Data.currManeuverDeltaV.ValueUnitString("f2")
); );
   
if (VOID_Data.upcomingManeuverNodes > 1) if (VOID_Data.upcomingManeuverNodes > 1)
{ {
rightHUD.AppendFormat("Next Burn Δv: {0}\n", rightHUD.AppendFormat("Next Burn Δv: {0}\n",
VOID_Data.nextManeuverDeltaV.ValueUnitString("f2") VOID_Data.nextManeuverDeltaV.ValueUnitString("f2")
); );
} }
   
rightHUD.AppendFormat("Burn Time (Rem/Total): {0} / {1}\n", rightHUD.AppendFormat("Burn Time (Rem/Total): {0} / {1}\n",
VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnRemaining.Value), VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnRemaining.Value),
VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnDuration.Value) VOID_Tools.FormatInterval(VOID_Data.currentNodeBurnDuration.Value)
); );
   
if (VOID_Data.burnTimeDoneAtNode.Value != string.Empty) if (VOID_Data.burnTimeDoneAtNode.Value != string.Empty)
{ {
rightHUD.AppendFormat("{0} (done @ node)\n", rightHUD.AppendFormat("{0} (done @ node)\n",
VOID_Data.burnTimeDoneAtNode.Value VOID_Data.burnTimeDoneAtNode.Value
); );
   
rightHUD.AppendFormat("{0} (½ done @ node)", rightHUD.AppendFormat("{0} (½ done @ node)",
VOID_Data.burnTimeHalfDoneAtNode.Value VOID_Data.burnTimeHalfDoneAtNode.Value
); );
} }
else else
{ {
rightHUD.Append("Node is past"); rightHUD.Append("Node is past");
} }
} }
else else
{ {
VOID_Styles.labelHud.normal.textColor = Color.red; VOID_Styles.labelHud.normal.textColor = Color.red;
rightHUD.Append(string.Intern("-- POWER LOST --")); rightHUD.Append(string.Intern("-- POWER LOST --"));
} }
   
GUILayout.Label( GUILayout.Label(
rightHUD.ToString(), rightHUD.ToString(),
VOID_Styles.labelHud, VOID_Styles.labelHud,
GUILayout.ExpandWidth(true), GUILayout.ExpandWidth(true),
GUILayout.ExpandHeight(true) GUILayout.ExpandHeight(true)
); );
   
if (!this.positionsLocked) if (!this.positionsLocked)
{ {
GUI.DragWindow(); GUI.DragWindow();
} }
   
GUI.BringWindowToBack(id); GUI.BringWindowToBack(id);
} }
} }
   
public override void DrawGUI() public override void DrawGUI()
{ {
if (this.primaryHUD == null) if (this.primaryHUD == null)
{ {
IVOID_Module module; IVOID_Module module;
for (int idx = 0; idx < this.core.Modules.Count; idx++) for (int idx = 0; idx < this.core.Modules.Count; idx++)
{ {
module = this.core.Modules[idx]; module = this.core.Modules[idx];
   
if (module is VOID_HUD) if (module is VOID_HUD)
{ {
this.primaryHUD = module as VOID_HUD; this.primaryHUD = module as VOID_HUD;
} }
} }
} }
   
if (VOID_Data.upcomingManeuverNodes < 1 && this.Windows.Contains(this.rightHUD)) if (VOID_Data.upcomingManeuverNodes < 1 && this.Windows.Contains(this.rightHUD))
{ {
this.Windows.Remove(this.rightHUD); this.Windows.Remove(this.rightHUD);
} }
else if (VOID_Data.upcomingManeuverNodes > 0 && !this.Windows.Contains(this.rightHUD)) else if (VOID_Data.upcomingManeuverNodes > 0 && !this.Windows.Contains(this.rightHUD))
{ {
this.Windows.Add(this.rightHUD); this.Windows.Add(this.rightHUD);
} }
   
base.DrawGUI(); base.DrawGUI();
} }
   
public override void DrawConfigurables() public override void DrawConfigurables()
{ {
base.DrawConfigurables(); base.DrawConfigurables();
   
if (GUILayout.Button(string.Intern("Reset Advanced HUD Positions"), GUILayout.ExpandWidth(false))) if (GUILayout.Button(string.Intern("Reset Advanced HUD Positions"), GUILayout.ExpandWidth(false)))
{ {
HUDWindow window; HUDWindow window;
for (int idx = 0; idx < this.Windows.Count; idx++) for (int idx = 0; idx < this.Windows.Count; idx++)
{ {
window = this.Windows[idx]; window = this.Windows[idx];
   
window.WindowPos = new Rect(window.defaultWindowPos); window.WindowPos = new Rect(window.defaultWindowPos);
} }
} }
   
this.positionsLocked.value = Layout.Toggle(this.positionsLocked, string.Intern("Lock Advanced HUD Positions")); this.positionsLocked.value = Layout.Toggle(this.positionsLocked, string.Intern("Lock Advanced HUD Positions"));
} }
} }
} }
   
// VOID // VOID
// //
// VOID_Orbital.cs // VOID_Orbital.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KSP; using KSP;
using System; using System;
  using ToadicusTools;
using ToadicusTools.GUIUtils; using ToadicusTools.GUIUtils;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_Orbital : VOID_WindowModule public class VOID_Orbital : VOID_WindowModule
{ {
[AVOID_SaveValue("toggleExtended")] [AVOID_SaveValue("toggleExtended")]
protected VOID_SaveValue<bool> toggleExtended; protected VOID_SaveValue<bool> toggleExtended;
   
[AVOID_SaveValue("precisionValues")] [AVOID_SaveValue("precisionValues")]
protected VOID_SaveValue<long> _precisionValues; protected VOID_SaveValue<long> _precisionValues;
protected ToadicusTools.IntCollection precisionValues; protected IntCollection precisionValues;
   
public VOID_Orbital() public VOID_Orbital()
{ {
this.Name = "Orbital Information"; this.Name = "Orbital Information";
   
this.WindowPos.x = Screen.width - 520f; this.WindowPos.x = Screen.width - 520f;
this.WindowPos.y = 250f; this.WindowPos.y = 250f;
   
this.toggleExtended = (VOID_SaveValue<bool>)false; this.toggleExtended = (VOID_SaveValue<bool>)false;
   
this._precisionValues = (VOID_SaveValue<long>)384307168202282325; this._precisionValues = (VOID_SaveValue<long>)384307168202282325;
} }
   
public override void ModuleWindow(int id) public override void ModuleWindow(int id)
{ {
int idx = 0; int idx = 0;
   
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
VOID_Data.primaryName.DoGUIHorizontal (); VOID_Data.primaryName.DoGUIHorizontal ();
   
this.precisionValues [idx]= (ushort)VOID_Data.orbitAltitude.DoGUIHorizontal (this.precisionValues [idx]); this.precisionValues [idx]= (ushort)VOID_Data.orbitAltitude.DoGUIHorizontal (this.precisionValues [idx]);
idx++; idx++;
   
this.precisionValues [idx]= (ushort)VOID_Data.orbitVelocity.DoGUIHorizontal (this.precisionValues [idx]); this.precisionValues [idx]= (ushort)VOID_Data.orbitVelocity.DoGUIHorizontal (this.precisionValues [idx]);
idx++; idx++;
   
this.precisionValues [idx]= (ushort)VOID_Data.orbitApoAlt.DoGUIHorizontal (this.precisionValues [idx]); this.precisionValues [idx]= (ushort)VOID_Data.orbitApoAlt.DoGUIHorizontal (this.precisionValues [idx]);
idx++; idx++;
   
VOID_Data.timeToApo.DoGUIHorizontal(); VOID_Data.timeToApo.DoGUIHorizontal();
   
this.precisionValues [idx]= (ushort)VOID_Data.oribtPeriAlt.DoGUIHorizontal (this.precisionValues [idx]); this.precisionValues [idx]= (ushort)VOID_Data.oribtPeriAlt.DoGUIHorizontal (this.precisionValues [idx]);
idx++; idx++;
   
VOID_Data.timeToPeri.DoGUIHorizontal(); VOID_Data.timeToPeri.DoGUIHorizontal();
   
VOID_Data.orbitInclination.DoGUIHorizontal("F3"); VOID_Data.orbitInclination.DoGUIHorizontal("F3");
   
this.precisionValues [idx]= (ushort)VOID_Data.gravityAccel.DoGUIHorizontal (this.precisionValues [idx]); this.precisionValues [idx]= (ushort)VOID_Data.gravityAccel.DoGUIHorizontal (this.precisionValues [idx]);
idx++; idx++;
   
this.toggleExtended.value = Layout.Toggle(this.toggleExtended, "Extended info"); this.toggleExtended.value = Layout.Toggle(this.toggleExtended, "Extended info");
   
if (this.toggleExtended) if (this.toggleExtended)
{ {
VOID_Data.orbitPeriod.DoGUIHorizontal(); VOID_Data.orbitPeriod.DoGUIHorizontal();
   
this.precisionValues [idx]= (ushort)VOID_Data.semiMajorAxis.DoGUIHorizontal (this.precisionValues [idx]); this.precisionValues [idx]= (ushort)VOID_Data.semiMajorAxis.DoGUIHorizontal (this.precisionValues [idx]);
idx++; idx++;
   
VOID_Data.eccentricity.DoGUIHorizontal("F4"); VOID_Data.eccentricity.DoGUIHorizontal("F4");
   
VOID_Data.meanAnomaly.DoGUIHorizontal("F3"); VOID_Data.meanAnomaly.DoGUIHorizontal("F3");
   
VOID_Data.trueAnomaly.DoGUIHorizontal("F3"); VOID_Data.trueAnomaly.DoGUIHorizontal("F3");
   
VOID_Data.eccAnomaly.DoGUIHorizontal("F3"); VOID_Data.eccAnomaly.DoGUIHorizontal("F3");
   
VOID_Data.longitudeAscNode.DoGUIHorizontal("F3"); VOID_Data.longitudeAscNode.DoGUIHorizontal("F3");
   
VOID_Data.timeToAscendingNode.DoGUIHorizontal(); VOID_Data.timeToAscendingNode.DoGUIHorizontal();
   
VOID_Data.timeToDescendingNode.DoGUIHorizontal(); VOID_Data.timeToDescendingNode.DoGUIHorizontal();
   
VOID_Data.argumentPeriapsis.DoGUIHorizontal("F3"); VOID_Data.argumentPeriapsis.DoGUIHorizontal("F3");
   
VOID_Data.localSiderealLongitude.DoGUIHorizontal("F3"); VOID_Data.localSiderealLongitude.DoGUIHorizontal("F3");
} }
   
GUILayout.EndVertical(); GUILayout.EndVertical();
base.ModuleWindow(id); base.ModuleWindow(id);
} }
   
public override void LoadConfig(KSP.IO.PluginConfiguration config) public override void LoadConfig(KSP.IO.PluginConfiguration config)
{ {
base.LoadConfig(config); base.LoadConfig(config);
   
this.precisionValues = new ToadicusTools.IntCollection (4, this._precisionValues); this.precisionValues = new IntCollection (4, this._precisionValues);
} }
   
public override void Save (KSP.IO.PluginConfiguration config, string sceneKey) public override void Save (KSP.IO.PluginConfiguration config, string sceneKey)
{ {
this._precisionValues.value = this.precisionValues.collection; this._precisionValues.value = this.precisionValues.collection;
   
base.Save (config, sceneKey); base.Save (config, sceneKey);
} }
} }
} }
   
   
// VOID // VOID
// //
// VOID_Rendezvous.cs // VOID_Rendezvous.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
  using ToadicusTools;
using ToadicusTools.GUIUtils; using ToadicusTools.GUIUtils;
using ToadicusTools.Text; using ToadicusTools.Text;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_Rendezvous : VOID_WindowModule public class VOID_Rendezvous : VOID_WindowModule
{ {
[AVOID_SaveValue("untoggleRegisterInfo")] [AVOID_SaveValue("untoggleRegisterInfo")]
protected VOID_SaveValue<bool> untoggleRegisterInfo; protected VOID_SaveValue<bool> untoggleRegisterInfo;
   
[AVOID_SaveValue("toggleExtendedOrbital")] [AVOID_SaveValue("toggleExtendedOrbital")]
protected VOID_SaveValue<bool> toggleExtendedOrbital; protected VOID_SaveValue<bool> toggleExtendedOrbital;
   
protected VOID_VesselRegister RegisterModule; protected VOID_VesselRegister RegisterModule;
   
public VOID_Rendezvous() public VOID_Rendezvous()
{ {
this.Name = "Rendezvous Information"; this.Name = "Rendezvous Information";
   
this.WindowPos.x = 845; this.WindowPos.x = 845;
this.WindowPos.y = 85; this.WindowPos.y = 85;
   
this.untoggleRegisterInfo = (VOID_SaveValue<bool>)false; this.untoggleRegisterInfo = (VOID_SaveValue<bool>)false;
this.toggleExtendedOrbital = (VOID_SaveValue<bool>)false; this.toggleExtendedOrbital = (VOID_SaveValue<bool>)false;
} }
   
public override void ModuleWindow(int id) public override void ModuleWindow(int id)
{ {
Vessel rendezvessel; Vessel rendezvessel;
CelestialBody rendezbody; CelestialBody rendezbody;
   
if (this.RegisterModule == null) if (this.RegisterModule == null)
{ {
for (int idx = 0; idx < this.core.Modules.Count; idx++) for (int idx = 0; idx < this.core.Modules.Count; idx++)
{ {
if (this.core.Modules[idx] is VOID_VesselRegister) if (this.core.Modules[idx] is VOID_VesselRegister)
{ {
this.RegisterModule = this.core.Modules[idx] as VOID_VesselRegister; this.RegisterModule = this.core.Modules[idx] as VOID_VesselRegister;
break; break;
} }
} }
} }
   
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
//display both //display both
//Show Target Info //Show Target Info
GUILayout.Label("Target:", VOID_Styles.labelCenterBold); GUILayout.Label("Target:", VOID_Styles.labelCenterBold);
if (FlightGlobals.fetch.VesselTarget != null) if (FlightGlobals.fetch.VesselTarget != null)
{ {
//a KSP Target (body or vessel) is selected //a KSP Target (body or vessel) is selected
if (FlightGlobals.fetch.vesselTargetMode == VesselTargetModes.Direction) if (FlightGlobals.fetch.vesselTargetMode == VesselTargetModes.Direction)
{ {
//a Body is selected //a Body is selected
rendezbody = Vessel.patchedConicSolver.targetBody; rendezbody = Vessel.patchedConicSolver.targetBody;
display_rendezvous_info(null, rendezbody); display_rendezvous_info(null, rendezbody);
} }
else if (FlightGlobals.fetch.vesselTargetMode == VesselTargetModes.DirectionAndVelocity) else if (FlightGlobals.fetch.vesselTargetMode == VesselTargetModes.DirectionAndVelocity)
{ {
//a Vessel is selected //a Vessel is selected
rendezvessel = FlightGlobals.fetch.VesselTarget.GetVessel(); rendezvessel = FlightGlobals.fetch.VesselTarget.GetVessel();
display_rendezvous_info(rendezvessel, null); display_rendezvous_info(rendezvessel, null);
} }
//Show Unset button for both options above //Show Unset button for both options above
if (GUILayout.Button("Unset Target", GUILayout.ExpandWidth(false))) if (GUILayout.Button("Unset Target", GUILayout.ExpandWidth(false)))
{ {
FlightGlobals.fetch.SetVesselTarget(null); FlightGlobals.fetch.SetVesselTarget(null);
ToadicusTools.Logging.PostDebugMessage("VOID_Rendezvous: KSP Target set to null"); Logging.PostDebugMessage("VOID_Rendezvous: KSP Target set to null");
} }
   
} }
else else
{ {
//no KSP Target selected //no KSP Target selected
GUILayout.Label("No Target Selected", VOID_Styles.labelCenterBold); GUILayout.Label("No Target Selected", VOID_Styles.labelCenterBold);
} }
   
//Show Vessel Register vessel info //Show Vessel Register vessel info
if (untoggleRegisterInfo == false && this.RegisterModule != default(IVOID_Module)) if (untoggleRegisterInfo == false && this.RegisterModule != default(IVOID_Module))
{ {
GUILayout.Label("Vessel Register:", VOID_Styles.labelCenterBold); GUILayout.Label("Vessel Register:", VOID_Styles.labelCenterBold);
if (this.RegisterModule.selectedVessel != null) if (this.RegisterModule.selectedVessel != null)
{ {
rendezvessel = this.RegisterModule.selectedVessel; rendezvessel = this.RegisterModule.selectedVessel;
display_rendezvous_info(rendezvessel, null); display_rendezvous_info(rendezvessel, null);
   
//show set/unset buttons //show set/unset buttons
if (FlightGlobals.fetch.VesselTarget == null || (FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel() != this.RegisterModule.selectedVessel)) if (FlightGlobals.fetch.VesselTarget == null || (FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel() != this.RegisterModule.selectedVessel))
{ {
//no Tgt set or Tgt is not this vessel //no Tgt set or Tgt is not this vessel
//show a Set button //show a Set button
if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false))) if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false)))
{ {
FlightGlobals.fetch.SetVesselTarget(rendezvessel); FlightGlobals.fetch.SetVesselTarget(rendezvessel);
ToadicusTools.Logging.PostDebugMessage("[VOID] KSP Target set to " + rendezvessel.vesselName); Logging.PostDebugMessage("[VOID] KSP Target set to " + rendezvessel.vesselName);
} }
} }
} }
else else
{ {
//vesreg Vessel is null //vesreg Vessel is null
//targ = null; //targ = null;
GUILayout.Label("No Vessel Selected", VOID_Styles.labelCenterBold); GUILayout.Label("No Vessel Selected", VOID_Styles.labelCenterBold);
} }
} }
   
untoggleRegisterInfo.value = Layout.Toggle(untoggleRegisterInfo, "Hide Vessel Register Info"); untoggleRegisterInfo.value = Layout.Toggle(untoggleRegisterInfo, "Hide Vessel Register Info");
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(" ", GUILayout.ExpandWidth(true)); GUILayout.Label(" ", GUILayout.ExpandWidth(true));
if (GUILayout.Button("Close", GUILayout.ExpandWidth(false))) this.Active = false; if (GUILayout.Button("Close", GUILayout.ExpandWidth(false))) this.Active = false;
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
base.ModuleWindow(id); base.ModuleWindow(id);
} }
   
private void display_rendezvous_info(Vessel v, CelestialBody cb) private void display_rendezvous_info(Vessel v, CelestialBody cb)
{ {
if (cb == null && v != null) if (cb == null && v != null)
{ {
//Display vessel rendezvous info //Display vessel rendezvous info
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label(v.vesselName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true)); GUILayout.Label(v.vesselName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (v.situation == Vessel.Situations.ESCAPING || v.situation == Vessel.Situations.FLYING || v.situation == Vessel.Situations.ORBITING || v.situation == Vessel.Situations.SUB_ORBITAL) if (v.situation == Vessel.Situations.ESCAPING || v.situation == Vessel.Situations.FLYING || v.situation == Vessel.Situations.ORBITING || v.situation == Vessel.Situations.SUB_ORBITAL)
{ {
// Toadicus edit: added local sidereal longitude. // Toadicus edit: added local sidereal longitude.
// Toadicus edit: added local sidereal longitude. // Toadicus edit: added local sidereal longitude.
double LSL = v.longitude + v.orbit.referenceBody.rotationAngle; double LSL = v.longitude + v.orbit.referenceBody.rotationAngle;
LSL = VOID_Tools.FixDegreeDomain (LSL); LSL = VOID_Tools.FixDegreeDomain (LSL);
   
//display orbital info for orbiting/flying/suborbital/escaping vessels only //display orbital info for orbiting/flying/suborbital/escaping vessels only
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Ap/Pe:"); GUILayout.Label("Ap/Pe:");
GUILayout.Label(SIFormatProvider.ToSI(v.orbit.ApA, 3) + "m / " + SIFormatProvider.ToSI(v.orbit.PeA, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.Label(SIFormatProvider.ToSI(v.orbit.ApA, 3) + "m / " + SIFormatProvider.ToSI(v.orbit.PeA, 3) + "m", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Altitude:"); GUILayout.Label("Altitude:");
GUILayout.Label(SIFormatProvider.ToSI(v.orbit.altitude, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.Label(SIFormatProvider.ToSI(v.orbit.altitude, 3) + "m", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Inclination:"); GUILayout.Label("Inclination:");
GUILayout.Label(v.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(v.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (Vessel.mainBody == v.mainBody) if (Vessel.mainBody == v.mainBody)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Relative inclination:"); GUILayout.Label("Relative inclination:");
GUILayout.Label(Vector3d.Angle(Vessel.orbit.GetOrbitNormal(), v.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(Vector3d.Angle(Vessel.orbit.GetOrbitNormal(), v.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
//if (debugging) Debug.Log("[CHATR] v -> v relative incl OK"); //if (debugging) Debug.Log("[CHATR] v -> v relative incl OK");
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Velocity:"); GUILayout.Label("Velocity:");
GUILayout.Label(SIFormatProvider.ToSI(v.orbit.vel.magnitude, 3) + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label(SIFormatProvider.ToSI(v.orbit.vel.magnitude, 3) + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Relative velocity:"); GUILayout.Label("Relative velocity:");
GUILayout.Label(SIFormatProvider.ToSI(v.orbit.vel.magnitude - Vessel.orbit.vel.magnitude, 3) + "m/s", GUILayout.ExpandWidth(false)); GUILayout.Label(SIFormatProvider.ToSI(v.orbit.vel.magnitude - Vessel.orbit.vel.magnitude, 3) + "m/s", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Distance:"); GUILayout.Label("Distance:");
GUILayout.Label(SIFormatProvider.ToSI((Vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.Label(SIFormatProvider.ToSI((Vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude, 3) + "m", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
// Toadicus edit: added local sidereal longitude. // Toadicus edit: added local sidereal longitude.
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Local Sidereal Longitude:"); GUILayout.Label("Local Sidereal Longitude:");
GUILayout.Label(LSL.ToString("F3") + "°", VOID_Styles.labelRight); GUILayout.Label(LSL.ToString("F3") + "°", VOID_Styles.labelRight);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
toggleExtendedOrbital.value = Layout.Toggle(toggleExtendedOrbital, "Extended info"); toggleExtendedOrbital.value = Layout.Toggle(toggleExtendedOrbital, "Extended info");
   
if (toggleExtendedOrbital) if (toggleExtendedOrbital)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Period:"); GUILayout.Label("Period:");
GUILayout.Label(VOID_Tools.FormatInterval(v.orbit.period), GUILayout.ExpandWidth(false)); GUILayout.Label(VOID_Tools.FormatInterval(v.orbit.period), GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Semi-major axis:"); GUILayout.Label("Semi-major axis:");
GUILayout.Label((v.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", GUILayout.ExpandWidth(false)); GUILayout.Label((v.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Eccentricity:"); GUILayout.Label("Eccentricity:");
GUILayout.Label(v.orbit.eccentricity.ToString("F4"), GUILayout.ExpandWidth(false)); GUILayout.Label(v.orbit.eccentricity.ToString("F4"), GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
// Toadicus edit: convert mean anomaly into degrees. // Toadicus edit: convert mean anomaly into degrees.
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Mean anomaly:"); GUILayout.Label("Mean anomaly:");
GUILayout.Label((v.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label((v.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("True anomaly:"); GUILayout.Label("True anomaly:");
GUILayout.Label(v.orbit.trueAnomaly.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(v.orbit.trueAnomaly.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
// Toadicus edit: convert eccentric anomaly into degrees. // Toadicus edit: convert eccentric anomaly into degrees.
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Eccentric anomaly:"); GUILayout.Label("Eccentric anomaly:");
GUILayout.Label((v.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label((v.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Long. ascending node:"); GUILayout.Label("Long. ascending node:");
GUILayout.Label(v.orbit.LAN.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(v.orbit.LAN.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Arg. of periapsis:"); GUILayout.Label("Arg. of periapsis:");
GUILayout.Label(v.orbit.argumentOfPeriapsis.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(v.orbit.argumentOfPeriapsis.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
} }
else else
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Latitude:"); GUILayout.Label("Latitude:");
GUILayout.Label(VOID_Tools.GetLatitudeString(Vessel), GUILayout.ExpandWidth(false)); GUILayout.Label(VOID_Tools.GetLatitudeString(Vessel), GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Longitude:"); GUILayout.Label("Longitude:");
GUILayout.Label(VOID_Tools.GetLongitudeString(Vessel), GUILayout.ExpandWidth(false)); GUILayout.Label(VOID_Tools.GetLongitudeString(Vessel), GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Distance:"); GUILayout.Label("Distance:");
GUILayout.Label(SIFormatProvider.ToSI((Vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.Label(SIFormatProvider.ToSI((Vessel.findWorldCenterOfMass() - v.findWorldCenterOfMass()).magnitude, 3) + "m", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
} }
else if (cb != null && v == null) else if (cb != null && v == null)
{ {
//Display CelstialBody rendezvous info //Display CelstialBody rendezvous info
GUILayout.Label(cb.bodyName, VOID_Styles.labelCenterBold); GUILayout.Label(cb.bodyName, VOID_Styles.labelCenterBold);
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Ap/Pe:"); GUILayout.Label("Ap/Pe:");
GUILayout.Label(SIFormatProvider.ToSI(cb.orbit.ApA, 3) + "m / " + SIFormatProvider.ToSI(cb.orbit.PeA, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.Label(SIFormatProvider.ToSI(cb.orbit.ApA, 3) + "m / " + SIFormatProvider.ToSI(cb.orbit.PeA, 3) + "m", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
//if (debugging) Debug.Log("[VOID] Ap/Pe OK"); //if (debugging) Debug.Log("[VOID] Ap/Pe OK");
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Inclination:"); GUILayout.Label("Inclination:");
GUILayout.Label(cb.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(cb.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
//if (debugging) Debug.Log("[VOID] Inclination OK"); //if (debugging) Debug.Log("[VOID] Inclination OK");
   
if (cb.referenceBody == Vessel.mainBody) if (cb.referenceBody == Vessel.mainBody)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Relative inclination:"); GUILayout.Label("Relative inclination:");
GUILayout.Label(Vector3d.Angle(Vessel.orbit.GetOrbitNormal(), cb.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label(Vector3d.Angle(Vessel.orbit.GetOrbitNormal(), cb.orbit.GetOrbitNormal()).ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
//if (debugging) Debug.Log("[VOID] cb Relative inclination OK"); //if (debugging) Debug.Log("[VOID] cb Relative inclination OK");
} }
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("Distance:"); GUILayout.Label("Distance:");
GUILayout.Label(SIFormatProvider.ToSI((Vessel.mainBody.position - cb.position).magnitude, 3) + "m", GUILayout.ExpandWidth(false)); GUILayout.Label(SIFormatProvider.ToSI((Vessel.mainBody.position - cb.position).magnitude, 3) + "m", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
//if (debugging) Debug.Log("[VOID] Distance OK"); //if (debugging) Debug.Log("[VOID] Distance OK");
   
//SUN2PLANET: //SUN2PLANET:
if (Vessel.mainBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody) if (Vessel.mainBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody)
{ {
VOID_Tools.display_transfer_angles_SUN2PLANET(cb, Vessel); VOID_Tools.display_transfer_angles_SUN2PLANET(cb, Vessel);
//if (debugging) Debug.Log("[VOID] SUN2PLANET OK"); //if (debugging) Debug.Log("[VOID] SUN2PLANET OK");
} }
   
//PLANET2PLANET //PLANET2PLANET
else if (Vessel.mainBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody.referenceBody) else if (Vessel.mainBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody.referenceBody)
{ {
VOID_Tools.display_transfer_angles_PLANET2PLANET(cb, Vessel); VOID_Tools.display_transfer_angles_PLANET2PLANET(cb, Vessel);
//if (debugging) Debug.Log("[VOID] PLANET2PLANET OK"); //if (debugging) Debug.Log("[VOID] PLANET2PLANET OK");
} }
   
//PLANET2MOON //PLANET2MOON
else if (Vessel.mainBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody) else if (Vessel.mainBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody)
{ {
VOID_Tools.display_transfer_angles_PLANET2MOON(cb, Vessel); VOID_Tools.display_transfer_angles_PLANET2MOON(cb, Vessel);
//if (debugging) Debug.Log("[VOID] PLANET2MOON OK"); //if (debugging) Debug.Log("[VOID] PLANET2MOON OK");
} }
   
//MOON2MOON //MOON2MOON
else if (Vessel.mainBody.referenceBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody.referenceBody) else if (Vessel.mainBody.referenceBody.referenceBody.bodyName == "Sun" && cb.referenceBody == Vessel.mainBody.referenceBody)
{ {
VOID_Tools.display_transfer_angles_MOON2MOON(cb, Vessel); VOID_Tools.display_transfer_angles_MOON2MOON(cb, Vessel);
//if (debugging) Debug.Log("[VOID] MOON2MOON OK"); //if (debugging) Debug.Log("[VOID] MOON2MOON OK");
} }
   
//else GUILayout.Label("Transfer angle information\nunavailable for this target"); //else GUILayout.Label("Transfer angle information\nunavailable for this target");
   
} }
} }
} }
} }
// VOID // VOID
// //
// VOID_Transfer.cs // VOID_Transfer.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
// TODO: Remove ToadicusTools. prefixes after refactor is done.  
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
  using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_Transfer : VOID_WindowModule public class VOID_Transfer : VOID_WindowModule
{ {
protected List<CelestialBody> selectedBodies = new List<CelestialBody>(); protected List<CelestialBody> selectedBodies = new List<CelestialBody>();
   
public VOID_Transfer() : base() public VOID_Transfer() : base()
{ {
this.Name = "Transfer Angle Information"; this.Name = "Transfer Angle Information";
   
this.WindowPos.x = 475; this.WindowPos.x = 475;
this.WindowPos.y = 85; this.WindowPos.y = 85;
this.defWidth = 315; this.defWidth = 315;
} }
   
public override void ModuleWindow(int id) public override void ModuleWindow(int id)
{ {
CelestialBody body; CelestialBody body;
   
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
if (Vessel.mainBody.name == "Sun") //Vessel is orbiting the Sun if (Vessel.mainBody.name == "Sun") //Vessel is orbiting the Sun
{ {
for (int idx = 0; idx < Vessel.mainBody.orbitingBodies.Count; idx++) for (int idx = 0; idx < Vessel.mainBody.orbitingBodies.Count; idx++)
{ {
body = Vessel.mainBody.orbitingBodies[idx]; body = Vessel.mainBody.orbitingBodies[idx];
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button(body.bodyName)) if (GUILayout.Button(body.bodyName))
{ {
//add or remove this body to this list of bodies to display more info on //add or remove this body to this list of bodies to display more info on
if (selectedBodies.Contains(body)) selectedBodies.Remove(body); if (selectedBodies.Contains(body)) selectedBodies.Remove(body);
else selectedBodies.Add(body); else selectedBodies.Add(body);
} }
GUILayout.Label("Inclined " + body.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label("Inclined " + body.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (selectedBodies.Contains(body)) if (selectedBodies.Contains(body))
{ {
VOID_Tools.display_transfer_angles_SUN2PLANET(body, Vessel); //show phase angles for each selected body VOID_Tools.display_transfer_angles_SUN2PLANET(body, Vessel); //show phase angles for each selected body
tad_targeting(body); //display Set/Unset Target button for each selected body tad_targeting(body); //display Set/Unset Target button for each selected body
} }
} }
} }
else if (Vessel.mainBody.referenceBody.name == "Sun") //Vessel is orbiting a planet else if (Vessel.mainBody.referenceBody.name == "Sun") //Vessel is orbiting a planet
{ {
for (int idx = 0; idx < Vessel.mainBody.referenceBody.orbitingBodies.Count; idx++) for (int idx = 0; idx < Vessel.mainBody.referenceBody.orbitingBodies.Count; idx++)
{ {
body = Vessel.mainBody.referenceBody.orbitingBodies[idx]; body = Vessel.mainBody.referenceBody.orbitingBodies[idx];
if (body.name != Vessel.mainBody.name) // show other planets if (body.name != Vessel.mainBody.name) // show other planets
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button(body.bodyName)) if (GUILayout.Button(body.bodyName))
{ {
//add or remove this body to this list of bodies to display more info on //add or remove this body to this list of bodies to display more info on
if (selectedBodies.Contains(body)) selectedBodies.Remove(body); if (selectedBodies.Contains(body)) selectedBodies.Remove(body);
else selectedBodies.Add(body); else selectedBodies.Add(body);
} }
GUILayout.Label("Inclined " + body.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label("Inclined " + body.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (selectedBodies.Contains(body)) if (selectedBodies.Contains(body))
{ {
VOID_Tools.display_transfer_angles_PLANET2PLANET(body, Vessel); VOID_Tools.display_transfer_angles_PLANET2PLANET(body, Vessel);
tad_targeting(body); //display Set/Unset Target button tad_targeting(body); //display Set/Unset Target button
} }
} }
} }
for (int moonIdx = 0; moonIdx < Vessel.mainBody.orbitingBodies.Count; moonIdx++) for (int moonIdx = 0; moonIdx < Vessel.mainBody.orbitingBodies.Count; moonIdx++)
{ {
body = Vessel.mainBody.orbitingBodies[moonIdx]; body = Vessel.mainBody.orbitingBodies[moonIdx];
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button(body.bodyName)) if (GUILayout.Button(body.bodyName))
{ {
//add or remove this body to this list of bodies to display more info on //add or remove this body to this list of bodies to display more info on
if (selectedBodies.Contains(body)) selectedBodies.Remove(body); if (selectedBodies.Contains(body)) selectedBodies.Remove(body);
else selectedBodies.Add(body); else selectedBodies.Add(body);
} }
GUILayout.Label("Inclined " + body.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label("Inclined " + body.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (selectedBodies.Contains(body)) if (selectedBodies.Contains(body))
{ {
VOID_Tools.display_transfer_angles_PLANET2MOON(body, Vessel); VOID_Tools.display_transfer_angles_PLANET2MOON(body, Vessel);
tad_targeting(body); //display Set/Unset Target button tad_targeting(body); //display Set/Unset Target button
} }
} }
} }
else if (Vessel.mainBody.referenceBody.referenceBody.name == "Sun") // Vessel is orbiting a moon else if (Vessel.mainBody.referenceBody.referenceBody.name == "Sun") // Vessel is orbiting a moon
{ {
for (int idx = 0; idx < Vessel.mainBody.referenceBody.orbitingBodies.Count; idx++) for (int idx = 0; idx < Vessel.mainBody.referenceBody.orbitingBodies.Count; idx++)
{ {
body = Vessel.mainBody.referenceBody.orbitingBodies[idx]; body = Vessel.mainBody.referenceBody.orbitingBodies[idx];
   
if (body.name != Vessel.mainBody.name) // show other moons if (body.name != Vessel.mainBody.name) // show other moons
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button(body.bodyName)) if (GUILayout.Button(body.bodyName))
{ {
//add or remove this body to this list of bodies to display more info on //add or remove this body to this list of bodies to display more info on
if (selectedBodies.Contains(body)) selectedBodies.Remove(body); if (selectedBodies.Contains(body)) selectedBodies.Remove(body);
else selectedBodies.Add(body); else selectedBodies.Add(body);
} }
GUILayout.Label("Inclined " + body.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false)); GUILayout.Label("Inclined " + body.orbit.inclination.ToString("F3") + "°", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
if (selectedBodies.Contains(body)) if (selectedBodies.Contains(body))
{ {
VOID_Tools.display_transfer_angles_MOON2MOON(body, Vessel); VOID_Tools.display_transfer_angles_MOON2MOON(body, Vessel);
tad_targeting(body); //display Set/Unset Target button tad_targeting(body); //display Set/Unset Target button
} }
} }
} }
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
   
base.ModuleWindow(id); base.ModuleWindow(id);
} }
   
private void tad_targeting(CelestialBody body) private void tad_targeting(CelestialBody body)
{ {
//Target Set/Unset buttons //Target Set/Unset buttons
if (FlightGlobals.fetch.VesselTarget == null || (FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel() == null)) if (FlightGlobals.fetch.VesselTarget == null || (FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel() == null))
{ {
//No TGT set or TGT is a Body //No TGT set or TGT is a Body
if ((CelestialBody)FlightGlobals.fetch.VesselTarget != body) if ((CelestialBody)FlightGlobals.fetch.VesselTarget != body)
{ {
if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false))) if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false)))
{ {
FlightGlobals.fetch.SetVesselTarget(body); FlightGlobals.fetch.SetVesselTarget(body);
ToadicusTools.Logging.PostDebugMessage("[VOID] KSP Target set to CelestialBody " + body.bodyName); Logging.PostDebugMessage("[VOID] KSP Target set to CelestialBody " + body.bodyName);
} }
} }
else if ((CelestialBody)FlightGlobals.fetch.VesselTarget == body) else if ((CelestialBody)FlightGlobals.fetch.VesselTarget == body)
{ {
if (GUILayout.Button("Unset Target", GUILayout.ExpandWidth(false))) if (GUILayout.Button("Unset Target", GUILayout.ExpandWidth(false)))
{ {
FlightGlobals.fetch.SetVesselTarget(null); FlightGlobals.fetch.SetVesselTarget(null);
ToadicusTools.Logging.PostDebugMessage("[VOID] KSP Target set to null"); Logging.PostDebugMessage("[VOID] KSP Target set to null");
} }
} }
} }
else if (FlightGlobals.fetch.VesselTarget == null || (FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel() != null)) else if (FlightGlobals.fetch.VesselTarget == null || (FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel() != null))
{ {
//No TGT or TGT is a vessel //No TGT or TGT is a vessel
if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false))) if (GUILayout.Button("Set Target", GUILayout.ExpandWidth(false)))
{ {
FlightGlobals.fetch.SetVesselTarget(body); FlightGlobals.fetch.SetVesselTarget(body);
ToadicusTools.Logging.PostDebugMessage("[VOID] KSP Target set to CelestialBody " + body.bodyName); Logging.PostDebugMessage("[VOID] KSP Target set to CelestialBody " + body.bodyName);
} }
} }
} }
} }
} }