Index: binaries/data/mods/public/gui/session_new/input.js
===================================================================
--- binaries/data/mods/public/gui/session_new/input.js	(revision 7822)
+++ binaries/data/mods/public/gui/session_new/input.js	(working copy)
@@ -62,6 +62,25 @@
 }
 
 /**
+ * Checks if all the given entities are buildings.
+ * @param entities
+ */
+function areAllBuildings(entities)
+{
+	for each (var ent in entities)
+	{
+		var entState = Engine.GuiInterfaceCall("GetEntityState", ent);
+		//If the entity does not have a RallyPoint defined,
+		if (!entState.isABuilding)
+		{
+			return false;
+		}
+			
+	}
+	return true;
+}
+
+/**
  * Determine the context-sensitive action that should be performed when the mouse is at (x,y)
  */
 function determineAction(x, y)
@@ -86,8 +105,18 @@
 
 	// If there's no unit, just walk
 	if (!targets.length)
-		return {"type": "move"};
-
+	{
+		//If all selected entities are buildings,
+		//set gather points, else make them walk
+		if (areAllBuildings(selection))
+		{
+			return {"type": "set-rallypoint"};
+		}
+		else
+		{
+			return {"type": "move"};
+		}
+	}
 	// Look at the first targeted entity
 	// (TODO: maybe we eventually want to look at more, and be more context-sensitive?
 	// e.g. prefer to attack an enemy unit, even if some friendly units are closer to the mouse)
@@ -266,6 +295,10 @@
 				g_Selection.reset();
 				g_Selection.addList(ents);
 
+				Engine.GuiInterfaceCall("DisplayRallyPoint", {
+					"entities": ents[0]
+				});
+				
 				// Create the selection groups
 				g_Selection.groups.createGroups(ents);
 
@@ -463,7 +496,15 @@
 				case "gather":
 					Engine.PostNetworkCommand({"type": "gather", "entities": selection, "target": action.target, "queued": queued});
 					return true;
-
+				case "set-rallypoint":
+					var target = Engine.GetTerrainAtPoint(ev.x, ev.y);
+					Engine.PostNetworkCommand({"type": "set-rallypoint", "entities": selection, "x": target.x, "z": target.z});
+					//Display rally point passing just the coordinates
+					Engine.GuiInterfaceCall("SetRallyPoint", {
+						"x": target.x,
+						"z": target.z
+					});
+					return true;
 				default:
 					throw new Error("Invalid action.type "+action.type);
 				}
@@ -497,14 +538,19 @@
 				if (!ents.length)
 				{
 					g_Selection.reset();
-					
 					inputState = INPUT_NORMAL;
+					//Clear Rally Points
+					Engine.GuiInterfaceCall("DisplayRallyPoint", {
+						"entities": undefined
+					});
 					return true;
 				}
-
+				//Display Rally Point
+				Engine.GuiInterfaceCall("DisplayRallyPoint", {
+					"entities": [ents[0]]
+				});
 				g_Selection.reset();
 				g_Selection.addList([ents[0]]);
-
 				inputState = INPUT_NORMAL;
 				return true;
 			}
Index: binaries/data/mods/public/simulation/helpers/Commands.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Commands.js	(revision 7822)
+++ binaries/data/mods/public/simulation/helpers/Commands.js	(working copy)
@@ -123,7 +123,14 @@
 		});
 
 		break;
-
+	case "set-rallypoint":
+		for each (var ent in cmd.entities)
+		{
+			var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
+			if (cmpRallyPoint)
+				cmpRallyPoint.SetPosition(cmd.x, cmd.z);
+		}
+		break;
 	default:
 		error("Ignoring unrecognised command type '" + cmd.type + "'");
 	}
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js	(revision 7822)
+++ binaries/data/mods/public/simulation/components/GuiInterface.js	(working copy)
@@ -11,6 +11,7 @@
 GuiInterface.prototype.Init = function()
 {
 	this.placementEntity = undefined; // = undefined or [templateName, entityID]
+	this.rallyPoints = undefined;
 };
 
 GuiInterface.prototype.GetSimulationState = function(player)
@@ -124,6 +125,19 @@
 		ret.resourceGatherRates = cmpResourceGatherer.GetGatherRates();
 	}
 
