Index: binaries/data/mods/public/gui/session/input.js
===================================================================
--- binaries/data/mods/public/gui/session/input.js	(revision 14512)
+++ binaries/data/mods/public/gui/session/input.js	(working copy)
@@ -36,6 +36,7 @@
 var mouseX = 0;
 var mouseY = 0;
 var mouseIsOverObject = false;
+var SELECTION_SEARCH_RANGE = 20;
 
 // Number of pixels the mouse can move before the action is considered a drag
 var maxDragDelta = 4;
@@ -495,7 +496,7 @@
 	var targets = [];
 	var target = undefined;
 	if (!fromMinimap)
-		targets = Engine.PickEntitiesAtPoint(x, y);
+		targets = Engine.PickEntitiesAtPoint(x, y, SELECTION_SEARCH_RANGE);
 
 	if (targets.length)
 		target = targets[0];
@@ -1108,7 +1109,7 @@
 		{
 		case "mousemotion":
 			// Highlight the first hovered entity (if any)
-			var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
+			var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y, SELECTION_SEARCH_RANGE);
 			if (ents.length)
 				g_Selection.setHighlightList([ents[0]]);
 			else
@@ -1162,7 +1163,7 @@
 		{
 		case "mousemotion":
 			// Highlight the first hovered entity (if any)
-			var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
+			var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y, SELECTION_SEARCH_RANGE);
 			if (ents.length)
 				g_Selection.setHighlightList([ents[0]]);
 			else
@@ -1212,14 +1213,14 @@
 				return false;
 			}
 
-			var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
+			var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y, SELECTION_SEARCH_RANGE);
 			g_Selection.setHighlightList(ents);
 			return false;
 
 		case "mousebuttonup":
 			if (ev.button == SDL_BUTTON_LEFT)
 			{
-				var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
+				var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y, SELECTION_SEARCH_RANGE);
 				if (!ents.length)
 				{
 					if (!Engine.HotkeyIsPressed("selection.add") && !Engine.HotkeyIsPressed("selection.remove"))
Index: source/gui/scripting/ScriptFunctions.cpp
===================================================================
--- source/gui/scripting/ScriptFunctions.cpp	(revision 14512)
+++ source/gui/scripting/ScriptFunctions.cpp	(working copy)
@@ -148,9 +148,9 @@
 	cmpCommandQueue->PostNetworkCommand(cmd2);
 }
 
-std::vector<entity_id_t> PickEntitiesAtPoint(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x, int y)
+std::vector<entity_id_t> PickEntitiesAtPoint(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x, int y, int range)
 {
-	return EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, g_Game->GetPlayerID(), false);
+	return EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, g_Game->GetPlayerID(), false, range);
 }
 
 std::vector<entity_id_t> PickFriendlyEntitiesInRect(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x0, int y0, int x1, int y1, int player)
@@ -804,7 +804,7 @@
 	scriptInterface.RegisterFunction<void, CScriptVal, &PostNetworkCommand>("PostNetworkCommand");
 
 	// Entity picking
-	scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, &PickEntitiesAtPoint>("PickEntitiesAtPoint");
+	scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, &PickEntitiesAtPoint>("PickEntitiesAtPoint");
 	scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickFriendlyEntitiesInRect>("PickFriendlyEntitiesInRect");
 	scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, &PickFriendlyEntitiesOnScreen>("PickFriendlyEntitiesOnScreen");
 	scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, bool, bool, &PickSimilarFriendlyEntities>("PickSimilarFriendlyEntities");
Index: source/simulation2/components/CCmpRangeManager.cpp
===================================================================
--- source/simulation2/components/CCmpRangeManager.cpp	(revision 14512)
+++ source/simulation2/components/CCmpRangeManager.cpp	(working copy)
@@ -97,17 +97,17 @@
  * Checks whether v is in a parabolic range of (0,0,0)
  * The highest point of the paraboloid is (0,range/2,0)
  * and the circle of distance 'range' around (0,0,0) on height y=0 is part of the paraboloid
- * 
+ *
  * Avoids sqrting and overflowing.
  */
