Added new single nested 'for' loop to the core, which can be subscribed to by modules and data members.
Added new single nested 'for' loop to the core, which can be subscribed to by modules and data members.

* text=auto * text=auto
* eol=lf * eol=lf
   
  # These files are text and should be normalized (convert crlf => lf)
  *.cs text diff=csharp
  *.cfg text
  *.csproj text
  *.sln text
   
  # Images should be treated as binary
  # (binary is a macro for -text -diff)
  *.png binary
   
  // VOID
  //
  // AVOID_SaveValue.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  using System;
 
  namespace VOID
  {
  [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
  public class AVOID_SaveValue : Attribute
  {
  public string Name
  {
  get;
  private set;
  }
 
  public AVOID_SaveValue(string fieldName)
  {
  this.Name = fieldName;
  }
  }
  }
 
 
  // VOID
  //
  // VOID_ScenesAttribute.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  using System;
 
  namespace VOID
  {
  [AttributeUsage(AttributeTargets.Class)]
  public class VOID_ScenesAttribute : Attribute
  {
  public GameScenes[] ValidScenes
  {
  get;
  private set;
  }
 
  public VOID_ScenesAttribute(params GameScenes[] validScenes)
  {
  this.ValidScenes = validScenes;
  }
  }
  }
 
 
  // VOID
  //
  // VOID_ScenesAttribute.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  using System;
 
  namespace VOID
  {
  [AttributeUsage(AttributeTargets.Class)]
  public class VOID_GameModesAttribute : Attribute
  {
  public Game.Modes[] ValidModes
  {
  get;
  private set;
  }
 
  public VOID_GameModesAttribute(params Game.Modes[] validModes)
  {
  this.ValidModes = validModes;
  }
  }
  }
 
 
file:b/API/Enums.cs (new)
  // VOID © 2015 toadicus
  //
  // This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a
  // copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
  using System;
 
  namespace VOID
  {
  public enum VOID_TimeScale : UInt32
  {
  KERBIN_TIME = 1, // Earth if 0
  SOLAR_DAY = 4, // Sidereal if 0
  ROUNDED_SCALE = 1024 // Real values if 0
  }
 
  public enum IconState : UInt32
  {
  PowerOff = 1,
  PowerOn = 2,
  Inactive = 4,
  Active = 8
  }
  }
 
 
  // VOID
  //
  // IVOID_DataValue.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  using System;
 
  namespace VOID
  {
  public interface IVOID_DataValue
  {
  string Label { get; }
  string Units { get; }
  object Value { get; }
 
  void Refresh();
  string ValueUnitString();
  void DoGUIHorizontal();
  }
  }
 
 
  // VOID
  //
  // IVOID_Module.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using System;
 
  namespace VOID
  {
  public interface IVOID_Module
  {
  string Name { get; }
  bool Active { get; set; }
  bool GUIRunning { get; }
  bool InValidScene { get; }
  bool InValidGame { get; }
 
  void DrawGUI(object sender);
  void StartGUI();
  void StopGUI();
 
  void DrawConfigurables();
 
  // void LoadConfig();
  void LoadConfig(KSP.IO.PluginConfiguration config);
 
  void Save(KSP.IO.PluginConfiguration config, string sceneKey);
  }
 
  public interface IVOID_BehaviorModule : IVOID_Module
  {
  void Update();
  void FixedUpdate();
  void OnDestroy();
  }
  }
 
  // VOID
  //
  // IVOID_SaveValue.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  using System;
 
  namespace VOID
  {
  public interface IVOID_SaveValue
  {
  Type type { get; }
  object value { get; }
  void SetValue(object v);
  }
  }
 
 
file:b/API/VOIDCore.cs (new)
  // VOID
  //
  // IVOID_Core.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KerbalEngineer.VesselSimulator;
  using KSP;
  using System;
  using System.Linq;
  using System.Collections.Generic;
  using UnityEngine;
 
  namespace VOID
  {
  public abstract class VOIDCore : VOID_WindowModule, IVOID_Module
  {
  public const double Constant_G = 6.674e-11;
  public const int CONFIG_VERSION = 2;
 
  public static event VOIDEventHandler onModulesLoaded;
  public static event VOIDEventHandler onModulesDestroyed;
 
  protected static void FireOnModulesLoaded(object sender)
  {
  if (onModulesLoaded != null)
  {
  onModulesLoaded(sender);
  }
  }
 
  protected static void FireOnModulesDestroyed(object sender)
  {
  if (onModulesDestroyed != null)
  {
  onModulesDestroyed(sender);
  }
  }
 
  public abstract int ConfigVersion { get; }
  public virtual bool configNeedsUpdate { get; set; }
 
  public virtual string SaveGamePath { get; protected set; }
  public virtual string VOIDSettingsPath { get; protected set; }
 
  public abstract string SceneKey { get; }
 
  public abstract int WindowID { get; }
  public abstract bool configDirty { get; set; }
  public abstract bool powerAvailable { get; protected set; }
 
  public abstract IList<IVOID_Module> Modules { get; }
 
  public abstract float UpdateTimer { get; protected set; }
  public abstract double UpdatePeriod { get; }
 
  public virtual float saveTimer { get; protected set; }
 
  public abstract GUISkin Skin { get; }
 
  public abstract CelestialBody HomeBody { get; }
  public abstract List<CelestialBody> SortedBodyList { get; protected set; }
 
  public abstract VesselType[] AllVesselTypes { get; protected set; }
  public abstract Stage LastStage { get; protected set; }
  public abstract Stage[] Stages { get; protected set; }
 
  public abstract VOID_TimeScale TimeScale { get; protected set; }
 
  public abstract event VOIDEventHandler onApplicationQuit;
  public abstract event VOIDEventHandler onSkinChanged;
  public abstract event VOIDEventHandler onUpdate;
 
  public abstract event VOIDEventHandler onPreForEach;
  public abstract event VOIDForEachPartHandler onForEachPart;
  public abstract event VOIDForEachPartModuleHandler onForEachModule;
  public abstract event VOIDEventHandler onPostForEach;
 
  public virtual event VOIDEventHandler onPreRender;
  public virtual event VOIDEventHandler onPostRender;
 
  public virtual bool MethodInPreRenderQueue(VOIDEventHandler method)
  {
  if (this.onPreRender != null)
  {
  ToadicusTools.Logging.PostDebugMessage(this, "Looking in onPreRender for method {0} in onGui", method);
 
  foreach (Delegate invoker in this.onPreRender.GetInvocationList())
  {
  ToadicusTools.Logging.PostDebugMessage(this, "Checking invoker {0}", invoker);
 
  if (invoker == method)
  {
  ToadicusTools.Logging.PostDebugMessage(this, "Found match.");
  return true;
  }
  }
  }
  #if DEBUG
  else
  {
  ToadicusTools.Logging.PostDebugMessage(this, "this.onPreRender == null");
  }
  #endif
 
 
  return false;
  }
 
  public virtual bool MethodInPostRenderQueue(VOIDEventHandler method)
  {
  if (this.onPostRender != null)
  {
  ToadicusTools.Logging.PostDebugMessage(this, "Looking in onPostRender for method {0} in onGui", method);
 
  foreach (Delegate invoker in this.onPostRender.GetInvocationList())
  {
  ToadicusTools.Logging.PostDebugMessage(this, "Checking invoker {0}", invoker);
 
  if (invoker == method)
  {
  ToadicusTools.Logging.PostDebugMessage(this, "Found match.");
  return true;
  }
  }
  }
  #if DEBUG
  else
  {
  ToadicusTools.Logging.PostDebugMessage(this, "this.onPostRender == null");
  }
  #endif
 
 
  return false;
  }
 
  public void OnGUI()
  {
  if (Event.current.type == EventType.Repaint || Event.current.isMouse)
  {
  if (this.onPreRender != null)
  {
  ToadicusTools.Logging.PostDebugMessage(this, "In OnGUI; doing 'pre draw' stuff");
  this.onPreRender(this);
  }
  }
 
  if (this.onPostRender != null)
  {
  ToadicusTools.Logging.PostDebugMessage(this, "In OnGUI; doing 'post draw' stuff");
  this.onPostRender(this);
  }
  }
 
  public abstract void SaveConfig();
 
  public override void Save(KSP.IO.PluginConfiguration config, string sceneKey)
  {
  base.Save(config, sceneKey);
 
  }
  }
 
  public delegate void VOIDEventHandler(object sender);
  public delegate void VOIDForEachPartHandler(object sender, VOIDForEachPartArgs args);
  public delegate void VOIDForEachPartModuleHandler(object sender, VOIDForEachPartModuleArgs args);
 
  public abstract class VOIDForEachEventArgs<T> : EventArgs where T : class
  {
  public T Data;
 
  public VOIDForEachEventArgs(T data)
  {
  this.Data = data;
  }
  }
 
  public class VOIDForEachPartArgs : VOIDForEachEventArgs<Part>
  {
  public VOIDForEachPartArgs(Part data) : base(data) {}
  }
  public class VOIDForEachPartModuleArgs : VOIDForEachEventArgs<PartModule>
  {
  public VOIDForEachPartModuleArgs(PartModule data) : base(data) {}
  }
  }
 
 
file:b/API/VOIDMaster.cs (new)
  // VOID
  //
  // VOIDMaster.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  ///////////////////////////////////////////////////////////////////////////////
  //
  // Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors
  // behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some
  // invaluable functions and making your nicely written code available to learn from.
  //
  ///////////////////////////////////////////////////////////////////////////////
  //
  // This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.
  // Engineer Redux (c) 2013 cybutek
  // Used by permission.
  //
  ///////////////////////////////////////////////////////////////////////////////
 
  using System;
  using UnityEngine;
  using KerbalEngineer.VesselSimulator;
  using ToadicusTools.Extensions;
 
  namespace VOID
  {
  public abstract class VOIDMaster<T> : MonoBehaviour
  where T : VOIDCore_Generic<T>, new()
  {
  protected T Core;
 
  public abstract void Awake();
 
  public virtual void Update()
  {
  if (this.Core != null && !this.InValidScene())
  {
  this.LogDebug("We have a Core but the scene is not valid for this master. Saving and disposing.");
 
  this.Core.SaveConfig ();
  this.Core.Dispose();
  this.Core = null;
  return;
  }
 
  if (this.Core == null && this.InValidScene())
  {
  this.LogDebug("We have no Core and the scene is valid for this master; re-trying Awake.");
  this.Awake();
  return;
  }
 
  this.Core.Update ();
 
  if (this.Core.FactoryReset)
  {
  this.LogDebug("Factory reset is true; deleting config and disposing!");
 
  KSP.IO.File.Delete<T>("config.xml");
  System.IO.File.Delete(this.Core.VOIDSettingsPath);
 
  this.Core.Dispose();
  this.Core = null;
  }
  }
 
  public virtual void FixedUpdate()
  {
  if (this.Core == null)
  {
  return;
  }
 
  this.Core.FixedUpdate ();
  }
 
  public virtual void OnGUI()
  {
  if (this.Core == null)
  {
  return;
  }
 
  this.Core.OnGUI();
  }
 
  public virtual void OnDestroy()
  {
  if (this.Core == null)
  {
  return;
  }
 
  this.Core.OnDestroy();
  }
 
  public virtual void OnApplicationQuit()
  {
  if (this.Core == null)
  {
  return;
  }
 
  this.Core.OnApplicationQuit();
  }
 
  protected virtual bool InValidScene()
  {
  object[] attributes = this.GetType().GetCustomAttributes(true);
  object attr;
  for (int idx = 0; idx < attributes.Length; idx++)
  {
  attr = attributes[idx];
  if (attr is KSPAddon)
  {
  KSPAddon addonAttr = (KSPAddon)attr;
 
  switch (addonAttr.startup)
  {
  case KSPAddon.Startup.EveryScene:
  return true;
  case KSPAddon.Startup.EditorAny:
  return HighLogic.LoadedSceneIsEditor;
  case KSPAddon.Startup.Flight:
  return HighLogic.LoadedSceneIsFlight;
  case KSPAddon.Startup.MainMenu:
  return HighLogic.LoadedScene == GameScenes.MAINMENU;
  case KSPAddon.Startup.SpaceCentre:
  return HighLogic.LoadedScene == GameScenes.SPACECENTER;
  case KSPAddon.Startup.TrackingStation:
  return HighLogic.LoadedScene == GameScenes.TRACKSTATION;
  default:
  return false;
  }
  }
  }
 
  return false;
  }
  }
  }
 
  // VOID
  //
  // VOID_HUDModule.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KerbalEngineer.VesselSimulator;
  using KSP;
  using System;
  using System.Collections.Generic;
  using System.Text;
  using ToadicusTools.GUIUtils;
  using UnityEngine;
 
  namespace VOID
  {
  public abstract class VOID_HUDModule : VOID_Module
  {
  [AVOID_SaveValue("colorIndex")]
  protected VOID_SaveValue<int> _colorIndex;
 
  protected List<Color> textColors;
 
  [AVOID_SaveValue("positionsLocked")]
  protected VOID_SaveValue<bool> positionsLocked;
 
  public virtual int ColorIndex
  {
  get
  {
  return this._colorIndex;
  }
  set
  {
  if (this._colorIndex >= this.textColors.Count - 1)
  {
  this._colorIndex.value = 0;
  return;
  }
 
  this._colorIndex.value = value;
  }
  }
 
  public virtual List<HUDWindow> Windows
  {
  get;
  protected set;
  }
 
  public VOID_HUDModule() : base()
  {
  this._colorIndex = (VOID_SaveValue<int>)0;
 
  this.textColors = new List<Color>();
 
  this.textColors.Add(Color.green);
  this.textColors.Add(Color.black);
  this.textColors.Add(Color.white);
  this.textColors.Add(Color.red);
  this.textColors.Add(Color.blue);
  this.textColors.Add(Color.yellow);
  this.textColors.Add(Color.gray);
  this.textColors.Add(Color.cyan);
  this.textColors.Add(Color.magenta);
 
  this.positionsLocked = (VOID_SaveValue<bool>)true;
 
  this.Windows = new List<HUDWindow>();
  }
 
  public override void DrawGUI(object sender)
  {
  if (this.core == null)
  {
  return;
  }
 
  VOID_Styles.labelHud.normal.textColor = textColors [ColorIndex];
 
  GUI.skin = this.core.Skin;
 
  if (HighLogic.LoadedSceneIsEditor ||
  (TimeWarp.WarpMode == TimeWarp.Modes.LOW) || (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate)
  )
  {
  SimManager.RequestSimulation();
  }
 
  HUDWindow window;
  for (int idx = 0; idx < this.Windows.Count; idx++)
  {
  window = this.Windows[idx];
 
  window.WindowPos = GUILayout.Window(
  this.core.WindowID,
  window.WindowPos,
  VOID_Tools.GetWindowHandler(window.WindowFunction),
  GUIContent.none,
  GUIStyle.none
  );
  }
  }
 
  public override void DrawConfigurables()
  {
  base.DrawConfigurables();
 
  if (GUILayout.Button (string.Intern("Change HUD color"), GUILayout.ExpandWidth (false)))
  {
  ++this.ColorIndex;
  }
 
  if (GUILayout.Button(string.Intern("Reset HUD Positions"), GUILayout.ExpandWidth(false)))
  {
  HUDWindow window;
  for (int idx = 0; idx < this.Windows.Count; idx++)
  {
  window = this.Windows[idx];
 
  window.WindowPos = new Rect(window.defaultWindowPos);
  }
  }
 
  this.positionsLocked.value = Layout.Toggle(this.positionsLocked, "Lock HUD Positions");
  }
 
  public override void LoadConfig(KSP.IO.PluginConfiguration config)
  {
  base.LoadConfig(config);
 
  config.load();
 
  HUDWindow window;
  for (int idx = 0; idx < this.Windows.Count; idx++)
  {
  window = this.Windows[idx];
 
  string saveName = string.Format("{0}_{1}", this.GetType().Name, window.WindowName);
  Rect loadedPos = config.GetValue(saveName, window.defaultWindowPos);
 
  window.WindowPos = loadedPos;
  }
  }
 
  public override void Save(KSP.IO.PluginConfiguration config, string sceneKey)
  {
  base.Save(config, sceneKey);
 
  HUDWindow window;
  for (int idx = 0; idx < this.Windows.Count; idx++)
  {
  window = this.Windows[idx];
 
  string saveName = string.Format("{0}_{1}", this.GetType().Name, window.WindowName);
  config.SetValue(saveName, window.WindowPos);
  }
  }
  }
 
  public class HUDWindow
  {
  public readonly Rect defaultWindowPos;
 
  private Rect _windowPos;
 
  public Action<int> WindowFunction
  {
  get;
  private set;
  }
 
  public Rect WindowPos
  {
  get
  {
  return this._windowPos;
  }
  set
  {
  if (value != this._windowPos)
  {
  this._windowPos = value;
 
  if (VOID_Data.Core != null)
  {
  VOID_Data.Core.configDirty = true;
  }
  }
  }
  }
 
  public string WindowName
  {
  get;
  private set;
  }
 
  private HUDWindow() {}
 
  public HUDWindow(string name, Action<int> windowFunc, Rect defaultPos)
  {
  this.WindowName = name;
  this.WindowFunction = windowFunc;
  this.defaultWindowPos = defaultPos;
  this.WindowPos = new Rect(this.defaultWindowPos);
  }
  }
  }
 
 
  // VOID
  //
  // VOID_Module.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  // TODO: Remove ToadicusTools. prefixes after refactor is done.
 
  using System;
  using System.Collections.Generic;
  using System.Reflection;
  using ToadicusTools.Extensions;
  using ToadicusTools.GUIUtils;
  using UnityEngine;
 
  namespace VOID
  {
  public abstract class VOID_Module : IVOID_Module
  {
  /*
  * Fields
  * */
  [AVOID_SaveValue("Active")]
  protected VOID_SaveValue<bool> active = (VOID_SaveValue<bool>)false;
 
  protected float lastUpdate = 0;
 
  private GameScenes[] validScenes;
  private Game.Modes[] validModes;
 
  /*
  * Properties
  * */
 
  public virtual bool Active
  {
  get
  {
  return this.active && this.InValidGame && this.InValidScene;
  }
  set
  {
  this.active.value = value && this.InValidGame && this.InValidScene;
  }
  }
 
  public virtual bool GUIRunning
  {
  get
  {
  using (var log = ToadicusTools.DebugTools.PooledDebugLogger.New(this))
  {
  log.AppendFormat("this.core: {0}\n", this.core != null ? this.core.ToString() : "null");
  if (this.core != null)
  {
  log.AppendFormat("this.core.MethodInPostRenderQueue(this.DrawGUI): {0}\n",
  this.core.MethodInPostRenderQueue(this.DrawGUI));
  }
 
  log.AppendFormat("this.GUIRunning: {0}\n",
  this.core != null && this.core.MethodInPostRenderQueue(this.DrawGUI));
 
  log.Print(false);
  }
 
  return this.core != null && this.core.MethodInPostRenderQueue(this.DrawGUI);
  }
  }
 
  public virtual bool InValidGame
  {
  get
  {
  return this.ValidModes.Contains(HighLogic.CurrentGame.Mode);
  }
  }
 
  public virtual bool InValidScene
  {
  get
  {
  return this.ValidScenes.Contains(HighLogic.LoadedScene);
  }
  }
 
  public virtual string Name
  {
  get;
  protected set;
  }
 
  public virtual Game.Modes[] ValidModes
  {
  get
  {
  if (this.validModes == null)
  {
  ToadicusTools.Logging.PostDebugMessage(this, "validModes is null when checking inValidGame; fetching attribute.");
 
  object[] attributes = this.GetType().GetCustomAttributes(false);
  object attr;
  for (int idx = 0; idx < attributes.Length; idx++)
  {
  attr = attributes[idx];
 
  if (attr is VOID_GameModesAttribute)
  {
  VOID_GameModesAttribute addonAttr = (VOID_GameModesAttribute)attr;
 
  this.validModes = addonAttr.ValidModes;
 
  ToadicusTools.Logging.PostDebugMessage("Found VOID_GameModesAttribute; validScenes set.");
 
  break;
  }
  }
 
  if (this.validModes == null)
  {
  this.validModes = new Game.Modes[]
  {
  Game.Modes.CAREER,
  Game.Modes.SANDBOX,
  Game.Modes.SCENARIO,
  Game.Modes.SCENARIO_NON_RESUMABLE,
  Game.Modes.SCIENCE_SANDBOX
  };
 
  ToadicusTools.Logging.PostDebugMessage("No VOID_GameModesAttribute found; validScenes defaulted to flight.");
  }
  }
 
  return this.validModes;
  }
  }
 
  public virtual GameScenes[] ValidScenes
  {
  get
  {
  if (this.validScenes == null)
  {
  ToadicusTools.Logging.PostDebugMessage(this, "validScenes is null when checking inValidScene; fetching attribute.");
  object[] attributes = this.GetType().GetCustomAttributes(false);
  object attr;
  for (int idx = 0; idx < attributes.Length; idx++)
  {
  attr = attributes[idx];
 
  if (attr is VOID_ScenesAttribute)
  {
  VOID_ScenesAttribute addonAttr = (VOID_ScenesAttribute)attr;
 
  this.validScenes = addonAttr.ValidScenes;
 
  ToadicusTools.Logging.PostDebugMessage("Found VOID_ScenesAttribute; validScenes set.");
 
  break;
  }
  }
 
  if (this.validScenes == null)
  {
  this.validScenes = new GameScenes[] { GameScenes.FLIGHT };
  ToadicusTools.Logging.PostDebugMessage("No VOID_ScenesAttribute found; validScenes defaulted to flight.");
  }
  }
 
  return this.validScenes;
  }
  }
 
  public virtual Vessel Vessel
  {
  get
  {
  return FlightGlobals.ActiveVessel;
  }
  }
 
  protected virtual VOIDCore core
  {
  get
  {
  return VOID_Data.Core;
  }
  }
 
  protected virtual bool timeToUpdate
  {
  get
  {
  return (
  (this.core.UpdateTimer - this.lastUpdate) > this.core.UpdatePeriod ||
  this.lastUpdate > this.core.UpdateTimer
  );
  }
  }
 
  /*
  * Methods
  * */
  public virtual void StartGUI()
  {
  if (!this.Active || this.GUIRunning)
  {
  return;
  }
 
  ToadicusTools.Logging.PostDebugMessage (string.Format("Adding {0} to the draw queue.", this.GetType().Name));
  this.core.onPostRender += this.DrawGUI;
  }
 
  public virtual void StopGUI()
  {
  if (!this.GUIRunning)
  {
  return;
  }
  ToadicusTools.Logging.PostDebugMessage (string.Format("Removing {0} from the draw queue.", this.GetType().Name));
  this.core.onPostRender -= this.DrawGUI;
  }
 
  public abstract void DrawGUI(object sender);
 
  public virtual void DrawConfigurables() {}
 
  public virtual void LoadConfig(KSP.IO.PluginConfiguration config)
  {
  config.load ();
 
  if (this is VOIDCore)
  {
  int configVersion = config.GetValue("VOID_Core_configValue", 2);
 
  if (configVersion < VOIDCore.CONFIG_VERSION)
  {
  ((VOIDCore)this).configNeedsUpdate = true;
  }
  }
 
  MemberInfo[] members = this.GetType().GetMembers(
  BindingFlags.NonPublic |
  BindingFlags.Public |
  BindingFlags.Instance |
  BindingFlags.FlattenHierarchy
  );
  MemberInfo member;
 
  for (int fIdx = 0; fIdx < members.Length; fIdx++)
  {
  member = members[fIdx];
 
  if (!(member is FieldInfo || member is PropertyInfo))
  {
  continue;
  }
 
  if (member is PropertyInfo && (member as PropertyInfo).GetIndexParameters().Length > 0)
  {
  continue;
  }
 
  object[] attrs = member.GetCustomAttributes(typeof(AVOID_SaveValue), false);
 
  AVOID_SaveValue attr;
 
  if (attrs.Length > 0)
  {
  attr = (AVOID_SaveValue)attrs[0];
  }
  else
  {
  continue;
  }
 
  string fieldName = string.Empty;
 
  if (this is VOIDCore || this.core.configNeedsUpdate)
  {
  string typeName = this.GetType().Name;;
 
  if (this is VOIDCore && ((VOIDCore)this).configNeedsUpdate)
  {
  if (this is VOIDCore_Flight)
  {
  typeName = "VOID_Core";
  }
  else if (this is VOIDCore_Editor)
  {
  typeName = "VOID_EditorCore";
  }
  }
 
  fieldName = string.Format("{0}_{1}", typeName, attr.Name);
  }
  else
  {
  fieldName = string.Format(
  "{0}_{1}_{2}",
  this.GetType().Name,
  Enum.GetName(typeof(GameScenes), HighLogic.LoadedScene),
  attr.Name
  );
  }
 
  ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Loading field {1}.", this.GetType().Name, fieldName));
 
  object fieldValue;
 
  if (member is FieldInfo)
  {
  fieldValue = (member as FieldInfo).GetValue(this);
  }
  else
  {
  fieldValue = (member as PropertyInfo).GetValue(this, null);
  }
 
  bool convertBack = false;
  if (fieldValue is IVOID_SaveValue)
  {
  fieldValue = (fieldValue as IVOID_SaveValue).value;
  convertBack = true;
  }
 
  fieldValue = config.GetValue(fieldName, fieldValue);
 
  if (convertBack)
  {
  Type type = typeof(VOID_SaveValue<>).MakeGenericType (fieldValue.GetType ());
  IVOID_SaveValue convertValue = Activator.CreateInstance (type) as IVOID_SaveValue;
  convertValue.SetValue (fieldValue);
  fieldValue = convertValue;
  }
 
  if (member is FieldInfo)
  {
  (member as FieldInfo).SetValue(this, fieldValue);
  }
  else
  {
  (member as PropertyInfo).SetValue(this, fieldValue, null);
  }
 
  ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Loaded field {1}.", this.GetType().Name, fieldName));
  }
  }
 
  public virtual void Save(KSP.IO.PluginConfiguration config, string sceneKey)
  {
  if (config == null)
  {
  ToadicusTools.Logging.PostErrorMessage(
  "{0}: config argument was null, bailing out.",
  this.GetType().Name
  );
  }
 
  if (sceneKey == null)
  {
  ToadicusTools.Logging.PostErrorMessage(
  "{0}: sceneKey argument was null, bailing out.",
  this.GetType().Name
  );
  }
 
  MemberInfo[] members = this.GetType().GetMembers(
  BindingFlags.NonPublic |
  BindingFlags.Public |
  BindingFlags.Instance |
  BindingFlags.FlattenHierarchy
  );
  MemberInfo member;
 
  for (int fIdx = 0; fIdx < members.Length; fIdx++)
  {
  member = members[fIdx];
 
  object[] attrs = member.GetCustomAttributes(typeof(AVOID_SaveValue), false);
 
  AVOID_SaveValue attr;
 
  if (attrs.Length > 0)
  {
  attr = (AVOID_SaveValue)attrs[0];
  }
  else
  {
  continue;
  }
 
  string fieldName;
 
  if (this is VOIDCore)
  {
  fieldName = string.Format("{0}_{1}", this.GetType().Name, attr.Name);
  }
  else
  {
  fieldName = string.Format(
  "{0}_{1}_{2}",
  this.GetType().Name,
  sceneKey,
  attr.Name
  );
  }
 
  object fieldValue;
 
  if (member is FieldInfo)
  {
  fieldValue = (member as FieldInfo).GetValue(this);
  }
  else
  {
  fieldValue = (member as PropertyInfo).GetValue(this, null);
  }
 
  if (fieldValue is IVOID_SaveValue)
  {
  fieldValue = (fieldValue as IVOID_SaveValue).value;
  }
 
  config.SetValue(fieldName, fieldValue);
 
  ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Saved field {1}.", this.GetType().Name, fieldName));
  }
  }
  }
 
  public abstract class VOID_WindowModule : VOID_Module
  {
  [AVOID_SaveValue("WindowPos")]
  protected Rect WindowPos;
  protected float defWidth;
  protected float defHeight;
 
  protected bool decorateWindow;
 
  protected string inputLockName;
 
  public VOID_WindowModule() : base()
  {
  this.defWidth = 250f;
  this.defHeight = 50f;
 
  this.decorateWindow = true;
 
  this.inputLockName = string.Concat(this.Name, "_edlock");
 
  this.WindowPos = new Rect(Screen.width / 2, Screen.height / 2, this.defWidth, this.defHeight);
  }
 
  public virtual void ModuleWindow(int id)
  {
  GUIStyle buttonStyle = this.core.Skin.button;
  RectOffset padding = buttonStyle.padding;
  RectOffset border = buttonStyle.border;
 
  Rect closeRect = new Rect(
  0f,
  0f,
  border.left + border.right,
  border.top + border.bottom
  );
 
  closeRect.width = Mathf.Max(closeRect.width, 16f);
  closeRect.height = Mathf.Max(closeRect.height, 16f);
 
  closeRect.x = this.WindowPos.width - closeRect.width - 2f;
  closeRect.y = 2f;
 
  GUI.Button(closeRect, GUIContent.none, buttonStyle);
 
  if (Event.current.type == EventType.repaint && Input.GetMouseButtonUp(0))
  {
  if (closeRect.Contains(Event.current.mousePosition))
  {
  this.Active = false;
  this.removeUILock();
  }
  }
 
  GUI.DragWindow();
  }
 
  public override void DrawGUI(object sender)
  {
  if (this.core == null)
  {
  return;
  }
 
  GUI.skin = this.core.Skin;
 
  Rect _Pos = this.WindowPos;
 
  _Pos = GUILayout.Window(
  this.core.WindowID,
  _Pos,
  VOID_Tools.GetWindowHandler(this.ModuleWindow),
  this.Name,
  GUILayout.Width(this.defWidth),
  GUILayout.Height(this.defHeight)
  );
 
  bool cursorInWindow = _Pos.Contains(Mouse.screenPos);
 
  if (cursorInWindow)
  {
  this.setUILock();
  }
  else
  {
  this.removeUILock();
  }
 
  if (HighLogic.LoadedSceneIsEditor)
  {
  _Pos = WindowTools.ClampRectToEditorPad(_Pos);
  }
  else
  {
  _Pos = WindowTools.ClampRectToScreen(_Pos);
  }
 
  if (_Pos != this.WindowPos)
  {
  this.WindowPos = _Pos;
  this.core.configDirty = true;
  }
  }
 
  protected void setUILock()
  {
  switch (HighLogic.LoadedScene)
  {
  case GameScenes.EDITOR:
  InputLockManager.SetControlLock(
  ControlTypes.EDITOR_ICON_HOVER | ControlTypes.EDITOR_ICON_PICK |
  ControlTypes.EDITOR_PAD_PICK_COPY | ControlTypes.EDITOR_PAD_PICK_COPY,
  this.inputLockName
  );
  EditorLogic.fetch.Lock(false, false, false, this.inputLockName);
  break;
  case GameScenes.FLIGHT:
  InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS, this.inputLockName);
  break;
  case GameScenes.SPACECENTER:
  InputLockManager.SetControlLock(
  ControlTypes.KSC_FACILITIES | ControlTypes.CAMERACONTROLS,
  this.inputLockName
  );
  break;
  }
  }
 
  protected void removeUILock()
  {
  switch (HighLogic.LoadedScene)
  {
  case GameScenes.EDITOR:
  EditorLogic.fetch.Unlock(this.inputLockName);
  break;
  case GameScenes.FLIGHT:
  InputLockManager.RemoveControlLock(this.inputLockName);
  break;
  case GameScenes.SPACECENTER:
  InputLockManager.RemoveControlLock(this.inputLockName);
  break;
  }
  }
  }
  }
 
 
  // VOID
  //
  // VOID_SingletonModule.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using System;
  using UnityEngine;
 
  namespace VOID
  {
  public abstract class VOID_SingletonCore<T> : VOIDCore, IVOID_Module, IDisposable
  where T : VOID_Module, new()
  {
  #region Singleton Members
  /*
  * Static Members
  * */
  protected static bool _initialized = false;
 
  public static bool Initialized
  {
  get
  {
  return _initialized;
  }
  }
 
  protected static T _instance;
 
  public static T Instance
  {
  get
  {
  if (_instance == null)
  {
  _instance = new T();
  _initialized = true;
  }
  return _instance;
  }
  }
 
  public abstract void Dispose();
  #endregion
  }
  }
 
 
  // VOID
  //
  // VOID_SingletonModule.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  using System;
 
  namespace VOID
  {
  public abstract class VOID_SingletonWindow<T> : VOID_WindowModule, IVOID_Module, IDisposable
  where T : VOID_WindowModule, new()
  {
  #region Singleton Members
  /*
  * Static Members
  * */
  protected static bool _initialized = false;
 
  public static bool Initialized
  {
  get
  {
  return _initialized;
  }
  }
 
  protected static T _instance;
 
  public static T Instance
  {
  get
  {
  if (_instance == null)
  {
  _instance = new T();
  _initialized = true;
  }
  return _instance;
  }
  }
 
  public virtual void Dispose()
  {
  _instance = null;
  _initialized = false;
  }
  #endregion
  }
  }
 
 
  ACTIVE_TEXTURE_MANAGER_CONFIG
  {
  folder = VOID
  enabled = true
  OVERRIDES
  {
  VOID/Textures/.*
  {
  compress = false
  mipmaps = false
  scale = 1
  max_size = 0
  }
  }
  }
 
 Binary files /dev/null and b/GameData/VOID/Textures/fundsgreen.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/fundsred.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/repgreen.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/repred.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/science.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_appIcon_dark.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_appIcon_dark_glow.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_appIcon_light.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_appIcon_light_glow.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_icon_dark.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_icon_dark_glow.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_icon_light.png differ
 Binary files /dev/null and b/GameData/VOID/Textures/void_icon_light_glow.png differ