+	var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
+	if(cmpRallyPoint)
+	{
+		ret.isABuilding = true;
+		if (cmpRallyPoint.GetPosition() != undefined)
+		{
+			ret.isRallyPointSet = true;
+		}
+		else
+		{
+			ret.isRallyPointSet = false;
+		}
+	}
 	return ret;
 };
 
@@ -170,6 +184,54 @@
 };
 
 /**
+ * Displays the rally point of a building
+ */
+GuiInterface.prototype.DisplayRallyPoint = function(player, cmd)
+{
+	var positions;
+	if (this.rallyPoints)
+	{
+		//If there are rally points already displayed, destroy them
+		for each (var rallyPoint in this.rallyPoints)
+		{
+			Engine.DestroyEntity(rallyPoint);
+		}
+	}	
+	if (cmd.entities)
+	{
+		//DisplayRallyPoints is called passing a list of entities for which
+		//Rally Points must be displayed
+		positions = new Array();
+		for each (var ent in cmd.entities)
+		{
+			var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
+			if (cmpRallyPoint && cmpRallyPoint.GetPosition())
+			{
+				positions.push(cmpRallyPoint.GetPosition());
+			}
+		}
+	}
+	else if (cmd.x && cmd.z)
+	{
+		//Sometimes DisplayRallyPoint() is called specifying just a coordinate.
+		positions = [{"x": cmd.x, "z": cmd.z}];
+	}
+	if (positions)
+	{
+		this.rallyPoints = new Array();
+		//Add Rally Point entitied for each building
+		for each (var pos in positions)
+		{
+			var rallyPoint = Engine.AddLocalEntity("actor|props/special/common/waypoint_flag.xml");
+			var cmpPosition = Engine.QueryInterface(rallyPoint, IID_Position);
+			cmpPosition.JumpTo(pos.x, pos.z);
+			this.rallyPoints.push(rallyPoint);
+		}
+	}
+	
+}
+
+/**
  * Display the building placement preview.
  * cmd.template is the name of the entity template, or "" to disable the preview.
  * cmd.x, cmd.z, cmd.angle give the location.
@@ -248,12 +310,6 @@
 	}
 };
 
-GuiInterface.prototype.SetRangeDebugOverlay = function(player, enabled)
-{
-	var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
-	cmpRangeManager.SetDebugOverlay(enabled);
-};
-
 // List the GuiInterface functions that can be safely called by GUI scripts.
 // (GUI scripts are non-deterministic and untrusted, so these functions must be
 // appropriately careful. They are called with a first argument "player", which is
@@ -268,7 +324,7 @@
 	"SetPathfinderDebugOverlay": 1,
 	"SetObstructionDebugOverlay": 1,
 	"SetMotionDebugOverlay": 1,
-	"SetRangeDebugOverlay": 1,
+	"DisplayRallyPoint": 1
 };
 
 GuiInterface.prototype.ScriptCall = function(player, name, args)
Index: binaries/data/mods/public/simulation/components/TrainingQueue.js
===================================================================
--- binaries/data/mods/public/simulation/components/TrainingQueue.js	(revision 7822)
+++ binaries/data/mods/public/simulation/components/TrainingQueue.js	(working copy)
@@ -158,7 +158,8 @@
 	var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
 	var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
 	var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
-
+	var cmpRallyPoint = Engine.QueryInterface(this.entity, IID_RallyPoint);
+	
 	for (var i = 0; i < count; ++i)
 	{
 		var ent = Engine.AddEntity(templateName);
@@ -181,6 +182,9 @@
 		cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
 
 		// TODO: move to rally points
+		var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
+		if (cmpUnitAI && cmpRallyPoint.GetPosition() != undefined)
+			cmpUnitAI.Walk(cmpRallyPoint.GetPosition().x, cmpRallyPoint.GetPosition().z, false);
 	}
 };
 
Index: binaries/data/mods/public/simulation/templates/template_structure.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure.xml	(revision 7822)
+++ binaries/data/mods/public/simulation/templates/template_structure.xml	(working copy)
@@ -36,4 +36,6 @@
     <Range>36</Range>
     <RetainInFog>true</RetainInFog>
   </Vision>
+  <RallyPoint>
+  </RallyPoint>
 </Entity>

