Index: binaries/data/mods/public/gui/session/input.js
===================================================================
--- binaries/data/mods/public/gui/session/input.js	(revision 10671)
+++ binaries/data/mods/public/gui/session/input.js	(working copy)
@@ -139,7 +139,7 @@
 	if (!target)
 	{
 		if (action == "set-rallypoint" && haveRallyPoints)
-			return {"possible": true};
+			return {"possible": true, "command": "walk"};
 		else if (action == "move")
 			return {"possible": true};
 		else
@@ -163,6 +163,59 @@
 	// Check if any entities in the selection can gather the requested resource,
 	// can return to the dropsite, can build the foundation, or can attack the enemy
 	var simState = Engine.GuiInterfaceCall("GetSimulationState");
+	
+	// Look to see what type of command units going to the rally point should use
+	if (haveRallyPoints && action == "set-rallypoint"){
+		// haveRallyPoints ensures all selected entities can have rally points.
+		// We assume that all entities are owned by the same player.
+		var entState = GetEntityState(selection[0]);
+		
+		var playerState = simState.players[entState.player];
+		var playerOwned = (targetState.player == entState.player);
+		var allyOwned = playerState.isAlly[targetState.player];
+		var enemyOwned = playerState.isEnemy[targetState.player];
+		var gaiaOwned = (targetState.player == 0);
+		
+		var cursor = "";
+		
+		// default to walking there
+		var data = {command: "walk"};
+		if (targetState.garrisonHolder && playerOwned)
+		{
+			data.command = "garrison";
+			data.target = target;
+			cursor = "action-garrison";
+		}
+		else if (targetState.resourceSupply && (playerOwned || gaiaOwned))
+		{
+			var resourceType = targetState.resourceSupply.type.generic;
+			if (resourceType === "treasure")
+			{
+				resourceType = targetState.resourceSupply.type.specific;
+				cursor = "action-gather-" + targetState.resourceSupply.type.generic;
+			}
+			else
+			{
+				cursor = "action-gather-" + targetState.resourceSupply.type.specific;
+			}
+			data.command = "gather";
+			data.resourceType = resourceType;
+		}
+		else if (targetState.foundation && entState.buildEntities)
+		{
+			data.command = "build";
+			data.target = target;
+			cursor = "action-build";
+		}
+		else if (targetState.needsRepair && allyOwned)
+		{
+			data.command = "repair";
+			data.target = target;
+			cursor = "action-repair";
+		}
+		
+		return {"possible": true, "data": data, "position": targetState.position, "cursor": cursor};
+	}
 
 	for each (var entityID in selection)
 	{
@@ -312,10 +365,10 @@
 			return {"type": "build", "cursor": "action-repair", "target": target};
 		else if (getActionInfo("attack", target).possible)
 			return {"type": "attack", "cursor": "action-attack", "target": target};
-		else if(getActionInfo("set-rallypoint", target).possible)
-			return {"type": "set-rallypoint"};
+		else if((actionInfo = getActionInfo("set-rallypoint", target)).possible)
+			return {"type": "set-rallypoint", "cursor": actionInfo.cursor, "data": actionInfo.data, "position": actionInfo.position};
 		else if(getActionInfo("unset-rallypoint", target).possible)
-				return {"type": "unset-rallypoint"};
+			return {"type": "unset-rallypoint"};
 		else if (getActionInfo("move", target).possible)
 			return {"type": "move"};
 	}
@@ -932,13 +985,23 @@
 		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});
+		var pos = undefined;
+		// if there is a position set in the action then use this so that when setting a 
+		// rally point on an entity it is centered on that entity
+		if (action.position)
+		{
+			pos = action.position;
+		}
+		else
+		{
+			pos = Engine.GetTerrainAtPoint(ev.x, ev.y);
+		}
+		Engine.PostNetworkCommand({"type": "set-rallypoint", "entities": selection, "x": pos.x, "z": pos.z, "data": action.data});
 		// Display rally point at the new coordinates, to avoid display lag
 		Engine.GuiInterfaceCall("DisplayRallyPoint", {
 			"entities": selection,
-			"x": target.x,
-			"z": target.z
+			"x": pos.x,
+			"z": pos.z
 		});
 		return true;
 
Index: binaries/data/mods/public/simulation/helpers/Commands.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Commands.js	(revision 10671)
+++ binaries/data/mods/public/simulation/helpers/Commands.js	(working copy)
@@ -94,6 +94,13 @@
 			cmpUnitAI.Gather(cmd.target, cmd.queued);
 		});
 		break;
+		
+	case "gatherNearPosition":
+		var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
+		GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
+			cmpUnitAI.GatherNearPosition([cmd.x, cmd.z], cmd.resourceType, cmd.queued);
+		});
+		break;
 
 	case "returnresource":
 		// Check dropsite is owned by player
@@ -288,7 +295,10 @@
 		{
 			var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
 			if (cmpRallyPoint)
+			{
 				cmpRallyPoint.SetPosition(cmd.x, cmd.z);
+				cmpRallyPoint.SetData(cmd.data);
+			}
 		}
 		break;
 