-static bool InParabolicRange(CFixedVector3D v, fixed range) 
+static bool InParabolicRange(CFixedVector3D v, fixed range)
 {
 	i32 x = v.X.GetInternalValue(); // abs(x) <= 2^31
 	i32 z = v.Z.GetInternalValue();
 	u64 xx = (u64)FIXED_MUL_I64_I32_I32(x, x); // xx <= 2^62
 	u64 zz = (u64)FIXED_MUL_I64_I32_I32(z, z);
 	i64 d2 = (xx + zz) >> 1; // d2 <= 2^62 (no overflow)
-	
+
 	i32 y = v.Y.GetInternalValue();
 	i32 c = range.GetInternalValue();
 	i32 c_2 = c >> 1;
@@ -327,7 +327,7 @@
 		// will get confused when trying to run from enemies
 		m_LosRevealAll.resize(MAX_LOS_PLAYER_ID+2,false);
 		m_SharedLosMasks.resize(MAX_LOS_PLAYER_ID+2,0);
-		
+
 		m_LosCircular = false;
 		m_TerrainVerticesPerSide = 0;
 
@@ -601,6 +601,11 @@
 			debug_warn(L"inconsistent subdivs");
 	}
 
+	SpatialSubdivision * GetSubdivision()
+	{
+		return & m_Subdivision;
+	}
+
 	// Reinitialise subdivisions and LOS data, based on entity data
 	void ResetDerivedData(bool skipLosState)
 	{
@@ -844,7 +849,7 @@
 			if (!query.enabled)
 				continue;
 
-			CmpPtr<ICmpPosition> cmpSourcePosition(query.source);			
+			CmpPtr<ICmpPosition> cmpSourcePosition(query.source);
 			if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld())
 				continue;
 
@@ -858,9 +863,9 @@
 			removed.clear();
 			// Return the 'added' list sorted by distance from the entity
 			// (Don't bother sorting 'removed' because they might not even have positions or exist any more)
-			std::set_difference(results.begin(), results.end(), query.lastMatch.begin(), query.lastMatch.end(), 
+			std::set_difference(results.begin(), results.end(), query.lastMatch.begin(), query.lastMatch.end(),
 				std::back_inserter(added));
-			std::set_difference(query.lastMatch.begin(), query.lastMatch.end(), results.begin(), results.end(), 
+			std::set_difference(query.lastMatch.begin(), query.lastMatch.end(), results.begin(), results.end(),
 				std::back_inserter(removed));
 			if (added.empty() && removed.empty())
 				continue;
@@ -927,7 +932,7 @@
 			}
 		}
 		// Not the entire world, so check a parabolic range, or a regular range
-		else if (q.parabolic) 
+		else if (q.parabolic)
 		{
 			// elevationBonus is part of the 3D position, as the source is really that much heigher
 			CmpPtr<ICmpPosition> cmpSourcePosition(q.source);
@@ -944,7 +949,7 @@
 
 				if (!TestEntityQuery(q, it->first, it->second))
 					continue;
-				
+
 				CmpPtr<ICmpPosition> cmpSecondPosition(GetSimContext(), ents[i]);
 				if (!cmpSecondPosition || !cmpSecondPosition->IsInWorld())
 					continue;
@@ -952,8 +957,8 @@
 
 				// Restrict based on precise distance
 				if (!InParabolicRange(
-						CFixedVector3D(it->second.x, secondPosition.Y, it->second.z) 
-							- pos3d, 
+						CFixedVector3D(it->second.x, secondPosition.Y, it->second.z)
+							- pos3d,
 						q.maxRange))
 					continue;
 
@@ -968,12 +973,12 @@
 			}
 		}
 		// check a regular range (i.e. not the entire world, and not parabolic)
