Module: Add a maxTransmitDistance set to OnStart to handle EVA Kerbals. Also remove the 'N/A' set for UImaxTransmitDistance because that's not really ever relevant.
Module: Add a maxTransmitDistance set to OnStart to handle EVA Kerbals. Also remove the 'N/A' set for UImaxTransmitDistance because that's not really ever relevant.

--- a/ARFlightController.cs
+++ b/ARFlightController.cs
@@ -2,7 +2,7 @@
 //
 // ARFlightController.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,
@@ -40,7 +40,7 @@
 	public class ARFlightController : MonoBehaviour
 	{
 		#region Fields
-		private Dictionary<ConnectionStatus, string> connectionTextures;
+		private Dictionary<ConnectionStatus, string> toolbarTextures;
 		private Dictionary<ConnectionStatus, Texture> appLauncherTextures;
 
 		private ARMapRenderer mapRenderer;
@@ -64,7 +64,7 @@
 		{
 			get
 			{
-				return this.connectionTextures[this.currentConnectionStatus];
+				return this.toolbarTextures[this.currentConnectionStatus];
 			}
 		}
 
@@ -126,11 +126,11 @@
 
 			this.updateTimer = new System.Diagnostics.Stopwatch();
 
-			this.connectionTextures = new Dictionary<ConnectionStatus, string>();
-
-			this.connectionTextures[ConnectionStatus.None] = "AntennaRange/Textures/toolbarIconNoConnection";
-			this.connectionTextures[ConnectionStatus.Suboptimal] = "AntennaRange/Textures/toolbarIconSubOptimal";
-			this.connectionTextures[ConnectionStatus.Optimal] = "AntennaRange/Textures/toolbarIcon";
+			this.toolbarTextures = new Dictionary<ConnectionStatus, string>();
+
+			this.toolbarTextures[ConnectionStatus.None] = "AntennaRange/Textures/toolbarIconNoConnection";
+			this.toolbarTextures[ConnectionStatus.Suboptimal] = "AntennaRange/Textures/toolbarIconSubOptimal";
+			this.toolbarTextures[ConnectionStatus.Optimal] = "AntennaRange/Textures/toolbarIcon";
 
 			this.appLauncherTextures = new Dictionary<ConnectionStatus, Texture>();
 
@@ -145,7 +145,7 @@
 			{
 				this.toolbarButton = ToolbarManager.Instance.add("AntennaRange", "ARConnectionStatus");
 
-				this.toolbarButton.TexturePath = this.connectionTextures[ConnectionStatus.None];
+				this.toolbarButton.TexturePath = this.toolbarTextures[ConnectionStatus.None];
 				this.toolbarButton.Text = "AntennaRange";
 				this.toolbarButton.Visibility = new GameScenesVisibility(GameScenes.FLIGHT);
 				this.toolbarButton.Enabled = false;
@@ -224,7 +224,7 @@
 
 		private void Update()
 		{
-			if (!this.updateTimer.IsRunning || this.updateTimer.ElapsedMilliseconds > 83L)
+			if (!this.updateTimer.IsRunning || this.updateTimer.ElapsedMilliseconds > 16L)
 			{
 				this.updateTimer.Restart();
 			}

--- a/ARMapRenderer.cs
+++ b/ARMapRenderer.cs
@@ -2,7 +2,7 @@
 //
 // ARMapRenderer.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,

--- a/AntennaRelay.cs
+++ b/AntennaRelay.cs
@@ -2,7 +2,7 @@
 //
 // AntennaRelay.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,
@@ -198,6 +198,7 @@
 			this.KerbinDirect = true;
 
 			CelestialBody bodyOccludingBestOccludedRelay = null;
+			IAntennaRelay needle;
 
 			double nearestRelaySqrDistance = double.PositiveInfinity;
 			double bestOccludedSqrDistance = double.PositiveInfinity;
@@ -325,19 +326,49 @@
 
 				log.Append("\n\t\t...passed distance check");
 
-				if (
-					potentialBestRelay.CanTransmit() &&
-					(potentialBestRelay.targetRelay == null || potentialBestRelay.targetRelay.vessel != this.vessel))
-				{
-					// @TODO: Moved this here from outside the loop; why was it there?
-					nearestRelaySqrDistance = potentialSqrDistance;
-					this.nearestRelay = potentialBestRelay;
-
-					log.AppendFormat("\n\t{0}: found new nearest relay {1} ({2}m)",
-						this.ToString(),
-						this.nearestRelay.ToString(),
-						Math.Sqrt(nearestRelaySqrDistance)
-					);
+				if (potentialBestRelay.CanTransmit())
+				{
+					needle = potentialBestRelay;
+					bool isCircular = false;
+
+					while (needle != null)
+					{
+						if (needle.KerbinDirect)
+						{
+							break;
+						}
+
+						if (needle.targetRelay == null)
+						{
+							break;
+						}
+
+						if (needle.targetRelay.vessel == this.vessel || needle == this.moduleRef)
+						{
+							isCircular = true;
+							break;
+						}
+
+						needle = needle.targetRelay;
+					}
+
+					if (!isCircular)
+					{
+						nearestRelaySqrDistance = potentialSqrDistance;
+						this.nearestRelay = potentialBestRelay;
+
+						log.AppendFormat("\n\t{0}: found new nearest relay {1} ({2}m)",
+							this.ToString(),
+							this.nearestRelay.ToString(),
+							Math.Sqrt(nearestRelaySqrDistance)
+						);
+					}
+					else
+					{
+						log.AppendFormat("\n\t\t...connection to {0} would result in a circular network, skipping",
+							potentialBestRelay
+						);
+					}
 				}
 			}
 
@@ -347,6 +378,15 @@
 			kerbinSqrDistance *= kerbinSqrDistance;
 
 			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(),
+				nearestRelaySqrDistance,
+				this.bestOccludedRelay == null ? "null" : this.bestOccludedRelay.ToString(),
+				bestOccludedSqrDistance,
+				kerbinSqrDistance
+			);
 
 			// If we don't have LOS to Kerbin, focus on relays
 			if (!this.vessel.hasLineOfSightTo(Kerbin, out bodyOccludingKerbin, ARConfiguration.RadiusRatio))
@@ -390,7 +430,7 @@
 							log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
 								nearestRelaySqrDistance, bestOccludedSqrDistance);
 							
-							this.targetRelay = nearestRelay;
+							this.targetRelay = this.nearestRelay;
 							this.firstOccludingBody = null;
 						}
 						// Otherwise, target the best occluded relay.