file:a/IVOID_Module.cs (deleted)
//  
// IVOID_Module.cs  
//  
// Author:  
// toadicus <>  
//  
// Copyright (c) 2013 toadicus  
//  
// This program is free software: you can redistribute it and/or modify  
// it under the terms of the GNU General Public License as published by  
// the Free Software Foundation, either version 3 of the License, or  
// (at your option) any later version.  
//  
// This program is distributed in the hope that it will be useful,  
// but WITHOUT ANY WARRANTY; without even the implied warranty of  
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
// GNU General Public License for more details.  
//  
// You should have received a copy of the GNU General Public License  
// along with this program. If not, see <http://www.gnu.org/licenses/>.  
using System;  
 
namespace VOID  
{  
public interface IVOID_Module  
{  
string Name { get; }  
bool toggleActive { get; set; }  
bool guiRunning { get; }  
 
void DrawGUI();  
void StartGUI();  
void StopGUI();  
 
void DrawConfigurables();  
 
void LoadConfig();  
 
void _SaveToConfig(KSP.IO.PluginConfiguration config);  
}  
 
public interface IVOID_BehaviorModule : IVOID_Module  
{  
void Update();  
void FixedUpdate();  
}  
 
public interface IVOID_EditorModule : IVOID_Module {}  
}  
 
file:a/IntCollection.cs (deleted)
//  
// IntCollection.cs  
//  
// Author:  
// toadicus <>  
//  
// Copyright (c) 2013 toadicus  
//  
// This program is free software: you can redistribute it and/or modify  
// it under the terms of the GNU General Public License as published by  
// the Free Software Foundation, either version 3 of the License, or  
// (at your option) any later version.  
//  
// This program is distributed in the hope that it will be useful,  
// but WITHOUT ANY WARRANTY; without even the implied warranty of  
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
// GNU General Public License for more details.  
//  
// You should have received a copy of the GNU General Public License  
// along with this program. If not, see <http://www.gnu.org/licenses/>.  
using System;  
 
namespace VOID  
{  
public class IntCollection  
{  
public static implicit operator long(IntCollection c)  
{  
return c.collection;  
}  
 
protected long mask;  
 
public long collection { get; protected set; }  
public ushort maxCount { get; protected set; }  
public ushort wordLength { get; protected set; }  
 
public IntCollection (ushort wordLength = 4, long initialCollection = 0)  
{  
this.collection = initialCollection;  
this.wordLength = wordLength;  
this.maxCount = (ushort)((sizeof(long) * 8 - 1) / wordLength);  
this.mask = ((1 << this.wordLength) - 1);  
}  
 
public ushort this[int idx]  
{  
get {  
if (idx < 0) {  
idx += this.maxCount;  
}  
 
if (idx >= maxCount || idx < 0) {  
throw new IndexOutOfRangeException ();  
}  
 
idx *= wordLength;  
 
return (ushort)((this.collection & (this.mask << idx)) >> idx);  
}  
set {  
if (idx < 0) {  
idx += this.maxCount;  
}  
 
if (idx >= maxCount || idx < 0) {  
throw new IndexOutOfRangeException ();  
}  
 
idx *= wordLength;  
 
long packvalue = value & this.mask;  
 
this.collection &= ~(this.mask << idx);  
this.collection |= packvalue << idx;  
}  
}  
}  
}  
 
 
  // VOID
  //
  // AssemblyInfo.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  using System.Reflection;
  using System.Runtime.CompilerServices;
 
  [assembly: KSPAssemblyDependency("ToadicusTools", 0, 0)]
  [assembly: KSPAssemblyDependency("VesselSimulator", 0, 0)]
 
  // Information about this assembly is defined by the following attributes.
  // Change them to the values specific to your project.
  [assembly: AssemblyTitle("VOID")]
  [assembly: AssemblyDescription("A KSP mod that provides at-a-glance information about Vessels, Orbits, and their states.")]
  [assembly: AssemblyCopyright("toadicus")]
  // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
  // The form "{Major}.{Minor}.*" will automatically update the build and revision,
  // and "{Major}.{Minor}.{Build}.*" will update just the revision.
  [assembly: AssemblyVersion("0.19.0.*")]
  // The following attributes are used to specify the signing key for the assembly,
  // if desired. See the Mono documentation for more information about signing.
  //[assembly: AssemblyDelaySign(false)]
  //[assembly: AssemblyKeyFile("")]
 
file:a/Tools.cs (deleted)
//  
// Tools.cs  
//  
// Author:  
// toadicus  
//  
// Copyright (c) 2013 toadicus  
//  
// This program is free software: you can redistribute it and/or modify  
// it under the terms of the GNU General Public License as published by  
// the Free Software Foundation, either version 3 of the License, or  
// (at your option) any later version.  
//  
// This program is distributed in the hope that it will be useful,  
// but WITHOUT ANY WARRANTY; without even the implied warranty of  
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
// GNU General Public License for more details.  
//  
// You should have received a copy of the GNU General Public License  
// along with this program. If not, see <http://www.gnu.org/licenses/>.  
//  
// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.  
// Engineer Redux (c) 2013 cybutek  
// Used by permission.  
//  
///////////////////////////////////////////////////////////////////////////////  
 
using System;  
using System.Collections.Generic;  
using UnityEngine;  
 
namespace VOID  
{  
public static class VOIDLabels  
{  
public static string void_primary = "Primary";  
public static string void_altitude_asl = "Altitude (ASL)";  
public static string void_velocity = "Velocity";  
public static string void_apoapsis = "Apoapsis";  
public static string void_periapsis = "Periapsis";  
}  
 
public static class Tools  
{  
// Toadicus edit: Added re-implementation of the CBAttributeMap.GetAtt function that does not fire a debug message to the game screen.  
public static CBAttributeMap.MapAttribute Toadicus_GetAtt(Vessel vessel)  
{  
CBAttributeMap.MapAttribute mapAttribute;  
 
try  
{  
CBAttributeMap BiomeMap = vessel.mainBody.BiomeMap;  
 
double lat = vessel.latitude * Math.PI / 180d;  
double lon = vessel.longitude * Math.PI / 180d;  
 
mapAttribute = BiomeMap.GetAtt(lat, lon);  
 
/*  
lon -= Math.PI / 2d;  
 
if (lon < 0d)  
{  
lon += 2d * Math.PI;  
}  
 
float v = (float)(lat / Math.PI) + 0.5f;  
float u = (float)(lon / (2d * Math.PI));  
 
Color pixelBilinear = BiomeMap.Map.GetPixelBilinear(u, v);  
mapAttribute = BiomeMap.defaultAttribute;  
 
if (BiomeMap.Map != null)  
{  
if (BiomeMap.exactSearch)  
{  
for (int i = 0; i < BiomeMap.Attributes.Length; ++i)  
{  
if (pixelBilinear == BiomeMap.Attributes[i].mapColor)  
{  
mapAttribute = BiomeMap.Attributes[i];  
}  
}  
}  
else  
{  
float zero = 0;  
float num = 1 / zero;  
for (int j = 0; j < BiomeMap.Attributes.Length; ++j)  
{  
Color mapColor = BiomeMap.Attributes[j].mapColor;  
float sqrMagnitude = ((Vector4)(mapColor - pixelBilinear)).sqrMagnitude;  
if (sqrMagnitude < num)  
{  
bool testCase = true;  
if (BiomeMap.nonExactThreshold != -1)  
{  
testCase = (sqrMagnitude < BiomeMap.nonExactThreshold);  
}  
if (testCase)  
{  
mapAttribute = BiomeMap.Attributes[j];  
num = sqrMagnitude;  
}  
}  
}  
}  
}  
*/  
}  
catch (NullReferenceException)  
{  
mapAttribute = new CBAttributeMap.MapAttribute();  
mapAttribute.name = "N/A";  
}  
 
return mapAttribute;  
}  
 
public static string GetLongitudeString(Vessel vessel, string format = "F4")  
{  
string dir_long = "W";  
double v_long = vessel.longitude;  
 
v_long = FixDegreeDomain(v_long);  
 
if (v_long < -180d)  
{  
v_long += 360d;  
}  
if (v_long >= 180)  
{  
v_long -= 360d;  
}  
 
if (v_long > 0)  
dir_long = "E";  
 
return string.Format("{0}° {1}", Math.Abs(v_long).ToString(format), dir_long);  
}  
 
public static string GetLatitudeString(Vessel vessel, string format = "F4")  
{  
string dir_lat = "S";  
double v_lat = vessel.latitude;  
if (v_lat > 0)  
dir_lat = "N";  
 
return string.Format("{0}° {1}", Math.Abs(v_lat).ToString(format), dir_lat);  
}  
 
///////////////////////////////////////////////////////////////////////////////  
 
//For MuMech_get_heading()  
public class MuMech_MovingAverage  
{  
private double[] store;  
private int storeSize;  
private int nextIndex = 0;  
 
public double value  
{  
get  
{  
double tmp = 0;  
foreach (double i in store)  
{  
tmp += i;  
}  
return tmp / storeSize;  
}  
set  
{  
store[nextIndex] = value;  
nextIndex = (nextIndex + 1) % storeSize;  
}  
}  
 
public MuMech_MovingAverage(int size = 10, double startingValue = 0)  
{  
storeSize = size;  
store = new double[size];  
force(startingValue);  
}  
 
public void force(double newValue)  
{  
for (int i = 0; i < storeSize; i++)  
{  
store[i] = newValue;  
}  
}  
 
public static implicit operator double(MuMech_MovingAverage v)  
{  
return v.value;  
}  
 
public override string ToString()  
{  
return value.ToString();  
}  
 
public string ToString(string format)  
{  
return value.ToString(format);  
}  
}  
//From http://svn.mumech.com/KSP/trunk/MuMechLib/VOID.vesselState.cs  
public static double MuMech_get_heading(Vessel vessel)  
{  
Vector3d CoM;  
 
try  
{  
CoM = vessel.findWorldCenterOfMass();  
}  
catch  
{  
return double.NaN;  
}  
 
Vector3d up = (CoM - vessel.mainBody.position).normalized;  
Vector3d north = Vector3d.Exclude(  
up,  
(vessel.mainBody.position +  
vessel.mainBody.transform.up * (float)vessel.mainBody.Radius  
) - CoM).normalized;  
 
Quaternion rotationSurface = Quaternion.LookRotation(north, up);  
Quaternion rotationvesselSurface = Quaternion.Inverse(  
Quaternion.Euler(90, 0, 0) *  
Quaternion.Inverse(vessel.transform.rotation) *  
rotationSurface);  
 
return rotationvesselSurface.eulerAngles.y;  
}  
//From http://svn.mumech.com/KSP/trunk/MuMechLib/MuUtils.cs  
public static string MuMech_ToSI(  
double d, int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue  
)  
{  
float exponent = (float)Math.Log10(Math.Abs(d));  
exponent = Mathf.Clamp(exponent, (float)MinMagnitude, (float)MaxMagnitude);  
 
if (exponent >= 0)  
{  
switch ((int)Math.Floor(exponent))  
{  
case 0:  
case 1:  
case 2:  
return d.ToString("F" + digits);  
case 3:  
case 4:  
case 5:  
return (d / 1e3).ToString("F" + digits) + "k";  
case 6:  
case 7:  
case 8:  
return (d / 1e6).ToString("F" + digits) + "M";  
case 9:  
case 10:  
case 11:  
return (d / 1e9).ToString("F" + digits) + "G";  
case 12:  
case 13:  
case 14:  
return (d / 1e12).ToString("F" + digits) + "T";  
case 15:  
case 16:  
case 17:  
return (d / 1e15).ToString("F" + digits) + "P";  
case 18:  
case 19:  
case 20:  
return (d / 1e18).ToString("F" + digits) + "E";  
case 21:  
case 22:  
case 23:  
return (d / 1e21).ToString("F" + digits) + "Z";  
default:  
return (d / 1e24).ToString("F" + digits) + "Y";  
}  
}  
else if (exponent < 0)  
{  
switch ((int)Math.Floor(exponent))  
{  
case -1:  
case -2:  
case -3:  
return (d * 1e3).ToString("F" + digits) + "m";  
case -4:  
case -5:  
case -6:  
return (d * 1e6).ToString("F" + digits) + "μ";  
case -7:  
case -8:  
case -9:  
return (d * 1e9).ToString("F" + digits) + "n";  
case -10:  
case -11:  
case -12:  
return (d * 1e12).ToString("F" + digits) + "p";  
case -13:  
case -14:  
case -15:  
return (d * 1e15).ToString("F" + digits) + "f";  
case -16:  
case -17:  
case -18:  
return (d * 1e18).ToString("F" + digits) + "a";  
case -19:  
case -20:  
case -21:  
return (d * 1e21).ToString("F" + digits) + "z";  
default:  
return (d * 1e24).ToString("F" + digits) + "y";  
}  
}  
else  
{  
return "0";  
}  
}  
 
public static string ConvertInterval(double seconds)  
{  
string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:D2}.{5:D1}s";  
string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:D2}.{4:D1}s";  
string format_3 = "{0:D2}h {1:D2}m {2:D2}.{3:D1}s";  
 
TimeSpan interval;  
 
try  
{  
interval = TimeSpan.FromSeconds(seconds);  
}  
catch (OverflowException)  
{  
return "NaN";  
}  
 
int years = interval.Days / 365;  
 
string output;  
if (years > 0)  
{  
output = string.Format(format_1,  
years,  
interval.Days - (years * 365), // subtract years * 365 for accurate day count  
interval.Hours,  
interval.Minutes,  
interval.Seconds,  
interval.Milliseconds.ToString().Substring(0, 1));  
}  
else if (interval.Days > 0)  
{  
output = string.Format(format_2,  
interval.Days,  
interval.Hours,  
interval.Minutes,  
interval.Seconds,  
interval.Milliseconds.ToString().Substring(0, 1));  
}  
else  
{  
output = string.Format(format_3,  
interval.Hours,  
interval.Minutes,  
interval.Seconds,  
interval.Milliseconds.ToString().Substring(0, 1));  
}  
return output;  
}  
 
public static string UppercaseFirst(string s)  
{  
if (string.IsNullOrEmpty(s))  
{  
return string.Empty;  
}  
char[] a = s.ToCharArray();  
a[0] = char.ToUpper(a[0]);  
return new string(a);  
}  
//transfer angles  
public static double Nivvy_CalcTransferPhaseAngle(double r_current, double r_target, double grav_param)  
{  
double T_target = (2 * Math.PI) * Math.Sqrt(Math.Pow((r_target / 1000), 3) / (grav_param / 1000000000));  
double T_transfer = (2 * Math.PI) * Math.Sqrt(Math.Pow((((r_target / 1000) + (r_current / 1000)) / 2), 3) / (grav_param / 1000000000));  
return 360 * (0.5 - (T_transfer / (2 * T_target)));  
}  
 
