Index: binaries/data/mods/public/simulation/components/ProductionQueue.js
===================================================================
--- binaries/data/mods/public/simulation/components/ProductionQueue.js	(revision 12189)
+++ binaries/data/mods/public/simulation/components/ProductionQueue.js	(working copy)
@@ -212,6 +212,13 @@
 			if (!cmpPlayer.TrySubtractResources(totalCosts))
 				return;
 
+			//Update player's entity limits to reflect queued units
+			var cmpEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits);
+			for (var i = 0; i < count; ++i)
+			{
+				cmpEntityLimits.AddUnitByTemplate(template);
+			}
+				
 			this.queue.push({
 				"id": this.nextID++,
 				"player": cmpPlayer.GetPlayerID(),
@@ -305,6 +312,10 @@
 		
 		var cmpPlayer = QueryPlayerIDInterface(item.player, IID_Player);
 
+		var cmpEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits);
+		var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
+		cmpEntityLimits.RemoveUnitByTemplate(cmpTempMan.GetTemplate(item.unitTemplate), true);
+		
 		// Refund the resource cost for this batch
 		var totalCosts = {};
 		for each (var r in ["food", "wood", "stone", "metal"])
@@ -414,7 +425,13 @@
 		//	so only create them once and use as needed
 		for (var i = 0; i < count; ++i)
 		{
-			this.entityCache.push(Engine.AddEntity(templateName));
+			var ent = Engine.AddEntity(templateName);
+			
+			//Remove the virtual unit from the unit count that represented this unit in the queue- it will be replaced by the actual unit being spawned
+			var cmpEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits);
+			cmpEntityLimits.RemoveUnit(ent, true);
+			
+			this.entityCache.push(ent);
 		}
 	}
 
Index: binaries/data/mods/public/simulation/components/EntityLimit.js
===================================================================
--- binaries/data/mods/public/simulation/components/EntityLimit.js	(revision 0)
+++ binaries/data/mods/public/simulation/components/EntityLimit.js	(working copy)
@@ -0,0 +1,104 @@
+function EntityLimit() {}
+
+EntityLimit.prototype.Schema = 
+	"<a:help>Specifies the number of this unit that can be build, and the categories of units that count toward the limit</a:help>" +
+	"<a:example>" +
+		"<ConcurrentLimit>" +
+			"<Limit>" +
+				"5" +
+			"</Limit>" +
+			"<Classes> Hero </Classes>" +
+		"</ConcurrentLimit>" +
+	"</a:example>" +
+	"<interleave>" +
+		"<optional>" +
+			"<element name='ConcurrentLimit' a:help='A limit on the number of this unit that can be built by a player at any one time.'>"+
+				"<interleave>" +
+					"<element name='Limit'>" +
+						"<data type='positiveInteger' />" +
+					"</element>" +
+					"<optional>" +
+						"<element name='Classes'>" +
+							"<attribute name='datatype'>" +
+								"<value>tokens</value>" +
+							"</attribute>" +
+							"<text/>" +
+						"</element>" +
+					"</optional>" +
+				"</interleave>" +
+			"</element>" +
+		"</optional>" +
+		"<optional>" +
+			"<element name='TotalLimit' a:help='A limit on the total number of this unit that can be built by a player during a game.'>" +
+				"<interleave>" +
+					"<element name='Limit'>" +
+						"<data type='positiveInteger' />" +
+					"</element>" +
+					"<optional>"+
+						"<element name='Classes' a:help='See Classes under ConcurrentLimit'>" +
+							"<attribute name='datatype'>" +
+								"<value>tokens</value>" +
+							"</attribute>" +
+							"<text />" +
+						"</element>" +
+					"</optional>" +
+				"</interleave>" +
+			"</element>" +
+		"</optional>" +
+	"</interleave>";
+
+EntityLimit.prototype.Init = function()
+{
+};
+
+/*
+ Return value of 0 indicates no limit
+ */
+EntityLimit.prototype.GetConcurrentLimit = function()
+{
+	if(this.template.ConcurrentLimit)
+	{
+		return this.template.ConcurrentLimit.Limit;
+	}
+	return 0;
+}
+
+/*
+ Empty list return value indicates no classes
+ */
+EntityLimit.prototype.GetConcurrentLimitClasses = function()
+{
+	if(this.template.ConcurrentLimit && this.template.ConcurrentLimit.Classes && "_string" in this.template.ConcurrentLimit.Classes)
+	{
+		var string = this.template.ConcurrentLimit.Classes._string;
+		return string.split(/\s+/);
+	}
+	return [];
+}
+
+/*
+ Return value of 0 indicates no limit
+ */
+EntityLimit.prototype.GetTotalLimit = function()
+{
+	if(this.template.TotalLimit)
+	{
+		return this.template.TotalLimit.Limit;
+	}
+	return 0;
+}
+
+/*
+ Empty list return value indicates no classes
+ */
+EntityLimit.prototype.GetTotalLimitClasses = function()
+{
+	if(this.template.TotalLimit && this.template.TotalLimit.Classes && "_string" in this.template.TotalLimit.Classes)
+	{
+		var string = this.template.TotalLimit.Classes._string;
+		return string.split(/\s+/);
+	}
+	return [];
+}
+
+Engine.RegisterComponentType(IID_EntityLimit, "EntityLimit", EntityLimit);
\ No newline at end of file
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js	(revision 12189)
+++ binaries/data/mods/public/simulation/components/GuiInterface.js	(working copy)
@@ -122,6 +122,13 @@
 	return ret;
 };
 