-		else 
+		else
 		{
 			// Get a quick list of entities that are potentially in range
 			SpatialQueryArray ents;
 			m_Subdivision.GetNear(ents, pos, q.maxRange);
-			
+
 			for (int i = 0; i < ents.size(); ++i)
 			{
 				EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
@@ -1002,7 +1007,7 @@
 	virtual entity_pos_t GetElevationAdaptedRange(CFixedVector3D pos, CFixedVector3D rot, entity_pos_t range, entity_pos_t elevationBonus, entity_pos_t angle)
 	{
 		entity_pos_t r = entity_pos_t::Zero() ;
-		
+
 		pos.Y += elevationBonus;
 		entity_pos_t orientation = rot.Y;
 
@@ -1022,26 +1027,26 @@
 		{
 			r = r + CFixedVector2D(coords[2*i],coords[2*i+1]).Length() / part;
 		}
-		
+
 		return r;
-		
+
 	}
 
-	virtual std::vector<entity_pos_t> getParabolicRangeForm(CFixedVector3D pos, entity_pos_t maxRange, entity_pos_t cutoff, entity_pos_t minAngle, entity_pos_t maxAngle, int numberOfSteps) 
+	virtual std::vector<entity_pos_t> getParabolicRangeForm(CFixedVector3D pos, entity_pos_t maxRange, entity_pos_t cutoff, entity_pos_t minAngle, entity_pos_t maxAngle, int numberOfSteps)
 	{
-		
+
 		// angle = 0 goes in the positive Z direction
 		entity_pos_t precision = entity_pos_t::FromInt((int)TERRAIN_TILE_SIZE)/8;
 
 		std::vector<entity_pos_t> r;
-		
 
+
 		CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity());
 		CmpPtr<ICmpWaterManager> cmpWaterManager(GetSystemEntity());
 		entity_pos_t waterLevel = cmpWaterManager->GetWaterLevel(pos.X,pos.Z);
 		entity_pos_t thisHeight = pos.Y > waterLevel ? pos.Y : waterLevel;
 
-		if (cmpTerrain) 
+		if (cmpTerrain)
 		{
 			for (int i = 0; i < numberOfSteps; i++)
 			{
@@ -1064,7 +1069,7 @@
 					r.push_back(maxVector.Y);
 					continue;
 				}
-				
+
 				// Loop until vectors come close enough
 				while ((maxVector - minVector).CompareLength(precision) > 0)
 				{
@@ -1083,26 +1088,26 @@
 						minVector = newVector;
 						minDistance = newDistance;
 					}
-					else 
+					else
 					{
 						// new vector is out parabolic range, so this is a new maxVector
 						maxVector = newVector;
 						maxDistance = newDistance;
 					}
-					
+
 				}
 				r.push_back(maxVector.X);
 				r.push_back(maxVector.Y);
-				
+
 			}
 			r.push_back(r[0]);
-			r.push_back(r[1]); 
+			r.push_back(r[1]);
 
 		}
 		return r;
 
 	}
-	
+
 	Query ConstructQuery(entity_id_t source,
 		entity_pos_t minRange, entity_pos_t maxRange,
 		const std::vector<int>& owners, int requiredInterface, u8 flagsMask)
@@ -1150,7 +1155,7 @@
 			return;
 		static CColor disabledRingColour(1, 0, 0, 1);	// red
 		static CColor enabledRingColour(0, 1, 0, 1);	// green
-		static CColor subdivColour(0, 0, 1, 1);			// blue 
+		static CColor subdivColour(0, 0, 1, 1);			// blue
 		static CColor rayColour(1, 1, 0, 0.2f);
 
 		if (m_DebugOverlayDirty)
@@ -1173,26 +1178,26 @@
 					m_DebugOverlayLines.back().m_Color = (q.enabled ? enabledRingColour : disabledRingColour);
 					SimRender::ConstructCircleOnGround(GetSimContext(), pos.X.ToFloat(), pos.Y.ToFloat(), q.maxRange.ToFloat(), m_DebugOverlayLines.back(), true);
 				}