public static double Younata_DeltaVToGetToOtherBody(double mu, double r1, double r2)  
{  
/*  
def deltaVToGetToOtherBody(mu, r1, r2):  
# mu = gravity param of common orbiting body of r1 and r2  
# (e.g. for mun to minmus, mu is kerbin's gravity param  
# r1 = initial body's orbit radius  
# r2 = target body's orbit radius  
 
# return value is km/s  
sur1 = math.sqrt(mu / r1)  
sr1r2 = math.sqrt(float(2*r2)/float(r1+r2))  
mult = sr1r2 - 1  
return sur1 * mult  
*/  
double sur1, sr1r2, mult;  
sur1 = Math.Sqrt(mu / r1);  
sr1r2 = Math.Sqrt((2 * r2) / (r1 + r2));  
mult = sr1r2 - 1;  
return sur1 * mult;  
}  
 
public static double Younata_DeltaVToExitSOI(double mu, double r1, double r2, double v)  
{  
/*  
def deltaVToExitSOI(mu, r1, r2, v):  
# mu = gravity param of current body  
# r1 = current orbit radius  
# r2 = SOI radius  
# v = SOI exit velocity  
foo = r2 * (v**2) - 2 * mu  
bar = r1 * foo + (2 * r2 * mu)  
r = r1*r2  
return math.sqrt(bar / r)  
*/  
double foo = r2 * Math.Pow(v, 2) - 2 * mu;  
double bar = r1 * foo + (2 * r2 * mu);  
double r = r1 * r2;  
return Math.Sqrt(bar / r);  
}  
 
public static double Younata_TransferBurnPoint(double r, double v, double angle, double mu)  
{  
/*  
def transferBurnPoint(r, v, angle, mu):  
# r = parking orbit radius  
# v = ejection velocity  
# angle = phase angle (from function phaseAngle())  
# mu = gravity param of current body.  
epsilon = ((v**2)/2) - (mu / r)  
h = r * v * math.sin(angle)  
e = math.sqrt(1 + ((2 * epsilon * h**2)/(mu**2)))  
theta = math.acos(1.0 / e)  
degrees = theta * (180.0 / math.pi)  
return 180 - degrees  
*/  
double epsilon, h, ee, theta, degrees;  
epsilon = (Math.Pow(v, 2) / 2) - (mu / r);  
h = r * v * Math.Sin(angle);  
ee = Math.Sqrt(1 + ((2 * epsilon * Math.Pow(h, 2)) / Math.Pow(mu, 2)));  
theta = Math.Acos(1.0 / ee);  
degrees = theta * (180.0 / Math.PI);  
return 180 - degrees;  
// returns the ejection angle  
}  
 
public static double Adammada_CurrrentPhaseAngle(  
double body_LAN,  
double body_orbitPct,  
double origin_LAN,  
double origin_orbitPct  
)  
{  
double angle = (body_LAN / 360 + body_orbitPct) - (origin_LAN / 360 + origin_orbitPct);  
if (angle > 1)  
angle = angle - 1;  
if (angle < 0)  
angle = angle + 1;  
if (angle > 0.5)  
angle = angle - 1;  
angle = angle * 360;  
return angle;  
}  
 
public static double Adammada_CurrentEjectionAngle(  
double vessel_long,  
double origin_rotAngle,  
double origin_LAN,  
double origin_orbitPct  
)  
{  
//double eangle = ((FlightGlobals.ActiveVOID.vessel.longitude + orbiting.rotationAngle) - (orbiting.orbit.LAN / 360 + orbiting.orbit.orbitPercent) * 360);  
double eangle = ((vessel_long + origin_rotAngle) - (origin_LAN / 360 + origin_orbitPct) * 360);  
 
while (eangle < 0)  
eangle = eangle + 360;  
while (eangle > 360)  
eangle = eangle - 360;  
if (eangle < 270)  
eangle = 90 - eangle;  
else  
eangle = 450 - eangle;  
return eangle;  
}  
 
public static double mrenigma03_calcphase(Vessel vessel, CelestialBody target) //calculates phase angle between the current body and target body  
{  
Vector3d vecthis = new Vector3d();  
Vector3d vectarget = new Vector3d();  
vectarget = target.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());  
 
if ((vessel.mainBody.name == "Sun") || (vessel.mainBody.referenceBody.referenceBody.name == "Sun"))  
{  
vecthis = vessel.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());  
}  
else  
{  
vecthis = vessel.mainBody.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());  
}  
 
vecthis = Vector3d.Project(new Vector3d(vecthis.x, 0, vecthis.z), vecthis);  
vectarget = Vector3d.Project(new Vector3d(vectarget.x, 0, vectarget.z), vectarget);  
 
Vector3d prograde = new Vector3d();  
prograde = Quaternion.AngleAxis(90, Vector3d.forward) * vecthis;  
 
double phase = Vector3d.Angle(vecthis, vectarget);  
 
if (Vector3d.Angle(prograde, vectarget) > 90)  
phase = 360 - phase;  
 
return (phase + 360) % 360;  
}  
 
public static double FixAngleDomain(double Angle, bool Degrees = false)  
{  
double Extent = 2d * Math.PI;  
if (Degrees)  
{  
Extent = 360d;  
}  
 
Angle = Angle % (Extent);  
if (Angle < 0d)  
{  
Angle += Extent;  
}  
 
return Angle;  
}  
 
public static double FixDegreeDomain(double Angle)  
{  
return FixAngleDomain(Angle, true);  
}  
 
public static double adjustCurrPhaseAngle(double transfer_angle, double curr_phase)  
{  
if (transfer_angle < 0)  
{  
if (curr_phase > 0)  
return (-1 * (360 - curr_phase));  
else if (curr_phase < 0)  
return curr_phase;  
}  
else if (transfer_angle > 0)  
{  
if (curr_phase > 0)  
return curr_phase;  
else if (curr_phase < 0)  
return (360 + curr_phase);  
}  
return curr_phase;  
}  
 
public static double adjust_current_ejection_angle(double curr_ejection)  
{  
//curr_ejection WILL need to be adjusted once for all transfers as it returns values ranging -180 to 180  
// need 0-360 instead  
//  
// ie i have -17 in the screenshot  
// need it to show 343  
//  
// do this  
//  
// if < 0, add curr to 360 // 360 + (-17) = 343  
// else its good as it is  
 
if (curr_ejection < 0)  
return 360 + curr_ejection;  
else  
return curr_ejection;  
 
}  
 
public static double adjust_transfer_ejection_angle(double trans_ejection, double trans_phase)  
{  
// if transfer_phase_angle < 0 its a lower transfer  
//180 + curr_ejection  
// else if transfer_phase_angle > 0 its good as it is  
 
if (trans_phase < 0)  
return 180 + trans_ejection;  
else  
return trans_ejection;  
 
}  
 
public static double TrueAltitude(Vessel vessel)  
{  
double trueAltitude = vessel.orbit.altitude - vessel.terrainAltitude;  
 
// HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,  
// and water covers the whole surface at 0 m.  
if (vessel.terrainAltitude < 0 && vessel.mainBody.ocean)  
{  
trueAltitude = vessel.orbit.altitude;  
}  
 
return trueAltitude;  
}  
 
public static string get_heading_text(double heading)  
{  
if (heading > 348.75 || heading <= 11.25)  
return "N";  
else if (heading > 11.25 && heading <= 33.75)  
return "NNE";  
else if (heading > 33.75 && heading <= 56.25)  
return "NE";  
else if (heading > 56.25 && heading <= 78.75)  
return "ENE";  
else if (heading > 78.75 && heading <= 101.25)  
return "E";  
else if (heading > 101.25 && heading <= 123.75)  
return "ESE";  
else if (heading > 123.75 && heading <= 146.25)  
return "SE";  
else if (heading > 146.25 && heading <= 168.75)  
return "SSE";  
else if (heading > 168.75 && heading <= 191.25)  
return "S";  
else if (heading > 191.25 && heading <= 213.75)  
return "SSW";  
else if (heading > 213.75 && heading <= 236.25)  
return "SW";  
else if (heading > 236.25 && heading <= 258.75)  
return "WSW";  
else if (heading > 258.75 && heading <= 281.25)  
return "W";  
else if (heading > 281.25 && heading <= 303.75)  
return "WNW";  
else if (heading > 303.75 && heading <= 326.25)  
return "NW";  
else if (heading > 326.25 && heading <= 348.75)  
return "NNW";  
else  
return "";  
}  
 
public static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel)  
{  
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Phase angle (curr/trans):");  
GUILayout.Label(  
Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + Tools.Nivvy_CalcTransferPhaseAngle(  
vessel.orbit.semiMajorAxis,  
body.orbit.semiMajorAxis,  
vessel.mainBody.gravParameter  
).ToString("F3") + "°",  
GUILayout.ExpandWidth(false)  
);  
GUILayout.EndHorizontal();  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Transfer velocity:");  
GUILayout.Label(  
(Tools.Younata_DeltaVToGetToOtherBody(  
(vessel.mainBody.gravParameter / 1000000000),  
(vessel.orbit.semiMajorAxis / 1000),  
(body.orbit.semiMajorAxis / 1000)  
) * 1000).ToString("F2") + "m/s",  
GUILayout.ExpandWidth(false)  
);  
GUILayout.EndHorizontal();  
}  
 
public static void display_transfer_angles_PLANET2PLANET(CelestialBody body, Vessel vessel)  
{  
double dv1 = Tools.Younata_DeltaVToGetToOtherBody(  
(vessel.mainBody.referenceBody.gravParameter / 1000000000),  
(vessel.mainBody.orbit.semiMajorAxis / 1000),  
(body.orbit.semiMajorAxis / 1000)  
);  
double dv2 = Tools.Younata_DeltaVToExitSOI(  
(vessel.mainBody.gravParameter / 1000000000),  
(vessel.orbit.semiMajorAxis / 1000),  
(vessel.mainBody.sphereOfInfluence / 1000),  
Math.Abs(dv1)  
);  
 
double trans_ejection_angle = Tools.Younata_TransferBurnPoint(  
(vessel.orbit.semiMajorAxis / 1000),  
dv2,  
(Math.PI / 2.0),  
(vessel.mainBody.gravParameter / 1000000000)  
);  
double curr_ejection_angle = Tools.Adammada_CurrentEjectionAngle(  
FlightGlobals.ActiveVessel.longitude,  
FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle,  
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,  
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent  
);  
 
double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(  
vessel.mainBody.orbit.semiMajorAxis,  
body.orbit.semiMajorAxis,  
vessel.mainBody.referenceBody.gravParameter  
) % 360;  
double curr_phase_angle = Tools.Adammada_CurrrentPhaseAngle(  
body.orbit.LAN,  
body.orbit.orbitPercent,  
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,  
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent  
);  
 
double adj_phase_angle = Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle);  
double adj_trans_ejection_angle = Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle);  
double adj_curr_ejection_angle = Tools.adjust_current_ejection_angle(curr_ejection_angle);  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Phase angle (curr/trans):");  
GUILayout.Label(  
adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",  
GUILayout.ExpandWidth(false)  
);  
GUILayout.EndHorizontal();  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Ejection angle (curr/trans):");  
GUILayout.Label(  
adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°",  
GUILayout.ExpandWidth(false)  
);  
GUILayout.EndHorizontal();  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Transfer velocity:");  
GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));  
GUILayout.EndHorizontal();  
}  
 
public static void display_transfer_angles_PLANET2MOON(CelestialBody body, Vessel vessel)  
{  
double dv1 = Tools.Younata_DeltaVToGetToOtherBody(  
(vessel.mainBody.gravParameter / 1000000000),  
(vessel.orbit.semiMajorAxis / 1000),  
(body.orbit.semiMajorAxis / 1000)  
);  
 
double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(  
vessel.orbit.semiMajorAxis,  
body.orbit.semiMajorAxis,  
vessel.mainBody.gravParameter  
);  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Phase angle (curr/trans):");  
GUILayout.Label(  
Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",  
GUILayout.ExpandWidth(false)  
);  
GUILayout.EndHorizontal();  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Transfer velocity:");  
GUILayout.Label((dv1 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));  
GUILayout.EndHorizontal();  
}  
 
public static void display_transfer_angles_MOON2MOON(CelestialBody body, Vessel vessel)  
{  
double dv1 = Tools.Younata_DeltaVToGetToOtherBody(  
(vessel.mainBody.referenceBody.gravParameter / 1000000000),  
(vessel.mainBody.orbit.semiMajorAxis / 1000),  
(body.orbit.semiMajorAxis / 1000)  
);  
double dv2 = Tools.Younata_DeltaVToExitSOI(  
(vessel.mainBody.gravParameter / 1000000000),  
(vessel.orbit.semiMajorAxis / 1000),  
(vessel.mainBody.sphereOfInfluence / 1000),  
Math.Abs(dv1)  
);  
double trans_ejection_angle = Tools.Younata_TransferBurnPoint(  
(vessel.orbit.semiMajorAxis / 1000),  
dv2,  
(Math.PI / 2.0),  
(vessel.mainBody.gravParameter / 1000000000)  
);  
 
double curr_phase_angle = Tools.Adammada_CurrrentPhaseAngle(  
body.orbit.LAN,  
body.orbit.orbitPercent,  
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,  
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent  
);  
double curr_ejection_angle = Tools.Adammada_CurrentEjectionAngle(  
FlightGlobals.ActiveVessel.longitude,  
FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle,  
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,  
FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent  
);  
 
double trans_phase_angle = Tools.Nivvy_CalcTransferPhaseAngle(  
vessel.mainBody.orbit.semiMajorAxis,  
body.orbit.semiMajorAxis,  
vessel.mainBody.referenceBody.gravParameter  
) % 360;  
 
double adj_phase_angle = Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle);  
//double adj_ejection_angle = adjustCurrEjectionAngle(trans_phase_angle, curr_ejection_angle);  
 
//new stuff  
//  
double adj_trans_ejection_angle = Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle);  
double adj_curr_ejection_angle = Tools.adjust_current_ejection_angle(curr_ejection_angle);  
//  
//  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Phase angle (curr/trans):");  
GUILayout.Label(  
adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",  
GUILayout.ExpandWidth(false)  
);  
GUILayout.EndHorizontal();  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Ejection angle (curr/trans):");  
GUILayout.Label(  
adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°",  
GUILayout.ExpandWidth(false)  
);  
GUILayout.EndHorizontal();  
 
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));  
GUILayout.Label("Transfer velocity:");  
GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));  
GUILayout.EndHorizontal();  
}  
// This implementation is adapted from FARGUIUtils.ClampToScreen  
public static Rect ClampRectToScreen(Rect window, int xMargin, int yMargin)  
{  
window.x = Mathf.Clamp(window.x, xMargin - window.width, Screen.width - xMargin);  
window.y = Mathf.Clamp(window.y, yMargin - window.height, Screen.height - yMargin);  
 
return window;  
}  
 
public static Rect ClampRectToScreen(Rect window, int Margin)  
{  
return ClampRectToScreen(window, Margin, Margin);  
}  
 
public static Rect ClampRectToScreen(Rect window)  
{  
return ClampRectToScreen(window, 30);  
}  
 
public static Vector2 ClampV2ToScreen(Vector2 vec, uint xMargin, uint yMargin)  
{  
vec.x = Mathf.Clamp(vec.x, xMargin, Screen.width - xMargin);  
vec.y = Mathf.Clamp(vec.y, yMargin, Screen.height - yMargin);  
 
return vec;  
}  
 
public static Vector2 ClampV2ToScreen(Vector2 vec, uint Margin)  
{  
return ClampV2ToScreen(vec, Margin, Margin);  
}  
 
public static Vector2 ClampV2ToScreen(Vector2 vec)  
{  
return ClampV2ToScreen(vec, 15);  
}  
// UNDONE: This seems messy. Can we clean it up?  
public static Rect DockToWindow(Rect icon, Rect window)  
{  
// We can't set the x and y of the center point directly, so build a new vector.  
Vector2 center = new Vector2();  
 
// If we are near the top or bottom of the screen...  
if (window.yMax > Screen.height - icon.height ||  
window.yMin < icon.height)  
{  
// If we are in a corner...  
if (window.xMax > Screen.width - icon.width ||  
window.xMin < icon.width)  
{  
// If it is a top corner, put the icon below the window.  
if (window.yMax < Screen.height / 2)  
{  
center.y = window.yMax + icon.height / 2;  
}  
// If it is a bottom corner, put the icon above the window.  
else  
{  
center.y = window.yMin - icon.height / 2;  
}  
}  
// If we are not in a corner...  
else  
{  
// If we are along the top edge, align the icon's top edge with the top edge of the window  
if (window.yMax > Screen.height / 2)  
{  
center.y = window.yMax - icon.height / 2;  
}  
// If we are along the bottom edge, align the icon's bottom edge with the bottom edge of the window  
else  
{  
center.y = window.yMin + icon.height / 2;  
}  
}  
 
// At the top or bottom, if we are towards the right, put the icon to the right of the window  
if (window.center.x < Screen.width / 2)  
{  
center.x = window.xMin - icon.width / 2;  
}  
// At the top or bottom, if we are towards the left, put the icon to the left of the window  
else  
{  
center.x = window.xMax + icon.width / 2;  
}  
 
}  
// If we are not along the top or bottom of the screen...  
else  
{  
// By default, center the icon above the window  
center.y = window.yMin - icon.height / 2;  
center.x = window.center.x;  
 
// If we are along a side...  
if (window.xMax > Screen.width - icon.width ||  
window.xMin < icon.width)  
{  
// UNDONE: I'm not sure I like the feel of this part.  
// If we are along a side towards the bottom, put the icon below the window  
if (window.center.y > Screen.height / 2)  
{  
center.y = window.yMax + icon.height / 2;  
}  
 
// Along the left side, align the left edge of the icon with the left edge of the window.  
if (window.xMax > Screen.width - icon.width)  
{  
center.x = window.xMax - icon.width / 2;  
}  
// Along the right side, align the right edge of the icon with the right edge of the window.  
else if (window.xMin < icon.width)  
{  
center.x = window.xMin + icon.width / 2;  
}  
}  
}  
 
// Assign the vector to the center of the rect.  
icon.center = center;  
 
// Return the icon's position.  
return icon;  
}  
 
public static ExperimentSituations GetExperimentSituation(this Vessel vessel)  
{  
Vessel.Situations situation = vessel.situation;  
 
switch (situation)  
{  
case Vessel.Situations.PRELAUNCH:  
case Vessel.Situations.LANDED:  
return ExperimentSituations.SrfLanded;  
case Vessel.Situations.SPLASHED:  
return ExperimentSituations.SrfSplashed;  
case Vessel.Situations.FLYING:  
if (vessel.altitude < (double)vessel.mainBody.scienceValues.flyingAltitudeThreshold)  
{  
return ExperimentSituations.FlyingLow;  
}  
else  
{  
return ExperimentSituations.FlyingHigh;  
}  
}  
 
if (vessel.altitude < (double)vessel.mainBody.scienceValues.spaceAltitudeThreshold)  
{  
return ExperimentSituations.InSpaceLow;  
}  
else  
{  
return ExperimentSituations.InSpaceHigh;  
}  
}  
 
public static double Radius(this Vessel vessel)  
{  
double radius;  
 
radius = vessel.altitude;  
 
if (vessel.mainBody != null)  
{  
radius += vessel.mainBody.Radius;  
}  
 
return radius;  
}  
 
public static double TryGetLastMass(this Engineer.VesselSimulator.SimManager simManager)  
{  
if (simManager.Stages == null || simManager.Stages.Length <= Staging.lastStage)  
{  
return double.NaN;  
}  
 
return simManager.Stages[Staging.lastStage].totalMass;  
}  
 
public static string HumanString(this ExperimentSituations situation)  
{  
switch (situation)  
{  
case ExperimentSituations.FlyingHigh:  
return "Upper Atmosphere";  
case ExperimentSituations.FlyingLow:  
return "Flying";  
case ExperimentSituations.SrfLanded:  
return "Surface";  
case ExperimentSituations.InSpaceLow:  
return "Near in Space";  
case ExperimentSituations.InSpaceHigh:  
return "High in Space";  
case ExperimentSituations.SrfSplashed:  
return "Splashed Down";  
default:  
return "Unknown";  
}  
}  
 
private static ScreenMessage debugmsg = new ScreenMessage("", 2f, ScreenMessageStyle.UPPER_RIGHT);  
 
