Index: binaries/data/mods/public/gui/session/selection_details.js
===================================================================
--- binaries/data/mods/public/gui/session/selection_details.js	(revision 17087)
+++ binaries/data/mods/public/gui/session/selection_details.js	(working copy)
@@ -111,7 +111,23 @@
 		});
 	}
 
-	// TODO: Stamina
+    // Stamina 
+    let player = Engine.GetPlayerID(); 
+    if (entState.stamina && (entState.player == player || g_DevSettings.controlAll)) 
+    { 
+        let unitStaminaBar = Engine.GetGUIObjectByName("staminaBar"); 
+        let staminaSize = unitStaminaBar.size; 
+        staminaSize.rright = 100*Math.max(0, Math.min(1, entState.stamina.stamina / entState.stamina.maxStamina)); 
+        unitStaminaBar.size = staminaSize; 
+ 
+        Engine.GetGUIObjectByName("staminaStats").caption = sprintf(translate("%(stamina)s / %(maxStamina)s"), { 
+            stamina: Math.ceil(entState.stamina.stamina), 
+            maxStamina: entState.stamina.maxStamina 
+        }); 
+        Engine.GetGUIObjectByName("staminaSection").hidden = false; 
+    } 
+    else 
+        Engine.GetGUIObjectByName("staminaSection").hidden = true; 
 
 	// Experience
 	Engine.GetGUIObjectByName("experience").hidden = !entState.promotion;
@@ -295,6 +311,8 @@
 	var maxCapturePoints = 0;
 	var capturePoints = (new Array(9)).fill(0);
 	var playerID = 0;
+    let averageStamina = 0; 
+    let maxStamina = 0; 
 
 	for (let i = 0; i < selection.length; i++)
 	{
@@ -312,6 +330,11 @@
 			maxCapturePoints += entState.maxCapturePoints;
 			capturePoints = entState.capturePoints.map(function(v, i) { return v + capturePoints[i]; });
 		}
+		if (entState.stamina) 
+		{ 
+			averageStamina += entState.stamina.stamina; 
+			maxStamina += entState.stamina.maxStamina; 
+		}
 	}
 
 	Engine.GetGUIObjectByName("healthMultiple").hidden = averageHealth <= 0;
@@ -357,8 +380,23 @@
 		Engine.GetGUIObjectByName("captureMultiple").tooltip = capturePointsTooltip;
 	}
 
-	// TODO: Stamina
-	// Engine.GetGUIObjectByName("staminaBarMultiple");
+    if (averageStamina > 0) 
+    { 
+        let unitStaminaBar = Engine.GetGUIObjectByName("staminaBarMultiple"); 
+        let staminaSize = unitStaminaBar.size;   
+        staminaSize.rtop = 100-100*Math.max(0, Math.min(1, averageStamina / maxStamina)); 
+        unitStaminaBar.size = staminaSize; 
+ 
+        let staminaLabel = "[font=\"sans-bold-13\"]" + translate("Stamina:") + "[/font]" 
+        let stamina = sprintf(translate("%(label)s %(current)s / %(max)s"), { label: staminaLabel, current: averageStamina, max: maxStamina }); 
+        let staminaMultiple = Engine.GetGUIObjectByName("staminaMultiple"); 
+        staminaMultiple.tooltip = stamina; 
+        staminaMultiple.hidden = false; 
+    } 
+    else 
+    { 
+        Engine.GetGUIObjectByName("staminaMultiple").hidden = true; 
+    } 
 
 	Engine.GetGUIObjectByName("numberOfUnits").caption = selection.length;
 
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js	(revision 17087)
+++ binaries/data/mods/public/simulation/components/GuiInterface.js	(working copy)
@@ -238,6 +238,7 @@
 		"rallyPoint": null,
 		"resourceCarrying": null,
 		"rotation": null,
+        "stamina": null, 
 		"trader": null,
 		"unitAI": null,
 		"visibility": null,
@@ -410,7 +411,16 @@
 			"hasRaisedAlert": cmpAlertRaiser.HasRaisedAlert(),
 		};
 	}
