Some EOL and file mode changes because reasons.
Some EOL and file mode changes because reasons.

--- a/.gitattributes
+++ b/.gitattributes
@@ -4,8 +4,8 @@
 # These files are text and should be normalized (convert crlf => lf)
 *.cs      text diff=csharp
 *.cfg     text
-*.csproj  text
-*.sln     text
+*.csproj  text eol=crlf
+*.sln     text eol=crlf
 
 # Images should be treated as binary
 # (binary is a macro for -text -diff)

--- a/ARConfiguration.cs
+++ b/ARConfiguration.cs
@@ -4,6 +4,7 @@
 // copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
 
 using KSP;
+using KSP.UI.Screens;
 using System;
 using ToadicusTools.Extensions;
 using ToadicusTools.Text;
@@ -31,6 +32,8 @@
 		private const string TRACKING_STATION_RANGES_KEY = "TRACKING_STATION_RANGES";
 		private const string RANGE_KEY = "range";
 
+		private const string USE_TOOLBAR_KEY = "useToolbarIfAvailable";
+
 		/// <summary>
 		/// Indicates whether connections require line of sight.
 		/// </summary>
@@ -115,6 +118,12 @@
 			}
 		}
 
+		public static bool UseToolbarIfAvailable
+		{
+			get;
+			private set;
+		}
+
 #pragma warning disable 1591
 
 		private bool showConfigWindow;
@@ -177,6 +186,8 @@
 
 			ARConfiguration.UpdateDelay = this.LoadConfigValue(UPDATE_DELAY_KEY, 16L);
 			this.updateDelayStr = ARConfiguration.UpdateDelay.ToString();
+
+			ARConfiguration.UseToolbarIfAvailable = this.LoadConfigValue(USE_TOOLBAR_KEY, true);
 
 			GameEvents.onGameSceneLoadRequested.Add(this.onSceneChangeRequested);
 			GameEvents.OnKSCFacilityUpgraded.Add(this.onFacilityUpgraded);
@@ -236,11 +247,17 @@
 		public void OnGUI()
 		{
 			// Only runs once, if the Toolbar is available.
-			if (ToolbarManager.ToolbarAvailable)
+			if (ToolbarManager.ToolbarAvailable && ARConfiguration.UseToolbarIfAvailable)
 			{
 				if (this.toolbarButton == null)
 				{
 					this.LogDebug("Toolbar available; initializing toolbar button.");
+
+					if (this.appLauncherButton != null)
+					{
+						ApplicationLauncher.Instance.RemoveModApplication(this.appLauncherButton);
+						this.appLauncherButton = null;
+					}
 
 					this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConfiguration");
 					this.toolbarButton.Visibility = new GameScenesVisibility(GameScenes.SPACECENTER);
@@ -255,6 +272,12 @@
 			}
 			else if (this.appLauncherButton == null && ApplicationLauncher.Ready)
 			{
+				if (this.toolbarButton != null)
+				{
+					this.toolbarButton.Destroy();
+					this.toolbarButton = null;
+				}
+
 				this.LogDebug("Toolbar available; initializing AppLauncher button.");
 
 				this.appLauncherButton = ApplicationLauncher.Instance.AddModApplication(
@@ -353,6 +376,17 @@
 
 			GUILayout.BeginHorizontal();
 
+			bool useToolbar = Layout.Toggle(ARConfiguration.UseToolbarIfAvailable, "Use Blizzy's Toolbar, if Available");
+			if (useToolbar != ARConfiguration.UseToolbarIfAvailable)
+			{
+				ARConfiguration.UseToolbarIfAvailable = useToolbar;
+				this.SaveConfigValue(USE_TOOLBAR_KEY, useToolbar);
+			}
+
+			GUILayout.EndHorizontal();
+
+			GUILayout.BeginHorizontal();
+
 			GUILayout.Label("Update Delay", GUILayout.ExpandWidth(false));
 
 			this.updateDelayStr = GUILayout.TextField(this.updateDelayStr, 4, GUILayout.Width(40f));

--- a/ARFlightController.cs
+++ b/ARFlightController.cs
@@ -29,6 +29,7 @@
 #pragma warning disable 1591
 
 using KSP;
+using KSP.UI.Screens;
 using System;
 using System.Collections.Generic;
 using ToadicusTools.Extensions;
@@ -149,7 +150,7 @@
 			this.appLauncherTextures[ConnectionStatus.Optimal] =
 				GameDatabase.Instance.GetTexture("AntennaRange/Textures/appLauncherIcon", false);
 
-			if (ToolbarManager.ToolbarAvailable)
+			if (ToolbarManager.ToolbarAvailable && ARConfiguration.UseToolbarIfAvailable)
 			{
 				this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConnectionStatus");
 
@@ -258,7 +259,7 @@
 			{
 				Vessel vessel;
 				IAntennaRelay relay;
-				IAntennaRelay bestActiveRelay;
+				IAntennaRelay bestActiveRelay = null;
 				IList<IAntennaRelay> activeVesselRelays;
 
 				usefulRelays.Clear();
@@ -272,6 +273,14 @@
 						continue;
 					}
 
+					switch (vessel.vesselType)
+					{
+						case VesselType.Debris:
+						case VesselType.Flag:
+						case VesselType.Unknown:
+							continue;
+					}
+
 					log.AppendFormat("\nFetching best relay for vessel {0}", vessel);
 
 					relay = vessel.GetBestRelay();
@@ -290,21 +299,6 @@
 				{
 					bestActiveRelay = RelayDatabase.Instance.GetBestVesselRelay(FlightGlobals.ActiveVessel);
 
-					for (int rIdx = 0; rIdx < activeVesselRelays.Count; rIdx++)
-					{
-						relay = activeVesselRelays[rIdx];
-
-						// The best active relay will get checked with the other useful relays later.
-						if (relay == null || relay == bestActiveRelay)
-						{
-							continue;
-						}
-
-						log.AppendFormat("\nFinding nearest relay for active vessel relay {0}", relay);
-
-						relay.FindNearestRelay();
-					}
-
 					log.AppendFormat("\n\tAdding best active vessel relay {0} to usefulRelays", bestActiveRelay);
 
 					usefulRelays.Add(bestActiveRelay);
@@ -323,6 +317,24 @@
 
 					log.AppendFormat("\n\tDoing target search for useful relay {0}", relay);
 
+					relay.RecalculateTransmissionRates();
+					relay.FindNearestRelay();
+				}
+
+				// Very last, find routes for the non-best relays on the active vessel.
+				for (int rIdx = 0; rIdx < activeVesselRelays.Count; rIdx++)
+				{
+					relay = activeVesselRelays[rIdx];
+
+					// The best active relay will get checked with the other useful relays later.
+					if (relay == null || relay == bestActiveRelay)
+					{
+						continue;
+					}
+
+					log.AppendFormat("\nFinding nearest relay for active vessel relay {0}", relay);
+
+					relay.RecalculateTransmissionRates();
 					relay.FindNearestRelay();
 				}
 

--- a/ARMapRenderer.cs
+++ b/ARMapRenderer.cs
@@ -100,7 +100,7 @@
 			this.timer = new System.Diagnostics.Stopwatch();
 			#endif
 			#if DEBUG
-			this.log = PooledDebugLogger.Get(this);
+			this.log = PooledDebugLogger.Get();
 			#endif
 		}
 
@@ -122,7 +122,7 @@
 				log.Clear();
 
 				log.AppendFormat("OnPreCull.\n");
-
+/* @ TODO: Fix
 				log.AppendFormat("\tMapView: Draw3DLines: {0}\n" +
 					"\tMapView.MapCamera.camera.fieldOfView: {1}\n" +
 					"\tMapView.MapCamera.Distance: {2}\n",
@@ -130,7 +130,7 @@
 					MapView.MapCamera.camera.fieldOfView,
 					MapView.MapCamera.Distance
 				);
-
+*/
 				log.AppendLine("FlightGlobals ready and Vessels list not null.");
 
 				IAntennaRelay relay;
@@ -213,20 +213,22 @@
 			}
 
 			LineRenderer renderer = this[relay.vessel.id];
-			Vector3d start = ScaledSpace.LocalToScaledSpace(relay.vessel.GetWorldPos3D());
+			Vector3 start = ScaledSpace.LocalToScaledSpace(relay.vessel.GetWorldPos3D());
 
 			float lineWidth;
 			float d = Screen.height / 2f + 0.01f;
 
 			if (MapView.Draw3DLines)
 			{
-				lineWidth = 0.005859375f * MapView.MapCamera.Distance;
+				lineWidth = 0.00833333333f * MapView.MapCamera.Distance;
 			}
 			else
 			{
-				lineWidth = 2f;
-
-				start = MapView.MapCamera.camera.WorldToScreenPoint(start);
+				lineWidth = 3f;
+
+				// TODO: No idea if this substitution is right.
+				// start = MapView.MapCamera.camera.WorldToScreenPoint(start);
+				start = PlanetariumCamera.Camera.WorldToScreenPoint(start);
 
 				start.z = start.z >= 0f ? d : -d;
 			}
@@ -241,7 +243,7 @@
 			relayStart = timer.ElapsedMilliseconds;
 			#endif
 
-			Vector3d nextPoint;
+			Vector3 nextPoint;
 
 			renderer.enabled = true;
 
@@ -278,6 +280,17 @@
 					return;
 				}
 
+				switch (relay.targetRelay.vessel.vesselType)
+				{
+					case VesselType.Debris:
+					case VesselType.Flag:
+					case VesselType.Unknown:
+						renderer.enabled = false;
+						return;
+					default:
+						break;
+				}
+
 				nextPoint = ScaledSpace.LocalToScaledSpace(relay.targetRelay.vessel.GetWorldPos3D());
 			}
 
@@ -285,7 +298,9 @@
 
 			if (!MapView.Draw3DLines)
 			{
-				nextPoint = MapView.MapCamera.camera.WorldToScreenPoint(nextPoint);
+				// TODO: No idea if this substitution is right.
+				// nextPoint = MapView.MapCamera.camera.WorldToScreenPoint(nextPoint);
+				nextPoint = PlanetariumCamera.Camera.WorldToScreenPoint(nextPoint);
 				nextPoint.z = nextPoint.z >= 0f ? d : -d;
 			}
 

--- a/AntennaRange.csproj
+++ b/AntennaRange.csproj
@@ -93,7 +93,12 @@
     </Reference>
     <Reference Include="UnityEngine">
       <HintPath>..\_KSPAssemblies\UnityEngine.dll</HintPath>
-      <Private>False</Private>
+    </Reference>
+    <Reference Include="KSPUtil">
+      <HintPath>..\_KSPAssemblies\KSPUtil.dll</HintPath>
+    </Reference>
+    <Reference Include="UnityEngine.UI">
+      <HintPath>..\_KSPAssemblies\UnityEngine.UI.dll</HintPath>
     </Reference>
   </ItemGroup>
   <ItemGroup>

--- a/AntennaRelay.cs
+++ b/AntennaRelay.cs
@@ -30,6 +30,7 @@
 using System.Collections.Generic;
 using ToadicusTools.DebugTools;
 using ToadicusTools.Extensions;
+using UnityEngine;
 
 namespace AntennaRange
 {
@@ -157,6 +158,42 @@
 		}
 
 		/// <summary>
+		/// Gets the current link resource rate in EC/MiT.
+		/// </summary>
+		/// <value>The current link resource rate in EC/MiT.</value>
+		public virtual double CurrentLinkResourceRate
+		{
+			get
+			{
+				return this.DataResourceCost;
+			}
+		}
+
+		public virtual double CurrentNetworkResourceRate
+		{
+			get
+			{
+				double totalRate = 0;
+
+				IAntennaRelay nextLink = this.moduleRef;
+
+				while (nextLink != null)
+				{
+					totalRate += nextLink.DataResourceCost;
+
+					if (nextLink.KerbinDirect)
+					{
+						break;
+					}
+
+					nextLink = nextLink.targetRelay;
+				}
+
+				return totalRate;
+			}
+		}
+
+		/// <summary>
 		/// Gets or sets the link status.
 		/// </summary>
 		public virtual ConnectionStatus LinkStatus
@@ -183,6 +220,69 @@
 			get;
 			set;
 		}
