Create README.md
Create README.md

Just the part dev portion so far, taken from http://goo.gl/3scCXl

--- a/ARConfiguration.cs
+++ b/ARConfiguration.cs
@@ -23,10 +23,6 @@
 		private const string FIXED_POWER_KEY = "fixedPowerCost";
 		private const string PRETTY_LINES_KEY = "drawPrettyLines";
 		private const string UPDATE_DELAY_KEY = "updateDelay";
-		private const string USE_ADDITIVE_KEY = "useAdditiveRanges";
-
-		private const string TRACKING_STATION_RANGES_KEY = "TRACKING_STATION_RANGES";
-		private const string RANGE_KEY = "range";
 
 		/// <summary>
 		/// Indicates whether connections require line of sight.
@@ -74,39 +70,10 @@
 			set;
 		}
 
-		/// <summary>
-		/// Gets the update delay.
-		/// </summary>
 		public static long UpdateDelay
 		{
 			get;
 			private set;
-		}
-
-		public static bool UseAdditiveRanges
-		{
-			get;
-			private set;
-		}
-
-		/// <summary>
-		/// Gets Kerbin's relay range based on the current tracking station level.
-		/// </summary>
-		public static double KerbinRelayRange
-		{
-			get;
-			private set;
-		}
-
-		/// <summary>
-		/// Gets Kerbin's nominal relay range based on the current tracking station level.
-		/// </summary>
-		public static double KerbinNominalRange
-		{
-			get
-			{
-				return KerbinRelayRange / 2.8284271247461901d;
-			}
 		}
 
 #pragma warning disable 1591
@@ -120,11 +87,7 @@
 		private IButton toolbarButton;
 		private ApplicationLauncherButton appLauncherButton;
 
-		private double[] trackingStationRanges;
-
 		private System.Version runningVersion;
-
-		private bool runOnce;
 
 		private KSP.IO.PluginConfiguration _config;
 		private KSP.IO.PluginConfiguration config
@@ -166,63 +129,13 @@
 
 			ARConfiguration.UpdateDelay = this.LoadConfigValue(UPDATE_DELAY_KEY, 16L);
 
-			ARConfiguration.UseAdditiveRanges = this.LoadConfigValue(USE_ADDITIVE_KEY, true);
-
 			this.updateDelayStr = ARConfiguration.UpdateDelay.ToString();
 
 			GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested);
-			GameEvents.OnKSCFacilityUpgraded.Add(this.onFacilityUpgraded);
 
 			Debug.Log(string.Format("{0} v{1} - ARConfiguration loaded!", this.GetType().Name, this.runningVersion));
 
-			ConfigNode[] tsRangeNodes = GameDatabase.Instance.GetConfigNodes(TRACKING_STATION_RANGES_KEY);
-
-			if (tsRangeNodes.Length > 0)
-			{
-				string[] rangeValues = tsRangeNodes[0].GetValues(RANGE_KEY);
-
-				this.trackingStationRanges = new double[rangeValues.Length];
-
-				for (int idx = 0; idx < rangeValues.Length; idx++)
-				{
-					if (!double.TryParse(rangeValues[idx], out this.trackingStationRanges[idx]))
-					{
-						this.LogError("Could not parse value '{0}' to double; Tracking Station ranges may not work!");
-						this.trackingStationRanges[idx] = 0d;
-					}
-				}
-
-				this.Log("Loaded Tracking Station ranges from config: [{0}]", this.trackingStationRanges.SPrint());
-			}
-			else
-			{
-				this.trackingStationRanges = new double[]
-				{
-					51696576d,
-					37152180000d,
-					224770770000d
-				};
-
-				this.LogWarning("Failed to load Tracking Station ranges from config, using hard-coded values: [{0}]",
-					this.trackingStationRanges.SPrint());
-			}
-
-			this.runOnce = true;
-
 			Tools.PostDebugMessage(this, "Awake.");
-		}
-
-		public void Update()
-		{
-			if (
-				this.runOnce &&
-				(ScenarioUpgradeableFacilities.Instance != null || HighLogic.CurrentGame.Mode != Game.Modes.CAREER)
-			)
-			{
-				this.runOnce = false;
-
-				this.SetKerbinRelayRange();
-			}
 		}
 
 		public void OnGUI()
@@ -323,17 +236,6 @@
 
 			GUILayout.BeginHorizontal();
 
-			bool useAdditive = GUITools.Toggle(ARConfiguration.UseAdditiveRanges, "Use Additive Ranges");
-			if (useAdditive != ARConfiguration.UseAdditiveRanges)
-			{
-				ARConfiguration.UseAdditiveRanges = useAdditive;
-				this.SaveConfigValue(USE_ADDITIVE_KEY, useAdditive);
-			}
-
-			GUILayout.EndHorizontal();
-
-			GUILayout.BeginHorizontal();
-
 			bool prettyLines = GUITools.Toggle(ARConfiguration.PrettyLines, "Draw Pretty Lines");
 			if (prettyLines != ARConfiguration.PrettyLines)
 			{
@@ -392,22 +294,19 @@
 		public void OnDestroy()
 		{
 			GameEvents.onGameSceneLoadRequested.Remove(this.onSceneChangeRequested);
-			GameEvents.OnKSCFacilityUpgraded.Remove(this.onFacilityUpgraded);
 
 			if (this.toolbarButton != null)
 			{
 				this.toolbarButton.Destroy();
-				this.toolbarButton = null;
 			}
 
 			if (this.appLauncherButton != null)
 			{
 				ApplicationLauncher.Instance.RemoveModApplication(this.appLauncherButton);
-				this.appLauncherButton = null;
-			}
-		}
-
-		private void onSceneChangeRequested(GameScenes scene)
+			}
+		}
+
+		protected void onSceneChangeRequested(GameScenes scene)
 		{
 			if (scene != GameScenes.SPACECENTER)
 			{
@@ -416,42 +315,6 @@
 			}
 		}
 