-
+    var cmpStamina = Engine.QueryInterface(ent, IID_Stamina); 
+	
+    if (cmpStamina) 
+    { 
+        ret.stamina = { 
+            "stamina": cmpStamina.GetStamina(), 
+            "maxStamina": cmpStamina.GetMaxStamina(), 
+        }; 
+    }
+	
 	var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
 	ret.visibility = cmpRangeManager.GetLosVisibility(ent, player);
 
Index: binaries/data/mods/public/simulation/components/interfaces/Stamina.js
===================================================================
--- binaries/data/mods/public/simulation/components/interfaces/Stamina.js	(revision 17087)
+++ binaries/data/mods/public/simulation/components/interfaces/Stamina.js	(working copy)
@@ -1 +1,6 @@
 Engine.RegisterInterface("Stamina");
+
+
+// Message of the form { "from": 100, "to", 90 }, 
+// sent whenever stamina changes. 
+Engine.RegisterMessageType("StaminaChanged"); 
\ No newline at end of file
Index: binaries/data/mods/public/simulation/components/Stamina.js
===================================================================
--- binaries/data/mods/public/simulation/components/Stamina.js	(revision 17087)
+++ binaries/data/mods/public/simulation/components/Stamina.js	(working copy)
@@ -1,12 +1,99 @@
 function Stamina() {}
 
 Stamina.prototype.Schema =
-	"<element name='Max' a:help='Maximum stamina (msecs of running)'>" +
-		"<data type='positiveInteger'/>" +
-	"</element>";
+    "<element name='Max' a:help='Maximum stamina'>" + 
+        "<ref name='nonNegativeDecimal'/>" + 
+    "</element>" + 
+    "<element name='RegenRate' a:help='Stamina regeneration rate per second.'>" + 
+        "<ref name='nonNegativeDecimal'/>" + 
+    "</element>" + 
+    "<optional>" + 
+        "<element name='Initial' a:help='Initial stamina. Default if unspecified is equal to 0'>" + 
+            "<ref name='nonNegativeDecimal'/>" + 
+        "</element>" + 
+    "</optional>";
 
-/*
- * TODO: this all needs to be designed and implemented
- */
-
-Engine.RegisterComponentType(IID_Stamina, "Stamina", Stamina);
+Stamina.prototype.Init = function() 
+{ 
+    this.maxStamina = +this.template.Max; 
+    this.regenRate = +this.template.RegenRate; 
+ 
+    this.stamina = +(this.template.Initial || 0); 
+ 
+    this.CheckRegenTimer(); 
+}; 
+ 
+Stamina.prototype.GetStamina = function() 
+{ 
+    return this.stamina; 
+}; 
+ 
+Stamina.prototype.GetMaxStamina = function() 
+{ 
+    return this.maxStamina; 
+}; 
+ 
+Stamina.prototype.CheckRegenTimer = function() 
+{ 
+    if ((this.stamina == this.maxStamina && this.regenRate > 0) || (this.stamina == 0 && this.regenRate < 0)) 
+    { 
+        // We don't need to regenerate stamina 
+        if (this.regenTimer) 
+        { 
+            var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 
+            cmpTimer.CancelTimer(this.regenTimer); 
+            this.regenTimer = undefined; 
+        } 
+        return; 
+    } 
+ 
+    // We need to regenerate, enable a timer if one doesn't exist 
+    if (this.regenTimer) 
+        return; 
+ 
+    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 
+    this.regenTimer = cmpTimer.SetInterval(this.entity, IID_Stamina, "UpdateStamina", 1000, 1000, null); 
+}; 
+ 
+Stamina.prototype.ToggleStaminaConsumer = function(enabled, costRate) 
+{ 
+    if (costRate >= 0) 
+    { 
+        warn("Activated stamina consumer with wrong cost"); 
+        return; 
+    } 
+ 
+    if (enabled) 
+    { 
+        if (this.regenRate > 0) 
+            this.regenRate = 0; 
+        this.regenRate += costRate; 
+    } 
+    else 
+    { 
+        this.regenRate -= costRate; 
+        if (this.regenRate >= 0) 
+            this.regenRate = +this.template.RegenRate; 
+    } 
+    this.CheckRegenTimer(); 
+}; 
+ 
+Stamina.prototype.UpdateStamina = function() 
+{ 
+    if (this.regenRate == 0) 
+        return; 
+ 
+    let oldStamina = this.stamina; 
+    this.stamina += this.regenRate; 
+    if (this.stamina > this.maxStamina) 
+        this.stamina = this.maxStamina; 
+ 
+    Engine.PostMessage(this.entity, MT_StaminaChanged, { "from": oldStamina, "to": this.stamina }); 
+}; 
+ 
+Stamina.prototype.OnStaminaChanged = function(msg) 
+{ 
+    this.CheckRegenTimer(); 
+}; 
+ 
+Engine.RegisterComponentType(IID_Stamina, "Stamina", Stamina); 
Index: binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml	(revision 17087)
+++ binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml	(working copy)
@@ -91,6 +91,8 @@
   </Sound>
   <Stamina>
     <Max>2000</Max>