+		/*
+		 * The next two functions overwrite the behavior of the stock functions and do not perform equivalently, except
+		 * in that they both return floats.  Here's some quick justification:
+		 * 
+		 * The stock implementation of GetTransmitterScore (which I cannot override) is:
+		 * 		Score = (1 + DataResourceCost) / DataRate
+		 * 
+		 * The stock DataRate and DataResourceCost are:
+		 * 		DataRate = packetSize / packetInterval
+		 * 		DataResourceCost = packetResourceCost / packetSize
+		 * 
+		 * So, the resulting score is essentially in terms of joules per byte per baud.  Rearranging that a bit, it
+		 * could also look like joule-seconds per byte per byte, or newton-meter-seconds per byte per byte.  Either way,
+		 * that metric is not a very reasonable one.
+		 * 
+		 * Two metrics that might make more sense are joules per byte or joules per byte per second.  The latter case
+		 * would look like:
+		 * 		DataRate = packetSize / packetInterval
+		 * 		DataResourceCost = packetResourceCost
+		 * 
+		 * The former case, which I've chosen to implement below, is:
+		 * 		DataRate = packetSize
+		 * 		DataResourceCost = packetResourceCost
+		 * 
+		 * So... hopefully that doesn't screw with anything else.
+		 * */
+		/// <summary>
+		/// Override ModuleDataTransmitter.DataRate to just return packetSize, because we want antennas to be scored in
+		/// terms of joules/byte
+		/// </summary>
+		public virtual float DataRate
+		{
+			get
+			{
+				if (this.CanTransmit())
+				{
+					return this.moduleRef.PacketSize;
+				}
+				else
+				{
+					return float.Epsilon;
+				}
+			}
+		}
+
+		/// <summary>
+		/// Override ModuleDataTransmitter.DataResourceCost to just return packetResourceCost, because we want antennas
+		/// to be scored in terms of joules/byte
+		/// </summary>
+		public virtual double DataResourceCost
+		{
+			get
+			{
+				if (this.CanTransmit())
+				{
+					return this.moduleRef.PacketResourceCost;
+				}
+				else
+				{
+					return float.PositiveInfinity;
+				}
+			}
+		}
 
 		/// <summary>
 		/// Determines whether this instance can transmit.