-		private void onFacilityUpgraded(Upgradeables.UpgradeableFacility fac, int lvl)
-		{
-			if (fac.id == "SpaceCenter/TrackingStation")
-			{
-				this.Log("Caught onFacilityUpgraded for {0} at level {1}", fac.id, lvl);
-				this.SetKerbinRelayRange();
-			}
-		}
-
-		private void SetKerbinRelayRange()
-		{
-			int tsLevel;
-
-			if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER)
-			{
-				tsLevel = ScenarioUpgradeableFacilities.protoUpgradeables["SpaceCenter/TrackingStation"]
-					.facilityRefs[0].FacilityLevel;
-			
-
-			}
-			else
-			{
-				tsLevel = this.trackingStationRanges.Length - 1;
-			}
-
-			if (tsLevel < this.trackingStationRanges.Length && tsLevel >= 0)
-			{
-				KerbinRelayRange = this.trackingStationRanges[tsLevel];
-				this.Log("Setting Kerbin's range to {0}", KerbinRelayRange);
-			}
-			else
-			{
-				this.LogError("Could not set Kerbin's range with invalid Tracking Station level {0}", tsLevel);
-			}
-		}
-
 		private void toggleConfigWindow()
 		{
 			this.showConfigWindow = !this.showConfigWindow;

--- a/ARMapRenderer.cs
+++ b/ARMapRenderer.cs
@@ -261,7 +261,7 @@
 			}
 			else
 			{
-				if (relay.LinkStatus == ConnectionStatus.Optimal)
+				if (relay.transmitDistance < relay.nominalTransmitDistance)
 				{
 					thisColor = Color.green;
 				}

--- a/AntennaRelay.cs
+++ b/AntennaRelay.cs
@@ -90,6 +90,53 @@
 		}
 
 		/// <summary>