[System.Diagnostics.Conditional("DEBUG")]  
public static void PostDebugMessage(string Msg)  
{  
if (HighLogic.LoadedScene > GameScenes.SPACECENTER)  
{  
debugmsg.message = Msg;  
ScreenMessages.PostScreenMessage(debugmsg, true);  
}  
 
KSPLog.print(Msg);  
}  
}  
}  
  // VOID
  //
  // VOID_DataValue.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  // TODO: Remove ToadicusTools. prefixes after refactor is done.
 
  using System;
  using ToadicusTools.MuMechTools;
  using ToadicusTools.Text;
  using UnityEngine;
 
  namespace VOID
  {
  public class VOID_DataValue<T> : IVOID_DataValue
  {
  /*
  * Static Members
  * */
  public static implicit operator T(VOID_DataValue<T> v)
  {
  return (T)v.Value;
  }
 
  /*
  * Instance Members
  * */
  /*
  * Fields
  * */
  protected T cache;
  protected Func<T> ValueFunc;
  protected float lastUpdate;
 
  /*
  * Properties
  * */
  public string Label { get; protected set; }
  public string Units { get; protected set; }
 
  object IVOID_DataValue.Value
  {
  get
  {
  return this.Value;
  }
  }
 
  public T Value
  {
  get
  {
  if (
  (VOID_Data.Core.UpdateTimer - this.lastUpdate > VOID_Data.Core.UpdatePeriod) ||
  (this.lastUpdate > VOID_Data.Core.UpdateTimer)
  )
  {
  this.Refresh();
  }
  return (T)this.cache;
  }
  }
 
  /*
  * Methods
  * */
  public VOID_DataValue(string Label, Func<T> ValueFunc, string Units = "")
  {
  this.Label = Label;
  this.Units = Units;
  this.ValueFunc = ValueFunc;
  this.lastUpdate = 0;
 
  VOID_Data.DataValues[this.GetHashCode()] = this;
  }
 
  public void Refresh()
  {
  this.cache = this.ValueFunc.Invoke ();
  this.lastUpdate = VOID_Data.Core.UpdateTimer;
  }
 
  public T GetFreshValue()
  {
  this.Refresh ();
  return (T)this.cache;
  }
 
  public virtual string ValueUnitString()
  {
  if (this.Value == null || this.Units == null)
  {
  using (PooledStringBuilder sb = PooledStringBuilder.Get())
  {
  if (this.Value == null)
  {
  sb.AppendFormat("{0}: Value is null during ValueUnitString\n", this.Label);
  }
  if (this.Units == null)
  {
  sb.AppendFormat("{0}: Units is null during ValueUnitString\n", this.Label);
  }
 
  ToadicusTools.Logging.PostErrorMessage(sb.ToString());
  }
  }
 
  return string.Format("{0}{1}", this.Value == null ? "NULL" : this.Value.ToString(), this.Units);
  }
 
  public virtual void DoGUIHorizontal()
  {
  GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true));
  GUILayout.Label (this.Label + ":");
  GUILayout.FlexibleSpace ();
  GUILayout.Label (this.ValueUnitString(), GUILayout.ExpandWidth (false));
  GUILayout.EndHorizontal ();
  }
 
  public override int GetHashCode()
  {
  int hash;
  unchecked
  {
  hash = 79999;
 
  hash = hash * 104399 + this.Label.GetHashCode();
  hash = hash * 104399 + this.ValueFunc.GetHashCode();
  hash = hash * 104399 + this.Units.GetHashCode();
  }
 
  return hash;
  }
 
  public override string ToString()
  {
  return string.Format (
  "{0}: {1}{2}",
  this.Label,
  this.Value.ToString (),
  this.Units
  );
  }
  }
 
  public abstract class VOID_NumValue<T> : VOID_DataValue<T>, IFormattable
  where T : IFormattable, IConvertible, IComparable
  {
  public static IFormatProvider formatProvider = SIFormatProvider.SIFormatter;
 
  public static implicit operator Double(VOID_NumValue<T> v)
  {
  return v.ToDouble();
  }
 
  public static implicit operator Int32(VOID_NumValue<T> v)
  {
  return v.ToInt32();
  }
 
  public static implicit operator Single(VOID_NumValue<T> v)
  {
  return v.ToSingle();
  }
 
  public VOID_NumValue(string Label, Func<T> ValueFunc, string Units = "") : base(Label, ValueFunc, Units)
  {
 
  }
 
  public virtual double ToDouble(IFormatProvider provider)
  {
  return this.Value.ToDouble(provider);
  }
 
  public virtual double ToDouble()
  {
  return this.ToDouble(formatProvider);
  }
 
  public virtual int ToInt32(IFormatProvider provider)
  {
  return this.Value.ToInt32(provider);
  }
 
  public virtual int ToInt32()
  {
  return this.ToInt32(formatProvider);
  }
 
  public virtual float ToSingle(IFormatProvider provider)
  {
  return this.Value.ToSingle(provider);
  }
 
  public virtual float ToSingle()
  {
  return this.ToSingle(formatProvider);
  }
 
  public virtual string ToString(string format)
  {
  return this.ToString(format, formatProvider);
  }
 
  public virtual string ToString(string format, IFormatProvider provider)
  {
  return string.Format (
  "{0}{1}",
  this.Value.ToString(format, provider),
  this.Units
  );
  }
 
  public virtual string ToSIString(int digits = 3, int MinMagnitude = 0, int MaxMagnitude = int.MaxValue)
  {
  return string.Format (
  "{0}{1}",
  MuMechTools.MuMech_ToSI (this, digits, MinMagnitude, MaxMagnitude),
  this.Units
  );
  }
 
  public virtual string ValueUnitString(string format)
  {
  return this.Value.ToString(format, formatProvider) + this.Units;
  }
 
  public virtual string ValueUnitString(int digits) {
  return string.Format("{0}{1}", SIFormatProvider.ToSI(this, digits), Units);
  }
 
  public virtual string ValueUnitString(int digits, int MinMagnitude, int MaxMagnitude)
  {
  return MuMechTools.MuMech_ToSI(this, digits, MinMagnitude, MaxMagnitude) + this.Units;
  }
 
  public virtual void DoGUIHorizontal(string format)
  {
  GUILayout.BeginHorizontal (GUILayout.ExpandWidth (true));
  GUILayout.Label (this.Label + ":");
  GUILayout.FlexibleSpace ();
  GUILayout.Label (this.ValueUnitString(format), GUILayout.ExpandWidth (false));
  GUILayout.EndHorizontal ();
  }
 
  public virtual int DoGUIHorizontal(int digits, bool precisionButton = true)
  {
  if (precisionButton)
  {
  return this.DoGUIHorizontalPrec(digits);
  }
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label(this.Label + ":", GUILayout.ExpandWidth(true));
  GUILayout.FlexibleSpace();
  GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false));
  GUILayout.EndHorizontal();
 
  return digits;
  }
 
  public virtual int DoGUIHorizontalPrec(int digits)
  {
  if (digits < 0 || digits > 8)
  {
  digits = 5;
  }
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label(this.Label + "ⁱ:", GUILayout.ExpandWidth(true));
  GUILayout.FlexibleSpace();
 
  GUILayout.Label(this.ValueUnitString(digits), GUILayout.ExpandWidth(false));
 
  GUILayout.EndHorizontal();
 
  if (Event.current.type == EventType.mouseUp)
  {
  Rect lastRect = GUILayoutUtility.GetLastRect();
  if (lastRect.Contains(Event.current.mousePosition))
  {
  ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Changing digits from {1}",
  this.GetType().Name,
  digits
  ));
 
  if (Event.current.button == 0)
  {
  digits = (digits + 3) % 9;
  }
  else if (Event.current.button == 1)
  {
  digits = (digits - 3) % 9;
  }
 
  if (digits < 0)
  {
  digits += 9;
  }
 
  ToadicusTools.Logging.PostDebugMessage(string.Format("{0}: Changed digits to {1}.",
  this.GetType().Name,
  digits
  ));
  }
  }
 
  return digits;
  }
  }
 
  public class VOID_DoubleValue : VOID_NumValue<double>
  {
  public VOID_DoubleValue(string Label, Func<double> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
  }
 
  public class VOID_FloatValue : VOID_NumValue<float>
  {
  public VOID_FloatValue(string Label, Func<float> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
  }
 
  public class VOID_IntValue : VOID_NumValue<int>
  {
  public VOID_IntValue(string Label, Func<int> ValueFunc, string Units) : base(Label, ValueFunc, Units) {}
  }
 
  public class VOID_StrValue : VOID_DataValue<string>
  {
  public VOID_StrValue(string Label, Func<string> ValueFunc) : base(Label, ValueFunc, "") {}
  }
 
  public class VOID_Vector3Value : VOID_DataValue<Vector3>
  {
  public VOID_Vector3Value(string Label, Func<Vector3> ValueFunc, string Units)
  : base(Label, ValueFunc, Units)
  {}
 
  public string ToString(string format)
  {
  return string.Format("{0}: {1}{2}",
  this.Label,
  this.Value.ToString(format),
  this.Units
  );
  }
 
  public string ValueUnitString(string format) {
  return this.Value.ToString(format) + this.Units;
  }
  }
  }
 
 
  // VOID
  //
  // VOID_Localization.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  public static class VOID_Localization
  {
  public static string void_primary = "Primary";
  public static string void_altitude_asl = "Altitude (ASL)";
  public static string void_velocity = "Velocity";
  public static string void_apoapsis = "Apoapsis";
  public static string void_periapsis = "Periapsis";
  }
  // VOID
  //
  // VOID_SaveValue.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  // TODO: Remove ToadicusTools. prefixes after refactor is done.
 
  using KSP;
  using System;
  using System.Collections.Generic;
  using UnityEngine;
 
  namespace VOID
  {
  public struct VOID_SaveValue<T> : IVOID_SaveValue
  {
  private T _value;
  private Type _type;
 
  private VOIDCore Core
  {
  get
  {
  return VOID_Data.Core;
  }
  }
 
  object IVOID_SaveValue.value
  {
  get
  {
  return this.value;
  }
  }
 
  public T value
  {
  get
  {
  return this._value;
  }
  set
  {
  if (this.Core != null && !System.Object.Equals(this._value, value))
  {
  ToadicusTools.Logging.PostDebugMessage (string.Format (
  "VOID: Dirtying config for type {0}." +
  "\n\t Old Value: {1}, New Value: {2}" +
  "\n\t Object.Equals(New, Old): {3}\n" +
  this._type,
  this._value,
  value,
  System.Object.Equals(this._value, value)
  ));
  this.Core.configDirty = true;
  }
  this._value = value;
  }
  }
 
  public Type type
  {
  get
  {
  if (this._type == null && this._value != null)
  {
  this._type = this._value.GetType ();
  }
  return this._type;
  }
  set
  {
  this._type = value;
  }
  }
 
  public void SetValue(object v)
  {
  this.value = (T)v;
  }
 
  public static implicit operator T(VOID_SaveValue<T> v)
  {
  return (T)v.value;
  }
 
  public static explicit operator VOID_SaveValue<T>(T v)
  {
  VOID_SaveValue<T> r = new VOID_SaveValue<T>();
  r.type = v.GetType();
  r.value = v;
 
  return r;
  }
 
  public override string ToString()
  {
  return this.value.ToString();
  }
  }
  }
 
 
  // VOID © 2015 toadicus
  //
  // This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a
  // copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
 
  using KerbalEngineer.VesselSimulator;
  using KSP;
  using System;
  using System.Collections.Generic;
  using UnityEngine;
 
  namespace VOID
  {
  public static class VOID_StageExtensions
  {
  public static double NominalThrust(this Stage stage)
  {
  if (stage.actualThrust == 0d)
  {
  return stage.thrust;
  }
  else
  {
  return stage.actualThrust;
  }
  }
 
  public static double MassFlow(this Stage stage)
  {
  double stageIsp = VOID_Data.Core.LastStage.isp;
  double stageThrust = stage.NominalThrust();
 
  return stageThrust / (stageIsp * VOID_Data.KerbinGee);
  }
  }
  }
 
 
  // VOID
  //
  // VOID_Tools.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KSP;
  using System;
  using System.Collections.Generic;
  using ToadicusTools;
  using UnityEngine;
 
  namespace VOID
  {
  public static class VOID_Tools
  {
  #region CelestialBody Utilities
  public static bool hasAncestor(this CelestialBody bodyA, CelestialBody bodyB)
  {
  if (bodyA == null || bodyB == null)
  {
  return false;
  }
 
  while (bodyA.orbitDriver != null)
  {
  if (bodyA.orbit.referenceBody == bodyB)
  {
  return true;
  }
 
  bodyA = bodyA.orbit.referenceBody;
  }
 
  return false;
  }
 
  public static bool NearestRelatedParents(ref CelestialBody bodyA, ref CelestialBody bodyB)
  {
  if (bodyA == null || bodyB == null || bodyA.orbitDriver == null || bodyB.orbitDriver == null)
  {
  throw new ArgumentException(string.Concat(
  "CelestialBody::FindRelatedParents: ",
  "Neither body may be null, and both bodies must have orbits."
  ));
  }
 
  CelestialBody a, b;
 
  a = bodyA;
 
  while (bodyA.orbitDriver != null)
  {
  b = bodyB;
 
  while (b.orbitDriver != null)
  {
  if (a.orbit.referenceBody == b.orbit.referenceBody)
  {
  bodyA = a;
  bodyB = b;
  return true;
  }
 
  b = b.orbit.referenceBody;
  }
 
  a = a.orbit.referenceBody;
  }
 
  return false;
  }
  #endregion
 
  #region VESSEL_EXTENSIONS_SCIENCE
  public static CBAttributeMapSO.MapAttribute GetBiome(this Vessel vessel)
  {
  CBAttributeMapSO.MapAttribute mapAttribute;
 
  try
  {
  CBAttributeMapSO BiomeMap = vessel.mainBody.BiomeMap;
 
  double lat = vessel.latitude * Math.PI / 180d;
  double lon = vessel.longitude * Math.PI / 180d;
 
  mapAttribute = BiomeMap.GetAtt(lat, lon);
 
  /*
  lon -= Math.PI / 2d;
 
  if (lon < 0d)
  {
  lon += 2d * Math.PI;
  }
 
  float v = (float)(lat / Math.PI) + 0.5f;
  float u = (float)(lon / (2d * Math.PI));
 
  Color pixelBilinear = BiomeMap.Map.GetPixelBilinear(u, v);
  mapAttribute = BiomeMap.defaultAttribute;
 
  if (BiomeMap.Map != null)
  {
  if (BiomeMap.exactSearch)
  {
  for (int i = 0; i < BiomeMap.Attributes.Length; ++i)
  {
  if (pixelBilinear == BiomeMap.Attributes[i].mapColor)
  {
  mapAttribute = BiomeMap.Attributes[i];
  }
  }
  }
  else
  {
  float zero = 0;
  float num = 1 / zero;
  for (int j = 0; j < BiomeMap.Attributes.Length; ++j)
  {
  Color mapColor = BiomeMap.Attributes[j].mapColor;
  float sqrMagnitude = ((Vector4)(mapColor - pixelBilinear)).sqrMagnitude;
  if (sqrMagnitude < num)
  {
  bool testCase = true;
  if (BiomeMap.nonExactThreshold != -1)
  {
  testCase = (sqrMagnitude < BiomeMap.nonExactThreshold);
  }
  if (testCase)
  {
  mapAttribute = BiomeMap.Attributes[j];
  num = sqrMagnitude;
  }
  }
  }
  }
  }
  */
  }
  catch (NullReferenceException)
  {
  mapAttribute = new CBAttributeMapSO.MapAttribute();
  mapAttribute.name = "N/A";
  }
 
  return mapAttribute;
  }
 
  public static ExperimentSituations GetExperimentSituation(this Vessel vessel)
  {
  if (vessel == null)
  {
  return ExperimentSituations.SrfSplashed;
  }
 
  Vessel.Situations situation = vessel.situation;
 
  switch (situation)
  {
  case Vessel.Situations.PRELAUNCH:
  case Vessel.Situations.LANDED:
  return ExperimentSituations.SrfLanded;
  case Vessel.Situations.SPLASHED:
  return ExperimentSituations.SrfSplashed;
  case Vessel.Situations.FLYING:
  if (vessel.altitude < (double)vessel.mainBody.scienceValues.flyingAltitudeThreshold)
  {
  return ExperimentSituations.FlyingLow;
  }
  else
  {
  return ExperimentSituations.FlyingHigh;
  }
  }
 
  if (vessel.altitude < (double)vessel.mainBody.scienceValues.spaceAltitudeThreshold)
  {
  return ExperimentSituations.InSpaceLow;
  }
  else
  {
  return ExperimentSituations.InSpaceHigh;
  }
  }
 
  public static string HumanString(this ExperimentSituations situation)
  {
  switch (situation)
  {
  case ExperimentSituations.FlyingHigh:
  return "Upper Atmosphere";
  case ExperimentSituations.FlyingLow:
  return "Flying";
  case ExperimentSituations.SrfLanded:
  return "Surface";
  case ExperimentSituations.InSpaceLow:
  return "Near in Space";
  case ExperimentSituations.InSpaceHigh:
  return "High in Space";
  case ExperimentSituations.SrfSplashed:
  return "Splashed Down";
  default:
  return "Unknown";
  }
  }
  #endregion
 
  #region VESSEL_EXTENSIONS_LAT_LONG
  public static string GetLongitudeString(this Vessel vessel, string format = "F4")
  {
  string dir_long = "W";
  double v_long = vessel.longitude;
 
  v_long = FixDegreeDomain(v_long);
 
  if (v_long < -180d)
  {
  v_long += 360d;
  }
  if (v_long >= 180)
  {
  v_long -= 360d;
  }
 
  if (v_long > 0)
  dir_long = "E";
 
  return string.Format("{0}° {1}", Math.Abs(v_long).ToString(format), dir_long);
  }
 
  public static string GetLatitudeString(this Vessel vessel, string format = "F4")
  {
  string dir_lat = "S";
  double v_lat = vessel.latitude;
  if (v_lat > 0)
  dir_lat = "N";
 
  return string.Format("{0}° {1}", Math.Abs(v_lat).ToString(format), dir_lat);
  }
  #endregion
 
  #region VESSEL_EXTENSIONS_GENERAL
  public static double TrueAltitude(Vessel vessel)
  {
  double trueAltitude = vessel.orbit.altitude - vessel.terrainAltitude;
 
  // HACK: This assumes that on worlds with oceans, all water is fixed at 0 m,
  // and water covers the whole surface at 0 m.
  if (vessel.terrainAltitude < 0 && vessel.mainBody.ocean)
  {
  trueAltitude = vessel.orbit.altitude;
  }
 
  return trueAltitude;
  }
 
  public static double Radius(this Vessel vessel)
  {
  double radius;
 
  radius = vessel.altitude;
 
  if (vessel.mainBody != null)
  {
  radius += vessel.mainBody.Radius;
  }
 
  return radius;
  }
  #endregion
 
  #region GEOMETRY_UTILS
  public static double FixAngleDomain(double Angle, bool Degrees = false)
  {
  double Extent = 2d * Math.PI;
  if (Degrees)
  {
  Extent = 360d;
  }
 
  Angle = Angle % (Extent);
  if (Angle < 0d)
  {
  Angle += Extent;
  }
 
  return Angle;
  }
 
  public static double FixDegreeDomain(double Angle)
  {
  return FixAngleDomain(Angle, true);
  }
  #endregion
 
  #region WINDOW_UTILS
  private static Dictionary<int, GUI.WindowFunction> functionCache;
  public static UnityEngine.GUI.WindowFunction GetWindowHandler(Action<int> func)
  {
  if (functionCache == null)
  {
  functionCache = new Dictionary<int, GUI.WindowFunction>();
  }
 
  int hashCode = func.GetHashCode();
 
  if (!functionCache.ContainsKey(hashCode))
  {
  functionCache[hashCode] = delegate (int id)
  {
  try
  {
  func(id);
  }
  #if !DEBUG
  catch (ArgumentException)
  {
  Debug.LogWarning(
  string.Format("[{0}]: ArgumentException caught during window call." +
  " This may not be a bug when occuring during scene changes.",
  func.Target.GetType().Name
  ));
  }
  #endif
  catch (Exception ex)
  {
  Debug.LogError(
  string.Format("[{0}]: {1} caught during window call.\nMessage:\n{2}\nStackTrace:\n{3}",
  func.Target.GetType().Name,
  ex.GetType().Name,
  ex.Message,
  ex.StackTrace
  ));
  }
  };
  }
 
  return functionCache[hashCode];
  }
 
  public static void UncacheWindow(Action<int> func)
  {
  if (functionCache != null)
  {
  int hashCode = func.GetHashCode();
 
  if (functionCache.ContainsKey(hashCode))
  {
  functionCache.Remove(hashCode);
  }
  }
  }
  #endregion
 
  #region TIME_UTILS
  /// <summary>
  /// Formats the interval given in seconds as a human-friendly
  /// time period in [[[[years, ]days, ]hours, ]minutes, and ]seconds.
  ///
  /// Uses sidereal days, since "6 hours per day" is the Kerbal standard.
  /// </summary>
  /// <returns>Human readable interval</returns>
  /// <param name="seconds"></param>
  public static string FormatInterval(double seconds)
  {
  return UnpackedTime.FromSeconds(seconds).FormatAsSpan();
  }
 
  /// <summary>
  /// Formats the date given in seconds since epoch as a human-friendly
  /// date in the format YY, DD, HH:MM:SS
  /// </summary>
  /// <returns>The date.</returns>
  /// <param name="seconds">Seconds.</param>
  public static string FormatDate(double seconds)
  {
  return UnpackedTime.FromSeconds(seconds).FormatAsDate();
  }
 
  public class UnpackedTime
  {
  public const double SecondsPerMinute = 60d;
  public const double SecondsPerHour = 3600d;
 
  public static double SecondsPerDay
  {
  get
  {
  VOID_TimeScale flags = VOID_Data.Core.TimeScale &
  (VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.SOLAR_DAY | VOID_TimeScale.ROUNDED_SCALE);
 
  switch (flags)
  {
  // Earth day, sidereal
  case 0:
  return 86164.1d;
  // Earth day, solar (also rounded)
  case VOID_TimeScale.ROUNDED_SCALE | VOID_TimeScale.SOLAR_DAY:
  case VOID_TimeScale.ROUNDED_SCALE:
  case VOID_TimeScale.SOLAR_DAY:
  return 86400d;
  // Kerbin day, solar
  case VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.SOLAR_DAY:
  return 21650.813d;
  // Kerbin day, sidereal (also rounded)
  default:
  return 21600d;
  }
  }
  }
 
  public static double SecondsPerYear
  {
  get
  {
  VOID_TimeScale flags = VOID_Data.Core.TimeScale &
  (VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.SOLAR_DAY | VOID_TimeScale.ROUNDED_SCALE);
 
  switch (flags)
  {
  // Earth year, rounded
  case VOID_TimeScale.SOLAR_DAY | VOID_TimeScale.ROUNDED_SCALE:
  case VOID_TimeScale.ROUNDED_SCALE:
  return 60 * 60 * 24 * 365;
  // Kerbin year, rounded
  case VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.SOLAR_DAY | VOID_TimeScale.ROUNDED_SCALE:
  case VOID_TimeScale.KERBIN_TIME | VOID_TimeScale.ROUNDED_SCALE:
  return 60 * 60 * 6 * 426;
  // Earth year, solar time
  case VOID_TimeScale.SOLAR_DAY:
  return 31556925.2507328;
  // Earth year, sidereal time
  case 0:
  return 31558149.7635456d;
  // Kerbin year, solar & sidereal time
  default:
  return 9203544.61750141d;
  }
  }
  }
 
  public static UnpackedTime FromSeconds(double seconds)
  {
  UnpackedTime time = new UnpackedTime();
 
  time.years = (int)(seconds / SecondsPerYear);
 
  seconds %= SecondsPerYear;
 
  time.days = (int)(seconds / SecondsPerDay);
 
  seconds %= SecondsPerDay;
 
  time.hours = (int)(seconds / SecondsPerHour);
 
  seconds %= SecondsPerHour;
 
  time.minutes = (int)(seconds / SecondsPerMinute);
 
  seconds %= SecondsPerMinute;
 
  time.seconds = seconds;
 
  return time;
  }
 
  public static explicit operator UnpackedTime(double seconds)
  {
  return FromSeconds(seconds);
  }
 
  public static implicit operator double(UnpackedTime time)
  {
  return time.ToSeconds();
  }
 
  public static UnpackedTime operator+ (UnpackedTime lhs, UnpackedTime rhs)
  {
  return FromSeconds(lhs.ToSeconds() + rhs.ToSeconds());
  }
 
  public static UnpackedTime operator- (UnpackedTime lhs, UnpackedTime rhs)
  {
  return FromSeconds(lhs.ToSeconds() - rhs.ToSeconds());
  }
 
  public int years;
  public int days;
  public int hours;
  public int minutes;
  public double seconds;
 
  public double ToSeconds()
  {
  return (double)years * SecondsPerYear +
  (double)days * SecondsPerDay +
  (double)hours * SecondsPerHour +
  (double)minutes * SecondsPerMinute +
  seconds;
  }
 
  public string FormatAsSpan()
  {
  string format_1 = "{0:D1}y {1:D1}d {2:D2}h {3:D2}m {4:00.0}s";
  string format_2 = "{0:D1}d {1:D2}h {2:D2}m {3:00.0}s";
  string format_3 = "{0:D2}h {1:D2}m {2:00.0}s";
  string format_4 = "{0:D2}m {1:00.0}s";
  string format_5 = "{0:00.0}s";
 
  if (this.years > 0)
  {
  return string.Format(format_1, this.years, this.days, this.hours, this.minutes, this.seconds);
  }
  else if (this.days > 0)
  {
  return string.Format(format_2, this.days, this.hours, this.minutes, this.seconds);
  }
  else if (this.hours > 0)
  {
  return string.Format(format_3, this.hours, this.minutes, this.seconds);
  }
  else if (this.minutes > 0)
  {
  return string.Format(format_4, this.minutes, this.seconds);
  }
  else
  {
  return string.Format(format_5, this.seconds);
  }
  }
 
  public string FormatAsDate()
  {
  string format = "Y{0:#0}, D{1:#0} {2:00}:{3:00}:{4:00.0}s";
 
  return string.Format(format, years + 1, days + 1, hours, minutes, seconds);
  }
 
  public UnpackedTime(int years, int days, int hours, int minutes, double seconds)
  {
  this.years = years;
  this.days = days;
  this.hours = hours;
  this.minutes = minutes;
  this.seconds = seconds;
  }
 
  public UnpackedTime() : this(0, 0, 0, 0, 0d) {}
  }
  #endregion
 
  public static string UppercaseFirst(string s)
  {
  if (string.IsNullOrEmpty(s))
  {
  return string.Empty;
  }
  char[] a = s.ToCharArray();
  a[0] = char.ToUpper(a[0]);
  return new string(a);
  }
 
  //transfer angles
  public static double Nivvy_CalcTransferPhaseAngle(double r_current, double r_target, double grav_param)
  {
  r_target /= 1000;
  r_current /= 1000;
  grav_param /= 1000000000;
 
  double midpoint = (r_target + r_current) / 2;
 
  double T_target = (2 * Math.PI) * Math.Sqrt((r_target * r_target * r_target) / grav_param);
  double T_transfer = (2 * Math.PI) * Math.Sqrt((midpoint * midpoint * midpoint) / grav_param);
  return 360 * (0.5 - (T_transfer / (2 * T_target)));
  }
 
  public static double Younata_DeltaVToGetToOtherBody(double mu, double r1, double r2)
  {
  /*
  def deltaVToGetToOtherBody(mu, r1, r2):
  # mu = gravity param of common orbiting body of r1 and r2
  # (e.g. for mun to minmus, mu is kerbin's gravity param
  # r1 = initial body's orbit radius
  # r2 = target body's orbit radius
 
  # return value is km/s
  sur1 = math.sqrt(mu / r1)
  sr1r2 = math.sqrt(float(2*r2)/float(r1+r2))
  mult = sr1r2 - 1
  return sur1 * mult
  */
  double sur1, sr1r2, mult;
  sur1 = Math.Sqrt(mu / r1);
  sr1r2 = Math.Sqrt((2 * r2) / (r1 + r2));
  mult = sr1r2 - 1;
  return sur1 * mult;
  }
 
  public static double Younata_DeltaVToExitSOI(double mu, double r1, double r2, double v)
  {
  /*
  def deltaVToExitSOI(mu, r1, r2, v):
  # mu = gravity param of current body
  # r1 = current orbit radius
  # r2 = SOI radius
  # v = SOI exit velocity
  foo = r2 * (v**2) - 2 * mu
  bar = r1 * foo + (2 * r2 * mu)
  r = r1*r2
  return math.sqrt(bar / r)
  */
  double foo = r2 * (v * v) - 2 * mu;
  double bar = r1 * foo + (2 * r2 * mu);
  double r = r1 * r2;
  return Math.Sqrt(bar / r);
  }
 
  public static double Younata_TransferBurnPoint(double r, double v, double angle, double mu)
  {
  /*
  def transferBurnPoint(r, v, angle, mu):
  # r = parking orbit radius
  # v = ejection velocity
  # angle = phase angle (from function phaseAngle())
  # mu = gravity param of current body.
  epsilon = ((v**2)/2) - (mu / r)
  h = r * v * math.sin(angle)
  e = math.sqrt(1 + ((2 * epsilon * h**2)/(mu**2)))
  theta = math.acos(1.0 / e)
  degrees = theta * (180.0 / math.pi)
  return 180 - degrees
  */
  double epsilon, h, ee, theta, degrees;
  epsilon = ((v * v) / 2) - (mu / r);
  h = r * v * Math.Sin(angle);
  ee = Math.Sqrt(1 + ((2 * epsilon * (h * h)) / (mu * mu)));
  theta = Math.Acos(1.0 / ee);
  degrees = theta * (180.0 / Math.PI);
  return 180 - degrees;
  // returns the ejection angle
  }
 
  public static double Adammada_CurrrentPhaseAngle(
  double body_LAN,
  double body_orbitPct,
  double origin_LAN,
  double origin_orbitPct
  )
  {
  double angle = (body_LAN / 360 + body_orbitPct) - (origin_LAN / 360 + origin_orbitPct);
  if (angle > 1)
  angle = angle - 1;
  if (angle < 0)
  angle = angle + 1;
  if (angle > 0.5)
  angle = angle - 1;
  angle = angle * 360;
  return angle;
  }
 
  public static double Adammada_CurrentEjectionAngle(
  double vessel_long,
  double origin_rotAngle,
  double origin_LAN,
  double origin_orbitPct
  )
  {
  //double eangle = ((FlightGlobals.ActiveVOID.vessel.longitude + orbiting.rotationAngle) - (orbiting.orbit.LAN / 360 + orbiting.orbit.orbitPercent) * 360);
  double eangle = ((vessel_long + origin_rotAngle) - (origin_LAN / 360 + origin_orbitPct) * 360);
 
  while (eangle < 0)
  eangle = eangle + 360;
  while (eangle > 360)
  eangle = eangle - 360;
  if (eangle < 270)
  eangle = 90 - eangle;
  else
  eangle = 450 - eangle;
  return eangle;
  }
 
  public static double mrenigma03_calcphase(Vessel vessel, CelestialBody target) //calculates phase angle between the current body and target body
  {
  Vector3 vecthis = new Vector3();
  Vector3 vectarget = new Vector3();
  vectarget = target.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
 
  if ((vessel.mainBody.name == "Sun") || (vessel.mainBody.referenceBody.referenceBody.name == "Sun"))
  {
  vecthis = vessel.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
  }
  else
  {
  vecthis = vessel.mainBody.orbit.getRelativePositionAtUT(Planetarium.GetUniversalTime());
  }
 
  vecthis = Vector3.Project(new Vector3(vecthis.x, 0, vecthis.z), vecthis);
  vectarget = Vector3.Project(new Vector3(vectarget.x, 0, vectarget.z), vectarget);
 
  Vector3 prograde = new Vector3();
  prograde = Quaternion.AngleAxis(90, Vector3.forward) * vecthis;
 
  double phase = Vector3.Angle(vecthis, vectarget);
 
  if (Vector3.Angle(prograde, vectarget) > 90)
  phase = 360 - phase;
 
  return (phase + 360) % 360;
  }
 
  public static double adjustCurrPhaseAngle(double transfer_angle, double curr_phase)
  {
  if (transfer_angle < 0)
  {
  if (curr_phase > 0)
  return (-1 * (360 - curr_phase));
  else if (curr_phase < 0)
  return curr_phase;
  }
  else if (transfer_angle > 0)
  {
  if (curr_phase > 0)
  return curr_phase;
  else if (curr_phase < 0)
  return (360 + curr_phase);
  }
  return curr_phase;
  }
 
  public static double adjust_current_ejection_angle(double curr_ejection)
  {
  //curr_ejection WILL need to be adjusted once for all transfers as it returns values ranging -180 to 180
  // need 0-360 instead
  //
  // ie i have -17 in the screenshot
  // need it to show 343
  //
  // do this
  //
  // if < 0, add curr to 360 // 360 + (-17) = 343
  // else its good as it is
 
  if (curr_ejection < 0)
  return 360 + curr_ejection;
  else
  return curr_ejection;
 
  }
 
  public static double adjust_transfer_ejection_angle(double trans_ejection, double trans_phase)
  {
  // if transfer_phase_angle < 0 its a lower transfer
  //180 + curr_ejection
  // else if transfer_phase_angle > 0 its good as it is
 
  if (trans_phase < 0)
  return 180 + trans_ejection;
  else
  return trans_ejection;
 
  }
 
  public static void display_transfer_angles_SUN2PLANET(CelestialBody body, Vessel vessel)
  {
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Phase angle (curr/trans):");
  GUILayout.Label(
  VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + VOID_Tools.Nivvy_CalcTransferPhaseAngle(
  vessel.orbit.semiMajorAxis,
  body.orbit.semiMajorAxis,
  vessel.mainBody.gravParameter
  ).ToString("F3") + "°",
  GUILayout.ExpandWidth(false)
  );
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Transfer velocity:");
  GUILayout.Label(
  (VOID_Tools.Younata_DeltaVToGetToOtherBody(
  (vessel.mainBody.gravParameter / 1000000000),
  (vessel.orbit.semiMajorAxis / 1000),
  (body.orbit.semiMajorAxis / 1000)
  ) * 1000).ToString("F2") + "m/s",
  GUILayout.ExpandWidth(false)
  );
  GUILayout.EndHorizontal();
  }
 
  public static void display_transfer_angles_PLANET2PLANET(CelestialBody body, Vessel vessel)
  {
  double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody(
  (vessel.mainBody.referenceBody.gravParameter / 1000000000),
  (vessel.mainBody.orbit.semiMajorAxis / 1000),
  (body.orbit.semiMajorAxis / 1000)
  );
  double dv2 = VOID_Tools.Younata_DeltaVToExitSOI(
  (vessel.mainBody.gravParameter / 1000000000),
  (vessel.orbit.semiMajorAxis / 1000),
  (vessel.mainBody.sphereOfInfluence / 1000),
  Math.Abs(dv1)
  );
 
  double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint(
  (vessel.orbit.semiMajorAxis / 1000),
  dv2,
  (Math.PI / 2.0),
  (vessel.mainBody.gravParameter / 1000000000)
  );
  double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle(
  FlightGlobals.ActiveVessel.longitude,
  FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle,
  FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,
  FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent
  );
 
  double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle(
  vessel.mainBody.orbit.semiMajorAxis,
  body.orbit.semiMajorAxis,
  vessel.mainBody.referenceBody.gravParameter
  ) % 360;
  double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle(
  body.orbit.LAN,
  body.orbit.orbitPercent,
  FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,
  FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent
  );
 
  double adj_phase_angle = VOID_Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle);
  double adj_trans_ejection_angle = VOID_Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle);
  double adj_curr_ejection_angle = VOID_Tools.adjust_current_ejection_angle(curr_ejection_angle);
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Phase angle (curr/trans):");
  GUILayout.Label(
  adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",
  GUILayout.ExpandWidth(false)
  );
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Ejection angle (curr/trans):");
  GUILayout.Label(
  adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°",
  GUILayout.ExpandWidth(false)
  );
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Transfer velocity:");
  GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
  GUILayout.EndHorizontal();
  }
 
  public static void display_transfer_angles_PLANET2MOON(CelestialBody body, Vessel vessel)
  {
  double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody(
  (vessel.mainBody.gravParameter / 1000000000),
  (vessel.orbit.semiMajorAxis / 1000),
  (body.orbit.semiMajorAxis / 1000)
  );
 
  double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle(
  vessel.orbit.semiMajorAxis,
  body.orbit.semiMajorAxis,
  vessel.mainBody.gravParameter
  );
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Phase angle (curr/trans):");
  GUILayout.Label(
  VOID_Tools.mrenigma03_calcphase(vessel, body).ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",
  GUILayout.ExpandWidth(false)
  );
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Transfer velocity:");
  GUILayout.Label((dv1 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
  GUILayout.EndHorizontal();
  }
 
  public static void display_transfer_angles_MOON2MOON(CelestialBody body, Vessel vessel)
  {
  double dv1 = VOID_Tools.Younata_DeltaVToGetToOtherBody(
  (vessel.mainBody.referenceBody.gravParameter / 1000000000),
  (vessel.mainBody.orbit.semiMajorAxis / 1000),
  (body.orbit.semiMajorAxis / 1000)
  );
  double dv2 = VOID_Tools.Younata_DeltaVToExitSOI(
  (vessel.mainBody.gravParameter / 1000000000),
  (vessel.orbit.semiMajorAxis / 1000),
  (vessel.mainBody.sphereOfInfluence / 1000),
  Math.Abs(dv1)
  );
  double trans_ejection_angle = VOID_Tools.Younata_TransferBurnPoint(
  (vessel.orbit.semiMajorAxis / 1000),
  dv2,
  (Math.PI / 2.0),
  (vessel.mainBody.gravParameter / 1000000000)
  );
 
  double curr_phase_angle = VOID_Tools.Adammada_CurrrentPhaseAngle(
  body.orbit.LAN,
  body.orbit.orbitPercent,
  FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,
  FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent
  );
  double curr_ejection_angle = VOID_Tools.Adammada_CurrentEjectionAngle(
  FlightGlobals.ActiveVessel.longitude,
  FlightGlobals.ActiveVessel.orbit.referenceBody.rotationAngle,
  FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.LAN,
  FlightGlobals.ActiveVessel.orbit.referenceBody.orbit.orbitPercent
  );
 
  double trans_phase_angle = VOID_Tools.Nivvy_CalcTransferPhaseAngle(
  vessel.mainBody.orbit.semiMajorAxis,
  body.orbit.semiMajorAxis,
  vessel.mainBody.referenceBody.gravParameter
  ) % 360;
 
  double adj_phase_angle = VOID_Tools.adjustCurrPhaseAngle(trans_phase_angle, curr_phase_angle);
  //double adj_ejection_angle = adjustCurrEjectionAngle(trans_phase_angle, curr_ejection_angle);
 
  //new stuff
  //
  double adj_trans_ejection_angle = VOID_Tools.adjust_transfer_ejection_angle(trans_ejection_angle, trans_phase_angle);
  double adj_curr_ejection_angle = VOID_Tools.adjust_current_ejection_angle(curr_ejection_angle);
  //
  //
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Phase angle (curr/trans):");
  GUILayout.Label(
  adj_phase_angle.ToString("F3") + "° / " + trans_phase_angle.ToString("F3") + "°",
  GUILayout.ExpandWidth(false)
  );
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Ejection angle (curr/trans):");
  GUILayout.Label(
  adj_curr_ejection_angle.ToString("F3") + "° / " + adj_trans_ejection_angle.ToString("F3") + "°",
  GUILayout.ExpandWidth(false)
  );
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label("Transfer velocity:");
  GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
  GUILayout.EndHorizontal();
  }
 
  public static string get_heading_text(double heading)
  {
  if (heading > 348.75 || heading <= 11.25)
  return "N";
  else if (heading > 11.25 && heading <= 33.75)
  return "NNE";
  else if (heading > 33.75 && heading <= 56.25)
  return "NE";
  else if (heading > 56.25 && heading <= 78.75)
  return "ENE";
  else if (heading > 78.75 && heading <= 101.25)
  return "E";
  else if (heading > 101.25 && heading <= 123.75)
  return "ESE";
  else if (heading > 123.75 && heading <= 146.25)
  return "SE";
  else if (heading > 146.25 && heading <= 168.75)
  return "SSE";
  else if (heading > 168.75 && heading <= 191.25)
  return "S";
  else if (heading > 191.25 && heading <= 213.75)
  return "SSW";
  else if (heading > 213.75 && heading <= 236.25)
  return "SW";
  else if (heading > 236.25 && heading <= 258.75)
  return "WSW";
  else if (heading > 258.75 && heading <= 281.25)
  return "W";
  else if (heading > 281.25 && heading <= 303.75)
  return "WNW";
  else if (heading > 303.75 && heading <= 326.25)
  return "NW";
  else if (heading > 326.25 && heading <= 348.75)
  return "NNW";
  else
  return "";
  }
  }
 
  public class CBListComparer : IComparer<CelestialBody>
  {
  public int Compare(CelestialBody bodyA, CelestialBody bodyB)
  {
  Logging.PostDebugMessage(this, "got bodyA: {0} & bodyB: {1}", bodyA, bodyB);
 
  if (bodyA == null && bodyB == null)
  {
  Logging.PostDebugMessage(this, "both bodies are null, returning 0");
  return 0;
  }
  if (bodyA == null)
  {
  Logging.PostDebugMessage(this, "bodyA is null, returning -1");
  return -1;
  }
  if (bodyB == null)
  {
  Logging.PostDebugMessage(this, "bodyB is null, returning 1");
  return 1;
  }
 
  Logging.PostDebugMessage(this, "bodies are not null, carrying on");
 
  if (object.ReferenceEquals(bodyA, bodyB))
  {
  Logging.PostDebugMessage(this, "bodies are equal, returning 0");
  return 0;
  }
 
  Logging.PostDebugMessage(this, "bodies are not equal, carrying on");
 
  if (bodyA.orbitDriver == null)
  {
  Logging.PostDebugMessage(this, "bodyA.orbit is null (bodyA is the sun, returning 1");
  return 1;
  }
  if (bodyB.orbitDriver == null)
  {
  Logging.PostDebugMessage(this, "bodyB.orbit is null (bodyB is the sun, returning -1");
  return -1;
  }
 
  Logging.PostDebugMessage(this, "orbits are not null, carrying on");
 
  if (bodyA.orbit.referenceBody == bodyB.orbit.referenceBody)
  {
  Logging.PostDebugMessage(this, "bodies share a parent, comparing SMAs");
  return -bodyA.orbit.semiMajorAxis.CompareTo(bodyB.orbit.semiMajorAxis);
  }
 
  Logging.PostDebugMessage(this, "orbits do not share a parent, carrying on");
 
  if (bodyA.hasAncestor(bodyB))
  {
  Logging.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning -1");
  return -1;
  }
  if (bodyB.hasAncestor(bodyA))
  {
  Logging.PostDebugMessage(this, "bodyA is a moon or sub-moon of bodyB, returning 1");
  return 1;
  }
 
  Logging.PostDebugMessage(this, "bodies do not have an obvious relationship, searching for one");
 
  if (VOID_Tools.NearestRelatedParents(ref bodyA, ref bodyB))
  {
  Logging.PostDebugMessage(this, "good relation {0} and {1}, comparing", bodyA.bodyName, bodyB.bodyName);
  return this.Compare(bodyA, bodyB);
  }
 
  Logging.PostDebugMessage(this, "bad relation {0} and {1}, giving up", bodyA.bodyName, bodyB.bodyName);
 
  return 0;
  }
  }
  }
 
file:b/VOID.csproj (new)
  <?xml version="1.0" encoding="utf-8"?>
  <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
  <Configuration Condition=" '$(Configuration)' == '' ">Debug_win</Configuration>
  <ProductVersion>8.0.30703</ProductVersion>
  <SchemaVersion>2.0</SchemaVersion>
  <ProjectGuid>{45ACC1CC-942C-4A66-BFC7-8BE375938B18}</ProjectGuid>
  <OutputType>Library</OutputType>
  <RootNamespace>VOID</RootNamespace>
  <AssemblyName>VOID</AssemblyName>
  <CodePage>65001</CodePage>
  <UseMSBuildEngine>False</UseMSBuildEngine>
  <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
  <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
  <ReleaseVersion>0.11</ReleaseVersion>
  <SynchReleaseVersion>false</SynchReleaseVersion>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_win|AnyCPU' ">
  <DebugSymbols>true</DebugSymbols>
  <DebugType>full</DebugType>
  <Optimize>false</Optimize>
  <OutputPath>bin\Debug</OutputPath>
  <DefineConstants>DEBUG; TRACE</DefineConstants>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
  <CustomCommands>
  <CustomCommands>
  <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\VOID\Plugins\" />
  </CustomCommands>
  </CustomCommands>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_win|AnyCPU' ">
  <Optimize>false</Optimize>
  <OutputPath>bin\Release</OutputPath>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
  <DefineConstants>TRACE</DefineConstants>
  <CustomCommands>
  <CustomCommands>
  <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ${ProjectDir}\GameData\VOID\Plugins\" />
  </CustomCommands>
  </CustomCommands>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_linux|AnyCPU' ">
  <DebugSymbols>true</DebugSymbols>
  <DebugType>full</DebugType>
  <Optimize>false</Optimize>
  <OutputPath>bin\Debug</OutputPath>
  <DefineConstants>DEBUG; TRACE</DefineConstants>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
  <CustomCommands>
  <CustomCommands>
  <Command type="AfterBuild" command="cp -afv ${TargetFile} ${ProjectDir}/GameData/${ProjectName}/Plugins/" />
  </CustomCommands>
  </CustomCommands>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_linux|AnyCPU' ">
  <Optimize>false</Optimize>
  <OutputPath>bin\Release</OutputPath>
  <DefineConstants>TRACE</DefineConstants>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
  <CustomCommands>
  <CustomCommands>
  <Command type="AfterBuild" command="cp -afv ${TargetFile} ${ProjectDir}/GameData/${ProjectName}/Plugins/" />
  </CustomCommands>
  </CustomCommands>
  </PropertyGroup>
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <ItemGroup>
  <Compile Include="VOID_HUD.cs" />
  <Compile Include="VOID_Orbital.cs" />
  <Compile Include="VOID_SurfAtmo.cs" />
  <Compile Include="VOID_VesselInfo.cs" />
  <Compile Include="VOID_Transfer.cs" />
  <Compile Include="VOID_CBInfoBrowser.cs" />
  <Compile Include="VOID_Rendezvous.cs" />
  <Compile Include="VOID_VesselRegister.cs" />
  <Compile Include="VOID_DataLogger.cs" />
  <Compile Include="VOID_EditorHUD.cs" />
  <Compile Include="Properties\AssemblyInfo.cs" />
  <Compile Include="VOID_HUDAdvanced.cs" />
  <Compile Include="VOID_TWR.cs" />
  <Compile Include="VOID_CareerStatus.cs" />
  <Compile Include="VOID_StageInfo.cs" />
  <Compile Include="VOID_Styles.cs" />
  <Compile Include="VOID_Data.cs" />
  <Compile Include="VOIDMaster_Flight.cs" />
  <Compile Include="VOIDMaster_Editor.cs" />
  <Compile Include="VOIDMaster_SpaceCentre.cs" />
  <Compile Include="VOIDCore_SpaceCentre.cs" />
  <Compile Include="VOIDCore_Flight.cs" />
  <Compile Include="VOIDCore_Editor.cs" />
  <Compile Include="VOIDCore_Generic.cs" />
  <Compile Include="API\IVOID_Module.cs" />
  <Compile Include="API\VOIDCore.cs" />
  <Compile Include="API\IVOID_SaveValue.cs" />
  <Compile Include="API\IVOID_DataValue.cs" />
  <Compile Include="API\VOID_Module.cs" />
  <Compile Include="Tools\VOID_Tools.cs" />
  <Compile Include="Tools\VOID_DataValue.cs" />
  <Compile Include="Tools\VOID_SaveValue.cs" />
  <Compile Include="API\VOID_HUDModule.cs" />
  <Compile Include="API\Attributes\VOID_ScenesAttribute.cs" />
  <Compile Include="API\Attributes\AVOID_SaveValue.cs" />
  <Compile Include="API\VOIDMaster.cs" />
  <Compile Include="API\Attributes\VOID_GameModesAttribute.cs" />
  <Compile Include="VOID_ConfigWindow.cs" />
  <Compile Include="Tools\VOID_Localization.cs" />
  <Compile Include="Tools\VOID_StageExtensions.cs" />
  <Compile Include="API\VOID_SingletonCore.cs" />
  <Compile Include="API\VOID_SingletonWindow.cs" />
  <Compile Include="API\Enums.cs" />
  </ItemGroup>
  <ProjectExtensions>
  <MonoDevelop>
  <Properties>
  <Policies>
  <TextStylePolicy FileWidth="120" TabsToSpaces="False" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
  </Policies>
  </Properties>
  </MonoDevelop>
  </ProjectExtensions>
  <ItemGroup>
  <Reference Include="System">
  <HintPath>..\_KSPAssemblies\System.dll</HintPath>
  </Reference>
  <Reference Include="Assembly-CSharp">
  <HintPath>..\_KSPAssemblies\Assembly-CSharp.dll</HintPath>
  </Reference>
  <Reference Include="UnityEngine">
  <HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath>
  </Reference>
  <Reference Include="KSPUtil">
  <HintPath>..\_KSPAssemblies\KSPUtil.dll</HintPath>
  </Reference>
  <Reference Include="UnityEngine.UI">
  <HintPath>..\_KSPAssemblies\UnityEngine.UI.dll</HintPath>
  </Reference>
  <Reference Include="Assembly-CSharp-firstpass">
  <HintPath>..\_KSPAssemblies\Assembly-CSharp-firstpass.dll</HintPath>
  </Reference>
  </ItemGroup>
  <ItemGroup>
  <ProjectReference Include="..\ToadicusTools\ToadicusTools.csproj">
  <Project>{D48A5542-6655-4149-BC27-B27DF0466F1C}</Project>
  <Name>ToadicusTools</Name>
  </ProjectReference>
  <ProjectReference Include="..\VesselSimulator\VesselSimulator.csproj">
  <Project>{30FD6C0B-D36E-462F-B0FF-F0FAC9C666CF}</Project>
  <Name>VesselSimulator</Name>
  </ProjectReference>
  </ItemGroup>
  <ItemGroup>
  <None Include="GameData\VOID\Textures\ATM_VOID.cfg" />
  </ItemGroup>
  <ItemGroup>
  <Folder Include="API\" />
  <Folder Include="Tools\" />
  <Folder Include="API\Attributes\" />
  </ItemGroup>
  </Project>
 
  // VOID
  //
  // VOID_EditorCore.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KerbalEngineer.VesselSimulator;
  using KSP;
  using System;
  using System.Collections.Generic;
  using UnityEngine;
 
  namespace VOID
  {
  [VOID_Scenes(GameScenes.EDITOR)]
  public class VOIDCore_Editor : VOIDCore_Generic<VOIDCore_Editor>
  {
  public override string SceneKey
  {
  get
  {
  return "EDITOR";
  }
  }
 
 
  public override void FixedUpdate() {}
  }
  }
 
 
  // VOID
  //
  // VOIDCore_Flight.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KSP;
  using System;
  using UnityEngine;
  using ToadicusTools.GUIUtils;
 
  namespace VOID
  {
  [VOID_Scenes(GameScenes.FLIGHT)]
  public class VOIDCore_Flight : VOIDCore_Generic<VOIDCore_Flight>
  {
  public override string SceneKey
  {
  get
  {
  return "FLIGHT";
  }
  }
 
 
  public override void DrawConfigurables()
  {
  if (HighLogic.LoadedSceneIsFlight)
  {
  this.consumeResource.value = Layout.Toggle(this.consumeResource, "Consume Resources");
  }
 
  base.DrawConfigurables();
  }
  }
  }
 
 
  // VOID
  //
  // VOIDCore_Generic.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KerbalEngineer.Editor;
  using KerbalEngineer.Helpers;
  using KerbalEngineer.VesselSimulator;
  using KSP;
  using KSP.UI.Screens;
  using System;
  using System.Collections.Generic;
  using System.Text;
  using ToadicusTools;
  using ToadicusTools.DebugTools;
  using ToadicusTools.Extensions;
  using ToadicusTools.GUIUtils;
  using ToadicusTools.Wrappers;
  using UnityEngine;
 
  namespace VOID
  {
  public abstract class VOIDCore_Generic<T> : VOID_SingletonCore<T>, IVOID_Module, IDisposable
  where T : VOID_Module, new()
  {
  /*
  * Fields
  * */
  protected string VoidName = "VOID";
  protected string VoidVersion;
 
  [AVOID_SaveValue("configValue")]
  protected VOID_SaveValue<int> configVersion = (VOID_SaveValue<int>)VOIDCore.CONFIG_VERSION;
 
  protected List<IVOID_Module> modules = new List<IVOID_Module>();
  protected bool modulesLoaded = false;
 
  protected Texture2D VOIDIconTexture;
  protected string VOIDIconOnActivePath;
  protected string VOIDIconOnInactivePath;
  protected string VOIDIconOffActivePath;
  protected string VOIDIconOffInactivePath;
 
  [AVOID_SaveValue("useToolbarManager")]
  protected VOID_SaveValue<bool> useToolbarManager;
 
  protected GUIStyle iconStyle;
 
  protected int windowBaseID = -96518722;
  protected int windowID = 0;
 
  protected bool GUIStylesLoaded = false;
 
  protected CelestialBody homeBody;
 
  [AVOID_SaveValue("togglePower")]
  public VOID_SaveValue<bool> togglePower = (VOID_SaveValue<bool>)true;
 
  public override bool powerAvailable { get; protected set; }
 
  [AVOID_SaveValue("consumeResource")]
  protected VOID_SaveValue<bool> consumeResource = (VOID_SaveValue<bool>)false;
 
  [AVOID_SaveValue("resourceName")]
  protected VOID_SaveValue<string> resourceName = (VOID_SaveValue<string>)"ElectricCharge";
 
  [AVOID_SaveValue("resourceRate")]
  protected VOID_SaveValue<float> resourceRate = (VOID_SaveValue<float>)0.2f;
 
  [AVOID_SaveValue("updatePeriod")]
  protected VOID_SaveValue<double> updatePeriod = (VOID_SaveValue<double>)(1001f / 15000f);
  protected string stringFrequency;
 
  [AVOID_SaveValue("vesselSimActive")]
  protected VOID_SaveValue<bool> vesselSimActive;
 
  [AVOID_SaveValue("timeScaleFlags")]
  protected VOID_SaveValue<UInt32> timeScaleFlags;
 
  // Load-up housekeeping
  protected bool vesselTypesLoaded = false;
  protected bool simManagerLoaded = false;
 
  protected string defaultSkin = "KSP window 2";
 
  [AVOID_SaveValue("defaultSkin")]
  protected VOID_SaveValue<string> skinName;
  protected int skinIdx;
 
  protected Dictionary<string, GUISkin> validSkins;
  protected List<string> skinNames;
  protected string[] forbiddenSkins =
  {
  "PlaqueDialogSkin",
  "FlagBrowserSkin",
  "SSUITextAreaDefault",
  "ExperimentsDialogSkin",
  "ExpRecoveryDialogSkin",
  "KSP window 1",
  "KSP window 3",
  "KSP window 5",
  "KSP window 6",
  "PartTooltipSkin",
  "KSCContextMenuSkin"
  };
  protected bool skinsLoaded = false;
 
  public override bool configDirty { get; set; }
 
  protected IButton ToolbarButton;
  protected ApplicationLauncherButton AppLauncherButton;
  protected IconState iconState;
 
  /*
  * Properties
  * */
  public override bool Active
  {
  get
  {
  return base.Active;
  }
  set
  {
  if (value != base.Active)
  {
  this.SetIconTexture(this.powerState | this.activeState);
  }
 
  base.Active = value;
  }
  }
 
  public override VesselType[] AllVesselTypes
  {
  get;
  protected set;
  }
 
  public override int ConfigVersion
  {
  get
  {
  return this.configVersion;
  }
  }
 
  public bool FactoryReset
  {
  get;
  protected set;
  }
 
  public override CelestialBody HomeBody
  {
  get
  {
  if (this.homeBody == null)
  {
  if (Planetarium.fetch != null)
  {
  this.homeBody = Planetarium.fetch.Home;
  }
  }
 
  return this.homeBody;
  }
  }
 
  public override IList<IVOID_Module> Modules
  {
  get
  {
  return this.modules.AsReadOnly();
  }
  }
 
  public override GUISkin Skin
  {
  get
  {
  if (this.skinsLoaded)
  {
  try
  {
  return this.validSkins[this.skinName];
  }
  catch
  {
  }
  }
 
  return AssetBase.GetGUISkin(this.defaultSkin);
  }
  }
 
  public override List<CelestialBody> SortedBodyList
  {
  get;
  protected set;
  }
 
  public override double UpdatePeriod
  {
  get
  {
  return this.updatePeriod;
  }
  }
 
  public override float UpdateTimer
  {
  get;
  protected set;
  }
 
  public override int WindowID
  {
  get
  {
  if (this.windowID == 0)
  {
  this.windowID = this.windowBaseID;
  }
  return this.windowID++;
  }
  }
 
  public override Stage[] Stages
  {
  get;
  protected set;
  }
 
  public override Stage LastStage
  {
  get;
  protected set;
  }
 
  public override VOID_TimeScale TimeScale
  {
  get
  {
  return (VOID_TimeScale)this.timeScaleFlags.value;
  }
  protected set
  {
  this.timeScaleFlags.value = (UInt32)value;
  }
  }
 
  protected IconState activeState
  {
  get
  {
  if (this.Active)
  {
  return IconState.Inactive;
  }
  else
  {
  return IconState.Active;
  }
 
  }
  }
 
  protected IconState powerState
  {
  get
  {
  if (this.togglePower && this.powerAvailable)
  {
  return IconState.PowerOn;
  }
  else
  {
  return IconState.PowerOff;
  }
 
  }
  }
 
  protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes
  {
  get
  {
  return HighLogic.LoadedScene.ToAppScenes();
  }
  }
 
  /*
  * Events
  * */
  // public
  public override event VOIDEventHandler onApplicationQuit;
  public override event VOIDEventHandler onSkinChanged;
  public override event VOIDEventHandler onUpdate;
 
  public override event VOIDEventHandler onPreForEach;
  public override event VOIDForEachPartHandler onForEachPart;
  public override event VOIDForEachPartModuleHandler onForEachModule;
  public override event VOIDEventHandler onPostForEach;
 
  /*
  * Methods
  * */
  public override void DrawGUI(object sender)
  {
  this.windowID = this.windowBaseID;
 
  if (!this.modulesLoaded)
  {
  this.LoadModulesOfType<IVOID_Module>();
 
  FireOnModulesLoaded(this);
  }
 
  if (!this.skinsLoaded)
  {
  this.LoadSkins();
  }
 
  GUI.skin = this.Skin;
 
  if (!this.GUIStylesLoaded)
  {
  this.LoadGUIStyles();
 
  Logging.PostDebugMessage(
  this,
  "ToolbarAvailable: {0}, UseToobarManager: {1}",
  ToolbarManager.ToolbarAvailable,
  this.useToolbarManager);
  }
 
  if (
  this.iconState != (this.powerState | this.activeState) ||
  (this.VOIDIconTexture == null && this.AppLauncherButton != null)
  )
  {
  this.iconState = this.powerState | this.activeState;
 
  this.SetIconTexture(this.iconState);
  }
 
  if (this.Active)
  {
  base.DrawGUI(sender);
  }
  }
 
  public virtual void Update()
  {
  this.LoadBeforeUpdate();
 
  if (
  this.vesselSimActive &&
  (
  this.Vessel != null ||
  (
  HighLogic.LoadedSceneIsEditor &&
  EditorLogic.RootPart != null &&
  EditorLogic.SortedShipList.Count > 0
  )
  )
  )
  {
  Logging.PostDebugMessage(this, "Updating SimManager.");
  this.UpdateSimManager();
 
  VOIDForEachPartArgs partArgs;
  VOIDForEachPartModuleArgs moduleArgs;
 
  Part part;
  PartModule partModule;
 
  bool doForEachPart = this.onForEachPart != null;
  bool doForEachModule = this.onForEachModule != null;
 
  if (
  (doForEachPart || doForEachModule) &&
  (this.Vessel != null) &&
  (this.Vessel.parts != null) &&
  this.timeToUpdate
  )
  {
  if (this.onPreForEach != null)
  {
  this.onPreForEach(this);
  }
 
  for (int pIdx = 0; pIdx < this.Vessel.parts.Count; pIdx++)
  {
  part = this.Vessel.parts[pIdx];
  partArgs = new VOIDForEachPartArgs(part);
 
  if (doForEachPart)
  {
  this.onForEachPart(this, partArgs);
  }
 
  if (doForEachModule && part.Modules != null)
  {
  for (int mIdx = 0; mIdx < part.Modules.Count; mIdx++)
  {
  partModule = part.Modules[mIdx];
  moduleArgs = new VOIDForEachPartModuleArgs(partModule);
 
  if (doForEachModule)
  {
  this.onForEachModule(this, moduleArgs);
  }
  }
  }
  }
 
  if (this.onPostForEach!= null)
  {
  this.onPostForEach(this);
  }
  }
  }
 
  if (!this.GUIRunning && !this.gameUIHidden)
  {
  this.StartGUI();
  }
 
  IVOID_Module module;
  for (int idx = 0; idx < this.modules.Count; idx++)
  {
  module = this.modules[idx];
 
  if (
  !module.GUIRunning &&
  module.Active &&
  module.InValidScene &&
  (
  !HighLogic.LoadedSceneIsEditor ||
  (EditorLogic.RootPart != null && EditorLogic.SortedShipList.Count > 0)
  )
  )
  {
  module.StartGUI();
  }
  if (
  module.GUIRunning &&
  (
  !module.Active ||
  !this.togglePower ||
  !module.InValidScene ||
  this.FactoryReset ||
  (
  HighLogic.LoadedSceneIsEditor &&
  (EditorLogic.RootPart == null || EditorLogic.SortedShipList.Count == 0)
  )
  )
  )
  {
  module.StopGUI();
  }
 
  if (module is IVOID_BehaviorModule)
  {
  ((IVOID_BehaviorModule)module).Update();
  }
  }
 
  if (ToolbarManager.ToolbarAvailable && this.useToolbarManager)
  {
  if (this.ToolbarButton == null)
  {
  this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle");
  this.ToolbarButton.Text = this.VoidName;
  this.SetIconTexture(this.powerState | this.activeState);
 
  this.ToolbarButton.Visible = true;
 
  this.ToolbarButton.OnClick +=
  (e) =>
  {
  this.ToggleMainWindow();
  };
 
  Logging.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name));
  }
 
  if (this.AppLauncherButton != null)
  {
  ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
  this.AppLauncherButton = null;
  }
  }
  else
  {
  if (this.AppLauncherButton == null)
  {
  if (ApplicationLauncher.Instance != null)
  {
  this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication(
  this.ToggleMainWindow, this.ToggleMainWindow,
  this.appIconVisibleScenes,
  this.VOIDIconTexture
  );
 
  Logging.PostDebugMessage(
  this,
  "AppLauncherButton initialized in {0}",
  Enum.GetName(
  typeof(GameScenes),
  HighLogic.LoadedScene
  )
  );
  }
  }
 
  if (this.ToolbarButton != null)
  {
  this.ToolbarButton.Destroy();
  this.ToolbarButton = null;
  }
  }
 
  if (this.onUpdate != null)
  {
  this.onUpdate(this);
  }
 
  this.saveTimer += Time.deltaTime;
 
  if (this.modulesLoaded && this.saveTimer > 2f)
  {
  if (this.configDirty)
  {
 
  Logging.PostDebugMessage(string.Format(
  "{0}: Time to save, checking if configDirty: {1}",
  this.GetType().Name,
  this.configDirty
  ));
 
  this.SaveConfig();
  this.saveTimer = 0;
  }
  }
 
  this.UpdateTimer += Time.deltaTime;
  }
 
  public virtual void FixedUpdate()
  {
  bool newPowerState = this.powerAvailable;
 
  if (this.togglePower && this.consumeResource &&
  this.Vessel.vesselType != VesselType.EVA &&
  TimeWarp.deltaTime != 0)
  {
  float powerReceived = this.Vessel.rootPart.RequestResource(
  this.resourceName,
  this.resourceRate * TimeWarp.fixedDeltaTime
  );
 
  if (powerReceived > 0)
  {
  newPowerState = true;
  }
  else
  {
  newPowerState = false;
  }
 
  if (this.powerAvailable != newPowerState)
  {
  this.powerAvailable = newPowerState;
  }
  }
 
  IVOID_Module module;
  for (int idx = 0; idx < this.modules.Count; idx++)
  {
  module = this.modules[idx];
 
  if (module is IVOID_BehaviorModule)
  {
  ((IVOID_BehaviorModule)module).FixedUpdate();
  }
  }
  }
 
  public void OnDestroy()
  {
  IVOID_Module module;
  for (int idx = 0; idx < this.modules.Count; idx++)
  {
  module = this.modules[idx];
 
  if (module is IVOID_BehaviorModule)
  {
  ((IVOID_BehaviorModule)module).OnDestroy();
  }
  }
 
  FireOnModulesDestroyed(this);
 
  this.Dispose();
  }
 
  public virtual void OnApplicationQuit()
  {
  if (this.onApplicationQuit != null)
  {
  this.onApplicationQuit(this);
  }
 
  this.OnDestroy();
  }
 
  public override void StartGUI()
  {
  if (!this.GUIRunning)
  {
  Logging.PostDebugMessage(this, "Adding DrawGUI to onGui");
  this.onPostRender += this.DrawGUI;
  }
  }
 
  public void ResetGUI()
  {
  this.StopGUI();
 
  IVOID_Module module;
  for (int idx = 0; idx < this.modules.Count; idx++)
  {
  module = this.modules[idx];
 
  module.StopGUI();
  module.StartGUI();
  }
 
  this.StartGUI();
  }
 
  public override void ModuleWindow(int id)
  {
  GUILayout.BeginVertical();
 
  if (this.powerAvailable || !HighLogic.LoadedSceneIsFlight)
  {
  if (!HighLogic.LoadedSceneIsEditor)
  {
  string str = string.Intern("ON");
  if (togglePower)
  str = string.Intern("OFF");
  if (GUILayout.Button("Power " + str))
  {
  togglePower.value = !togglePower;
  }
  }
 
  if (togglePower || !HighLogic.LoadedSceneIsFlight)
  {
  IVOID_Module module;
  for (int idx = 0; idx < this.modules.Count; idx++)
  {
  module = this.modules[idx];
 
  if (module is VOID_ConfigWindow)
  {
  continue;
  }
 
  module.Active = Layout.Toggle(module.Active, module.Name);
  }
  }
  }
  else
  {
  GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed);
  }
 
  VOID_ConfigWindow.Instance.Active = Layout.Toggle(
  VOID_ConfigWindow.Instance.Active,
  "Configuration"
  );
 
  GUILayout.EndVertical();
 
  base.ModuleWindow(id);
  }
 
  public override void DrawConfigurables()
  {
  GUIContent _content;
 
  this.useToolbarManager.value = Layout.Toggle(this.useToolbarManager, "Use Blizzy's Toolbar If Available");
 
  this.vesselSimActive.value = Layout.Toggle(this.vesselSimActive.value,
  "Enable Engineering Calculations");
 
  bool useEarthTime = (this.TimeScale & VOID_TimeScale.KERBIN_TIME) == 0u;
  bool useSiderealTime = (this.TimeScale & VOID_TimeScale.SOLAR_DAY) == 0u;
  bool useRoundedScale = (this.TimeScale & VOID_TimeScale.ROUNDED_SCALE) != 0u;
 
  useEarthTime = Layout.Toggle(useEarthTime, "Use Earth Time (changes KSP option)");
 
  GameSettings.KERBIN_TIME = !useEarthTime;
 
  useSiderealTime = Layout.Toggle(
  useSiderealTime,
  string.Format(
  "Time Scale: {0}",
  useSiderealTime ? "Sidereal" : "Solar"
  )
  );
 
  useRoundedScale = Layout.Toggle(
  useRoundedScale,
  string.Format(
  "Time Scale: {0}",
  useRoundedScale ? "Rounded" : "True"
  )
  );
 
  if (useEarthTime)
  {
  this.TimeScale &= ~VOID_TimeScale.KERBIN_TIME;
  }
  else
  {
  this.TimeScale |= VOID_TimeScale.KERBIN_TIME;
  }
 
  if (useSiderealTime)
  {
  this.TimeScale &= ~VOID_TimeScale.SOLAR_DAY;
  }
  else
  {
  this.TimeScale |= VOID_TimeScale.SOLAR_DAY;
  }
 
  if (useRoundedScale)
  {
  this.TimeScale |= VOID_TimeScale.ROUNDED_SCALE;
  }
  else
  {
  this.TimeScale &= ~VOID_TimeScale.ROUNDED_SCALE;
  }
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 
  GUILayout.Label("Skin:", GUILayout.ExpandWidth(false));
 
  _content = new GUIContent();
 
  _content.text = "◄";
  _content.tooltip = "Select previous skin";
  if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
  {
  this.skinIdx--;
  Logging.PostDebugMessage(string.Format(
  "{0}: new this.skinIdx = {1} :: skin_list.Count = {2}",
  this.GetType().Name,
  this.skinName,
  this.validSkins.Count
  ));
  }
 
  _content.text = this.Skin.name;
  _content.tooltip = "Current skin";
  GUILayout.Label(_content, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true));
 
  _content.text = "►";
  _content.tooltip = "Select next skin";
  if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
  {
  this.skinIdx++;
  Logging.PostDebugMessage(string.Format(
  "{0}: new this.skinIdx = {1} :: skin_list.Count = {2}",
  this.GetType().Name,
  this.skinName,
  this.validSkins.Count
  ));
  }
 
  this.skinIdx %= this.skinNames.Count;
  if (this.skinIdx < 0)
  {
  this.skinIdx += this.skinNames.Count;
  }
 
  if (this.skinName != skinNames[this.skinIdx])
  {
  this.skinName.value = skinNames[this.skinIdx];
  this.GUIStylesLoaded = false;
  }
 
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal();
  GUILayout.Label("Update Rate (Hz):");
  if (this.stringFrequency == null)
  {
  this.stringFrequency = (1f / this.UpdatePeriod).ToString();
  }
  this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true));
 
  if (GUILayout.Button("Apply"))
  {
  double updateFreq = 1f / this.UpdatePeriod;
  double.TryParse(stringFrequency, out updateFreq);
  this.updatePeriod.value = 1 / updateFreq;
  }
  GUILayout.EndHorizontal();
 
  IVOID_Module module;
  for (int idx = 0; idx < this.modules.Count; idx++)
  {
  module = this.modules[idx];
 
  module.DrawConfigurables();
  }
 
  this.FactoryReset = Layout.Toggle(this.FactoryReset, "Factory Reset");
  }
 
  protected void UpdateSimManager()
  {
  if (HighLogic.LoadedSceneIsFlight)
  {
  double radius = this.Vessel.Radius();
  SimManager.Gravity = this.Vessel.mainBody.gravParameter / (radius * radius);
  SimManager.Atmosphere = this.Vessel.staticPressurekPa * PhysicsGlobals.KpaToAtmospheres;
  SimManager.Mach = this.Vessel.mach;
  BuildAdvanced.Altitude = this.Vessel.altitude;
  CelestialBodies.SelectedBody = this.Vessel.mainBody;
  }
 
  #if DEBUG
  SimManager.logOutput = true;
  #endif
 
  SimManager.TryStartSimulation();
 
  Logging.PostDebugMessage(this, "Started Engineer simulation with Atmosphere={0} atm and Gravity={1} m/s²",
  SimManager.Atmosphere,
  SimManager.Gravity
  );
  }
 
  protected void GetSimManagerResults()
  {
  Logging.PostDebugMessage(this, "VesselSimulator results ready, setting Stages.");
 
  this.Stages = SimManager.Stages;
 
  if (this.Stages != null && this.Stages.Length > 0)
  {
  this.LastStage = this.Stages[this.Stages.Length - 1];
  }
  }
 
  protected void LoadModulesOfType<U>()
  {
  using (PooledDebugLogger sb = PooledDebugLogger.New(this))
  {
  sb.AppendLine("Loading modules...");
 
  AssemblyLoader.LoadedAssembly assy;
  for (int aIdx = 0; aIdx < AssemblyLoader.loadedAssemblies.Count; aIdx++)
  {
  assy = AssemblyLoader.loadedAssemblies[aIdx];
 
  Type[] loadedTypes = assy.assembly.GetExportedTypes();
  Type loadedType;
  for (int tIdx = 0; tIdx < loadedTypes.Length; tIdx++)
  {
  loadedType = loadedTypes[tIdx];
 
  if (
  loadedType.IsInterface ||
  loadedType.IsAbstract ||
  !typeof(U).IsAssignableFrom(loadedType) ||
  typeof(VOIDCore).IsAssignableFrom(loadedType))
  {
  continue;
  }
 
  sb.AppendFormat("Checking IVOID_Module type {0}...", loadedType.Name);
 
  try
  {
  this.LoadModule(loadedType);
  sb.AppendLine("Success.");
  }
  catch (Exception ex)
  {
  sb.AppendFormat("Failed, caught {0}\n", ex.GetType().Name);
 
  #if DEBUG
  Debug.LogException(ex);
  #endif
  }
  }
  }
 
  this.LoadConfig();
 
  this.modulesLoaded = true;
 
  sb.AppendFormat("Loaded {0} modules.\n", this.Modules.Count);
 
  sb.Print();
  }
  }
 
  protected void LoadModule(Type T)
  {
  /*var existingModules = this.modules.Where(mod => mod.GetType().Name == T.Name);
  if (existingModules.Any())*/
  for (int mIdx = 0; mIdx < this.modules.Count; mIdx++)
  {
  if (this.modules[mIdx].Name == T.Name)
  {
  Logging.PostErrorMessage("{0}: refusing to load {1}: already loaded", this.GetType().Name, T.Name);
  return;
  }
  }
 
  var InstanceProperty = T.GetProperty(
  "Instance",
  System.Reflection.BindingFlags.Static |
  System.Reflection.BindingFlags.Public |
  System.Reflection.BindingFlags.FlattenHierarchy
  );
 
  object modInstance = null;
  IVOID_Module module;
 
  if (InstanceProperty != null)
  {
  modInstance = InstanceProperty.GetValue(null, null);
  }
 
  if (modInstance != null)
  {
  module = modInstance as IVOID_Module;
  }
  else
  {
  module = Activator.CreateInstance(T) as IVOID_Module;
  }
 
  if (module.InValidGame && module.InValidScene)
  {
  this.modules.Add(module);
 
  Logging.PostDebugMessage(string.Format(
  "{0}: loaded module {1}.",
  this.GetType().Name,
  T.Name
  ));
  }
  else
  {
  if (module is IDisposable)
  {
  (module as IDisposable).Dispose();
  }
  }
  }
 
  protected void LoadSkins()
  {
  this.validSkins = new Dictionary<string, GUISkin>();
  this.skinNames = new List<string>();
 
  UnityEngine.Object[] skins = Resources.FindObjectsOfTypeAll(typeof(GUISkin));
  GUISkin skin;
  for (int sIdx = 0; sIdx < skins.Length; sIdx++)
  {
  skin = (GUISkin)skins[sIdx];
 
  if (!this.forbiddenSkins.Contains(skin.name))
  {
  this.validSkins[skin.name] = skin;
  this.skinNames.Add(skin.name);
  }
  }
 
  Logging.PostDebugMessage(string.Format(
  "{0}: loaded {1} GUISkins.",
  this.GetType().Name,
  this.validSkins.Count
  ));
 
  this.skinNames.Sort();
 
  int defaultIdx = int.MinValue;
 
  for (int i = 0; i < this.skinNames.Count; i++)
  {
  if (this.skinNames[i] == this.skinName)
  {
  this.skinIdx = i;
  }
  if (this.skinNames[i] == this.defaultSkin)
  {
  defaultIdx = i;
  }
  if (this.skinIdx != int.MinValue && defaultIdx != int.MinValue)
  {
  break;
  }
  }
 
  if (this.skinIdx == int.MinValue)
  {
  this.skinIdx = defaultIdx;
  }
 
  Logging.PostDebugMessage(string.Format(
  "{0}: _skinIdx = {1}.",
  this.GetType().Name,
  this.skinName.ToString()
  ));
 
  this.skinsLoaded = true;
  }
 
  protected void LoadGUIStyles()
  {
  VOID_Styles.OnSkinChanged();
 
  if (this.onSkinChanged != null)
  {
  this.onSkinChanged(this);
  }
 
  this.GUIStylesLoaded = true;
  }
 
  protected void LoadBeforeUpdate()
  {
  if (!this.vesselTypesLoaded)
  {
  Array typeObjs = Enum.GetValues(typeof(VesselType));
  this.AllVesselTypes = new VesselType[typeObjs.Length];
 
  for (int idx = 0; idx < typeObjs.Length; idx++)
  {
  this.AllVesselTypes[idx] = (VesselType)typeObjs.GetValue(idx);
  }
 
  this.vesselTypesLoaded = true;
  }
 
  if (this.SortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
  {
  this.SortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
  this.SortedBodyList.Sort(new CBListComparer());
  this.SortedBodyList.Reverse();
  }
 
  // SimManager initialization that we don't necessarily want to repeat every Update.
  if (!this.simManagerLoaded && this.HomeBody != null)
  {
  SimManager.Gravity = VOID_Data.KerbinGee;
  SimManager.Atmosphere = 0d;
  SimManager.Mach = 1d;
  CelestialBodies.SelectedBody = this.HomeBody;
  BuildAdvanced.Altitude = 0d;
  SimManager.OnReady += this.GetSimManagerResults;
 
  this.simManagerLoaded = true;
  }
  }
 
  protected void ToggleMainWindow()
  {
  this.Active = !this.Active;
  }
 
  protected void SetIconTexture(IconState state)
  {
  switch (state)
  {
  case (IconState.PowerOff | IconState.Inactive):
  this.SetIconTexture(this.VOIDIconOffInactivePath);
  break;
  case (IconState.PowerOff | IconState.Active):
  this.SetIconTexture(this.VOIDIconOffActivePath);
  break;
  case (IconState.PowerOn | IconState.Inactive):
  this.SetIconTexture(this.VOIDIconOnInactivePath);
  break;
  case (IconState.PowerOn | IconState.Active):
  this.SetIconTexture(this.VOIDIconOnActivePath);
  break;
  default:
  throw new NotImplementedException();
  }
  }
 
  protected void SetIconTexture(string texturePath)
  {
  if (texturePath == null)
  {
  return;
  }
 
  if (this.ToolbarButton != null)
  {
  this.ToolbarButton.TexturePath = texturePath;
  }
 
  if (this.AppLauncherButton != null)
  {
  this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false);
 
  this.AppLauncherButton.SetTexture(VOIDIconTexture);
  }
  }
 
  public void LoadConfig()
  {
 
  if (!System.IO.File.Exists(this.VOIDSettingsPath) && KSP.IO.File.Exists<VOID_Module>("config.xml"))
  {
  Logging.PostLogMessage(
  "VOID: No per-save config file but old file detected; copying from old file."
  );
 
  System.IO.File.Copy(
  KSP.IO.IOUtils.GetFilePathFor(typeof(VOID_Module), "config.xml"),
  this.VOIDSettingsPath
  );
  }
 
  this.LoadConfig(new PluginConfiguration(this.VOIDSettingsPath));
  }
 
  public override void LoadConfig(KSP.IO.PluginConfiguration config)
  {
  base.LoadConfig(config);
 
  IVOID_Module module;
  for (int idx = 0; idx < this.modules.Count; idx++)
  {
  module = this.modules[idx];
 
  module.LoadConfig(config);
  }
 
  this.TimeScale |= GameSettings.KERBIN_TIME ? VOID_TimeScale.KERBIN_TIME : 0u;
  }
 
  public override void SaveConfig()
  {
  if (this.configNeedsUpdate && this is VOIDCore_Flight)
  {
  KSP.IO.File.Delete<T>("config.xml");
  System.IO.File.Delete(this.VOIDSettingsPath);
  }
 
  KSP.IO.PluginConfiguration config = new PluginConfiguration(this.VOIDSettingsPath);
 
  config.load();
 
  this.Save(config, this.SceneKey);
 
  IVOID_Module module;
  for (int idx = 0; idx < this.modules.Count; idx++)
  {
  module = this.modules[idx];
 
  module.Save(config, this.SceneKey);
  }
 
  config.save();
 
  this.configDirty = false;
  }
 
  public VOIDCore_Generic()
  {
  System.Version version = this.GetType().Assembly.GetName().Version;
 
  this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision);
 
  this.Name = string.Format("VOID {0}", this.VoidVersion.ToString());
 
  this.powerAvailable = true;
 
  this.Active = true;
 
  this.skinName = (VOID_SaveValue<string>)this.defaultSkin;
  this.skinIdx = int.MinValue;
 
  this.VOIDIconOnActivePath = "VOID/Textures/void_icon_light_glow";
  this.VOIDIconOnInactivePath = "VOID/Textures/void_icon_dark_glow";
  this.VOIDIconOffActivePath = "VOID/Textures/void_icon_light";
  this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_dark";
 
  this.saveTimer = 0f;
  this.UpdateTimer = 0f;
 
  this.vesselSimActive = (VOID_SaveValue<bool>)true;
 
  this.useToolbarManager = (VOID_SaveValue<bool>)ToolbarManager.ToolbarAvailable;
 
  this.SaveGamePath = string.Format("{0}saves/{1}", IOTools.KSPRootPath, HighLogic.SaveFolder);
  this.VOIDSettingsPath = string.Format("{0}/VOIDConfig.xml", this.SaveGamePath);
 
  this.FactoryReset = false;
  }
 
  public override void Dispose()
  {
  this.StopGUI();
 
  this.onSkinChanged(this);
 
  if (this.AppLauncherButton != null)
  {
  ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
  this.AppLauncherButton = null;
  }
  if (this.ToolbarButton != null)
  {
  this.ToolbarButton.Destroy();
  this.ToolbarButton = null;
  }
 
  _instance = null;
  _initialized = false;
  }
  }
  }
 
  // VOID
  //
  // VOIDCore_SpaceCentre.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  using System;
 
  namespace VOID
  {
  [VOID_Scenes(GameScenes.SPACECENTER)]
  public class VOIDCore_SpaceCentre : VOIDCore_Generic<VOIDCore_SpaceCentre>
  {
  public override string SceneKey
  {
  get
  {
  return "SPACECENTER";
  }
  }
 
  public override void FixedUpdate() {}
  }
  }
 
 