@@ -191,6 +291,106 @@
 		public virtual bool CanTransmit()
 		{
 			return this.canTransmit;
+		}
+
+		// Before transmission, set packetSize.  Per above, packet size increases with the inverse square of
+		// distance.  packetSize maxes out at _basepacketSize * maxDataFactor.
+		public void RecalculateTransmissionRates()
+		{
+			float rangeFactor = (float)(this.NominalLinkSqrDistance / this.CurrentLinkSqrDistance);
+
+			if (ARConfiguration.FixedPowerCost)
+			{
+				this.moduleRef.PacketResourceCost = this.moduleRef.BasePacketResourceCost;
+
+				this.moduleRef.PacketSize = Mathf.Min(
+					this.moduleRef.BasePacketSize * rangeFactor,
+					this.moduleRef.BasePacketSize * this.moduleRef.MaxDataFactor
+				);
+			}
+			else
+			{
+				if (this.CurrentLinkSqrDistance > this.NominalLinkSqrDistance)
+				{
+					this.moduleRef.PacketSize = this.moduleRef.BasePacketSize;
+					this.moduleRef.PacketResourceCost = this.moduleRef.BasePacketResourceCost / rangeFactor;
+				}
+				else
+				{
+					this.moduleRef.PacketSize = Mathf.Min(
+						this.moduleRef.BasePacketSize * rangeFactor,
+						this.moduleRef.BasePacketSize * this.moduleRef.MaxDataFactor
+					);
+					this.moduleRef.PacketResourceCost = this.moduleRef.BasePacketResourceCost;
+				}
+			}
+
+			this.moduleRef.PacketSize *= this.moduleRef.PacketThrottle / 100f;
+			this.moduleRef.PacketResourceCost *= this.moduleRef.PacketThrottle / 100f;
+		}
+
+		public double GetPotentialLinkCost(double currentSqrDistance, double nominalSqrDistance)
+		{
+			double cost;
+
+			float rangeFactor = (float)(nominalSqrDistance / currentSqrDistance);
+
+			if (ARConfiguration.FixedPowerCost || currentSqrDistance <= NominalLinkSqrDistance)
+			{
+				cost = this.moduleRef.BasePacketResourceCost;
+			}
+			else
+			{
+				cost = this.moduleRef.BasePacketResourceCost / rangeFactor;
+			}
+
+			cost *= this.moduleRef.PacketThrottle / 100f;
+
+			return cost;
+		}
+
+		public double GetPotentialLinkCost(IAntennaRelay potentialTarget)
+		{
+			if (potentialTarget == null)
+			{
+				return double.PositiveInfinity;
+			}
+
+			double nominalSqrDistance;
+			if (ARConfiguration.UseAdditiveRanges)
+			{
+				nominalSqrDistance = this.nominalTransmitDistance * potentialTarget.nominalTransmitDistance;
+			}
+			else
+			{
+				nominalSqrDistance = this.nominalTransmitDistance * this.nominalTransmitDistance;
+			}
+
+			double currentSqrDistance = this.SqrDistanceTo(potentialTarget);
+
+			return GetPotentialLinkCost(currentSqrDistance, nominalSqrDistance);
+		}
+
+		public double GetPotentialLinkCost(CelestialBody body)
+		{
+			if (body == null || body != Kerbin)
+			{
+				return double.PositiveInfinity;
+			}
+
+			double nominalSqrDistance;
+			if (ARConfiguration.UseAdditiveRanges)
+			{
+				nominalSqrDistance = this.nominalTransmitDistance * ARConfiguration.KerbinNominalRange;
+			}
+			else
+			{
+				nominalSqrDistance = this.nominalTransmitDistance * this.nominalTransmitDistance;
+			}
+
+			double currentSqrDistance = this.SqrDistanceTo(body);
+
+			return GetPotentialLinkCost(currentSqrDistance, nominalSqrDistance);
 		}
 
 		/// <summary>
@@ -242,15 +442,12 @@
 			CelestialBody bodyOccludingBestOccludedRelay = null;
 			IAntennaRelay needle;
 
-			double nearestRelaySqrQuotient = double.PositiveInfinity;
-			double bestOccludedSqrQuotient = double.PositiveInfinity;
-
-			double potentialSqrDistance;
-			double maxLinkSqrDistance;
-			double potentialSqrQuotient;
-
-			double kerbinSqrDistance;
-			double kerbinSqrQuotient;
+			double cheapestRelayRate = double.PositiveInfinity;
+			double cheapestOccludedRelayRate = double.PositiveInfinity;
+
+			double potentialRelayRate;
+
+			double kerbinRelayRate = this.GetPotentialLinkCost(Kerbin);
 
 			bool isCircular;
 			int iterCount;
@@ -305,24 +502,8 @@
 				#endif
 
 				// Find the distance from here to the vessel...
-				log.Append("\n\tgetting distance to potential vessel");
-				potentialSqrDistance = this.SqrDistanceTo(potentialBestRelay);
-				log.Append("\n\tgetting best vessel relay");
-
-				log.Append("\n\tgetting max link distance to potential relay");
-
-				if (ARConfiguration.UseAdditiveRanges)
-				{
-					maxLinkSqrDistance = this.maxTransmitDistance * potentialBestRelay.maxTransmitDistance;
-				}
-				else
-				{
-					maxLinkSqrDistance = this.maxTransmitDistance * this.maxTransmitDistance;
-				}
-
-				log.AppendFormat("\n\tmax link distance: {0}", maxLinkSqrDistance);
-
-				potentialSqrQuotient = potentialSqrDistance / maxLinkSqrDistance;
+				log.Append("\n\tgetting cost to potential vessel");
+				potentialRelayRate = potentialBestRelay.CurrentNetworkResourceRate + this.GetPotentialLinkCost(potentialBestRelay);
 
 				#if BENCH
 				startLOSVesselTicks = performanceTimer.ElapsedTicks;
@@ -350,22 +531,21 @@
 					log.AppendFormat("\n\t\t\t{0}: Relay {1} not in line of sight.",
 						this.ToString(), potentialBestRelay);
 					
-					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\tpotentialRelayRate: {0}", potentialRelayRate);
+					log.AppendFormat("\n\t\t\tcheapestOccludedRelayRate: {0}", cheapestOccludedRelayRate);
 
 					if (
-						(potentialSqrQuotient < bestOccludedSqrQuotient) &&
-						(potentialSqrQuotient <= 1d) &&
+						(potentialRelayRate < cheapestRelayRate) &&
+						this.IsInRangeOf(potentialBestRelay) &&
 						potentialBestRelay.CanTransmit()
 					)
 					{
-						log.Append("\n\t\t...vessel is close enough to and potentialBestRelay can transmit");
+						log.Append("\n\t\t...vessel is cheapest and close enough and potentialBestRelay can transmit");
 						log.AppendFormat("\n\t\t...{0} found new best occluded relay {1}", this, potentialBestRelay);
 
 						this.bestOccludedRelay = potentialBestRelay;
 						bodyOccludingBestOccludedRelay = fob;
-						bestOccludedSqrQuotient = potentialSqrQuotient;
+						cheapestOccludedRelayRate = potentialRelayRate;
 					}
 					else
 					{
@@ -392,10 +572,10 @@
 				/*
 				 * ...so that we can skip the vessel if it is further away than a vessel we've already checked.
 				 * */
-				if (potentialSqrQuotient > nearestRelaySqrQuotient)
+				if (potentialRelayRate > cheapestRelayRate)
 				{
 					
-					log.AppendFormat("\n\t{0}: Relay {1} discarded because it is farther than another the nearest relay.",
+					log.AppendFormat("\n\t{0}: Relay {1} discarded because it is more expensive than another the nearest relay.",
 						this.ToString(),
 						potentialBestRelay
 					);
@@ -461,13 +641,13 @@
 
 					if (!isCircular)
 					{
-						nearestRelaySqrQuotient = potentialSqrQuotient;
+						cheapestRelayRate = potentialRelayRate;
 						this.nearestRelay = potentialBestRelay;
 
-						log.AppendFormat("\n\t{0}: found new nearest relay {1} ({2}m²)",
+						log.AppendFormat("\n\t{0}: found new cheapest relay {1} ({2} EC/MiT)",
 							this.ToString(),
 							this.nearestRelay.ToString(),
-							Math.Sqrt(nearestRelaySqrQuotient)
+							Math.Sqrt(cheapestRelayRate)
 						);
 					}
 					else
@@ -495,30 +675,16 @@
 			#endif
 
 			CelestialBody bodyOccludingKerbin = null;
-
-			kerbinSqrDistance = this.vessel.DistanceTo(Kerbin) - Kerbin.Radius;
-			kerbinSqrDistance *= kerbinSqrDistance;
-
-			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})), bestOccludedRelay={3} ({4}), kerbinSqrDistance={5}m²)",
 				this,
 				this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-				nearestRelaySqrQuotient,