+		/// Gets the first <see cref="CelestialBody"/> found to be blocking line of sight.
+		/// </summary>
+		public virtual CelestialBody firstOccludingBody
+		{
+			get;
+			protected set;
+		}
+
+		/// <summary>
+		/// Gets the transmit distance.
+		/// </summary>
+		/// <value>The transmit distance.</value>
+		public double transmitDistance
+		{
+			get
+			{
+				if (this.KerbinDirect || this.targetRelay == null)
+				{
+					return this.DistanceTo(Kerbin);
+				}
+				else
+				{
+					return this.DistanceTo(this.targetRelay);
+				}
+			}
+		}
+
+		/// <summary>
+		/// Gets the nominal transmit distance at which the Antenna behaves just as prescribed by Squad's config.
+		/// </summary>
+		public virtual double nominalTransmitDistance
+		{
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// The maximum distance at which this relay can operate.
+		/// </summary>
+		/// <value>The max transmit distance.</value>
+		public virtual double maxTransmitDistance
+		{
+			get;
+			set;
+		}
+
+		/// <summary>
 		/// Gets a value indicating whether this <see cref="AntennaRange.IAntennaRelay"/> Relay is communicating
 		/// directly with Kerbin.
 		/// </summary>
@@ -97,77 +144,6 @@
 		{
 			get;
 			protected set;
-		}
-
-		/// <summary>
-		/// Gets or sets the nominal link distance, in meters.
-		/// </summary>
-		public virtual double NominalLinkDistance
-		{
-			get;
-			protected set;
-		}
-
-		/// <summary>
-		/// Gets or sets the maximum link distance, in meters.
-		/// </summary>
-		public virtual double MaximumLinkDistance
-		{
-			get;
-			protected set;
-		}
-
-		/// <summary>
-		/// Gets the first <see cref="CelestialBody"/> found to be blocking line of sight.
-		/// </summary>
-		public virtual CelestialBody firstOccludingBody
-		{
-			get;
-			protected set;
-		}
-
-		/// <summary>
-		/// Gets the transmit distance.
-		/// </summary>
-		/// <value>The transmit distance.</value>
-		public double transmitDistance
-		{
-			get
-			{
-				if (this.KerbinDirect || this.targetRelay == null)
-				{
-					return this.DistanceTo(Kerbin);
-				}
-				else
-				{
-					return this.DistanceTo(this.targetRelay);
-				}
-			}
-		}
-
-		public virtual ConnectionStatus LinkStatus
-		{
-			get;
-			protected set;
-		}
-
-		/// <summary>
-		/// Gets the nominal transmit distance at which the Antenna behaves just as prescribed by Squad's config.
-		/// </summary>
-		public virtual double nominalTransmitDistance
-		{
-			get;
-			set;
-		}
-
-		/// <summary>
-		/// The maximum distance at which this relay can operate.
-		/// </summary>
-		/// <value>The max transmit distance.</value>
-		public virtual double maxTransmitDistance
-		{
-			get;
-			set;
 		}
 
 		/// <summary>
@@ -224,13 +200,9 @@
 			CelestialBody bodyOccludingBestOccludedRelay = null;
 			IAntennaRelay needle;
 
-			// double nearestRelaySqrDistance = double.PositiveInfinity;
-			// double bestOccludedSqrDistance = double.PositiveInfinity;
-
-			// double maxTransmitSqrDistance = double.NegativeInfinity;
-
-			double nearestRelaySqrQuotient = double.PositiveInfinity;
-			double bestOccludedSqrQuotient = double.PositiveInfinity;
+			double nearestRelaySqrDistance = double.PositiveInfinity;
+			double bestOccludedSqrDistance = double.PositiveInfinity;
+			double maxTransmitSqrDistance = this.maxTransmitDistance * this.maxTransmitDistance;
 
 			/*
 			 * Loop through all the vessels and exclude this vessel, vessels of the wrong type, and vessels that are too
@@ -285,36 +257,20 @@
 					continue;
 				}
 
-				potentialBestRelay = potentialVessel.GetBestRelay();
-				log.AppendFormat("\n\t\tgot best vessel relay {0}",
-					potentialBestRelay == null ? "null" : potentialBestRelay.ToString());
-
-				if (potentialBestRelay == null)
-				{
-					log.Append("\n\t\t...skipping null relay");
-					continue;
-				}
-
 				// Find the distance from here to the vessel...
 				log.Append("\n\tgetting distance to potential vessel");
 				double potentialSqrDistance = this.sqrDistanceTo(potentialVessel);
 				log.Append("\n\tgetting best vessel relay");
 
-				log.Append("\n\tgetting max link distance to potential relay");
-				double maxLinkSqrDistance;
-
-				if (ARConfiguration.UseAdditiveRanges)
-				{
-					maxLinkSqrDistance = this.maxTransmitDistance * potentialBestRelay.maxTransmitDistance;
-				}
-				else
-				{
-					maxLinkSqrDistance = this.maxTransmitDistance * this.maxTransmitDistance;
-				}
-
-				log.AppendFormat("\n\tmax link distance: {0}", maxLinkSqrDistance);
-
-				double potentialSqrQuotient = potentialSqrDistance / maxLinkSqrDistance;
+				potentialBestRelay = potentialVessel.GetBestRelay();
+				log.AppendFormat("\n\t\tgot best vessel relay {0}",
+					potentialBestRelay == null ? "null" : potentialBestRelay.ToString());
+
+				if (potentialBestRelay == null)
+				{
+					log.Append("\n\t\t...skipping null relay");
+					continue;
+				}
 
 				log.Append("\n\t\tdoing LOS check");
 				// Skip vessels to which we do not have line of sight.
@@ -329,12 +285,12 @@
 						this.ToString(), potentialVessel.vesselName);
 					
 					log.AppendFormat("\n\t\t\tpotentialSqrDistance: {0}", potentialSqrDistance);
-					log.AppendFormat("\n\t\t\tbestOccludedSqrQuotient: {0}", bestOccludedSqrQuotient);
-					log.AppendFormat("\n\t\t\tmaxTransmitSqrDistance: {0}", maxLinkSqrDistance);
+					log.AppendFormat("\n\t\t\tbestOccludedSqrDistance: {0}", bestOccludedSqrDistance);
+					log.AppendFormat("\n\t\t\tmaxTransmitSqrDistance: {0}", maxTransmitSqrDistance);
 
 					if (
-						(potentialSqrQuotient < bestOccludedSqrQuotient) &&
-						(potentialSqrQuotient <= 1d) &&
+						(potentialSqrDistance < bestOccludedSqrDistance) &&
+						(potentialSqrDistance < maxTransmitSqrDistance) &&
 						potentialBestRelay.CanTransmit()
 					)
 					{
@@ -343,7 +299,7 @@
 
 						this.bestOccludedRelay = potentialBestRelay;
 						bodyOccludingBestOccludedRelay = fob;
-						bestOccludedSqrQuotient = potentialSqrQuotient;
+						bestOccludedSqrDistance = potentialSqrDistance;
 					}
 					else
 					{
@@ -358,7 +314,7 @@
 				/*
 				 * ...so that we can skip the vessel if it is further away than a vessel we've already checked.
 				 * */
-				if (potentialSqrQuotient > nearestRelaySqrQuotient)
+				if (potentialSqrDistance > nearestRelaySqrDistance)
 				{
 					
 					log.AppendFormat("\n\t{0}: Vessel {1} discarded because it is farther than another the nearest relay.",
@@ -424,13 +380,13 @@
 
 					if (!isCircular)
 					{
-						nearestRelaySqrQuotient = potentialSqrQuotient;
+						nearestRelaySqrDistance = potentialSqrDistance;
 						this.nearestRelay = potentialBestRelay;
 
-						log.AppendFormat("\n\t{0}: found new nearest relay {1} ({2}m²)",
+						log.AppendFormat("\n\t{0}: found new nearest relay {1} ({2}m)",
 							this.ToString(),
 							this.nearestRelay.ToString(),
-							Math.Sqrt(nearestRelaySqrQuotient)
+							Math.Sqrt(nearestRelaySqrDistance)
 						);
 					}
 					else
@@ -446,28 +402,15 @@
 
 			double kerbinSqrDistance = this.vessel.DistanceTo(Kerbin) - Kerbin.Radius;
 			kerbinSqrDistance *= kerbinSqrDistance;
-
-			double kerbinSqrQuotient;
-
-			if (ARConfiguration.UseAdditiveRanges)
-			{
-				kerbinSqrQuotient = kerbinSqrDistance /
-					(this.maxTransmitDistance * ARConfiguration.KerbinRelayRange);
-			}
-			else
-			{
-				kerbinSqrQuotient = kerbinSqrDistance /
-					(this.maxTransmitDistance * this.maxTransmitDistance);
-			}
 
 			log.AppendFormat("\n{0} ({1}): Search done, figuring status.", this.ToString(), this.GetType().Name);
 			log.AppendFormat(
 				"\n{0}: nearestRelay={1} ({2}m²)), bestOccludedRelay={3} ({4}m²), kerbinSqrDistance={5}m²)",
 				this,
 				this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-				nearestRelaySqrQuotient,
+				nearestRelaySqrDistance,
 				this.bestOccludedRelay == null ? "null" : this.bestOccludedRelay.ToString(),
-				bestOccludedSqrQuotient,
+				bestOccludedSqrDistance,
 				kerbinSqrDistance
 			);
 
@@ -481,11 +424,11 @@
 
 				// nearestRelaySqrDistance will be infinity if all relays are occluded or none exist.
 				// Therefore, this will only be true if a valid relay is in range.
-				if (nearestRelaySqrQuotient <= 1d)
+				if (nearestRelaySqrDistance <= maxTransmitSqrDistance)
 				{
 					log.AppendFormat("\n\t\tCan transmit to nearby relay {0} ({1} <= {2}).",
 						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-						nearestRelaySqrQuotient, 1d);
+							nearestRelaySqrDistance, maxTransmitSqrDistance);
 
 					this.KerbinDirect = false;
 					this.canTransmit = true;
@@ -496,13 +439,13 @@
 				{
 					log.AppendFormat("\n\t\tCan't transmit to nearby relay {0} ({1} > {2}).",
 						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-						nearestRelaySqrQuotient, 1d);
+							nearestRelaySqrDistance, maxTransmitSqrDistance);
 
 					this.canTransmit = false;
 
 					// If the best occluded relay is closer than Kerbin, check it against the nearest relay.
 					// Since bestOccludedSqrDistance is infinity if there are no occluded relays, this is safe
-					if (bestOccludedSqrQuotient < kerbinSqrQuotient)
+					if (bestOccludedSqrDistance < kerbinSqrDistance)
 					{
 						log.AppendFormat("\n\t\t\tBest occluded relay is closer than Kerbin ({0} < {1})",
 							bestOccludedRelay, kerbinSqrDistance);
@@ -511,10 +454,10 @@
 
 						// If the nearest relay is closer than the best occluded relay, pick it.
 						// Since nearestRelaySqrDistane is infinity if there are no nearby relays, this is safe.
-						if (nearestRelaySqrQuotient < bestOccludedSqrQuotient)
+						if (nearestRelaySqrDistance < bestOccludedSqrDistance)
 						{
 							log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
-								nearestRelaySqrQuotient, bestOccludedSqrQuotient);
+								nearestRelaySqrDistance, bestOccludedSqrDistance);
 							
 							this.targetRelay = this.nearestRelay;
 							this.firstOccludingBody = null;
@@ -523,7 +466,7 @@
 						else
 						{
 							log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
-								nearestRelaySqrQuotient, bestOccludedSqrQuotient);
+								nearestRelaySqrDistance, bestOccludedSqrDistance);
 							
 							this.targetRelay = bestOccludedRelay;
 							this.firstOccludingBody = bodyOccludingBestOccludedRelay;
@@ -536,25 +479,25 @@
 						log.AppendFormat("\n\t\t\tKerbin is closer than the best occluded relay ({0} >= {1})",
 							bestOccludedRelay, kerbinSqrDistance);
 						
+						this.firstOccludingBody = null;
+
 						// If the nearest relay is closer than Kerbin, pick it.
 						// Since nearestRelaySqrDistane is infinity if there are no nearby relays, this is safe.
-						if (nearestRelaySqrQuotient < kerbinSqrQuotient)
+						if (nearestRelaySqrDistance < kerbinSqrDistance)
 						{
 							log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
-								nearestRelaySqrQuotient, kerbinSqrQuotient);
+								nearestRelaySqrDistance, kerbinSqrDistance);
 							
 							this.KerbinDirect = false;
-							this.firstOccludingBody = null;
 							this.targetRelay = this.nearestRelay;
 						}
 						// Otherwise, pick Kerbin.
 						else
 						{
 							log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
-								nearestRelaySqrQuotient, kerbinSqrQuotient);
+								nearestRelaySqrDistance, kerbinSqrDistance);
 							
 							this.KerbinDirect = true;