file:a/VOIDEditorMaster.cs (deleted)
///////////////////////////////////////////////////////////////////////////////  
//  
// VOID - Vessel Orbital Information Display for Kerbal Space Program  
// Copyright (C) 2012 Iannic-ann-od  
// Copyright (C) 2013 Toadicus  
//  
// This program is free software: you can redistribute it and/or modify  
// it under the terms of the GNU General Public License as published by  
// the Free Software Foundation, either version 3 of the License, or  
// (at your option) any later version.  
//  
// This program is distributed in the hope that it will be useful,  
// but WITHOUT ANY WARRANTY; without even the implied warranty of  
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
// GNU General Public License for more details.  
//  
// You should have received a copy of the GNU General Public License  
// along with this program. If not, see <http://www.gnu.org/licenses/>.  
//  
///////////////////////////////////////////////////////////////////////////////  
//  
// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors  
// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some  
// invaluable functions and making your nicely written code available to learn from.  
//  
///////////////////////////////////////////////////////////////////////////////  
//  
// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.  
// Engineer Redux (c) 2013 cybutek  
// Used by permission.  
//  
///////////////////////////////////////////////////////////////////////////////  
 
using System;  
using UnityEngine;  
using Engineer.VesselSimulator;  
 
namespace VOID  
{  
[KSPAddon(KSPAddon.Startup.EditorAny, false)]  
public class VOIDEditorMaster : MonoBehaviour  
{  
protected VOID_EditorCore Core;  
 
public void Awake()  
{  
Tools.PostDebugMessage ("VOIDEditorMaster: Waking up.");  
this.Core = VOID_EditorCore.Instance;  
this.Core.ResetGUI ();  
SimManager.HardReset();  
Tools.PostDebugMessage ("VOIDEditorMaster: Awake.");  
}  
 
public void Update()  
{  
if (!HighLogic.LoadedSceneIsEditor && this.Core != null)  
{  
this.Core.SaveConfig ();  
this.Core = null;  
VOID_EditorCore.Reset();  
return;  
}  
 
if (this.Core == null)  
{  
this.Awake();  
}  
 
this.Core.Update ();  
 
if (this.Core.factoryReset)  
{  
KSP.IO.File.Delete<VOID_EditorCore>("config.xml");  
this.Core = null;  
VOID_EditorCore.Reset();  
}  
}  
 
public void FixedUpdate()  
{  
if (this.Core == null || !HighLogic.LoadedSceneIsEditor)  
{  
return;  
}  
 
this.Core.FixedUpdate ();  
}  
 
public void OnGUI()  
{  
if (this.Core == null)  
{  
return;  
}  
 
this.Core.OnGUI();  
}  
}  
}  
 