+GuiInterface.prototype.AllowedToBuild = function(player, template)
+{
+	var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
+	var cmpEntityLimits = Engine.QueryInterface(cmpPlayerMan.GetPlayerByID(player), IID_EntityLimits);
+	return cmpEntityLimits.AllowedToBuild(template);
+};
+
 GuiInterface.prototype.GetRenamedEntities = function(player)
 {
 	return this.renamedEntities;
@@ -385,6 +392,15 @@
 		if (template.Cost.PopulationBonus) ret.cost.populationBonus = GetTechModifiedProperty(techMods, template, "Cost/PopulationBonus", +template.Cost.PopulationBonus);
 	}
 	
+	if (template.EntityLimit)
+	{
+		ret.entityLimit = {};
+		if (template.EntityLimit.ConcurrentLimit)
+		{
+			ret.EntityLimit = template.EntityLimit;
+		}
+	}
+	
 	if (template.Footprint)
 	{
 		ret.footprint = {"height": template.Footprint.Height};
@@ -442,6 +458,10 @@
 		ret.icon = template.Identity.Icon;
 		ret.tooltip =  template.Identity.Tooltip;
 		ret.requiredTechnology = template.Identity.RequiredTechnology;
+		if(template.Identity.Classes)
+		{
+			ret.classes = template.Identity.Classes;
+		}
 	}
 
 	if (template.UnitMotion)
@@ -1571,6 +1585,7 @@
 	
 	"GetSimulationState": 1,
 	"GetExtendedSimulationState": 1,
+	"AllowedToBuild": 1,
 	"GetRenamedEntities": 1,
 	"ClearRenamedEntities": 1,
 	"GetEntityState": 1,
Index: binaries/data/mods/public/simulation/components/Identity.js
===================================================================
--- binaries/data/mods/public/simulation/components/Identity.js	(revision 12189)
+++ binaries/data/mods/public/simulation/components/Identity.js	(working copy)
@@ -87,6 +87,11 @@
 	return this.template.Civ;
 };
 