-							this.firstOccludingBody = bodyOccludingKerbin;
 							this.targetRelay = null;
 						}
 					}
@@ -566,20 +509,20 @@
 				log.AppendFormat("\n\tKerbin is in LOS.");
 
 				// If the nearest relay is closer than Kerbin and in range, transmit to it.
-				if (nearestRelaySqrQuotient <= 1d)
+				if (nearestRelaySqrDistance <= maxTransmitSqrDistance)
 				{
 					log.AppendFormat("\n\t\tCan transmit to nearby relay {0} ({1} <= {2}).",
 						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-						nearestRelaySqrQuotient, 1d);
+							nearestRelaySqrDistance, maxTransmitSqrDistance);
 
 					this.canTransmit = true;
 
 					// If the nearestRelay is closer than Kerbin, use it.
-					if (nearestRelaySqrQuotient < kerbinSqrQuotient)
+					if (nearestRelaySqrDistance < kerbinSqrDistance)
 					{
 						log.AppendFormat("\n\t\t\tPicking relay {0} over Kerbin ({1} < {2}).",
 							this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-							nearestRelaySqrQuotient, kerbinSqrQuotient);
+							nearestRelaySqrDistance, kerbinSqrDistance);
 
 						this.KerbinDirect = false;
 						this.targetRelay = this.nearestRelay;
@@ -589,7 +532,7 @@
 					{
 						log.AppendFormat("\n\t\t\tBut picking Kerbin over nearby relay {0} ({1} >= {2}).",
 							this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-							nearestRelaySqrQuotient, kerbinSqrQuotient);
+								nearestRelaySqrDistance, kerbinSqrDistance);
 
 						this.KerbinDirect = true;
 						this.targetRelay = null;
@@ -600,13 +543,13 @@
 				{
 					log.AppendFormat("\n\t\tCan't transmit to nearby relay {0} ({1} > {2}).",
 						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-							nearestRelaySqrQuotient, 1d);
+							nearestRelaySqrDistance, maxTransmitSqrDistance);
 
 					// If Kerbin is in range, use it.
-					if (kerbinSqrQuotient <= 1d)
+					if (kerbinSqrDistance <= maxTransmitSqrDistance)
 					{
 						log.AppendFormat("\n\t\t\tCan transmit to Kerbin ({0} <= {1}).",
-							kerbinSqrQuotient, 1d);
+							kerbinSqrDistance, maxTransmitSqrDistance);
 
 						this.canTransmit = true;
 						this.KerbinDirect = true;
@@ -617,13 +560,13 @@
 					else
 					{
 						log.AppendFormat("\n\t\t\tCan't transmit to Kerbin ({0} > {1}).",
-								kerbinSqrQuotient, 1d);
+							kerbinSqrDistance, maxTransmitSqrDistance);
 
 						this.canTransmit = false;
 
 						// If the best occluded relay is closer than Kerbin, check it against the nearest relay.
 						// Since bestOccludedSqrDistance is infinity if there are no occluded relays, this is safe
-						if (bestOccludedSqrQuotient < kerbinSqrQuotient)
+						if (bestOccludedSqrDistance < kerbinSqrDistance)
 						{
 							log.AppendFormat("\n\t\t\tBest occluded relay is closer than Kerbin ({0} < {1})",
 								bestOccludedRelay, kerbinSqrDistance);
@@ -632,10 +575,10 @@
 
 							// If the nearest relay is closer than the best occluded relay, pick it.
 							// Since nearestRelaySqrDistane is infinity if there are no nearby relays, this is safe.
-							if (nearestRelaySqrQuotient < bestOccludedSqrQuotient)
+							if (nearestRelaySqrDistance < bestOccludedSqrDistance)
 							{
 								log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
-									nearestRelaySqrQuotient, bestOccludedSqrQuotient);
+									nearestRelaySqrDistance, bestOccludedSqrDistance);
 								
 								this.targetRelay = this.nearestRelay;
 								this.firstOccludingBody = null;
@@ -644,7 +587,7 @@
 							else
 							{
 								log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
-									nearestRelaySqrQuotient, bestOccludedSqrQuotient);
+									nearestRelaySqrDistance, bestOccludedSqrDistance);
 								
 								this.targetRelay = bestOccludedRelay;
 								this.firstOccludingBody = bodyOccludingBestOccludedRelay;
@@ -661,10 +604,10 @@
 
 							// If the nearest relay is closer than Kerbin, pick it.
 							// Since nearestRelaySqrDistane is infinity if there are no nearby relays, this is safe.
-							if (nearestRelaySqrQuotient < kerbinSqrQuotient)
+							if (nearestRelaySqrDistance < kerbinSqrDistance)
 							{
 								log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
-									nearestRelaySqrQuotient, kerbinSqrQuotient);
+									nearestRelaySqrDistance, kerbinSqrDistance);
 								
 								this.KerbinDirect = false;
 								this.targetRelay = this.nearestRelay;
@@ -673,7 +616,7 @@
 							else
 							{
 								log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
-									nearestRelaySqrQuotient, kerbinSqrQuotient);
+									nearestRelaySqrDistance, kerbinSqrDistance);
 								
 								this.KerbinDirect = true;
 								this.targetRelay = null;
@@ -681,41 +624,6 @@
 						}
 					}
 				}
-			}
-
-			if (ARConfiguration.UseAdditiveRanges)
-			{
-				if (this.KerbinDirect)
-				{
-					this.NominalLinkDistance = Math.Sqrt(this.nominalTransmitDistance * ARConfiguration.KerbinNominalRange);
-					this.MaximumLinkDistance = Math.Sqrt(this.maxTransmitDistance * ARConfiguration.KerbinRelayRange);
-				}
-				else
-				{
-					this.NominalLinkDistance = Math.Sqrt(this.nominalTransmitDistance * this.targetRelay.nominalTransmitDistance);
-					this.MaximumLinkDistance = Math.Sqrt(this.maxTransmitDistance * this.targetRelay.maxTransmitDistance);
-				}
-			}
-			else
-			{
-				this.NominalLinkDistance = this.nominalTransmitDistance;
-				this.MaximumLinkDistance = this.maxTransmitDistance;
-			}
-
-			if (this.canTransmit)
-			{
-				if (this.transmitDistance < this.NominalLinkDistance)
-				{
-					this.LinkStatus = ConnectionStatus.Optimal;
-				}
-				else
-				{
-					this.LinkStatus = ConnectionStatus.Suboptimal;
-				}
-			}
-			else
-			{
-				this.LinkStatus = ConnectionStatus.None;
 			}
 
 			log.AppendFormat("\n{0}: Target search and status determination complete.", this.ToString());