Index: binaries/data/mods/public/simulation/components/TrainingQueue.js
===================================================================
--- binaries/data/mods/public/simulation/components/TrainingQueue.js	(revision 10671)
+++ binaries/data/mods/public/simulation/components/TrainingQueue.js	(working copy)
@@ -280,19 +280,14 @@
 
 	if (spawnedEnts.length > 0)
 	{
-		// If a rally point is set, walk towards it (in formation)
+		// If a rally point is set, walk towards it (in formation) using a suitable command based on where the 
+		// rally point is placed.
 		if (cmpRallyPoint)
 		{
 			var rallyPos = cmpRallyPoint.GetPosition();
 			if (rallyPos)
 			{
-				ProcessCommand(cmpOwnership.GetOwner(), {
-					"type": "walk",
-					"entities": spawnedEnts,
-					"x": rallyPos.x,
-					"z": rallyPos.z,
-					"queued": false
-				});
+				ProcessCommand(cmpOwnership.GetOwner(), getRallyPointCommand(cmpRallyPoint, spawnedEnts));
 			}
 		}
 
Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js
===================================================================
--- binaries/data/mods/public/simulation/components/GarrisonHolder.js	(revision 10671)
+++ binaries/data/mods/public/simulation/components/GarrisonHolder.js	(working copy)
@@ -191,13 +191,7 @@
 		var rallyPos = cmpRallyPoint.GetPosition();
 		if (rallyPos)
 		{
-			ProcessCommand(cmpOwnership.GetOwner(), {
-				"type": "walk",
-				"entities": entities,
-				"x": rallyPos.x,
-				"z": rallyPos.z,
-				"queued": false
-			});
+			ProcessCommand(cmpOwnership.GetOwner(), getRallyPointCommand(cmpRallyPoint, entities));
 		}
 	}
 };
Index: binaries/data/mods/public/simulation/components/UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/UnitAI.js	(revision 10671)
+++ binaries/data/mods/public/simulation/components/UnitAI.js	(working copy)
@@ -284,6 +284,7 @@
 	},
 
 	"Order.Gather": function(msg) {
+		
 		// If the target is still alive, we need to kill it first
 		if (this.MustKillGatherTarget(this.order.data.target) && this.CheckTargetVisible(this.order.data.target))
 		{
@@ -315,6 +316,12 @@
 			this.SetNextState("INDIVIDUAL.GATHER.GATHERING");
 		}
 	},
+	
+	"Order.GatherNearPosition": function(msg){
+		// Move the unit to the position to gather from.
+		this.MoveToPoint(this.order.data.x, this.order.data.z);
+		this.SetNextState("INDIVIDUAL.GATHER.WALKING");
+	},
 
 	"Order.ReturnResource": function(msg) {
 		// Try to move to the dropsite
@@ -408,6 +415,12 @@
 			cmpFormation.CallMemberFunction("Gather", [msg.data.target, false]);
 			cmpFormation.Disband();
 		},
+		
+		"Order.GatherNearPosition": function(msg){
+			var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
+			cmpFormation.CallMemberFunction("GatherNearPosition", [[msg.data.x, msg.data.z], msg.data.type, false]);
+			cmpFormation.Disband();
+		},
 
 		"Order.ReturnResource": function(msg) {
 			// TODO: see notes in Order.Attack
@@ -815,7 +828,37 @@
 					this.SetNextState("GATHERING");
 				},
 			},
+			
+			// Walking to a good place to gather resoruce near, ued by gatherNearPosition
+			"WALKING": {
+				"enter": function() {
+					this.SelectAnimation("move");
+				},
 
+				"MoveCompleted": function(msg) {
+						var resourceType = this.order.data.type;
+						
+						// Try to find another nearby target of the same specific type
+						var nearby = this.FindNearbyResource(function (ent, type) {
+							if (type.generic === "treasure"){
+								return (type.specific == resourceType);
+							}
+							return (type.generic == resourceType);
+						});
+						
+						// If there is a nearby resource start gathering
+						if (nearby)
+						{
+							this.Gather(nearby, false);
+							return;
+						}
+						
+						// Couldn't find nearby resources, so give up
+						this.FinishOrder();
+
+				},
+			},
+
 			"GATHERING": {
 				"enter": function() {
 					this.StartTimer(1000, 1000);
@@ -2179,6 +2222,7 @@
 		switch (order.type)
 		{
 		case "Walk":
+		case "GatherNearPosition":
 			// Add the distance to the target point
 			var dx = order.data.x - pos.x;
 			var dz = order.data.z - pos.z;
@@ -2307,6 +2351,10 @@
 	this.AddOrder("Gather", { "target": target, "type": type, "lastPos": lastPos }, queued);
 };
 
+UnitAI.prototype.GatherNearPosition = function(position, type, queued){
+	this.AddOrder("GatherNearPosition", { "type": type, "x": position[0], "z": position[1] }, queued);
+}
+
 UnitAI.prototype.ReturnResource = function(target, queued)
 {
 	if (!this.CanReturnResource(target, true))
Index: binaries/data/mods/public/simulation/components/RallyPoint.js
===================================================================
--- binaries/data/mods/public/simulation/components/RallyPoint.js	(revision 10671)
+++ binaries/data/mods/public/simulation/components/RallyPoint.js	(working copy)
@@ -16,14 +16,31 @@
 	}
 };
 
-RallyPoint.prototype.Unset = function()
+RallyPoint.prototype.GetPosition = function()
 {
-	this.pos = undefined;
+	return this.pos;
 };
 
-RallyPoint.prototype.GetPosition = function()
+// Extra data for the rally point, should have a command property and then helpful data for that command
+// See getActionInfo in gui/input.js
+RallyPoint.prototype.SetData = function(data)
 {
-	return this.pos;
+	this.data = data;
 };
 
+// Returns the data associated with this rally point.  Uses the data structure:
+// {"type": "walk/gather/garrison/...", "target": targetEntityId, "resourceType": "wood/food/metal/stone"}
+// where target and resourceType are optional, also target may be an invalid entity, check for existance.
+RallyPoint.prototype.GetData = function()
+{
+	return this.data;
+};
+
+RallyPoint.prototype.Unset = function()
+{
+	this.pos = undefined;
+	this.data = undefined;
+};
+
+
 Engine.RegisterComponentType(IID_RallyPoint, "RallyPoint", RallyPoint);