file:a/VOIDFlightMaster.cs (deleted)
///////////////////////////////////////////////////////////////////////////////  
//  
// VOID - Vessel Orbital Information Display for Kerbal Space Program  
// Copyright (C) 2012 Iannic-ann-od  
// Copyright (C) 2013 Toadicus  
//  
// This program is free software: you can redistribute it and/or modify  
// it under the terms of the GNU General Public License as published by  
// the Free Software Foundation, either version 3 of the License, or  
// (at your option) any later version.  
//  
// This program is distributed in the hope that it will be useful,  
// but WITHOUT ANY WARRANTY; without even the implied warranty of  
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
// GNU General Public License for more details.  
//  
// You should have received a copy of the GNU General Public License  
// along with this program. If not, see <http://www.gnu.org/licenses/>.  
//  
///////////////////////////////////////////////////////////////////////////////  
//  
// Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors  
// behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some  
// invaluable functions and making your nicely written code available to learn from.  
//  
///////////////////////////////////////////////////////////////////////////////  
//  
// This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.  
// Engineer Redux (c) 2013 cybutek  
// Used by permission.  
//  
///////////////////////////////////////////////////////////////////////////////  
 
using System;  
using UnityEngine;  
using Engineer.VesselSimulator;  
 
namespace VOID  
{  
[KSPAddon(KSPAddon.Startup.Flight, false)]  
public class VOIDFlightMaster : MonoBehaviour  
{  
protected VOID_Core Core;  
 
public void Awake()  
{  
Tools.PostDebugMessage ("VOIDFlightMaster: Waking up.");  
this.Core = (VOID_Core)VOID_Core.Instance;  
this.Core.ResetGUI ();  
SimManager.HardReset();  
Tools.PostDebugMessage ("VOIDFlightMaster: Awake.");  
}  
 
public void Update()  
{  
if (!HighLogic.LoadedSceneIsFlight && this.Core != null)  
{  
this.Core.SaveConfig ();  
this.Core = null;  
VOID_Core.Reset();  
return;  
}  
 
if (this.Core == null)  
{  
this.Awake();  
}  
 
this.Core.Update ();  
 
if (this.Core.factoryReset)  
{  
KSP.IO.File.Delete<VOID_Core>("config.xml");  
this.Core = null;  
VOID_Core.Reset();  
}  
}  
 
public void FixedUpdate()  
{  
if (this.Core == null || !HighLogic.LoadedSceneIsFlight)  
{  
return;  
}  
 
this.Core.FixedUpdate ();  
}  
 
public void OnGUI()  
{  
if (this.Core == null)  
{  
return;  
}  
 
this.Core.OnGUI();  
}  
}  
}  
 
  // VOID
  //
  // VOIDEditorMaster.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  ///////////////////////////////////////////////////////////////////////////////
  //
  // Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors
  // behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some
  // invaluable functions and making your nicely written code available to learn from.
  //
  ///////////////////////////////////////////////////////////////////////////////
  //
  // This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.
  // Engineer Redux (c) 2013 cybutek
  // Used by permission.
  //
  ///////////////////////////////////////////////////////////////////////////////
 
  using KerbalEngineer.VesselSimulator;
  using KSP;
  using System;
  using ToadicusTools.Extensions;
  using UnityEngine;
 
  namespace VOID
  {
  [KSPAddon(KSPAddon.Startup.EditorAny, false)]
  public class VOIDMaster_Editor : VOIDMaster<VOIDCore_Editor>
  {
  public override void Awake()
  {
  this.LogDebug("VOIDEditorMaster: Waking up.");
  this.Core = VOIDCore_Editor.Instance;
  this.Core.ResetGUI ();
  this.LogDebug("VOIDEditorMaster: Awake.");
  }
  }
  }
 
  // VOID
  //
  // VOIDFlightMaster.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  ///////////////////////////////////////////////////////////////////////////////
  //
  // Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors
  // behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some
  // invaluable functions and making your nicely written code available to learn from.
  //
  ///////////////////////////////////////////////////////////////////////////////
  //
  // This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.
  // Engineer Redux (c) 2013 cybutek
  // Used by permission.
  //
  ///////////////////////////////////////////////////////////////////////////////
 
  using System;
  using UnityEngine;
  using KerbalEngineer.VesselSimulator;
  using ToadicusTools.Extensions;
 
  namespace VOID
  {
  [KSPAddon(KSPAddon.Startup.Flight, false)]
  public class VOIDMaster_Flight : VOIDMaster<VOIDCore_Flight>
  {
  public override void Awake()
  {
  this.LogDebug("Waking up.");
  this.Core = VOIDCore_Flight.Instance;
  this.Core.ResetGUI ();
  this.LogDebug("Awake.");
  }
  }
  }
 
  // VOID
  //
  // VOIDFlightMaster.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  ///////////////////////////////////////////////////////////////////////////////
  //
  // Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors
  // behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some
  // invaluable functions and making your nicely written code available to learn from.
  //
  ///////////////////////////////////////////////////////////////////////////////
  //
  // This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.
  // Engineer Redux (c) 2013 cybutek
  // Used by permission.
  //
  ///////////////////////////////////////////////////////////////////////////////
 
  using System;
  using UnityEngine;
  using KerbalEngineer.VesselSimulator;
  using ToadicusTools.Extensions;
 
  namespace VOID
  {
  [KSPAddon(KSPAddon.Startup.SpaceCentre, false)]
  public class VOIDMaster_SpaceCentre : VOIDMaster<VOIDCore_SpaceCentre>
  {
  public override void Awake()
  {
  this.LogDebug("Waking up.");
  this.Core = VOIDCore_SpaceCentre.Instance;
  this.Core.ResetGUI ();
  this.LogDebug("Awake.");
  }
  }
  }
 