--- a/GameData/AntennaRange/AntennaRange.cfg
+++ b/GameData/AntennaRange/AntennaRange.cfg
@@ -42,8 +42,7 @@
 	@MODULE[ModuleDataTransmitter]
 	{
 		@name = ModuleLimitedDataTransmitter
-		nominalRange = 6364
-		simpleRange = 20500000
+		nominalRange = 1500000
 		maxPowerFactor = 8
 		maxDataFactor = 4
 	}
@@ -64,10 +63,9 @@
 	@MODULE[ModuleDataTransmitter]
 	{
 		@name = ModuleLimitedDataTransmitter
-		nominalRange = 3500000000
-		simpleRange = 18000000000
-		maxPowerFactor = 4
-		maxDataFactor = 8
+		nominalRange = 30000000
+		maxPowerFactor = 8
+		maxDataFactor = 4
 	}
 
 	MODULE
@@ -86,11 +84,9 @@
 	@MODULE[ModuleDataTransmitter]
 	{
 		@name = ModuleLimitedDataTransmitter
-		@packetResourceCost /= 1.414213
-		nominalRange = 10000000000
-		simpleRange = 56250000000
-		maxPowerFactor = 16
-		maxDataFactor = 2
+		nominalRange = 80000000000
+		maxPowerFactor = 8
+		maxDataFactor = 4
 	}
 
 	MODULE
@@ -104,18 +100,11 @@
 	}
 }
 
-TRACKING_STATION_RANGES
-{
-	range = 800000
-	range = 200000000000
-	range = 2250000000000
-}
-
 EVA_MODULE
 {
 	name = ModuleLimitedDataTransmitter
 
-	nominalRange = 1389
+	nominalRange = 5000
 	maxPowerFactor = 1
 	maxDataFactor = 1
 

--- a/IAntennaRelay.cs
+++ b/IAntennaRelay.cs
@@ -47,31 +47,9 @@
 		IAntennaRelay targetRelay { get; }
 
 		/// <summary>
-		/// Gets a value indicating whether this <see cref="AntennaRange.IAntennaRelay"/> Relay is communicating
-		/// directly with Kerbin.
-		/// </summary>
-		bool KerbinDirect { get; }
-
-		/// <summary>
-		/// The link distance, in meters, at which this relay behaves nominally.
-		/// </summary>
-		double NominalLinkDistance { get; }
-
-
-		/// <summary>
-		/// The link distance, in meters, beyond which this relay cannot operate.
-		/// </summary>
-		double MaximumLinkDistance { get; }
-
-		/// <summary>
 		/// Gets the distance to the nearest relay or Kerbin, whichever is closer.
 		/// </summary>
 		double transmitDistance { get; }
-
-		/// <summary>
-		/// Gets the link status.
-		/// </summary>
-		ConnectionStatus LinkStatus { get; }
 
 		/// <summary>
 		/// Gets the nominal transmit distance at which the Antenna behaves just as prescribed by Squad's config.
@@ -87,6 +65,12 @@
 		/// The first CelestialBody blocking line of sight to a 
 		/// </summary>
 		CelestialBody firstOccludingBody { get; }
+
+		/// <summary>
+		/// Gets a value indicating whether this <see cref="AntennaRange.IAntennaRelay"/> Relay is communicating
+		/// directly with Kerbin.
+		/// </summary>
+		bool KerbinDirect { get; }
 
 		/// <summary>
 		/// Gets the Part title.

--- a/ModuleLimitedDataTransmitter.cs
+++ b/ModuleLimitedDataTransmitter.cs
@@ -61,20 +61,13 @@
 		private ScreenMessage ErrorMsg;
 
 		/// <summary>
-		/// When additive ranges are enabled, the distance from Kerbin at which the antenna will perform exactly as
-		/// prescribed by packetResourceCost and packetSize.
+		/// The distance from Kerbin at which the antenna will perform exactly as prescribed by packetResourceCost
+		/// and packetSize.
 		/// </summary>
 		[KSPField(isPersistant = false)]
 		public double nominalRange;
 
 		/// <summary>
-		/// When additive ranges are disabled, the distance from Kerbin at which the antenna will perform exactly as
-		/// prescribed by packetResourceCost and packetSize.
-		/// </summary>
-		[KSPField(isPersistant = false)]
-		public double simpleRange;
-
-		/// <summary>
 		/// Relay status string for use in action menus.
 		/// </summary>
 		[KSPField(isPersistant = false, guiActive = true, guiName = "Status")]
@@ -93,15 +86,9 @@
 		public string UItransmitDistance;
 
 		/// <summary>
-		/// The nominal range string for use in action menus.
-		/// </summary>
-		[KSPField(isPersistant = false, guiActive = true, guiName = "Nominal Range")]
-		public string UInominalLinkDistance;
-
-		/// <summary>
 		/// Maximum distance string for use in action menus.
 		/// </summary>
-		[KSPField(isPersistant = false, guiActive = true, guiName = "Maximum Range")]
+		[KSPField(isPersistant = false, guiActive = true, guiName = "Maximum Distance")]
 		public string UImaxTransmitDistance;
 
 		/// <summary>
@@ -195,101 +182,29 @@
 		}
 
 		/// <summary>