+    <RegenRate>20</RegenRate> 
+    <Initial>1000</Initial> 
   </Stamina>
   <StatusBars>
     <HeightOffset>6.5</HeightOffset>
Index: binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml	(revision 17087)
+++ binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml	(working copy)
@@ -55,7 +55,9 @@
 	</SoundGroups>
   </Sound>
   <Stamina>
-    <Max>2500</Max>
+    <Max>2500</Max>4
+    <RegenRate>20</RegenRate> 
+    <Initial>1000</Initial> 
   </Stamina>
   <StatusBars>
     <HeightOffset>6.5</HeightOffset>
Index: binaries/data/mods/public/simulation/templates/template_unit_champion_elephant.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_champion_elephant.xml	(revision 17087)
+++ binaries/data/mods/public/simulation/templates/template_unit_champion_elephant.xml	(working copy)
@@ -55,6 +55,8 @@
   </Sound>
   <Stamina>
     <Max>2500</Max>
+    <RegenRate>20</RegenRate> 
+    <Initial>1000</Initial> 
   </Stamina>
   <StatusBars>
     <HeightOffset>6.5</HeightOffset>
Index: binaries/data/mods/public/simulation/templates/template_unit_champion_infantry.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_champion_infantry.xml	(revision 17087)
+++ binaries/data/mods/public/simulation/templates/template_unit_champion_infantry.xml	(working copy)
@@ -46,6 +46,7 @@
   </Sound>
   <Stamina>
     <Max>1500</Max>
+    <RegenRate>20</RegenRate> 
   </Stamina>
   <UnitMotion>
     <WalkSpeed>8.5</WalkSpeed>
Index: binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry.xml	(revision 17087)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry.xml	(working copy)
@@ -47,6 +47,8 @@
   </Sound>
   <Stamina>
     <Max>2500</Max>
+    <RegenRate>20</RegenRate> 
+    <Initial>1000</Initial> 
   </Stamina>
   <StatusBars>
     <HeightOffset>6.5</HeightOffset>
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 17087)
+++ binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_pikeman.xml	(working copy)
@@ -33,9 +33,6 @@
     <wood>10</wood>
     <metal>10</metal>
   </Loot>
-  <Stamina>
-    <Max>1200</Max>
-  </Stamina>
   <UnitMotion>
     <WalkSpeed>8.5</WalkSpeed>
     <Run>
Index: binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_infantry.xml	(revision 17087)
+++ binaries/data/mods/public/simulation/templates/template_unit_infantry.xml	(working copy)
@@ -120,6 +120,7 @@
   </Sound>
   <Stamina>
     <Max>1000</Max>
+    <RegenRate>15</RegenRate>
   </Stamina>
   <UnitMotion>
     <WalkSpeed>9</WalkSpeed>
Index: binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml	(revision 17087)
+++ binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml	(working copy)
@@ -95,6 +95,7 @@
   </Sound>
   <Stamina>
     <Max>500</Max>
+    <RegenRate>5</RegenRate> 
   </Stamina>
   <UnitAI>
     <AlertReactiveLevel>1</AlertReactiveLevel>