+				cheapestRelayRate,
 				this.bestOccludedRelay == null ? "null" : this.bestOccludedRelay.ToString(),
-				bestOccludedSqrQuotient,
-				kerbinSqrDistance
+				cheapestOccludedRelayRate,
+				kerbinRelayRate
 			);
 			
 			#if BENCH
@@ -536,13 +702,12 @@
 				#endif
 				log.AppendFormat("\n\tKerbin LOS is blocked by {0}.", bodyOccludingKerbin.bodyName);
 
-				// 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)
-				{
-					log.AppendFormat("\n\t\tCan transmit to nearby relay {0} ({1} <= {2}).",
-						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-						nearestRelaySqrQuotient, 1d);
+				// If we're in range of the "nearest" (actually cheapest) relay, use it.
+				if (this.IsInRangeOf(this.nearestRelay))
+				{
+					log.AppendFormat("\n\t\tCan transmit to nearby relay {0}).",
+						this.nearestRelay == null ? "null" : this.nearestRelay.ToString()
+					);
 
 					this.KerbinDirect = false;
 					this.canTransmit = true;
@@ -551,27 +716,27 @@
 				// If this isn't true, we can't transmit, but pick a second best of bestOccludedRelay and Kerbin anyway
 				else
 				{
-					log.AppendFormat("\n\t\tCan't transmit to nearby relay {0} ({1} > {2}).",
-						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-						nearestRelaySqrQuotient, 1d);
+					log.AppendFormat("\n\t\tCan't transmit to nearby relay {0}.",
+						this.nearestRelay == null ? "null" : this.nearestRelay.ToString()
+					);
 
 					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)
-					{
-						log.AppendFormat("\n\t\t\tBest occluded relay is closer than Kerbin ({0} < {1})",
-							bestOccludedRelay, kerbinSqrDistance);
+					// If the best occluded relay is cheaper than Kerbin, check it against the nearest relay.
+					// Since cheapestOccludedRelayRate is infinity if there are no occluded relays, this is safe
+					if (cheapestOccludedRelayRate < kerbinRelayRate)
+					{
+						log.AppendFormat("\n\t\t\tBest occluded relay is cheaper than Kerbin ({0} < {1})",
+							cheapestOccludedRelayRate, kerbinRelayRate);
 						
 						this.KerbinDirect = false;
 
-						// 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 the nearest relay is cheaper than the best occluded relay, pick it.
+						// Since cheapestRelayRate is infinity if there are no nearby relays, this is safe.
+						if (cheapestRelayRate < cheapestOccludedRelayRate)
 						{
-							log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
-								nearestRelaySqrQuotient, bestOccludedSqrQuotient);
+							log.AppendFormat("\n\t\t\t\t...but the nearest relay is cheaper ({0} < {1}), so picking it.",
+								cheapestRelayRate, cheapestOccludedRelayRate);
 							
 							this.targetRelay = this.nearestRelay;
 							this.firstOccludingBody = null;
@@ -579,36 +744,37 @@
 						// Otherwise, target the best occluded relay.
 						else
 						{
-							log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
-								nearestRelaySqrQuotient, bestOccludedSqrQuotient);
+							log.AppendFormat("\n\t\t\t\t...and cheaper than the nearest relay ({0} >= {1}), so picking it.",
+								cheapestRelayRate, cheapestOccludedRelayRate);
 							
 							this.targetRelay = bestOccludedRelay;
 							this.firstOccludingBody = bodyOccludingBestOccludedRelay;
 						}
 					}
-					// Otherwise, check Kerbin against the nearest relay.
-					// Since we have LOS, blank the first occluding body.
+					// Otherwise, check Kerbin against the "nearest" (cheapest) relay.
 					else
 					{
-						log.AppendFormat("\n\t\t\tKerbin is closer than the best occluded relay ({0} >= {1})",
-							bestOccludedRelay, kerbinSqrDistance);
+						log.AppendFormat("\n\t\t\tKerbin is cheaper than the best occluded relay ({0} >= {1})",
+							cheapestOccludedRelayRate, kerbinRelayRate);
 						
-						// 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 the "nearest" (cheapest) relay is cheaper than Kerbin, pick it.
+						// Since cheapestRelayRate is infinity if there are no nearby relays, this is safe.
+						if (cheapestRelayRate < kerbinRelayRate)
 						{
-							log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
-								nearestRelaySqrQuotient, kerbinSqrQuotient);
-							
+							log.AppendFormat("\n\t\t\t\t...but the nearest relay is cheaper ({0} < {1}), so picking it.",
+								cheapestRelayRate, kerbinRelayRate);
+
+							// Since we have LOS, blank the first occluding body.
+							this.firstOccludingBody = null;
+
 							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);
+							log.AppendFormat("\n\t\t\t\t...and cheaper than the nearest relay ({0} >= {1}), so picking it.",
+								cheapestRelayRate, kerbinRelayRate);
 							
 							this.KerbinDirect = true;
 							this.firstOccludingBody = bodyOccludingKerbin;
@@ -626,21 +792,21 @@
 
 				log.AppendFormat("\n\tKerbin is in LOS.");
 
-				// If the nearest relay is closer than Kerbin and in range, transmit to it.
-				if (nearestRelaySqrQuotient <= 1d)
-				{
-					log.AppendFormat("\n\t\tCan transmit to nearby relay {0} ({1} <= {2}).",
-						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-						nearestRelaySqrQuotient, 1d);
+				// If the nearest relay is in range, we can transmit.
+				if (this.IsInRangeOf(this.nearestRelay))
+				{
+					log.AppendFormat("\n\t\tCan transmit to nearby relay {0} (in range).",
+						this.nearestRelay == null ? "null" : this.nearestRelay.ToString()
+					);
 
 					this.canTransmit = true;
 
 					// If the nearestRelay is closer than Kerbin, use it.
-					if (nearestRelaySqrQuotient < kerbinSqrQuotient)
+					if (cheapestRelayRate < kerbinRelayRate)
 					{
 						log.AppendFormat("\n\t\t\tPicking relay {0} over Kerbin ({1} < {2}).",
 							this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-							nearestRelaySqrQuotient, kerbinSqrQuotient);
+							cheapestRelayRate, kerbinRelayRate);
 
 						this.KerbinDirect = false;
 						this.targetRelay = this.nearestRelay;
@@ -650,7 +816,7 @@
 					{
 						log.AppendFormat("\n\t\t\tBut picking Kerbin over nearby relay {0} ({1} >= {2}).",
 							this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-							nearestRelaySqrQuotient, kerbinSqrQuotient);
+							cheapestRelayRate, kerbinRelayRate);
 
 						this.KerbinDirect = true;
 						this.targetRelay = null;
@@ -659,15 +825,14 @@
 				// If the nearest relay is out of range, we still need to check on Kerbin.
 				else
 				{
-					log.AppendFormat("\n\t\tCan't transmit to nearby relay {0} ({1} > {2}).",
-						this.nearestRelay == null ? "null" : this.nearestRelay.ToString(),
-							nearestRelaySqrQuotient, 1d);
+					log.AppendFormat("\n\t\tCheapest relay {0} is out of range.",
+						this.nearestRelay == null ? "null" : this.nearestRelay.ToString()
+					);
 
 					// If Kerbin is in range, use it.
-					if (kerbinSqrQuotient <= 1d)
-					{
-						log.AppendFormat("\n\t\t\tCan transmit to Kerbin ({0} <= {1}).",
-							kerbinSqrQuotient, 1d);
+					if (this.IsInRangeOf(Kerbin))
+					{
+						log.AppendFormat("\n\t\t\tCan transmit to Kerbin (in range).");
 
 						this.canTransmit = true;
 						this.KerbinDirect = true;
@@ -677,26 +842,25 @@
 					// Kerbin and bestOccludedRelay
 					else
 					{
-						log.AppendFormat("\n\t\t\tCan't transmit to Kerbin ({0} > {1}).",
-								kerbinSqrQuotient, 1d);
+						log.AppendFormat("\n\t\t\tCan't transmit to Kerbin (out of range).");
 
 						this.canTransmit = false;
 
-						// If the best occluded relay is closer than Kerbin, check it against the nearest relay.
+						// If the best occluded relay is cheaper 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 (cheapestOccludedRelayRate < kerbinRelayRate)
 						{
 							log.AppendFormat("\n\t\t\tBest occluded relay is closer than Kerbin ({0} < {1})",
-								bestOccludedRelay, kerbinSqrDistance);
+								cheapestOccludedRelayRate, kerbinRelayRate);
 							
 							this.KerbinDirect = false;
 
 							// 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)
+							// Since cheapestRelayRate is infinity if there are no nearby relays, this is safe.
+							if (cheapestRelayRate < cheapestOccludedRelayRate)
 							{
-								log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
-									nearestRelaySqrQuotient, bestOccludedSqrQuotient);
+								log.AppendFormat("\n\t\t\t\t...but the nearest relay is cheaper ({0} < {1}), so picking it.",
+									cheapestRelayRate, cheapestOccludedRelayRate);
 								
 								this.targetRelay = this.nearestRelay;
 								this.firstOccludingBody = null;
@@ -704,8 +868,8 @@
 							// Otherwise, target the best occluded relay.
 							else
 							{
-								log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
-									nearestRelaySqrQuotient, bestOccludedSqrQuotient);
+								log.AppendFormat("\n\t\t\t\t...and cheaper than the nearest relay ({0} >= {1}), so picking it.",
+									cheapestRelayRate, cheapestOccludedRelayRate);
 								
 								this.targetRelay = bestOccludedRelay;
 								this.firstOccludingBody = bodyOccludingBestOccludedRelay;
@@ -715,17 +879,17 @@
 						// Since we have LOS, blank the first occluding body.
 						else
 						{
-							log.AppendFormat("\n\t\t\tKerbin is closer than the best occluded relay ({0} >= {1})",
-								bestOccludedRelay, kerbinSqrDistance);
+							log.AppendFormat("\n\t\t\tKerbin is cheaper than the best occluded relay ({0} >= {1})",
+								cheapestOccludedRelayRate, kerbinRelayRate);
 							
 							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 the nearest relay is cheaper than Kerbin, pick it.
+							// Since cheapestRelayRate is infinity if there are no nearby relays, this is safe.
+							if (cheapestRelayRate < kerbinRelayRate)
 							{
-								log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
-									nearestRelaySqrQuotient, kerbinSqrQuotient);
+								log.AppendFormat("\n\t\t\t\t...but the nearest relay is cheaper ({0} < {1}), so picking it.",
+									cheapestRelayRate, kerbinRelayRate);
 								
 								this.KerbinDirect = false;
 								this.targetRelay = this.nearestRelay;
@@ -733,8 +897,8 @@
 							// Otherwise, pick Kerbin.
 							else
 							{
-								log.AppendFormat("\n\t\t\t\t...and closer than the nearest relay ({0} >= {1}), so picking it.",
-									nearestRelaySqrQuotient, kerbinSqrQuotient);
+								log.AppendFormat("\n\t\t\t\t...and cheaper than the nearest relay ({0} >= {1}), so picking it.",
+									cheapestRelayRate, kerbinRelayRate);
 								
 								this.KerbinDirect = true;
 								this.targetRelay = null;

--- a/GameData/AntennaRange/AntennaRange.cfg
+++ b/GameData/AntennaRange/AntennaRange.cfg
@@ -37,8 +37,10 @@
 // maxDataFactor:	The multipler on packetSize that defines the maximum data bandwidth of the antenna.
 // 
 
-@PART[longAntenna]:FOR[AntennaRange]:NEEDS[!RemoteTech2]
+@PART[longAntenna]:FOR[AntennaRange]:NEEDS[!RemoteTech]
 {
+	@TechRequired = start
+
 	@MODULE[ModuleDataTransmitter]
 	{
 		@name = ModuleLimitedDataTransmitter
@@ -59,7 +61,7 @@
 	}
 }
 
-@PART[mediumDishAntenna]:FOR[AntennaRange]:NEEDS[!RemoteTech2]
+@PART[mediumDishAntenna]:FOR[AntennaRange]:NEEDS[!RemoteTech]
 {
 	@MODULE[ModuleDataTransmitter]
 	{
@@ -81,7 +83,7 @@
 	}
 }
 
-@PART[commDish]:FOR[AntennaRange]:NEEDS[!RemoteTech2]
+@PART[commDish]:FOR[AntennaRange]:NEEDS[!RemoteTech]
 {
 	@MODULE[ModuleDataTransmitter]
 	{
@@ -91,6 +93,31 @@
 		simpleRange = 56250000000
 		maxPowerFactor = 16
 		maxDataFactor = 2
+	}
+
+	MODULE
+	{
+		name = ModuleScienceContainer
+
+		dataIsCollectable = true
+		dataIsStorable = false
+
+		storageRange = 2
+	}
+}
+
+@PART[HighGainAntenna]:FOR[AntennaRange]:NEEDS[!RemoteTech]
+{
+	@TechRequired = electronics
+	@description = Repurposed for medium range probes, the HG-55 provdes high speed directional data transmission.
+
+	@MODULE[ModuleDataTransmitter]
+	{
+		@name = ModuleLimitedDataTransmitter
+		nominalRange = 7774867578
+		simpleRange = 25030376544
+		maxPowerFactor = 2.6180339887498948
+		maxDataFactor = 9
 	}
 
 	MODULE
@@ -130,7 +157,7 @@
 EVA_RESOURCE
 {
 	name = ElectricCharge
-	amount = 100
+	amount = 0
 	maxAmount = 100
 }
 

 Binary files a/GameData/AntennaRange/Textures/appLauncherIcon.png and b/GameData/AntennaRange/Textures/appLauncherIcon.png differ
 Binary files a/GameData/AntennaRange/Textures/appLauncherIconNoConnection.png and b/GameData/AntennaRange/Textures/appLauncherIconNoConnection.png differ
 Binary files a/GameData/AntennaRange/Textures/appLauncherIconSubOptimal.png and b/GameData/AntennaRange/Textures/appLauncherIconSubOptimal.png differ
 Binary files a/GameData/AntennaRange/Textures/toolbarIcon.png and b/GameData/AntennaRange/Textures/toolbarIcon.png differ
 Binary files a/GameData/AntennaRange/Textures/toolbarIconNoConnection.png and b/GameData/AntennaRange/Textures/toolbarIconNoConnection.png differ
 Binary files a/GameData/AntennaRange/Textures/toolbarIconSubOptimal.png and b/GameData/AntennaRange/Textures/toolbarIconSubOptimal.png differ
--- a/IAntennaRelay.cs
+++ b/IAntennaRelay.cs
@@ -46,6 +46,30 @@
 		/// </summary>
 		IAntennaRelay targetRelay { get; }
 
+		float PacketSize { get; set; }
+
+		float BasePacketSize { get; }
+
+		float PacketResourceCost { get; set; }
+
+		float BasePacketResourceCost { get; }
+
+		float PacketThrottle { get; }
+
+		float MaxDataFactor { get; }
+
+		/// <summary>
+		/// Gets the data resource cost in EC/MiT.
+		/// </summary>
+		/// <value>The data resource cost in EC/MiT.</value>
+		double DataResourceCost { get; }
+
+		/// <summary>
+		/// Gets the current network resource rate in EC/MiT.
+		/// </summary>
+		/// <value>The current network resource rate in EC/MiT.</value>
+		double CurrentNetworkResourceRate { get; }
+
 		/// <summary>
 		/// Gets a value indicating whether this <see cref="AntennaRange.IAntennaRelay"/> Relay is communicating
 		/// directly with Kerbin.
@@ -56,7 +80,6 @@
 		/// The link distance, in meters, at which this relay behaves nominally.
 		/// </summary>
 		double NominalLinkSqrDistance { get; }
-
 
 		/// <summary>
 		/// The link distance, in meters, beyond which this relay cannot operate.
@@ -100,9 +123,19 @@
 		bool CanTransmit();
 
 		/// <summary>
+		/// Recalculates the transmission rates.
+		/// </summary>
+		void RecalculateTransmissionRates();
+
+		/// <summary>
 		/// Finds the nearest relay.
 		/// </summary>
 		void FindNearestRelay();
+
+		/// <summary>
+		/// Recalculates the max range; useful for making sure we're using additive ranges when enabled.
+		/// </summary>
+		void RecalculateMaxRange();
 
 		/// <summary>
 		/// Returns a <see cref="System.String"/> that represents the current <see cref="AntennaRange.IAntennaRelay"/>.

--- a/ModuleLimitedDataTransmitter.cs
+++ b/ModuleLimitedDataTransmitter.cs
@@ -56,12 +56,6 @@
 		private static GUIStyle partTooltipBodyStyle;
 		private static GUIStyle partTooltipHeaderStyle;
 
-		// Stores the packetResourceCost as defined in the .cfg file.
-		private float _basepacketResourceCost;
-
-		// Stores the packetSize as defined in the .cfg file.
-		private float _basepacketSize;
-
 		// Every antenna is a relay.
 		private AntennaRelay relay;
 
@@ -184,9 +178,63 @@
 				else
 				{
 					this.LogError("Vessel and/or part reference are null, returning null vessel.");
+					#if DEBUG && VERBOSE
 					this.LogError(new System.Diagnostics.StackTrace().ToString());
+					#endif
 					return null;
 				}
+			}
+		}
+
+		public float PacketSize
+		{
+			get
+			{
+				return this.packetSize;
+			}
+			set
+			{
+				this.packetSize = value;
+			}
+		}
+
+		public float BasePacketSize
+		{
+			get;
+			private set;
+		}
+
+		public float PacketResourceCost
+		{
+			get
+			{
+				return this.packetResourceCost;
+			}
+			set
+			{
+				this.packetResourceCost = value;
+			}
+		}
+
+		public float BasePacketResourceCost
+		{
+			get;
+			private set;
+		}
+
+		public float PacketThrottle
+		{
+			get
+			{
+				return this.packetThrottle;
+			}
+		}
+
+		public float MaxDataFactor
+		{
+			get
+			{
+				return this.maxDataFactor;
 			}
 		}
 
@@ -268,6 +316,23 @@
 				}
 
 				return this.relay.CurrentLinkSqrDistance;
+			}
+		}
+
+		/// <summary>
+		/// Gets the current link resource rate in EC/MiT.
+		/// </summary>
+		/// <value>The current link resource rate in EC/MiT.</value>
+		public double CurrentLinkResourceRate
+		{
+			get
+			{
+				if (this.relay == null)
+				{
+					return double.PositiveInfinity;
+				}
+
+				return this.relay.CurrentLinkResourceRate;
 			}
 		}
 
@@ -359,16 +424,12 @@
 		{
 			get
 			{
-				this.PreTransmit_SetPacketSize();
-
-				if (this.CanTransmit())
-				{
-					return this.packetSize;
-				}
-				else
-				{
-					return float.Epsilon;
-				}
+				if (this.relay == null)
+				{
+					return float.PositiveInfinity;
+				}
+
+				return this.relay.DataRate;
 			}
 		}
 
@@ -380,16 +441,25 @@
 		{
 			get
 			{
-				this.PreTransmit_SetPacketResourceCost();
-
-				if (this.CanTransmit())
-				{
-					return this.packetResourceCost;
-				}
-				else
-				{
-					return float.PositiveInfinity;
-				}
+				if (this.relay == null)
+				{
+					return double.PositiveInfinity;
+				}
+
+				return this.relay.DataResourceCost;
+			}
+		}
+
+		public double CurrentNetworkResourceRate
+		{
+			get
+			{
+				if (this.relay == null)
+				{
+					return double.PositiveInfinity;
+				}
+
+				return this.relay.CurrentNetworkResourceRate;
 			}
 		}
 
@@ -415,7 +485,7 @@
 		// Build ALL the objects.
 		public ModuleLimitedDataTransmitter () : base()
 		{
-			this.ErrorMsg = new ScreenMessage("", 4f, false, ScreenMessageStyle.UPPER_LEFT);
+			this.ErrorMsg = new ScreenMessage("", 4f, ScreenMessageStyle.UPPER_LEFT);
 			this.packetThrottle = 100f;
 		}
 
@@ -426,8 +496,8 @@
 		{
 			base.OnAwake();
 
-			this._basepacketSize = base.packetSize;
-			this._basepacketResourceCost = base.packetResourceCost;
+			this.BasePacketSize = base.packetSize;
+			this.BasePacketResourceCost = base.packetResourceCost;
 			this.moduleInfoContent = new GUIContent();
 
 			this.LogDebug("{0} loaded:\n" +
@@ -438,7 +508,7 @@
 				"maxDataFactor: {5}\n",
 				this,
 				base.packetSize,
-				this._basepacketResourceCost,
+				this.BasePacketResourceCost,
 				this.nominalTransmitDistance,
 				this.maxPowerFactor,
 				this.maxDataFactor
@@ -453,7 +523,7 @@
 		{
 			base.OnStart (state);
 
-			this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalTransmitDistance;
+			this.RecalculateMaxRange();
 
 			if (state >= StartState.PreLaunch)
 			{
@@ -481,7 +551,7 @@
 
 			base.OnLoad (node);
 
-			this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalTransmitDistance;
+			this.RecalculateMaxRange();
 		}
 
 		/// <summary>
@@ -621,6 +691,14 @@
 			return this.relay.CanTransmit();
 		}
 
+		public void RecalculateTransmissionRates()
+		{
+			if (this.relay != null)
+			{
+				this.relay.RecalculateTransmissionRates();
+			}
+		}
+
 		/// <summary>
 		/// Finds the nearest relay.
 		/// </summary>
@@ -637,37 +715,23 @@
 		/// returns false.
 		/// </summary>
 		/// <param name="dataQueue">List of <see cref="ScienceData"/> to transmit.</param>
-		/// <param name="callback">Callback function</param>
-		public new void TransmitData(List<ScienceData> dataQueue, Callback callback)
+		public new void TransmitData(List<ScienceData> dataQueue)
 		{
 			this.LogDebug(
 				"TransmitData(List<ScienceData> dataQueue, Callback callback) called.  dataQueue.Count={0}",
 				dataQueue.Count
 			);
 
-			this.FindNearestRelay();
-
-			this.PreTransmit_SetPacketSize();
-			this.PreTransmit_SetPacketResourceCost();
-
 			if (this.CanTransmit())
 			{
 				ScreenMessages.PostScreenMessage(this.buildTransmitMessage(), 4f, ScreenMessageStyle.UPPER_LEFT);
 
 				this.LogDebug(
 					"CanTransmit in TransmitData, calling base.TransmitData with dataQueue=[{0}] and callback={1}",
-					dataQueue.SPrint(),
-					callback == null ? "null" : callback.ToString()
+					dataQueue.SPrint()
 				);
 
-				if (callback == null)
-				{
-					base.TransmitData(dataQueue);
-				}
-				else
-				{
-					base.TransmitData(dataQueue, callback);
-				}
+				base.TransmitData(dataQueue);
 			}
 			else
 			{
@@ -760,31 +824,11 @@
 		}
 
 		/// <summary>
-		/// Override ModuleDataTransmitter.TransmitData to check against CanTransmit and fail out when CanTransmit
-		/// returns false.
-		/// </summary>
-		/// <param name="dataQueue">List of <see cref="ScienceData"/> to transmit.</param>
-		public new void TransmitData(List<ScienceData> dataQueue)
-		{
-			this.LogDebug(
-				"TransmitData(List<ScienceData> dataQueue) called, dataQueue.Count={0}",
-				dataQueue.Count
-			);
-
-			this.TransmitData(dataQueue, null);
-		}
-
-		/// <summary>
 		/// Override ModuleDataTransmitter.StartTransmission to check against CanTransmit and fail out when CanTransmit
 		/// returns false.
 		/// </summary>
 		public new void StartTransmission()
 		{
-			this.FindNearestRelay();
-
-			PreTransmit_SetPacketSize ();
-			PreTransmit_SetPacketResourceCost ();
-
 			this.LogDebug(
 				"distance: " + this.CurrentLinkSqrDistance
 				+ " packetSize: " + this.packetSize
@@ -858,6 +902,16 @@
 			}
 		}
 
+		public void RecalculateMaxRange()
+		{
+			this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalTransmitDistance;
+
+			#if DEBUG
+			this.Log("Recalculated max range: sqrt({0}) * {1} = {2}",
+				this.maxPowerFactor, this.nominalTransmitDistance, this.maxTransmitDistance);
+			#endif
+		}
+
 		/// <summary>
 		/// Returns a <see cref="System.String"/> that represents the current <see cref="AntennaRange.ModuleLimitedDataTransmitter"/>.
 		/// </summary>
@@ -868,7 +922,14 @@
 			{
 				string msg;
 
-				sb.Append(this.part.partInfo.title);
+				if (this.part != null && this.part.partInfo != null)
+				{
+					sb.Append(this.part.partInfo.title);
+				}
+				else
+				{
+					sb.Append(this.GetType().Name);
+				}
 
 				if (vessel != null)
 				{
@@ -926,47 +987,7 @@
 
 			this.LogDebug(this.ErrorMsg.message);
 
-			ScreenMessages.PostScreenMessage(this.ErrorMsg, false);
-		}
-
-		// Before transmission, set packetResourceCost.  Per above, packet cost increases with the square of
-		// distance.  packetResourceCost maxes out at _basepacketResourceCost * maxPowerFactor, at which point
-		// transmission fails (see CanTransmit).
-		private void PreTransmit_SetPacketResourceCost()
-		{
-			if (ARConfiguration.FixedPowerCost || this.CurrentLinkSqrDistance <= this.NominalLinkSqrDistance)
-			{
-				base.packetResourceCost = this._basepacketResourceCost;
-			}
-			else
-			{
-				float rangeFactor = (float)(this.CurrentLinkSqrDistance / this.NominalLinkSqrDistance);
-
-				base.packetResourceCost = this._basepacketResourceCost * rangeFactor;
-			}
-
-			base.packetResourceCost *= this.packetThrottle / 100f;
-		}
-
-		// Before transmission, set packetSize.  Per above, packet size increases with the inverse square of
-		// distance.  packetSize maxes out at _basepacketSize * maxDataFactor.
-		private void PreTransmit_SetPacketSize()
-		{
-			if (!ARConfiguration.FixedPowerCost && this.CurrentLinkSqrDistance >= this.NominalLinkSqrDistance)
-			{
-				base.packetSize = this._basepacketSize;
-			}
-			else
-			{
-				float rangeFactor = (float)(this.NominalLinkSqrDistance / this.CurrentLinkSqrDistance);
-
-				base.packetSize = Mathf.Min(
-					this._basepacketSize * rangeFactor,
-					this._basepacketSize * this.maxDataFactor
-				);
-			}
-
-			base.packetSize *= this.packetThrottle / 100f;
+			ScreenMessages.PostScreenMessage(this.ErrorMsg);
 		}
 
 		private string buildTransmitMessage()
@@ -1002,8 +1023,8 @@
 		[KSPEvent (guiName = "Show Debug Info", active = true, guiActive = true)]
 		public void DebugInfo()
 		{
-			PreTransmit_SetPacketSize ();
-			PreTransmit_SetPacketResourceCost ();
+			if (this.relay != null)
+				this.relay.RecalculateTransmissionRates();
 
 			DebugPartModule.DumpClassObject(this);
 		}
@@ -1011,27 +1032,26 @@
 		[KSPEvent (guiName = "Dump Vessels", active = true, guiActive = true)]
 		public void PrintAllVessels()
 		{
-			StringBuilder sb = Tools.GetStringBuilder();
-			
-			sb.Append("Dumping FlightGlobals.Vessels:");
-
-			Vessel vessel;
-			for (int i = 0; i < FlightGlobals.Vessels.Count; i++)
-			{
-				vessel = FlightGlobals.Vessels[i];
-				sb.AppendFormat("\n'{0} ({1})'", vessel.vesselName, vessel.id);
-			}
+			using (PooledStringBuilder sb = PooledStringBuilder.Get())
+			{
+				sb.Append("Dumping FlightGlobals.Vessels:");
+
+				Vessel vessel;
+				for (int i = 0; i < FlightGlobals.Vessels.Count; i++)
+				{
+					vessel = FlightGlobals.Vessels[i];
+					sb.AppendFormat("\n'{0} ({1})'", vessel.vesselName, vessel.id);
+				}
 		    
-			Tools.PostDebugMessage(sb.ToString());
-
-			Tools.PutStringBuilder(sb);
+				ToadicusTools.Logging.PostDebugMessage(sb.ToString());
+			}
 		}
 		 
-		[KSPEvent (guiName = "Dump RelayDB", active = true, guiActive = true)]
+		/*[KSPEvent (guiName = "Dump RelayDB", active = true, guiActive = true)]
 		public void DumpRelayDB()
 		{
 			RelayDatabase.Instance.Dump();
-		}
+		}*/
 		#endif
 	}
 }

--- 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.10.1.*")]
+[assembly: AssemblyVersion("1.10.3.*")]
 // 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)]

--- a/ProtoAntennaRelay.cs
+++ b/ProtoAntennaRelay.cs
@@ -72,6 +72,102 @@
 			}
 		}
 
+		public float PacketSize
+		{
+			get
+			{
+				if (this.moduleRef == null)
+				{
+					return float.NaN;
+				}
+
+				return this.moduleRef.PacketSize;
+			}
+			set
+			{
+				if (this.moduleRef == null)
+				{
+					return;
+				}
+
+				this.moduleRef.PacketSize = value;
+			}
+		}
+
+		public float BasePacketSize
+		{
+			get
+			{
+				if (this.moduleRef == null)
+				{
+					return float.NaN;
+				}
+
+				return this.moduleRef.BasePacketSize;
+			}
+		}
+
+		public float PacketResourceCost
+		{
+			get
+			{
+				if (this.moduleRef == null)
+				{
+					return float.NaN;
+				}
+
+				return this.moduleRef.PacketResourceCost;
+			}
+			set
+			{
+				if (this.moduleRef == null)
+				{
+					return;
+				}
+
+				this.moduleRef.PacketResourceCost = value;
+			}
+		}
+
+		public float BasePacketResourceCost
+		{
+			get
+			{
+				if (this.moduleRef == null)
+				{
+					return float.NaN;
+				}
+
+				return this.moduleRef.BasePacketResourceCost;
+			}
+		}
+
+		public float PacketThrottle
+		{
+			get
+			{
+				if (this.moduleRef == null)
+				{
+					return float.NaN;
+				}
+
+				return this.moduleRef.PacketThrottle;
+			}
+		}
+
+		public float MaxDataFactor
+		{
+			get
+			{
+				if (this.moduleRef == null)
+				{
+					return float.NaN;
+				}
+
+				return this.moduleRef.MaxDataFactor;
+			}
+		}
+
 		/// <summary>
 		/// Gets the nominal transmit distance at which the Antenna behaves just as prescribed by Squad's config.
 		/// </summary>
@@ -132,6 +228,14 @@
 			return base.CanTransmit();
 		}
 
+		public void RecalculateMaxRange()
+		{
+			if (this.moduleRef != null)
+			{
+				this.moduleRef.RecalculateMaxRange();
+			}
+		}
+
 		/// <summary>
 		/// Returns a <see cref="System.String"/> that represents the current <see cref="AntennaRange.ProtoAntennaRelay"/>.
 		/// </summary>
@@ -162,6 +266,8 @@
 			this.protoPart = pps;
 
 			this.Log("constructed ({0})", this.GetType().Name);
+
+			this.RecalculateMaxRange();
 		}
 	}
 }

--- a/RelayDatabase.cs
+++ b/RelayDatabase.cs
@@ -450,28 +450,27 @@
 		#if DEBUG
 		public void Dump()
 		{
-			StringBuilder sb = Tools.GetStringBuilder();
-
-			sb.Append("Dumping RelayDatabase:");
-
-			var dbEnum = this.relayDatabase.GetEnumerator();
-			IList<IAntennaRelay> vesselRelays;
-			while (dbEnum.MoveNext())
-			{
-				sb.AppendFormat("\nVessel {0}:", dbEnum.Current.Key);
-
-				vesselRelays = dbEnum.Current.Value;
-				IAntennaRelay relay;
-				for (int rIdx = 0; rIdx < vesselRelays.Count; rIdx++)
-				{
-					relay = vesselRelays[rIdx];
-					sb.AppendFormat("\n\t{0}", relay.ToString());
-				}
-			}
-
-			Logging.PostDebugMessage(sb.ToString());
-
-			Tools.PutStringBuilder(sb);
+			using (ToadicusTools.Text.PooledStringBuilder sb = ToadicusTools.Text.PooledStringBuilder.Get())
+			{
+				sb.Append("Dumping RelayDatabase:");
+
+				var dbEnum = this.relayDatabase.GetEnumerator();
+				IList<IAntennaRelay> vesselRelays;
+				while (dbEnum.MoveNext())
+				{
+					sb.AppendFormat("\nVessel {0}:", dbEnum.Current.Key);
+
+					vesselRelays = dbEnum.Current.Value;
+					IAntennaRelay relay;
+					for (int rIdx = 0; rIdx < vesselRelays.Count; rIdx++)
+					{
+						relay = vesselRelays[rIdx];
+						sb.AppendFormat("\n\t{0}", relay.ToString());
+					}
+				}
+
+				Logging.PostDebugMessage(sb.ToString());
+			}
 		}
 		#endif
 	}

--- a/RelayExtensions.cs
+++ b/RelayExtensions.cs
@@ -141,6 +141,56 @@
 		public static double SqrDistanceTo(this AntennaRelay relayOne, IAntennaRelay relayTwo)
 		{
 			return relayOne.vessel.sqrDistanceTo(relayTwo.vessel);
+		}
+
+		public static double MaxLinkSqrDistanceTo(this AntennaRelay relayOne, IAntennaRelay relayTwo)
+		{
+			if (ARConfiguration.UseAdditiveRanges)
+			{
+				return relayOne.maxTransmitDistance * relayTwo.maxTransmitDistance;
+			}
+			else
+			{
+				return relayOne.maxTransmitDistance * relayOne.maxTransmitDistance;
+			}
+		}
+
+		public static double MaxLinkSqrDistanceTo(this AntennaRelay relayOne, CelestialBody body)
+		{
+			if (body != AntennaRelay.Kerbin)
+			{
+				return 0d;
+			}
+
+			if (ARConfiguration.UseAdditiveRanges)
+			{
+				return relayOne.maxTransmitDistance * ARConfiguration.KerbinRelayRange;
+			}
+			else
+			{
+				return relayOne.maxTransmitDistance * relayOne.maxTransmitDistance;
+			}
+		}
+
+		public static bool IsInRangeOf(this AntennaRelay relayOne, IAntennaRelay relayTwo)
+		{
+			if (relayOne == null || relayTwo == null)
+			{
+				return false;
+			}
+
+			return relayOne.SqrDistanceTo(relayTwo) <= relayOne.MaxLinkSqrDistanceTo(relayTwo);
+		}
+
+
+		public static bool IsInRangeOf(this AntennaRelay relayOne, CelestialBody body)
+		{
+			if (relayOne == null || body == null)
+			{
+				return false;
+			}
+
+			return relayOne.SqrDistanceTo(body) <= relayOne.MaxLinkSqrDistanceTo(body);
 		}
 
 		/// <summary>