+Identity.prototype.GetGenericName = function()
+{
+	return this.template.GenericName;
+};
+
 Identity.prototype.GetRank = function()
 {
 	return (this.template.Rank || "");
Index: binaries/data/mods/public/simulation/components/EntityLimits.js
===================================================================
--- binaries/data/mods/public/simulation/components/EntityLimits.js	(revision 0)
+++ binaries/data/mods/public/simulation/components/EntityLimits.js	(working copy)
@@ -0,0 +1,317 @@
+function EntityLimits() {}
+
+EntityLimits.prototype.schema = 
+	"<a:help>Tracks limits on numbers of certain units that can be built</a:help>" +
+	"<a:component type='system'/><empty/>";
+	
+EntityLimits.prototype.Init = function()
+{
+	this.CurrentClassCounts = {};
+	this.TotalClassCounts = {};
+	this.CurrentEntityCounts = {};
+	this.TotalEntityCounts = {};
+};
+
+/*Add a newly created unit to the counts via its entity*/
+EntityLimits.prototype.AddUnit = function(entity)
+{
+	var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
+	if(cmpIdentity)
+	{
+		var classes = cmpIdentity.GetClassesList();
+		var entityName = cmpIdentity.GetGenericName();
+		this.Add(entityName, classes);
+	}
+};
+
+/*Remove a unit from the counts via its entity
+ removeTotals should be true to force the unit to be removed from Total count tables. 
+ Normally this is not desired- we want to keep track of all the units that have ever 
+ been built in those tables. Only set it to true if the unit is being replaced (as in 
+ the production queue). Do not include the parameter if you don't want to remove from totals.*/
+EntityLimits.prototype.RemoveUnit = function(entity, removeTotals)
+{
+	var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
+	if(cmpIdentity)
+	{
+		var classes = cmpIdentity.GetClassesList();
+		var entityName = cmpIdentity.GetGenericName();
+		this.Remove(entityName, classes);
+		if (removeTotals)
+		{
+			this.RemoveTotals(entityName, classes);
+		}
+	}
+};
+
+/*Adds a unit based on its template. Can either use the gui interface template, or the actual template*/
+EntityLimits.prototype.AddUnitByTemplate = function(template)
+{
+	var classes = [];
+	if (template.classes && template.classes._string)
+	{
+		classes = template.classes._string.split(/\s/);
+	}
+	else if (template.Identity && template.Identity.Classes && template.Identity.Classes._string)
+	{
+		classes = template.Identity.Classes._string.split(/\s/);
+	}
+	if (template.name)
+	{
+		var entityName = template.name.generic;
+	}
+	else if (template.Identity)
+	{
+		var entityName = template.Identity.GenericName;
+	}
+	this.Add(entityName, classes);
+};
+
+/*Removed a unit based on its template. Can either use the gui interface template, or the actual template
+ removeTotals- see the same parameter on RemoveUnit*/
+EntityLimits.prototype.RemoveUnitByTemplate = function(template, removeTotals)
+{
+	var classes = [];
+	if (template.classes && template.classes._string)
+	{
+		classes = template.classes._string.split(/\s/);
+	}
+	else if (template.Identity && template.Identity.Classes && template.Identity.Classes._string)
+	{
+		classes = template.Identity.Classes._string.split(/\s/);
+	}
+	if (template.name)
+	{
+		var entityName = template.name.generic;
+	}
+	else if (template.Identity)
+	{
+		var entityName = template.Identity.GenericName;
+	}
+	this.Remove(entityName, classes);
+	if (removeTotals)
+	{
+		this.RemoveTotals(entityName, classes);
+	}
+}
+
+/*Internal function for adding a unit. Do not call directly.*/
+EntityLimits.prototype.Add = function(entityName, classes)
+{
+	if (!(entityName in this.CurrentEntityCounts) || (isNaN(this.CurrentEntityCounts[entityName])))
+	{
+		this.CurrentEntityCounts[entityName] = 1;
+	}
+	else
+	{
+		++this.CurrentEntityCounts[entityName];
+	}
+	if (!(entityName in this.TotalEntityCounts) || (isNaN(this.TotalEntityCounts[entityName])))
+	{
+		this.TotalEntityCounts[entityName] = 1;
+	}
+	else
+	{
+		++this.TotalEntityCounts[entityName];
+	}
+	for (var i = 0; i<classes.length; ++i)
+	{
+		var entityClass = classes[i];
+		if (!(entityClass in this.CurrentClassCounts) || (isNaN(this.CurrentClassCounts[entityClass])))
+		{
+			this.CurrentClassCounts[entityClass] = 1;
+		}
+		else
+		{
+			++this.CurrentClassCounts[entityClass];
+		}
+		if (!(entityClass in this.TotalClassCounts) || (isNaN(this.TotalClassCounts[entityClass])))
+		{
+			this.TotalClassCounts[entityClass] = 1;
+		}
+		else
+		{
+			++this.TotalClassCounts[entityClass];
+		}
+	}
+};
+
+/*Internal function for removing a unit. Do not call directly.*/
+EntityLimits.prototype.Remove = function(entityName, classes)
+{
+	if (!(entityName in this.CurrentEntityCounts) || (isNaN(this.CurrentEntityCounts[entityName])))
+	{
+		this.CurrentEntityCounts[entityName] = 0;
+	}
+	else
+	{
+		--this.CurrentEntityCounts[entityName];
+	}
+	for (var i = 0; i<classes.length; ++i)
+	{
+		var entityClass = classes[i];
+		if (!(entityClass in this.CurrentClassCounts) || (isNaN(this.CurrentClassCounts[entityClass])))
+		{
+			this.CurrentClassCounts[entityClass] = 0;
+		}
+		else
+		{
+			--this.CurrentClassCounts[entityClass];
+		}
+	}
+};
+
+/*Internal function for removing a unit from the total counts. Do not call directly.*/
+EntityLimits.prototype.RemoveTotals= function(entityName, classes)
+{
+	if (!(entityName in this.TotalEntityCounts) || (isNaN(this.TotalEntityCounts[entityName])))
+	{
+		this.TotalEntityCounts[entityName] = 0;
+	}
+	else
+	{
+		--this.TotalEntityCounts[entityName];
+	}
+	for (var i = 0; i<classes.length; ++i)
+	{
+		var entityClass = classes[i];
+		if (!(entityClass in this.TotalClassCounts) || (isNaN(this.TotalClassCounts[entityClass])))
+		{
+			this.TotalClassCounts[entityClass] = 0;
+		}
+		else
+		{
+			--this.TotalClassCounts[entityClass];
+		}
+	}
+};
+
+EntityLimits.prototype.GetCurrentEntityCount = function(entityName)
+{
+	if (entityName in this.CurrentEntityCounts)
+	{
+		return this.CurrentEntityCounts[entityName];
+	}
+	return 0;
+};
+
+EntityLimits.prototype.GetCurrentClassCount = function(className)
+{
+	if (className in this.CurrentClassCounts)
+	{
+		return this.CurrentClassCounts[className];
+	}
+	return 0;
+};
+
+EntityLimits.prototype.GetTotalEntityCount = function(entityName)
+{
+	if (entityName in this.TotalEntityCounts)
+	{
+		return this.TotalEntityCounts[entityName];
+	}
+	return 0;
+};
+
+EntityLimits.prototype.GetTotalClassCount = function(className)
+{
+	if (className in this.TotalClassCounts)
+	{
+		return this.TotalClassCounts[className];
+	}
+	return 0;
+};
+
+/*Checks if the unit can be built, based on a gui-interface template. It would be relatively trivial to change this to work on actual templates too.
+ Will return false if a unit cannot be built because its limits are currently exceeded.*/
+EntityLimits.prototype.AllowedToBuild = function(template)
+{
+	if (template.EntityLimit){
+		/*Total limits are placed first because if both total and concurrent limits are present, total limits are more likely to be exceeded*/
+		var entityName = template.name.generic;
+		if (template.EntityLimit.TotalLimit)
+		{
+			var totalLimit = template.EntityLimit.TotalLimit.Limit;
+			if (this.GetTotalEntityCount(entityName) >= totalLimit)
+			{
+				return false;
+			}
+			if (template.EntityLimit.TotalLimit.Classes && "_string" in template.EntityLimit.TotalLimit.Classes)
+			{
+				var limitClasses = template.EntityLimit.TotalLimit.Classes._string.split(/\s/);
+				var entityClasses = [];
+				if (template.classes && "_string" in template.classes)
+				{
+					entityClasses = template.classes._string.split(/\s/);
+				}
+				var intersections = 0;
+				var curNumber = this.GetTotalEntityCount(entityName);
+				for (var i =0; i<limitClasses.length; ++i)
+				{
+					curNumber = curNumber+this.GetTotalClassCount(limitClasses[i]);
+					if (entityClasses.indexOf(limitClasses[i]) != -1)
+					{
+						++intersections;
+					}
+				}
+				curNumber = curNumber - intersections*this.GetTotalEntityCount(entityName);
+				if (curNumber >= totalLimit)
+				{
+					return false;
+				}
+			}
+		}
+		if (template.EntityLimit.ConcurrentLimit)
+		{
+			var concurrentLimit = template.EntityLimit.ConcurrentLimit.Limit;
+			var entityName = template.name.generic;
+			if (this.GetCurrentEntityCount(entityName) >= concurrentLimit)
+			{
+				return false;
+			}
+			if (template.EntityLimit.ConcurrentLimit.Classes && "_string" in template.EntityLimit.ConcurrentLimit.Classes)
+			{
+				var limitClasses = template.EntityLimit.ConcurrentLimit.Classes._string.split(/\s/);
+				var entityClasses = [];
+				if (template.classes && "_string" in template.classes)
+				{
+					entityClasses = template.classes._string.split(/\s/);
+				}
+				var intersections = 0;
+				var curNumber = this.GetCurrentEntityCount(entityName);
+				for (var i =0; i<limitClasses.length; ++i)
+				{
+					curNumber = curNumber+this.GetCurrentClassCount(limitClasses[i]);
+					if (entityClasses.indexOf(limitClasses[i]) != -1)
+					{
+						++intersections;
+					}
+				}
+				curNumber = curNumber - intersections*this.GetCurrentEntityCount(entityName);
+				if (curNumber >= concurrentLimit)
+				{
+					return false;
+				}
+			}
+		}
+	}
+	return true;
+};
+
+/*
+ Does not prevent ownership change, even if the change would exceed limits
+ */
+EntityLimits.prototype.OnGlobalOwnershipChanged = function(msg)
+{
+	var playerID = Engine.QueryInterface(this.entity, IID_Player).GetPlayerID();
+	if (msg.from == playerID)
+	{
+		this.RemoveUnit(msg.entity);
+	}
+	else if (msg.to == playerID)
+	{
+		this.AddUnit(msg.entity);
+	}
+};
+
+Engine.RegisterComponentType(IID_EntityLimits, "EntityLimits", EntityLimits);
\ No newline at end of file
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_swordsman.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_swordsman.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_swordsman.xml	(working copy)
@@ -48,6 +48,12 @@
 	  </Bonuses>
     </Charge>
   </Attack>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Identity>
     <Classes datatype="tokens">Melee Sword</Classes>
     <GenericName>Hero Swordsman</GenericName>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_infantry.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_infantry.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_infantry.xml	(working copy)
@@ -27,6 +27,12 @@
       <metal>200</metal>
     </Resources>
   </Cost>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Footprint>
     <Circle radius="2.0"/>
     <Height>2.5</Height>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_archer.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_archer.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_archer.xml	(working copy)
@@ -44,6 +44,12 @@
     <Max>500</Max>
     <RegenRate>0.5</RegenRate>
   </Health>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes>Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Identity>
     <Classes datatype="tokens">Hero Bow -Javelin</Classes>
     <GenericName>Hero Cavalry Archer</GenericName>
Index: binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml	(working copy)
@@ -32,6 +32,13 @@
       <stone>100</stone>
     </Resources>
   </Cost>
+  <EntityLimit>
+	  <ConcurrentLimit>
+		  <Limit>
+			  25
+		  </Limit>
+	  </ConcurrentLimit>
+  </EntityLimit>
   <Footprint>
     <Square width="10.0" depth="10.0"/>
     <Height>15.0</Height>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_javelinist.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_javelinist.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_javelinist.xml	(working copy)
@@ -28,6 +28,12 @@
       <metal>75</metal>
     </Resources>
   </Cost>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes>Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Footprint>
     <Circle radius="3.0"/>
     <Height>3.0</Height>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry.xml	(working copy)
@@ -29,6 +29,12 @@
       <metal>250</metal>
     </Resources>
   </Cost>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero </Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Footprint>
     <Circle radius="3.0"/>
     <Height>3.0</Height>
Index: binaries/data/mods/public/simulation/templates/special/player.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/special/player.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/special/player.xml	(working copy)
@@ -8,6 +8,7 @@
       <Fortress>10</Fortress>
     </Limits>
   </BuildLimits>
+  <EntityLimits />
   <Player/>
   <StatisticsTracker/>
   <TechnologyManager/>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_javelinist.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_javelinist.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_javelinist.xml	(working copy)
@@ -34,6 +34,12 @@
       <wood>200</wood>
     </Resources>
   </Cost>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Footprint>
     <Circle radius="2.0"/>
     <Height>2.5</Height>
Index: binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml	(working copy)
@@ -33,6 +33,11 @@
       <stone>650</stone>
     </Resources>
   </Cost>
+  <EntityLimit>
+	  <ConcurrentLimit>
+		  <Limit>10</Limit>
+	  </ConcurrentLimit>
+  </EntityLimit>
   <Footprint>
     <Square width="30.0" depth="30.0"/>
     <Height>8.0</Height>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_spearman.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_spearman.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_spearman.xml	(working copy)
@@ -23,6 +23,12 @@
 	  </Bonuses>
     </Charge>
   </Attack>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Identity>
     <Classes datatype="tokens">Melee Spear</Classes>
     <GenericName>Hero Spearman</GenericName>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero.xml	(working copy)
@@ -29,6 +29,12 @@
       <metal>250</metal>
     </Resources>
   </Cost>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Health>
     <Max>400</Max>
     <RegenRate>0.5</RegenRate>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_spearman.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_spearman.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_spearman.xml	(working copy)
@@ -61,6 +61,12 @@
       <PreferredClasses datatype="tokens">Organic Siege</PreferredClasses>
     </Charge>
   </Attack>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes>Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Identity>
     <Classes datatype="tokens">Melee Spear</Classes>
     <GenericName>Hero Cavalry Spearman</GenericName>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_pikeman.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_pikeman.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_pikeman.xml	(working copy)
@@ -30,6 +30,12 @@
 	  </Bonuses>
     </Charge>
   </Attack>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Identity>
     <Classes datatype="tokens">Melee Spear</Classes>
     <GenericName>Hero Pikeman</GenericName>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_ranged.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_ranged.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_ranged.xml	(working copy)
@@ -24,6 +24,12 @@
       <wood>500</wood>
     </Resources>
   </Cost>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Health>
     <Max>400</Max>
     <RegenRate>0.2</RegenRate>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_archer.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_archer.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_archer.xml	(working copy)
@@ -28,6 +28,12 @@
       <wood>200</wood>
     </Resources>
   </Cost>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes datatype="tokens">Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Footprint>
     <Circle radius="2.0"/>
     <Height>2.5</Height>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_swordsman.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_swordsman.xml	(revision 12189)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_swordsman.xml	(working copy)
@@ -48,6 +48,12 @@
       <PreferredClasses datatype="tokens">Organic Siege</PreferredClasses>
     </Charge>
   </Attack>
+	<EntityLimit>
+		<ConcurrentLimit>
+			<Limit>1</Limit>
+			<Classes>Hero</Classes>
+		</ConcurrentLimit>
+	</EntityLimit>
   <Identity>
     <Classes datatype="tokens">Sword</Classes>
     <GenericName>Hero Cavalry Swordsman</GenericName>
Index: binaries/data/mods/public/gui/session/unit_commands.js
===================================================================
--- binaries/data/mods/public/gui/session/unit_commands.js	(revision 12189)
+++ binaries/data/mods/public/gui/session/unit_commands.js	(working copy)
@@ -538,7 +539,17 @@
 				button.tooltip += "\nRequires " + techName;
 				grayscale = "grayscale:";
 			}
-			
+			if (guiName == TRAINING && template.EntityLimit)
+			{
+				if (!Engine.GuiInterfaceCall("AllowedToBuild", template))
+				{
+					grayscale = "grayscale:";
+					button.enabled = false;
+					button.tooltip += "\nLimit Reached: No more can be produced";
+				}
+			}
 			if (guiName == RESEARCH && !Engine.GuiInterfaceCall("CheckTechnologyRequirements", entType))
 			{
 				button.enabled = false;