-				else 
-				{ 
+				else
+				{
 					// elevation bonus is part of the 3D position. As if the unit is really that much higher
-					CFixedVector3D pos = cmpSourcePosition->GetPosition(); 
+					CFixedVector3D pos = cmpSourcePosition->GetPosition();
 					pos.Y += q.elevationBonus;
 
 					std::vector<entity_pos_t> coords;
-					
+
 					// Get the outline from cache if possible
 					if (ParabolicRangesOutlines.find(q.source.GetId()) != ParabolicRangesOutlines.end())
 					{
 						EntityParabolicRangeOutline e = ParabolicRangesOutlines[q.source.GetId()];
-						if (e.position == pos && e.range == q.maxRange) 
+						if (e.position == pos && e.range == q.maxRange)
 						{
 							// outline is cached correctly, use it
-							coords = e.outline;	
+							coords = e.outline;
 						}
 						else
 						{
-							// outline was cached, but important parameters changed 
+							// outline was cached, but important parameters changed
 							// (position, elevation, range)
 							// update it
 							coords = getParabolicRangeForm(pos,q.maxRange,q.maxRange*2, entity_pos_t::Zero(), entity_pos_t::FromFloat(2.0f*3.14f),70);
@@ -1202,9 +1207,9 @@
 							ParabolicRangesOutlines[q.source.GetId()] = e;
 						}
 					}
-					else 
+					else
 					{
-						// outline wasn't cached (first time you enable the range overlay 
+						// outline wasn't cached (first time you enable the range overlay
 						// or you created a new entiy)
 						// cache a new outline
 						coords = getParabolicRangeForm(pos,q.maxRange,q.maxRange*2, entity_pos_t::Zero(), entity_pos_t::FromFloat(2.0f*3.14f),70);
@@ -1215,10 +1220,10 @@
 						e.outline = coords;
 						ParabolicRangesOutlines[q.source.GetId()] = e;
 					}
-					
+
 					CColor thiscolor = q.enabled ? enabledRingColour : disabledRingColour;
-					
-					// draw the outline (piece by piece)	
+
+					// draw the outline (piece by piece)
 					for (size_t i = 3; i < coords.size(); i += 2)
 					{
 						std::vector<float> c;
@@ -1268,7 +1273,7 @@
 				{
 					m_DebugOverlayLines.push_back(SOverlayLine());
 					m_DebugOverlayLines.back().m_Color = subdivColour;
-					
+
 					float xpos = x*divSize + divSize/2;
 					float zpos = y*divSize + divSize/2;
 					SimRender::ConstructSquareOnGround(GetSimContext(), xpos, zpos, divSize, divSize, 0.0f,
Index: source/simulation2/components/ICmpRangeManager.h
===================================================================
--- source/simulation2/components/ICmpRangeManager.h	(revision 14512)
+++ source/simulation2/components/ICmpRangeManager.h	(working copy)
@@ -24,6 +24,7 @@
 #include "simulation2/system/Interface.h"
 #include "simulation2/helpers/Position.h"
 #include "simulation2/helpers/Player.h"
+#include "simulation2/helpers/Spatial.h"
 
 #include "graphics/Terrain.h" // for TERRAIN_TILE_SIZE
 
@@ -73,6 +74,12 @@
 	typedef u32 tag_t;
 
 	/**
+	 * Access the spatial subdivision kept by the range manager.
+	 * @return pointer to spatial subdivision structure.
+	 */
+	virtual SpatialSubdivision * GetSubdivision() = 0;
+
+	/**
 	 * Set the bounds of the world.
 	 * Entities should not be outside the bounds (else efficiency will suffer).
 	 * @param x0,z0,x1,z1 Coordinates of the corners of the world
@@ -118,12 +125,12 @@
 		entity_pos_t minRange, entity_pos_t maxRange, std::vector<int> owners, int requiredInterface, u8 flags) = 0;
 
     /**
-	 * Construct an active query of a paraboloic form around the unit. 
+	 * Construct an active query of a paraboloic form around the unit.
 	 * The query will be disabled by default.
 	 * @param source the entity around which the range will be computed.
 	 * @param minRange non-negative minimum horizontal distance in metres (inclusive). MinRange doesn't do parabolic checks.
-	 * @param maxRange non-negative maximum distance in metres (inclusive) for units on the same elevation; 
-	 *      or -1.0 to ignore distance. 
+	 * @param maxRange non-negative maximum distance in metres (inclusive) for units on the same elevation;
+	 *      or -1.0 to ignore distance.
 	 *      For units on a different elevation, a physical correct paraboloid with height=maxRange/2 above the unit is used to query them
 	 * @param elevationBonus extra bonus so the source can be placed higher and shoot further
 	 * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
Index: source/simulation2/helpers/Selection.cpp
===================================================================
--- source/simulation2/helpers/Selection.cpp	(revision 14512)
+++ source/simulation2/helpers/Selection.cpp	(working copy)
@@ -27,26 +27,36 @@
 #include "simulation2/components/ICmpTemplateManager.h"
 #include "simulation2/components/ICmpSelectable.h"
 #include "simulation2/components/ICmpVisual.h"
+#include "simulation2/helpers/Spatial.h"
 #include "ps/CLogger.h"
+#include "ps/Profiler2.h"
 
-std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables)
+std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables, int range)
 {
+	PROFILE2("PickEntitiesAtPoint");
 	CVector3D origin, dir;
 	camera.BuildCameraRay(screenX, screenY, origin, dir);
 
 	CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
 	ENSURE(cmpRangeManager);
 
+	SpatialQueryArray ents;
+	CVector3D pos3d = camera.GetWorldCoordinates(screenX, screenY, true);
+	// Change the position to 2D by just dropping the Z.
+	CFixedVector2D pos(fixed::FromFloat(pos3d.X), fixed::FromFloat(pos3d.Z));
+	cmpRangeManager->GetSubdivision()->GetNear(ents, pos, entity_pos_t::FromInt(range)); // TODO, Don't just use an arbitrary number.
+ 
 	std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs
-
-	const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
-	for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
+	for (int i = 0; i != ents.size(); ++i)
 	{
-		entity_id_t ent = it->first;
-		CEntityHandle handle = it->second->GetEntityHandle();
+		CmpPtr<ICmpSelectable> cmpSelectable(simulation, ents[i]);
+		if (!cmpSelectable)
+			continue;
 
+		CEntityHandle handle = cmpSelectable->GetEntityHandle();
+
 		// Check if this entity is only selectable in Atlas
-		if (!allowEditorSelectables && static_cast<ICmpSelectable*>(it->second)->IsEditorOnly())
+		if (!allowEditorSelectables && cmpSelectable->IsEditorOnly())
 			continue;
 
 		// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
@@ -91,7 +101,7 @@
 		CVector3D closest = origin + dir * (center - origin).Dot(dir);
 		dist2 = (closest - center).LengthSquared();
 
-		hits.push_back(std::make_pair(dist2, ent));
+		hits.push_back(std::make_pair(dist2, ents[i]));
 	}
 
 	// Sort hits by distance
@@ -148,7 +158,6 @@
 		CVector3D position = cmpVisual->GetPosition();
 
 		// Reject if it's not on-screen (e.g. it's behind the camera)
-
 		if (!camera.GetFrustum().IsPointVisible(position))
 			continue;
 
Index: source/simulation2/helpers/Selection.h
===================================================================
--- source/simulation2/helpers/Selection.h	(revision 14512)
+++ source/simulation2/helpers/Selection.h	(working copy)
@@ -43,10 +43,11 @@
  *	this value is ignored as the whole map is revealed.
  * @param allowEditorSelectables if true, all entities with the ICmpSelectable interface
  *	will be selected (including decorative actors), else only those selectable ingame.
+ * @param range Approximate range to check for entity in.
  *
  * @return ordered list of selected entities with the closest first.
  */
-std::vector<entity_id_t> PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables);
+std::vector<entity_id_t> PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables, int range);
 
 /**
  * Finds all selectable entities within the given screen coordinate rectangle,
Index: source/simulation2/helpers/Spatial.h
===================================================================
--- source/simulation2/helpers/Spatial.h	(revision 14512)
+++ source/simulation2/helpers/Spatial.h	(working copy)
@@ -18,6 +18,7 @@
 #ifndef INCLUDED_SPATIAL
 #define INCLUDED_SPATIAL
 
+#include "simulation2/system/Component.h"
 #include "simulation2/serialization/SerializeTemplates.h"
 #include "ps/CLogger.h"
 
Index: source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp
===================================================================
--- source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp	(revision 14512)
+++ source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp	(working copy)
@@ -442,7 +442,7 @@
 	
 	// Normally this function would be called with a player ID to check LOS,
 	//	but in Atlas the entire map is revealed, so just pass INVALID_PLAYER
-	std::vector<entity_id_t> ents = EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, INVALID_PLAYER, msg->selectActors);
+	std::vector<entity_id_t> ents = EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, INVALID_PLAYER, msg->selectActors, 200);
 
 	// Multiple entities may have been picked, but they are sorted by distance,
 	//	so only take the first one