// // VOID
// VOID_Orbital.cs //
// // VOID_CBInfoBrowser.cs
// Author: //
// toadicus <> // Copyright © 2014, toadicus
// // All rights reserved.
// Copyright (c) 2013 toadicus //
// // Redistribution and use in source and binary forms, with or without modification,
// This program is free software: you can redistribute it and/or modify // are permitted provided that the following conditions are met:
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation, either version 3 of the License, or // 1. Redistributions of source code must retain the above copyright notice,
// (at your option) any later version. // this list of conditions and the following disclaimer.
// //
// This program is distributed in the hope that it will be useful, // 2. Redistributions in binary form must reproduce the above copyright notice,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // this list of conditions and the following disclaimer in the documentation and/or other
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // materials provided with the distribution.
// GNU General Public License for more details. //
// // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// You should have received a copy of the GNU General Public License // to endorse or promote products derived from this software without specific prior written permission.
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
  using ToadicusTools.Text;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_CBInfoBrowser : VOID_WindowModule public class VOID_CBInfoBrowser : VOID_WindowModule
{ {
[AVOID_SaveValue("selectedBodyIdx1")] [AVOID_SaveValue("selectedBodyIdx1")]
protected VOID_SaveValue<int> selectedBodyIdx1 = 1; protected VOID_SaveValue<int> selectedBodyIdx1;
   
[AVOID_SaveValue("selectedBodyIdx2")] [AVOID_SaveValue("selectedBodyIdx2")]
protected VOID_SaveValue<int> selectedBodyIdx2 = 2; protected VOID_SaveValue<int> selectedBodyIdx2;
   
protected CelestialBody selectedBody1; protected CelestialBody selectedBody1;
protected CelestialBody selectedBody2; protected CelestialBody selectedBody2;
   
[AVOID_SaveValue("toggleOrbital")] [AVOID_SaveValue("toggleOrbital")]
protected VOID_SaveValue<bool> toggleOrbital = false; protected VOID_SaveValue<bool> toggleOrbital;
   
[AVOID_SaveValue("togglePhysical")] [AVOID_SaveValue("togglePhysical")]
protected VOID_SaveValue<bool> togglePhysical = false; protected VOID_SaveValue<bool> togglePhysical;
   
  [AVOID_SaveValue("toggleScience")]
  protected VOID_SaveValue<bool> toggleScience;
   
public VOID_CBInfoBrowser() public VOID_CBInfoBrowser()
{ {
this._Name = "Celestial Body Information Browser"; this.Name = "Celestial Body Information Browser";
   
this.WindowPos.x = 10; this.WindowPos.x = 10;
this.WindowPos.y = 85; this.WindowPos.y = 85;
   
  this.selectedBodyIdx1 = (VOID_SaveValue<int>)1;
  this.selectedBodyIdx2 = (VOID_SaveValue<int>)2;
   
  this.toggleOrbital = (VOID_SaveValue<bool>)false;
  this.togglePhysical = (VOID_SaveValue<bool>)false;
  this.toggleScience = (VOID_SaveValue<bool>)false;
} }
   
public override void ModuleWindow(int _) public override void ModuleWindow(int id)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
  if (this.core.SortedBodyList.Count < 1)
  {
  GUILayout.Label("Non-positive number of CelestialBodies here, bailing out.");
  GUILayout.EndHorizontal();
  }
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
GUILayout.Label("", GUILayout.ExpandWidth(true)); GUILayout.Label("", GUILayout.ExpandWidth(true));
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
selectedBody1 = VOID_Core.Instance.allBodies[selectedBodyIdx1]; if (selectedBodyIdx1 >= this.core.SortedBodyList.Count)
selectedBody2 = VOID_Core.Instance.allBodies[selectedBodyIdx2]; {
  selectedBodyIdx1.value %= this.core.SortedBodyList.Count;
  }
   
  if (selectedBodyIdx1 < 0)
  {
  selectedBodyIdx1.value += this.core.SortedBodyList.Count;
  }
   
  if (selectedBodyIdx2 >= this.core.SortedBodyList.Count)
  {
  selectedBodyIdx2.value %= this.core.SortedBodyList.Count;
  }
   
  if (selectedBodyIdx2 < 0)
  {
  selectedBodyIdx2.value += this.core.SortedBodyList.Count;
  }
   
  selectedBody1 = this.core.SortedBodyList[selectedBodyIdx1];
  selectedBody2 = this.core.SortedBodyList[selectedBodyIdx2];
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) if (GUILayout.Button("<", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx1--; selectedBodyIdx1.value--;
if (selectedBodyIdx1 < 0) selectedBodyIdx1 = VOID_Core.Instance.allBodies.Count - 1; if (selectedBodyIdx1 < 0)
} {
GUILayout.Label(VOID_Core.Instance.allBodies[selectedBodyIdx1].bodyName, VOID_Core.Instance.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); selectedBodyIdx1.value = this.core.SortedBodyList.Count - 1;
  }
  }
  GUILayout.Label(this.core.SortedBodyList[selectedBodyIdx1].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) if (GUILayout.Button(">", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx1++; selectedBodyIdx1.value++;
if (selectedBodyIdx1 > VOID_Core.Instance.allBodies.Count - 1) selectedBodyIdx1 = 0; if (selectedBodyIdx1 > this.core.SortedBodyList.Count - 1)
  {
  selectedBodyIdx1.value = 0;
  }
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) if (GUILayout.Button("<", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx2--; selectedBodyIdx2.value--;
if (selectedBodyIdx2 < 0) selectedBodyIdx2 = VOID_Core.Instance.allBodies.Count - 1; if (selectedBodyIdx2 < 0)
} {
GUILayout.Label(VOID_Core.Instance.allBodies[selectedBodyIdx2].bodyName, VOID_Core.Instance.LabelStyles["center_bold"], GUILayout.ExpandWidth(true)); selectedBodyIdx2.value = this.core.SortedBodyList.Count - 1;
  }
  }
  GUILayout.Label(this.core.SortedBodyList[selectedBodyIdx2].bodyName, VOID_Styles.labelCenterBold, GUILayout.ExpandWidth(true));
if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) if (GUILayout.Button(">", GUILayout.ExpandWidth(false)))
{ {
selectedBodyIdx2++; selectedBodyIdx2.value++;
if (selectedBodyIdx2 > VOID_Core.Instance.allBodies.Count - 1) selectedBodyIdx2 = 0; if (selectedBodyIdx2 > this.core.SortedBodyList.Count - 1)
  {
  selectedBodyIdx2.value = 0;
  }
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
//toggle for orbital info chunk //toggle for orbital info chunk
if (GUILayout.Button("Orbital Characteristics", GUILayout.ExpandWidth(true))) toggleOrbital.value = !toggleOrbital; if (GUILayout.Button("Orbital Characteristics", GUILayout.ExpandWidth(true))) toggleOrbital.value = !toggleOrbital;
   
if (toggleOrbital) if (toggleOrbital)
{ {
//begin orbital into horizontal chunk //begin orbital into horizontal chunk
//print("begin orbital info section..."); //print("begin orbital info section...");
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
//begin orbital value labels column //begin orbital value labels column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
//print("printing row labels..."); //print("printing row labels...");
   
GUILayout.Label("Apoapsis:"); GUILayout.Label("Apoapsis:");
GUILayout.Label("Time to Ap:"); GUILayout.Label("Time to Ap:");
GUILayout.Label("Periapsis:"); GUILayout.Label("Periapsis:");
GUILayout.Label("Time to Pe:"); GUILayout.Label("Time to Pe:");
GUILayout.Label("Semi-major axis:"); GUILayout.Label("Semi-major axis:");
GUILayout.Label("Eccentricity:"); GUILayout.Label("Eccentricity:");
GUILayout.Label("Orbital period:"); GUILayout.Label("Orbital period:");
GUILayout.Label("Rotational period:"); GUILayout.Label("Rotational period:");
GUILayout.Label("Velocity:"); GUILayout.Label("Velocity:");
GUILayout.Label("Mean anomaly:"); GUILayout.Label("Mean anomaly:");
GUILayout.Label("True anomaly:"); GUILayout.Label("True anomaly:");
GUILayout.Label("Eccentric anomaly:"); GUILayout.Label("Eccentric anomaly:");
GUILayout.Label("Inclination:"); GUILayout.Label("Inclination:");
GUILayout.Label("Long. ascending node:"); GUILayout.Label("Long. ascending node:");
GUILayout.Label("Arg. of periapsis:"); GUILayout.Label("Arg. of periapsis:");
GUILayout.Label("Tidally locked:"); GUILayout.Label("Tidally locked:");
   
//end orbital value labels column //end orbital value labels column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin primary orbital values column //begin primary orbital values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_orbital_info(selectedBody1); body_OP_show_orbital_info(selectedBody1);
   
//end primary orbital values column //end primary orbital values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin secondary orbital values column //begin secondary orbital values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_orbital_info(selectedBody2); body_OP_show_orbital_info(selectedBody2);
   
//end secondary orbital values column //end secondary orbital values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//end orbital info horizontal chunk //end orbital info horizontal chunk
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
//toggle for physical info chunk //toggle for physical info chunk
if (GUILayout.Button("Physical Characteristics", GUILayout.ExpandWidth(true))) togglePhysical.value = !togglePhysical; if (GUILayout.Button("Physical Characteristics", GUILayout.ExpandWidth(true))) togglePhysical.value = !togglePhysical;
   
if (togglePhysical) if (togglePhysical)
{ {
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
//begin physical info value label column //begin physical info value label column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
GUILayout.Label("Radius:"); GUILayout.Label("Radius:");
GUILayout.Label("Surface area:"); GUILayout.Label("Surface area:");
GUILayout.Label("Volume:"); GUILayout.Label("Volume:");
GUILayout.Label("Mass:"); GUILayout.Label("Mass:");
GUILayout.Label("Density:"); GUILayout.Label("Density:");
GUILayout.Label("Sphere of influence:"); GUILayout.Label("Sphere of influence:");
GUILayout.Label("Natural satellites:"); GUILayout.Label("Natural satellites:");
GUILayout.Label("Artificial satellites:"); GUILayout.Label("Artificial satellites:");
GUILayout.Label("Surface gravity:"); GUILayout.Label("Surface gravity:");
GUILayout.Label("Atmosphere altitude:"); GUILayout.Label("Atmosphere Depth:");
GUILayout.Label("Atmospheric O\u2082:"); GUILayout.Label("Atmospheric O\u2082:");
GUILayout.Label("Has ocean:"); GUILayout.Label("Has ocean:");
   
//end physical info value label column //end physical info value label column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin primary physical values column //begin primary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_physical_info(selectedBody1); body_OP_show_physical_info(selectedBody1);
   
//end primary physical column //end primary physical column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//begin secondary physical values column //begin secondary physical values column
GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.BeginVertical(GUILayout.Width(150));
   
body_OP_show_physical_info(selectedBody2); body_OP_show_physical_info(selectedBody2);
   
//end target physical values column //end target physical values column
GUILayout.EndVertical(); GUILayout.EndVertical();
   
//end physical value horizontal chunk //end physical value horizontal chunk
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
   
GUI.DragWindow(); if (GUILayout.Button("Scientific Parameters", GUILayout.ExpandWidth(true)))
  {
  toggleScience.value = !toggleScience;
  }
   
  if (toggleScience)
  {
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
  //begin physical info value label column
  GUILayout.BeginVertical(GUILayout.Width(150));
   
   
  /*
  * public float RecoveryValue = 1f;
   
  public float InSpaceHighDataValue = 1f;
   
  public float spaceAltitudeThreshold = 250000f;
   
  public float flyingAltitudeThreshold = 18000f;
   
  public float InSpaceLowDataValue = 1f;
   
  public float SplashedDataValue = 1f;
   
  public float LandedDataValue = 1f;
   
  public float FlyingHighDataValue = 1f;
   
  public float FlyingLowDataValue = 1f;
  */
   
  GUILayout.Label("Surface Multiplier:");
  GUILayout.Label("Ocean Multiplier:");
  GUILayout.Label("Flying-Low Multiplier:");
  GUILayout.Label("Flying-High Multiplier:");
  GUILayout.Label("Low Orbit Multiplier:");
  GUILayout.Label("High Orbit Multiplier:");
  GUILayout.Label("'Flying-High' Altitude:");
  GUILayout.Label("'High Orbit' Altitude:");
  GUILayout.Label("Recovery Multiplier:");
   
  //end physical info value label column
  GUILayout.EndVertical();
   
  //begin primary physical values column
  GUILayout.BeginVertical(GUILayout.Width(150));
   
  this.cbColumnScience(selectedBody1);
   
  //end primary physical column
  GUILayout.EndVertical();
   
  //begin secondary physical values column
  GUILayout.BeginVertical(GUILayout.Width(150));
   
  this.cbColumnScience(selectedBody2);
   
  //end target physical values column
  GUILayout.EndVertical();
   
  //end physical value horizontal chunk
  GUILayout.EndHorizontal();
  }
   
  base.ModuleWindow(id);
} }
   
private void body_OP_show_orbital_info(CelestialBody body) private void body_OP_show_orbital_info(CelestialBody body)
{ {
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(Tools.ConvertInterval(body.orbit.timeToAp), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToAp), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(Tools.ConvertInterval(body.orbit.timeToPe), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.timeToPe), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(Tools.ConvertInterval(body.orbit.period), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.orbit.period), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(Tools.ConvertInterval(body.rotationPeriod), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(VOID_Tools.FormatInterval(body.rotationPeriod), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// Toadicus edit: convert mean anomaly into degrees. // Toadicus edit: convert mean anomaly into degrees.
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// Toadicus edit: convert eccentric anomaly into degrees. // Toadicus edit: convert eccentric anomaly into degrees.
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else else
{ {
string body_tidally_locked = "No"; string body_tidally_locked = "No";
if (body.tidallyLocked) body_tidally_locked = "Yes"; if (body.tidallyLocked) body_tidally_locked = "Yes";
GUILayout.Label(body_tidally_locked, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(body_tidally_locked, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
} }
   
private void body_OP_show_physical_info(CelestialBody body) private void body_OP_show_physical_info(CelestialBody body)
{ {
   
GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label(((Math.Pow((body.Radius), 2) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label((((body.Radius * body.Radius) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
// divide by 1000 to convert m to km // divide by 1000 to convert m to km
GUILayout.Label((((4d / 3) * Math.PI * Math.Pow(body.Radius, 3)) / 1000).ToString("0.00e+00") + "km³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label((((4d / 3) * Math.PI * (body.Radius * body.Radius * body.Radius)) / 1000).ToString("0.00e+00") + "km³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
double p = body.Mass / (Math.Pow(body.Radius, 3) * (4d / 3) * Math.PI); double p = body.Mass / ((body.Radius * body.Radius * body.Radius) * (4d / 3) * Math.PI);
   
GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); if (body.bodyName == "Sun") GUILayout.Label(SIFormatProvider.ToSI(body.sphereOfInfluence, 3), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); else GUILayout.Label(SIFormatProvider.ToSI(body.sphereOfInfluence, 3), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
//show # artificial satellites //show # artificial satellites
int num_art_sats = 0; int num_art_sats = 0;
foreach (Vessel v in FlightGlobals.Vessels)  
{ Vessel v;
  for (int idx = 0; idx < FlightGlobals.Vessels.Count; idx++)
  {
  v = FlightGlobals.Vessels[idx];
   
if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++; if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++;
} }
   
GUILayout.Label(num_art_sats.ToString(), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(num_art_sats.ToString(), VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
double g_ASL = (VOID_Core.Constant_G * body.Mass) / Math.Pow(body.Radius, 2); double g_ASL = (VOIDCore.Constant_G * body.Mass) / (body.Radius * body.Radius);
   
GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(SIFormatProvider.ToSI(g_ASL, 3) + "m/s²", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
   
if (body.atmosphere) if (body.atmosphere)
{ {
GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m", GUILayout.Label("≈ " + SIFormatProvider.ToSI(body.atmosphereDepth, 3) + "m",
VOID_Core.Instance.LabelStyles["right"], VOID_Styles.labelRight,
GUILayout.ExpandWidth(true)); GUILayout.ExpandWidth(true));
   
string O2 = "No"; string O2 = "No";
if (body.atmosphereContainsOxygen == true) O2 = "Yes"; if (body.atmosphereContainsOxygen == true) O2 = "Yes";
GUILayout.Label(O2, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(O2, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
else else
{ {
GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label("N/A", VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
} }
   
string ocean = "No"; string ocean = "No";
if (body.ocean == true) ocean = "Yes"; if (body.ocean == true) ocean = "Yes";
GUILayout.Label(ocean, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true)); GUILayout.Label(ocean, VOID_Styles.labelRight, GUILayout.ExpandWidth(true));
  }
   
  private void cbColumnScience(CelestialBody body)
  {
  /*GUILayout.Label("Surface Science Multiplier:");
  GUILayout.Label("Ocean Science Multiplier:");
  GUILayout.Label("Low-Atmosphere Science Multiplier:");
  GUILayout.Label("High-Atmosphere Science Multiplier:");
  GUILayout.Label("Low Orbit Science Multiplier:");
  GUILayout.Label("High Orbit Science Multiplier:");
  GUILayout.Label("'In Space' Altitude:");
  GUILayout.Label("'Flying' Altitude:");
  GUILayout.Label("Recovery Multiplier:");*/
   
  var scienceValues = body.scienceValues;
   
  GUILayout.Label(scienceValues.LandedDataValue.ToString("0.0#"),
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
   
  GUILayout.Label(
  body.ocean ? scienceValues.SplashedDataValue.ToString("0.0#") : "N/A",
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
   
  GUILayout.Label(
  body.atmosphere ? scienceValues.FlyingLowDataValue.ToString("0.0#") : "N/A",
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
   
  GUILayout.Label(
  body.atmosphere ? scienceValues.FlyingHighDataValue.ToString("0.0#") : "N/A",
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
   
  GUILayout.Label(scienceValues.InSpaceLowDataValue.ToString("0.0#"),
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
   
  GUILayout.Label(scienceValues.InSpaceHighDataValue.ToString("0.0#"),
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
   
  GUILayout.Label(
  body.atmosphere ? scienceValues.flyingAltitudeThreshold.ToString("N0") : "N/A",
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
   
  GUILayout.Label(
  scienceValues.spaceAltitudeThreshold.ToString("N0"),
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
   
  GUILayout.Label(scienceValues.RecoveryValue.ToString("0.0#"),
  VOID_Styles.labelRight,
  GUILayout.ExpandWidth(true));
} }
} }
} }
  // VOID
  //
  // VOID_CareerStatus.cs
  //
  // Copyright © 2014, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KSP;
  using System;
  using System.Text;
  using ToadicusTools;
  using ToadicusTools.Text;
  using UnityEngine;
 
  namespace VOID
  {
  [VOID_Scenes(GameScenes.FLIGHT, GameScenes.EDITOR, GameScenes.SPACECENTER)]
  [VOID_GameModes(Game.Modes.CAREER, Game.Modes.SCIENCE_SANDBOX)]
  public class VOID_CareerStatus : VOID_SingletonWindow<VOID_CareerStatus>
  {
  public static string formatDelta(double delta, string numberFormat)
  {
  if (delta > 0)
  {
  return string.Format("<color='lime'>{0}↑</color>", delta.ToString(numberFormat, SIFormatProvider.SIFormatter));
  }
  else if (delta < 0)
  {
  return string.Format("<color='red'>{0}↓</color>", delta.ToString(numberFormat, SIFormatProvider.SIFormatter));
  }
  else
  {
  return "0";
  }
  }
 
  public static string formatDelta(double delta)
  {
  return formatDelta(delta, "#,##0.##");
  }
 
  public static string formatDelta(float delta)
  {
  return formatDelta((double)delta);
  }
 
  private GUIContent fundsContent;
  private GUIContent repContent;
  private GUIContent scienceContent;
 
  #pragma warning disable 0414
  private Texture2D fundsIconGreen;
  private Texture2D fundsIconRed;
  private Texture2D reputationIconGreen;
  private Texture2D reputationIconRed;
  private Texture2D scienceIcon;
  #pragma warning restore 0414
 
  public double lastFundsChange
  {
  get;
  private set;
  }
 
  public float lastRepChange
  {
  get;
  private set;
  }
 
  public float lastScienceChange
  {
  get;
  private set;
  }
 
  public double currentFunds
  {
  get;
  private set;
  }
 
  public float currentReputation
  {
  get;
  private set;
  }
 
  public float currentScience
  {
  get;
  private set;
  }
 
  private bool currenciesInitialized
  {
  get
  {
  Logging.PostDebugMessage(
  this,
  "Checking init state:" +
  "\n\tcurrentFunds={0}" +
  "\n\tcurrentScience={1}" +
  "\n\tcurrentReputation={2}",
  this.currentFunds,
  this.currentScience,
  this.currentReputation
  );
 
  return !(
  double.IsNaN(this.currentFunds) ||
  float.IsNaN(this.currentScience) ||
  float.IsNaN(this.currentReputation)
  );
  }
  }
 
  public override void DrawGUI(object sender)
  {
  if (Event.current.type != EventType.Layout && !this.currenciesInitialized)
  {
  this.initCurrencies();
  }
 
  base.DrawGUI(sender);
  }
 
  public override void ModuleWindow(int id)
  {
  GUILayout.BeginVertical();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label(VOID_Data.fundingStatus.Label);
  GUILayout.FlexibleSpace();
  this.fundsContent.text = VOID_Data.fundingStatus.Value;
  GUILayout.Label(this.fundsContent, GUILayout.ExpandWidth(true));
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label(VOID_Data.reputationStatus.Label);
  GUILayout.FlexibleSpace();
  this.repContent.text = VOID_Data.reputationStatus.Value;
  GUILayout.Label(this.repContent, GUILayout.ExpandWidth(true));
  GUILayout.EndHorizontal();
 
  GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
  GUILayout.Label(VOID_Data.scienceStatus.Label);
  GUILayout.FlexibleSpace();
  this.scienceContent.text = VOID_Data.scienceStatus.Value;
  GUILayout.Label(this.scienceContent, GUILayout.ExpandWidth(true));
  GUILayout.EndHorizontal();
 
  GUILayout.EndVertical();
 
  base.ModuleWindow(id);
  }
 
  // TODO: Update event handlers to do something useful with the new "reasons" parameter.
  private void onFundsChange(double newValue, TransactionReasons reasons)
  {
  this.lastFundsChange = newValue - this.currentFunds;
  this.currentFunds = newValue;
  }
 
  private void onRepChange(float newValue, TransactionReasons reasons)
  {
  this.lastRepChange = newValue - this.currentReputation;
  this.currentReputation = newValue;
  }
 
  private void onScienceChange(float newValue, TransactionReasons reasons)
  {
  this.lastScienceChange = newValue - this.currentScience;
  this.currentScience = newValue;
  }
 
  private void onGameStateLoad(ConfigNode node)
  {
  this.initCurrencies();
  }
 
  private void initCurrencies()
  {
  Logging.PostDebugMessage(
  this,
  "Initializing currencies." +
  "\n\tFunding.Instance={0}" +
  "ResearchAndDevelopment.Instance={1}" +
  "Reputation.Instance={2}",
  Funding.Instance == null ? "NULL" : Funding.Instance.ToString(),
  ResearchAndDevelopment.Instance == null ? "NULL" : ResearchAndDevelopment.Instance.ToString(),
  Reputation.Instance == null ? "NULL" : Reputation.Instance.ToString()
  );
 
  this.currentFunds = Funding.Instance != null ? Funding.Instance.Funds : double.NaN;
  this.currentReputation = Reputation.Instance != null ? Reputation.Instance.reputation : float.NaN;
  this.currentScience = ResearchAndDevelopment.Instance != null ?
  ResearchAndDevelopment.Instance.Science : float.NaN;
  }
 
  /*
  * MissionRecoveryDialog::fundsIconGreen.name: UiElements_05
  * MissionRecoveryDialog::fundsIconRed.name: UiElements_06
  * MissionRecoveryDialog::reputationIconGreen.name: UiElements_07
  * MissionRecoveryDialog::reputationIconRed.name: UiElements_08
  * MissionRecoveryDialog::scienceIcon.name: UiElements_12
  * */
  public VOID_CareerStatus() : base()
  {
  this.Name = "Career Status";
 
  GameEvents.OnFundsChanged.Add(this.onFundsChange);
  GameEvents.OnReputationChanged.Add(this.onRepChange);
  GameEvents.OnScienceChanged.Add(this.onScienceChange);
  GameEvents.onGameStateLoad.Add(this.onGameStateLoad);
 
  bool texturesLoaded;
 
  texturesLoaded = IOTools.LoadTexture(out this.fundsIconGreen, "VOID/Textures/fundsgreen.png", 10, 18);
  texturesLoaded &= IOTools.LoadTexture(out this.fundsIconRed, "VOID/Textures/fundsred.png", 10, 18);
  texturesLoaded &= IOTools.LoadTexture(out this.reputationIconGreen, "VOID/Textures/repgreen.png", 16, 18);
  texturesLoaded &= IOTools.LoadTexture(out this.reputationIconRed, "VOID/Textures/repred.png", 16, 18);
  texturesLoaded &= IOTools.LoadTexture(out this.scienceIcon, "VOID/Textures/science.png", 16, 18);
 
  this.fundsContent = new GUIContent();
  this.repContent = new GUIContent();
  this.scienceContent = new GUIContent();
 
  if (texturesLoaded)
  {
  this.fundsContent.image = this.fundsIconGreen;
  this.repContent.image = this.reputationIconGreen;
  this.scienceContent.image = this.scienceIcon;
  }
 
  this.currentFunds = double.NaN;
  this.currentScience = float.NaN;
  this.currentReputation = float.NaN;
  }
 
  public override void Dispose()
  {
  GameEvents.OnFundsChanged.Remove(this.onFundsChange);
  GameEvents.OnReputationChanged.Remove(this.onRepChange);
  GameEvents.OnScienceChanged.Remove(this.onScienceChange);
  GameEvents.onGameStateLoad.Remove(this.onGameStateLoad);
 
  base.Dispose();
  }
 
  ~VOID_CareerStatus()
  {
  this.Dispose();
  }
  }
  }
 
 
  // VOID
  //
  // VOID_ConfigModule.cs
  //
  // Copyright © 2015, toadicus
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification,
  // are permitted provided that the following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 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
  // materials provided with the distribution.
  //
  // 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.
  //
  // 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
  // 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
  // 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
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  using KSP;
  using System;
  using UnityEngine;
 
  namespace VOID
  {
  public class VOID_ConfigWindow : VOID_SingletonWindow<VOID_ConfigWindow>
  {
  public override bool InValidScene
  {
  get
  {
  return true;
  }
  }
 
  public override bool InValidGame
  {
  get
  {
  return true;
  }
  }
 
  public VOID_ConfigWindow() : base()
  {
  this.Name = "VOID Configuration";
  }
 
  public override void ModuleWindow(int id)
  {
  GUILayout.BeginVertical();
 
  this.core.DrawConfigurables();
 
  GUILayout.EndVertical();
 
  base.ModuleWindow(id);
  }
 
  ~VOID_ConfigWindow()
  {
  this.Dispose();
  }
  }
  }
 
file:a/VOID_Core.cs (deleted)
//  
// VOID_Core.cs  
//  
// Author:  
// toadicus <>  
//  
// Copyright (c) 2013 toadicus  
//  
// This program is free software: you can redistribute it and/or modify  
// it under the terms of the GNU General Public License as published by  
// the Free Software Foundation, either version 3 of the License, or  
// (at your option) any later version.  
//  
// This program is distributed in the hope that it will be useful,  
// but WITHOUT ANY WARRANTY; without even the implied warranty of  
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
// GNU General Public License for more details.  
//  
// You should have received a copy of the GNU General Public License  
// along with this program. If not, see <http://www.gnu.org/licenses/>.  
using System;  
using System.Collections.Generic;  
using System.Linq;  
using KSP;  
using UnityEngine;  
using Engineer.VesselSimulator;  
 
namespace VOID  
{  
public class VOID_Core : VOID_Module, IVOID_Module  
{  
/*  
* Static Members  
* */  
protected static bool _initialized = false;  
 
public static bool Initialized  
{  
get  
{  
return _initialized;  
}  
}  
 
protected static VOID_Core _instance;  
 
public static VOID_Core Instance  
{  
get  
{  
if (_instance == null)  
{  
_instance = new VOID_Core();  
_initialized = true;  
}  
return _instance;  
}  
}  
 
public static void Reset()  
{  
_instance.StopGUI();  
_instance = null;  
_initialized = false;  
}  
 
public static double Constant_G = 6.674e-11;  
/*  
* Fields  
* */  
protected string VoidName = "VOID";  
protected string VoidVersion = "0.9.20";  
 
protected bool _factoryReset = false;  
 
[AVOID_SaveValue("configValue")]  
protected VOID_SaveValue<int> configVersion = 1;  
 
protected List<IVOID_Module> _modules = new List<IVOID_Module>();  
protected bool _modulesLoaded = false;  
 
[AVOID_SaveValue("mainWindowPos")]  
protected VOID_SaveValue<Rect> mainWindowPos = new Rect(475, 575, 10f, 10f);  
[AVOID_SaveValue("mainGuiMinimized")]  
protected VOID_SaveValue<bool> mainGuiMinimized = false;  
 
[AVOID_SaveValue("configWindowPos")]  
protected VOID_SaveValue<Rect> configWindowPos = new Rect(825, 625, 10f, 10f);  
[AVOID_SaveValue("configWindowMinimized")]  
 
protected VOID_SaveValue<bool> configWindowMinimized = true;  
[AVOID_SaveValue("VOIDIconPos")]  
protected VOID_SaveValue<Rect> VOIDIconPos = new Rect(Screen.width / 2 - 200, Screen.height - 32, 32f, 32f);  
 
protected Texture2D VOIDIconTexture;  
protected string VOIDIconOnActivePath;  
protected string VOIDIconOnInactivePath;  
protected string VOIDIconOffActivePath;  
protected string VOIDIconOffInactivePath;  
 
protected bool VOIDIconLocked = true;  
 
protected GUIStyle iconStyle;  
 
protected int windowBaseID = -96518722;  
protected int _windowID = 0;  
 
protected bool GUIStylesLoaded = false;  
protected Dictionary<string, GUIStyle> _LabelStyles = new Dictionary<string, GUIStyle>();  
 
protected CelestialBody _Kerbin;  
 
[AVOID_SaveValue("togglePower")]  
public VOID_SaveValue<bool> togglePower = true;  
public bool powerAvailable = true;  
 
[AVOID_SaveValue("consumeResource")]  
protected VOID_SaveValue<bool> consumeResource = false;  
 
[AVOID_SaveValue("resourceName")]  
protected VOID_SaveValue<string> resourceName = "ElectricCharge";  
 
[AVOID_SaveValue("resourceRate")]  
protected VOID_SaveValue<float> resourceRate = 0.2f;  
 
[AVOID_SaveValue("updatePeriod")]  
protected VOID_SaveValue<double> _updatePeriod = 1001f / 15000f;  
protected float _updateTimer = 0f;  
protected string stringFrequency;  
 
// Vessel Type Housekeeping  
protected List<VesselType> _allVesselTypes = new List<VesselType>();  
protected bool vesselTypesLoaded = false;  
public float saveTimer = 0;  
 
protected string defaultSkin = "KSP window 2";  
[AVOID_SaveValue("defaultSkin")]  
protected VOID_SaveValue<string> _skinName;  
protected Dictionary<string, GUISkin> skin_list;  
protected List<string> skinNames;  
protected string[] forbiddenSkins =  
{  
"PlaqueDialogSkin",  
"FlagBrowserSkin",  
"SSUITextAreaDefault",  
"ExperimentsDialogSkin",  
"ExpRecoveryDialogSkin",  
"KSP window 5",  
"KSP window 6",  
"PartTooltipSkin"  
};  
protected bool skinsLoaded = false;  
 
public bool configDirty;  
 
[AVOID_SaveValue("UseBlizzyToolbar")]  
protected VOID_SaveValue<bool> _UseToolbarManager;  
internal IButton ToolbarButton;  
 
/*  
* Properties  
* */  
public bool factoryReset  
{  
get  
{  
return this._factoryReset;  
}  
}  
 
public List<IVOID_Module> Modules  
{  
get  
{  
return this._modules;  
}  
}  
 
public GUISkin Skin  
{  
get  
{  
if (!this.skinsLoaded || this._skinName == null)  
{  
return AssetBase.GetGUISkin(this.defaultSkin);