Index: binaries/data/mods/public/simulation/components/ResourceGatherer.js
===================================================================
--- binaries/data/mods/public/simulation/components/ResourceGatherer.js	(revision 11673)
+++ binaries/data/mods/public/simulation/components/ResourceGatherer.js	(working copy)
@@ -187,13 +187,11 @@
 /**
  * Gather from the target entity. This should only be called after a successful range check,
  * and if the target has a compatible ResourceSupply.
- * It should be called at a rate of once per second.
  */
 ResourceGatherer.prototype.PerformGather = function(target)
 {
-	var rate = this.GetTargetGatherRate(target);
-	if (!rate)
-		return { "exhausted": true };
+    // PerformGather call interval will be determined by gather rate, so always gather 1 amount here.
+    var gatherAmount = 1;
 
 	var cmpResourceSupply = Engine.QueryInterface(target, IID_ResourceSupply);
 	var type = cmpResourceSupply.GetType();
@@ -205,7 +203,7 @@
 	// Find the maximum so we won't exceed our capacity
 	var maxGathered = this.GetCapacities()[type.generic] - this.carrying[type.generic];
 
-	var status = cmpResourceSupply.TakeResources(Math.min(rate, maxGathered));
+    var status = cmpResourceSupply.TakeResources(Math.min(gatherAmount, maxGathered));
 
 	this.carrying[type.generic] += status.amount;
 
@@ -244,12 +242,14 @@
 
 	var type = cmpResourceSupply.GetType();
 
+    var rates = this.GetGatherRates();
+
 	var rate;
-	if (type.specific && this.GetGatherRates()[type.generic+"."+type.specific])
-		rate = this.GetGatherRates()[type.generic+"."+type.specific];
+	if (type.specific && rates[type.generic+"."+type.specific])
+		rate = rates[type.generic+"."+type.specific];
 	else
-		rate = this.GetGatherRates()[type.generic];
-
+		rate = rates[type.generic];
+    
 	return (rate || 0);
 };
 
Index: binaries/data/mods/public/simulation/components/UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/UnitAI.js	(revision 11673)
+++ binaries/data/mods/public/simulation/components/UnitAI.js	(working copy)
@@ -944,18 +944,38 @@
 
 			"GATHERING": {
 				"enter": function() {
-					this.StartTimer(1000, 1000);
+					var target = this.order.data.target;
+					
+                    // Calculate timing based on gather rates
+                    // This allows the gather rate to control how often we gather, instead of how much.
+					var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);
+                    var rate = cmpResourceGatherer.GetTargetGatherRate(target);
 
-					// We want to start the gather animation as soon as possible,
-					// but only if we're actually at the target and it's still alive
-					// (else it'll look like we're chopping empty air).
-					// (If it's not alive, the Timer handler will deal with sending us
-					// off to a different target.)
-					if (this.CheckTargetRange(this.order.data.target, IID_ResourceGatherer))
-					{
-						var typename = "gather_" + this.order.data.type.specific;
-						this.SelectAnimation(typename, false, 1.0, typename);
-					}
+                    if (rate)
+                    {
+                        // Scale timing interval based on rate, and start timer
+                        var offset = 0;
+                        var repeat = 1000 / rate;  
+                        this.StartTimer(offset, repeat);
+
+					    // We want to start the gather animation as soon as possible,
+					    // but only if we're actually at the target and it's still alive
+					    // (else it'll look like we're chopping empty air).
+					    // (If it's not alive, the Timer handler will deal with sending us
+					    // off to a different target.)
+					    if (this.CheckTargetRange(target, IID_ResourceGatherer))
+					    {
+						    var typename = "gather_" + this.order.data.type.specific;
+
+                            // TODO: Update animation speed based on gather rate?  (1000 / repeat) yields exaggerated results.
+						    this.SelectAnimation(typename, false, 1.0, typename);
+					    }
+                    }
+                    else
+                    {
+						// No rate, give up on gathering
+						this.FinishOrder();
+                    }
 				},
 
 				"leave": function() {
@@ -1970,11 +1990,6 @@
 	{
 		this.timer = undefined;
 	}
-	else
-	{
-		var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
-		this.timer = cmpTimer.SetTimeout(this.entity, IID_UnitAI, "TimerHandler", data.timerRepeat - lateness, data);
-	}
 
 	UnitFsm.ProcessMessage(this, {"type": "Timer", "data": data, "lateness": lateness});
 };
@@ -1992,7 +2007,10 @@
 	var data = { "timerRepeat": repeat };
 
 	var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
-	this.timer = cmpTimer.SetTimeout(this.entity, IID_UnitAI, "TimerHandler", offset, data);
+    if (repeat === undefined)
+    	this.timer = cmpTimer.SetTimeout(this.entity, IID_UnitAI, "TimerHandler", offset, data);
+    else
+        this.timer = cmpTimer.SetInterval(this.entity, IID_UnitAI, "TimerHandler", offset, repeat, data);
 };
 
 /**