-		/// Gets a value indicating whether this <see cref="AntennaRange.IAntennaRelay"/> Relay is communicating
-		/// directly with Kerbin.
-		/// </summary>
-		public bool KerbinDirect
+		/// Gets the distance to the nearest relay or Kerbin, whichever is closer.
+		/// </summary>
+		public double transmitDistance
 		{
 			get
 			{
-				if (this.relay != null)
-				{
-					return this.relay.KerbinDirect;
-				}
-
-				return false;
-			}
-		}
-
-		/// <summary>
-		/// Gets or sets the nominal link distance, in meters.
-		/// </summary>
-		public double NominalLinkDistance
+				if (this.relay == null)
+				{
+					return double.PositiveInfinity;
+				}
+
+				return this.relay.transmitDistance;
+			}
+		}
+
+		/// <summary>
+		/// Gets the nominal transmit distance at which the Antenna behaves just as prescribed by Squad's config.
+		/// </summary>
+		public double nominalTransmitDistance
 		{
 			get
 			{
-				if (this.relay != null)
-				{
-					return this.relay.NominalLinkDistance;
-				}
-
-				return 0d;
-			}
-		}
-
-		/// <summary>
-		/// Gets or sets the maximum link distance, in meters.
-		/// </summary>
-		public double MaximumLinkDistance
-		{
-			get
-			{
-				if (this.relay != null)
-				{
-					return this.relay.MaximumLinkDistance;
-				}
-
-				return 0d;
-			}
-		}
-
-		/// <summary>
-		/// Gets the distance to the nearest relay or Kerbin, whichever is closer.
-		/// </summary>
-		public double transmitDistance
-		{
-			get
-			{
-				if (this.relay == null)
-				{
-					return double.PositiveInfinity;
-				}
-
-				return this.relay.transmitDistance;
-			}
-		}
-
-		/// <summary>
-		/// Gets the link status.
-		/// </summary>
-		public ConnectionStatus LinkStatus
-		{
-			get
-			{
-				if (this.relay == null)
-				{
-					return ConnectionStatus.None;
-				}
-
-				return this.relay.LinkStatus;
-			}
-		}
-
-		/// <summary>
-		/// Gets the nominal transmit distance at which the Antenna behaves just as prescribed by Squad's config.
-		/// </summary>
-		public double nominalTransmitDistance
-		{
-			get
-			{
-				if (ARConfiguration.UseAdditiveRanges)
-				{
-					return this.nominalRange;
-				}
-				else
-				{
-					return this.simpleRange;
-				}
+				return this.nominalRange;
 			}
 		}
 
@@ -382,6 +297,23 @@
 		}
 
 		/// <summary>
+		/// Gets a value indicating whether this <see cref="AntennaRange.IAntennaRelay"/> Relay is communicating
+		/// directly with Kerbin.
+		/// </summary>
+		public bool KerbinDirect
+		{
+			get
+			{
+				if (this.relay != null)
+				{
+					return this.relay.KerbinDirect;
+				}
+
+				return false;
+			}
+		}
+
+		/// <summary>
 		/// Gets the Part title.
 		/// </summary>
 		public string Title
@@ -421,13 +353,13 @@
 				"{0} loaded:\n" +
 				"packetSize: {1}\n" +
 				"packetResourceCost: {2}\n" +
-				"nominalTransmitDistance: {3}\n" +
+				"nominalRange: {3}\n" +
 				"maxPowerFactor: {4}\n" +
 				"maxDataFactor: {5}\n",
 				this.name,
 				base.packetSize,
 				this._basepacketResourceCost,
-				this.nominalTransmitDistance,
+				this.nominalRange,
 				this.maxPowerFactor,
 				this.maxDataFactor
 			));
@@ -443,13 +375,13 @@
 
 			if (state >= StartState.PreLaunch)
 			{
-				this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalTransmitDistance;
+				this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalRange;
 
 				this.relay = new AntennaRelay(this);
-				this.relay.nominalTransmitDistance = this.nominalTransmitDistance;
 				this.relay.maxTransmitDistance = this.maxTransmitDistance;
-
-				this.UImaxTransmitDistance = string.Format(Tools.SIFormatter, "{0:S3}m", this.maxTransmitDistance);
+				this.relay.nominalTransmitDistance = this.nominalRange;
+
+				this.UImaxTransmitDistance = Tools.MuMech_ToSI(this.maxTransmitDistance) + "m";
 
 				GameEvents.onPartActionUICreate.Add(this.onPartActionUICreate);
 				GameEvents.onPartActionUIDismiss.Add(this.onPartActionUIDismiss);
@@ -469,7 +401,7 @@
 
 			base.OnLoad (node);
 
-			this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalTransmitDistance;
+			this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalRange;
 		}
 
 		/// <summary>
@@ -477,17 +409,9 @@
 		/// </summary>
 		public override string GetInfo()
 		{
-			StringBuilder sb = Tools.GetStringBuilder();
-			string text;
-
-			sb.Append(base.GetInfo());
-			sb.AppendFormat(Tools.SIFormatter, "Nominal Range: {0:S3}m\n", this.nominalTransmitDistance);
-			sb.AppendFormat(Tools.SIFormatter, "Maximum Range: {0:S3}m\n", this.maxTransmitDistance);
-
-			text = sb.ToString();
-
-			Tools.PutStringBuilder(sb);
-
+			string text = base.GetInfo();
+			text += "Nominal Range: " + Tools.MuMech_ToSI((double)this.nominalRange, 2) + "m\n";
+			text += "Maximum Range: " + Tools.MuMech_ToSI((double)this.maxTransmitDistance, 2) + "m\n";
 			return text;
 		}
 