@@ -420,7 +460,7 @@
 								nearestRelaySqrDistance, kerbinSqrDistance);
 							
 							this.KerbinDirect = false;
-							this.targetRelay = nearestRelay;
+							this.targetRelay = this.nearestRelay;
 						}
 						// Otherwise, pick Kerbin.
 						else
@@ -511,7 +551,7 @@
 								log.AppendFormat("\n\t\t\t\t...but the nearest relay is closer ({0} < {1}), so picking it.",
 									nearestRelaySqrDistance, bestOccludedSqrDistance);
 								
-								this.targetRelay = nearestRelay;
+								this.targetRelay = this.nearestRelay;
 								this.firstOccludingBody = null;
 							}
 							// Otherwise, target the best occluded relay.
@@ -541,7 +581,7 @@
 									nearestRelaySqrDistance, kerbinSqrDistance);
 								
 								this.KerbinDirect = false;
-								this.targetRelay = nearestRelay;
+								this.targetRelay = this.nearestRelay;
 							}
 							// Otherwise, pick Kerbin.
 							else

--- a/GameData/AntennaRange/AntennaRange.cfg
+++ b/GameData/AntennaRange/AntennaRange.cfg
@@ -2,7 +2,7 @@
 //
 // AntennaRange.cfg
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,

--- a/IAntennaRelay.cs
+++ b/IAntennaRelay.cs
@@ -2,7 +2,7 @@
 //
 // IAntennaRelay.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,

--- a/ModuleLimitedDataTransmitter.cs
+++ b/ModuleLimitedDataTransmitter.cs
@@ -2,7 +2,7 @@
 //
 // ModuleLimitedDataTransmitter.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,
@@ -205,11 +205,8 @@
 		/// </summary>
 		public double maxTransmitDistance
 		{
-			get
-			{
-				// TODO: Cache this in a way that doesn't break everything.
-				return Math.Sqrt(this.maxPowerFactor) * this.nominalRange;
-			}
+			get;
+			protected set;
 		}
 
 		/// <summary>
@@ -370,6 +367,8 @@
 
 			if (state >= StartState.PreLaunch)
 			{
+				this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalRange;
+
 				this.relay = new AntennaRelay(this);
 				this.relay.maxTransmitDistance = this.maxTransmitDistance;
 				this.relay.nominalTransmitDistance = this.nominalRange;
@@ -393,6 +392,8 @@
 			base.Fields.Load(node);
 
 			base.OnLoad (node);
+
+			this.maxTransmitDistance = Math.Sqrt(this.maxPowerFactor) * this.nominalRange;
 		}
 
 		/// <summary>
@@ -643,7 +644,6 @@
 					{
 						this.UIrelayStatus = string.Format("Blocked by {0}", this.relay.firstOccludingBody.bodyName);
 					}
-					this.UImaxTransmitDistance = "N/A";
 					this.UIpacketSize = "N/A";
 					this.UIpacketCost = "N/A";
 				}

--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -2,7 +2,7 @@
 //
 // AssemblyInfo.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,

--- a/ProtoAntennaRelay.cs
+++ b/ProtoAntennaRelay.cs
@@ -2,7 +2,7 @@
 //
 // ProtoAntennaRelay.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,

--- a/RelayDatabase.cs
+++ b/RelayDatabase.cs
@@ -2,7 +2,7 @@
 //
 // RelayDatabase.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,
@@ -37,27 +37,8 @@
 
 namespace AntennaRange
 {
-	public class RelayDatabase
+	public class RelayDatabase : Singleton<RelayDatabase>
 	{
-		/*
-		 * Static members
-		 * */
-		// Singleton storage
-		private static RelayDatabase _instance;
-		// Gets the singleton
-		public static RelayDatabase Instance
-		{
-			get
-			{	
-				if (_instance == null)
-				{
-					_instance = new RelayDatabase();
-				}
-
-				return _instance;
-			}
-		}
-
 		/*
 		 * Instance members
 		 * */

--- a/RelayExtensions.cs
+++ b/RelayExtensions.cs
@@ -2,7 +2,7 @@
 //
 // Extensions.cs
 //
-// Copyright © 2014, toadicus
+// Copyright © 2014-2015, toadicus
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without modification,