@@ -711,26 +635,21 @@
 		{
 			if (this.actionUIUpdate)
 			{
-				this.UImaxTransmitDistance = string.Format(Tools.SIFormatter, "{0:S3}m", this.MaximumLinkDistance);
-				this.UInominalLinkDistance = string.Format(Tools.SIFormatter, "{0:S3}m", this.NominalLinkDistance);
-				
 				if (this.CanTransmit())
 				{
-					this.UIrelayStatus = this.LinkStatus.ToString();
-					this.UItransmitDistance = string.Format(Tools.SIFormatter, "{0:S3}m", this.transmitDistance);
-					this.UIpacketSize = string.Format(Tools.SIFormatter, "{0:S3}MiT", this.DataRate);
-					this.UIpacketCost = string.Format(Tools.SIFormatter, "{0:S3}EC", this.DataResourceCost);
+					this.UIrelayStatus = "Connected";
+					this.UItransmitDistance = Tools.MuMech_ToSI(this.transmitDistance) + "m";
+					this.UIpacketSize = Tools.MuMech_ToSI(this.DataRate) + "MiT";
+					this.UIpacketCost = Tools.MuMech_ToSI(this.DataResourceCost) + "E";
 				}
 				else
 				{
 					if (this.relay.firstOccludingBody == null)
 					{
-						this.UItransmitDistance = string.Format(Tools.SIFormatter, "{0:S3}m", this.transmitDistance);
 						this.UIrelayStatus = "Out of range";
 					}
 					else
 					{
-						this.UItransmitDistance = "N/A";
 						this.UIrelayStatus = string.Format("Blocked by {0}", this.relay.firstOccludingBody.bodyName);
 					}
 					this.UIpacketSize = "N/A";
@@ -825,13 +744,13 @@
 		// transmission fails (see CanTransmit).
 		private void PreTransmit_SetPacketResourceCost()
 		{
-			if (ARConfiguration.FixedPowerCost || this.transmitDistance <= this.NominalLinkDistance)
+			if (ARConfiguration.FixedPowerCost || this.transmitDistance <= this.nominalRange)
 			{
 				base.packetResourceCost = this._basepacketResourceCost;
 			}
 			else
 			{
-				float rangeFactor = (float)(this.transmitDistance / this.NominalLinkDistance);
+				float rangeFactor = (float)(this.transmitDistance / this.nominalRange);
 				rangeFactor *= rangeFactor;
 
 				base.packetResourceCost = this._basepacketResourceCost
@@ -845,13 +764,13 @@
 		// distance.  packetSize maxes out at _basepacketSize * maxDataFactor.
 		private void PreTransmit_SetPacketSize()
 		{
-			if (!ARConfiguration.FixedPowerCost && this.transmitDistance >= this.NominalLinkDistance)
+			if (!ARConfiguration.FixedPowerCost && this.transmitDistance >= this.nominalRange)
 			{
 				base.packetSize = this._basepacketSize;
 			}
 			else
 			{
-				float rangeFactor = (float)(this.NominalLinkDistance / this.transmitDistance);
+				float rangeFactor = (float)(this.nominalRange / this.transmitDistance);
 				rangeFactor *= rangeFactor;
 
 				base.packetSize = Mathf.Min(

--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -39,7 +39,7 @@
 // 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("1.9.*")]
+[assembly: AssemblyVersion("1.9.1.*")]
 // 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)]

file:b/README.md (new)
--- /dev/null
+++ b/README.md
@@ -1,1 +1,212 @@
-
+# AntennaRange
+A KSP mod that enforces and encourages the use of the bigger antennas.
+
+# For Part Developers
+## The Fields
+AntennaRange extends and augments the functionality of the stock ModuleDataTransmitter through the new ModuleLimitedDataTransmitter class. This class uses five additional configurable fields to define the part's behavior.
+
+nominalRange is the range, in meters, at which the part should function identically to the stock module, i.e. without any modification to the power cost or packet size. This is used along with maxPowerFactor to calculate the maximum range of the part.
+simpleRange is the same as nominalRange, but is used when the mod is in "simple" mode. In general it will probably need to be a much larger number than nominalRange.
+maxPowerFactor effectively sets the maximum range of the antenna by essentially capping how much the power may be "turned up" to get better range. I originally used 8 for this number, because it felt right. I've since used 4 (for my DTS) and 16 (for my Comm. 88-88). You don't want this number to be too high, or small probes will go uncontrollable a lot when transmitting.
+maxDataFactor defines the maximum "speed up" bonus that comes from using antennas at less their nominal range. I originally used 4 for this number for all parts; the DTS has a higher bonus now.
+
+Note that all of the fields needed for Squad's ModuleDataTransmitter still need to be filled out. Depending on how you're defining your parts, they might need to go in your AntennaRange patch, or they might already be defined on the base part.
+
+## The Mechanic
+In general, the scaling functions assume the relation `D² α P/R,` where D is the total transmission distance, P is the transmission power, and R is the data rate.  Data rate increases as range decreases below nominalRange: `R α nominalRange² / D²`.  By default, power use increases as range increases above nominalRange: `P α D² / nominalRange²`.  Optionally, power use may remain fixed, and data rate instead decreases as range increases above nominalRange: `R α nominalRange² / D²`.
+
+## Patch Conventions
+To maximize cross-compatibility, please consider the following conventions for ModuleManager patches regarding AntennaRange:
+
+When providing new definitions for your own parts, always specify a :FOR[YourModHere] pass name.
+Whenever changing default AntennaRange definitions (e.g. if you were going to rebalance my antennas to suit your mod), please do so in the :AFTER[AntennaRange] pass.
+I recommend providing all optional functionality (e.g. enabling RemoteTech vs. AntennaRange modules) in separate patches using :NEEDS[] blocks.
+
+A sample AntennaRange configuration for an all-new mod part might look like this:
+```
+@PART[modPartName]:FOR[YourModName]:NEEDS[AntennaRange,!RemoteTech]
+{
+	MODULE
+	{
+		// ### Module Definition ###
+		name = ModuleLimitedDataTransmitter
+		
+		// ### Squad Definitions ###
+		// Delay between transmission packets, in seconds
+		packetInterval = 0.10
+		
+		// Data capacity of nominal transmission packets, in MiT
+		packetSize = 2
+		
+		// Resource cost of nominal transmission packets, in units
+		packetResourceCost = 20.0
+		
+		// Resource name to be consumed by transmission
+		requiredResource = ElectricCharge
+		
+		// Animation module index, 0-based, of the antenna extend/retract animation
+		DeployFxModules = 0
+		
+		// ### AntennaRange Defintions ###
+		// Range, in meters, at which the antenna behaves per the "nominal" characteristics above
+		// Used with "additive" ranges.
+		nominalRange = 10000000000
+		
+		// Range, in meters, at which the antenna behaves per the "nominal" characteristics above
+		// Used with "simple" ranges.
+		simpleRange = 56250000000
+		
+		// The maxmimum multiplier on packetResourceCost, essentially defining the maximum power output of the
+		// transmitter.  Maximum range is defined as: maxTransmitDistance = nominalRange * sqrt(maxPowerFactor)
+		maxPowerFactor = 16
+		
+		// The maximum multiplier on packetSize, essentially defining the maximum data throughput of the
+		// transmitter.
+		maxDataFactor = 2
+	}
+	
+	// We add this ModuleScienceContainer so that when transmission fails the antennas can try to stash the data instead of dumping it to the void.
+	MODULE
+	{
+		name = ModuleScienceContainer
+
+		dataIsCollectable = true
+		dataIsStorable = false
+
+		storageRange = 2
+	}
+}
+```
+
+This example assumes that the base part definition does not include a ModuleDataTransmitter module, or any RT modules. If the base part definition includes a ModuleDataTransmitter module, a sample AntennaRange patch could look like this:
+```
+@PART[modPartName]:FOR[YourModName]:NEEDS[AntennaRange,!RemoteTech]
+{
+	@MODULE[ModuleDataTransmitter]
+	{
+		@name = ModuleLimitedDataTransmitter
+		nominalRange = 10000000000
+		simpleRange = 56250000000
+		maxPowerFactor = 16
+		maxDataFactor = 2
+	}
+	
+	// We add this ModuleScienceContainer so that when transmission fails the antennas can try to stash the data instead of dumping it to the void.
+	MODULE
+	{
+		name = ModuleScienceContainer
+
+		dataIsCollectable = true
+		dataIsStorable = false
+
+		storageRange = 2
+	}
+}
+```
+
+IIRC, RemoteTech parts should not have ModuleDataTransmitter definitions. In that case, to facilitate RT, AR, and Stock compatibility, a suite of patches like this might be appropriate:
+
+```
+// If we don't have RemoteTech, add a stock ModuleDataTransmitter first.
+@PART[modPartName]:NEEDS[!RemoteTech]:BEFORE[YourModName]
+{
+	MODULE
+	{
+		// ### Module Definition ###
+		name = ModuleDataTransmitter
+		
+		// ### Squad Definitions ###
+		// Delay between transmission packets, in seconds
+		packetInterval = 0.10
+		
+		// Data capacity of nominal transmission packets, in MiT
+		packetSize = 2
+		
+		// Resource cost of nominal transmission packets, in units
+		packetResourceCost = 20.0
+		
+		// Resource name to be consumed by transmission
+		requiredResource = ElectricCharge
+		
+		// Animation module index, 0-based, of the antenna extend/retract animation
+		DeployFxModules = 0
+	}
+}
+
+// If AntennaRange is installed, convert that to a ModuleLimitedDataTransmitter
+@PART[modPartName]:NEEDS[AntennaRange,!RemoteTech]:FOR[YourModName]
+{
+	@MODULE[ModuleDataTransmitter]
+	{
+		// ### Module Redefinition ###
+		@name = ModuleLimitedDataTransmitter
+		
+		// ### AntennaRange Defintions ###
+		// Range, in meters, at which the antenna behaves per the "nominal" characteristics above
+		// Used with "additive" ranges.
+		nominalRange = 10000000000
+		
+		// Range, in meters, at which the antenna behaves per the "nominal" characteristics above
+		// Used with "simple" ranges.
+		simpleRange = 56250000000
+		
+		// The maxmimum multiplier on packetResourceCost, essentially defining the maximum power output of the
+		// transmitter.  Maximum range is defined as: maxTransmitDistance = nominalRange * sqrt(maxPowerFactor)
+		maxPowerFactor = 16
+		
+		// The maximum multiplier on packetSize, essentially defining the maximum data throughput of the
+		// transmitter.
+		maxDataFactor = 2
+	}
+
+	// We add this ModuleScienceContainer so that when transmission fails the antennas can try to stash the data instead of dumping it to the void.
+	MODULE
+	{
+		name = ModuleScienceContainer
+
+		dataIsCollectable = true
+		dataIsStorable = false
+
+		storageRange = 2
+	}
+}
+
+// If RemoteTech is installed, do their module(s) instead
+@PART[modPartName]:NEEDS[RemoteTech]:FOR[YourModName]
+{
+	// RemoteTech module(s) here
+}
+```
+
+## Useful Formulas
+
+### Per Antenna
+`nominalRange` is a given, and is never calculated
+`maxPowerFactor` is a given, and is never calculated
+`maxTransmitDistance = nominalRange * sqrt(maxPowerFactor)`
+
+### Per Link
+A "link" is any connected pair of antennas.  
+`NominalLinkDistance = sqrt(nominalRange1 * nominalRange2)`  
+`MaxLinkDistance = sqrt(maxTransmitDistance1 * maxTransmitDistance2)`
+
+Therefore, to find the `MaxLinkDistance` from two sets of `nominalRange` and `maxPowerFactor`:  
+`MaxLinkDistance = sqrt(nominalRange1 * sqrt(maxPowerFactor1) * nominalRange2 * sqrt(maxPowerFactor2))`
+
+To find a single antenna's `nominalRange` from a desired `maxTransmitDistance` given its `maxPowerFactor`:  
+`nominalRange = maxTransmitDistance / sqrt(maxPowerFactor)`
+
+To find a single antenna's desired maximum range given the desired maximum link distance and another set `maxTransmitDistance`:  
+`maxTransmitDistance1 = MaxLinkDistance * MaxLinkDistance / maxTransmitDistance2`
+
+Remember that `maxPowerFactor` may differ between antennas (and does, in my lastest configs: longAntenna is 8, mediumDish is 4, commDish is 16).
+
+Currently Kerbin's `maxPowerFactor` is hard-coded as 8.
+
+Feel free to use this spreadsheet for balancing antennas if it's useful to you: https://goo.gl/ChsbfL
+
+## On Balance
+In my configs I've balanced the three stock antennas to cover all of the stock solar system. Since you're introducing five more antennas and working with OPM, you will probably want to change the behavior of the stock parts and diversify the range to gradually cover the whole OPM system. Since you have some parts specifically designed for use in planetary subsystems, their balance when transmitting to other parts is probably more important than their balance when transmitting to Kerbin. For longer range parts designed to make the whole interplanetary leap, the inverse is probably true.
+
+Feel free to ask questions! If anything's unclear or you just want to bounce balance ideas off of me, don't be shy. I'm always happy to help.
+

--- a/RelayExtensions.cs
+++ b/RelayExtensions.cs
@@ -37,50 +37,6 @@
 	/// </summary>
 	public static class RelayExtensions
 	{
-		/// <summary>
-		/// Returns the distance between two IAntennaRelays.
-		/// </summary>
-		/// <param name="relayOne">Relay one.</param>
-		/// <param name="relayTwo">Relay two.</param>
-		public static double DistanceTo(this IAntennaRelay relayOne, IAntennaRelay relayTwo)
-		{
-			return relayOne.vessel.DistanceTo(relayTwo.vessel);
-		}
-
-		/// <summary>
-		/// Returns the distance from this IAntennaRelay to the given CelestialBody
-		/// </summary>
-		/// <param name="relay">Relay.</param>
-		/// <param name="body">Body.</param>
-		public static double SqrDistanceTo(this IAntennaRelay relay, CelestialBody body)
-		{
-			double range = relay.vessel.DistanceTo(body) - body.Radius;
-
-			return range * range;
-		}
-
-		/// <summary>
-		/// Returns the distance between two IAntennaRelays.
-		/// </summary>
-		/// <param name="relayOne">Relay one.</param>
-		/// <param name="relayTwo">Relay two.</param>
-		public static double SqrDistanceTo(this IAntennaRelay relayOne, IAntennaRelay relayTwo)
-		{
-			return relayOne.vessel.sqrDistanceTo(relayTwo.vessel);
-		}
-
-		/// <summary>
-		/// Returns the distance from this IAntennaRelay to the given CelestialBody
-		/// </summary>
-		/// <param name="relay">Relay.</param>
-		/// <param name="body">Body.</param>
-		public static double DistanceTo(this IAntennaRelay relay, CelestialBody body)
-		{
-			double range = relay.vessel.DistanceTo(body) - body.Radius;
-
-			return range;
-		}
-
 		/// <summary>
 		/// Returns the distance between this IAntennaRelay and a Vessel
 		/// </summary>
@@ -184,11 +140,10 @@
 			for (int rIdx = 0; rIdx < vesselRelays.Count; rIdx++)
 			{
 				relay = vesselRelays[rIdx];
-				if (relay.LinkStatus > ConnectionStatus.None)
+				if (relay.CanTransmit())
 				{
 					canTransmit = true;
-
-					if (relay.LinkStatus == ConnectionStatus.Optimal)
+					if (relay.transmitDistance <= relay.nominalTransmitDistance)
 					{
 						return ConnectionStatus.Optimal;
 					}