Index: binaries/data/mods/public/art/textures/cursors/action-heal-disabled.txt
===================================================================
--- binaries/data/mods/public/art/textures/cursors/action-heal-disabled.txt	(revision 0)
+++ binaries/data/mods/public/art/textures/cursors/action-heal-disabled.txt	(working copy)
@@ -0,0 +1 @@
+1 1
Index: binaries/data/mods/public/art/textures/cursors/action-heal.txt
===================================================================
--- binaries/data/mods/public/art/textures/cursors/action-heal.txt	(revision 0)
+++ binaries/data/mods/public/art/textures/cursors/action-heal.txt	(working copy)
@@ -0,0 +1 @@
+1 1
Index: binaries/data/mods/public/gui/session/input.js
===================================================================
--- binaries/data/mods/public/gui/session/input.js	(revision 11284)
+++ binaries/data/mods/public/gui/session/input.js	(working copy)
@@ -15,6 +15,7 @@
 const ACTION_NONE = 0;
 const ACTION_GARRISON = 1;
 const ACTION_REPAIR = 2;
+const ACTION_HEAL = 3;
 var preSelectedAction = ACTION_NONE;
 
 var INPUT_NORMAL = 0;
@@ -297,6 +298,29 @@
 				return {"possible": true, "tooltip": tooltip};
 			}
 			break;
+		case "heal":
+			// The check if the target is unhealable is done by targetState.needsHeal
+			if (entState.Ability && isUnit(targetState) && targetState.needsHeal && (playerOwned || allyOwned))
+			{
+				var unhealableClasses = entState.Ability.Healer.unhealableClasses;
+				for each (var unitClass in targetState.identity.classes)
+				{
+					if (unhealableClasses.indexOf(unitClass) != -1)
+					{
+						return {"possible": false};
+					}
+				}
+				
+				var healableClasses = entState.Ability.Healer.healableClasses;
+				for each (var unitClass in targetState.identity.classes)
+				{
+					if (healableClasses.indexOf(unitClass) != -1)
+					{
+						return {"possible": true};
+					}
+				}
+			}
+			break;
 		case "gather":
 			if (targetState.resourceSupply && (playerOwned || gaiaOwned))
 			{
@@ -393,6 +417,12 @@
 			else
 				return {"type": "none", "cursor": "action-repair-disabled", "target": undefined};
 			break;
+		case ACTION_HEAL:
+			if (getActionInfo("heal", target).possible)
+				return {"type": "heal", "cursor": "action-heal", "target": target};
+			else
+				return {"type": "none", "cursor": "action-heal-disabled", "target": undefined};
+			break;
 		}
 	}
 	else if (Engine.HotkeyIsPressed("session.garrison"))
@@ -417,6 +447,8 @@
 			return {"type": "build", "cursor": "action-repair", "target": target};
 		else if ((actionInfo = getActionInfo("set-rallypoint", target)).possible)
 			return {"type": "set-rallypoint", "cursor": actionInfo.cursor, "data": actionInfo.data, "position": actionInfo.position};
+		else if (getActionInfo("heal", target).possible)
+			return {"type": "heal", "cursor": "action-heal", "target": target};
 		else if (getActionInfo("attack", target).possible)
 			return {"type": "attack", "cursor": "action-attack", "target": target};
 		else if (getActionInfo("unset-rallypoint", target).possible)
@@ -1037,6 +1069,17 @@
 		Engine.GuiInterfaceCall("PlaySound", { "name": "order_attack", "entity": selection[0] });
 		return true;
 
+	case "promote":
+		Engine.PostNetworkCommand({"type": "promote", "entities": selection, "target": action.target, "queued": queued});
+		// TODO:Play a sound? 
+		return true;
+
+	case "heal":
+		Engine.PostNetworkCommand({"type": "heal", "entities": selection, "target": action.target, "queued": queued});
+		// TODO: Play a sound?
+//		Engine.GuiInterfaceCall("PlaySound", { "name": "order_heal", "entity": selection[0] });
+		return true;
+
 	case "build": // (same command as repair)
 	case "repair":
 		Engine.PostNetworkCommand({"type": "repair", "entities": selection, "target": action.target, "autocontinue": true, "queued": queued});
@@ -1258,6 +1301,13 @@
 				inputState = INPUT_PRESELECTEDACTION;
 				preSelectedAction = ACTION_REPAIR;
 				break;
+			case "heal":
+				inputState = INPUT_PRESELECTEDACTION;
+				preSelectedAction = ACTION_HEAL;
+				break;
+			case "promote":
+				doAction({ "type": "promote"})
+				break;
 			case "unload-all":
 				unloadAll(entity);
 				break;
Index: binaries/data/mods/public/gui/session/session.xml
===================================================================
--- binaries/data/mods/public/gui/session/session.xml	(revision 11284)
+++ binaries/data/mods/public/gui/session/session.xml	(working copy)
@@ -729,6 +729,18 @@
 					</object>
 				</object>
 
+				<object name="unitAbilityPanel"
+					size="14 12 100% 100%"
+				>
+					<object size="0 0 100% 100%">
+						<repeat count="24">
+							<object name="unitAbilityButton[n]" hidden="true" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottom">
+								<object name="unitAbilityIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
+							</object>
+						</repeat>
+					</object>
+				</object>
+
 				<object name="unitResearchPanel"
 					style="TranslucentPanelThinBorder"
 					size="0 100%-56 100% 100%"
Index: binaries/data/mods/public/gui/session/unit_commands.js
===================================================================
--- binaries/data/mods/public/gui/session/unit_commands.js	(revision 11284)
+++ binaries/data/mods/public/gui/session/unit_commands.js	(working copy)
@@ -5,6 +5,7 @@
 const FORMATION = "Formation";
 const TRAINING = "Training";
 const CONSTRUCTION = "Construction";
+const ABILITY = "Ability";
 const COMMAND = "Command";
 const STANCE = "Stance";
 
@@ -22,11 +23,11 @@
 const BARTER_RESOURCES = ["food", "wood", "stone", "metal"];
 const BARTER_ACTIONS = ["Sell", "Buy"];
 
-// The number of currently visible buttons (used to optimise showing/hiding)
-var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Barter": 0, "Trading": 0, "Construction": 0, "Command": 0, "Stance": 0};
+// The number of currently visible buttons (used to optimise showing/hiding)
+var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Barter": 0, "Trading": 0, "Construction": 0, "Ability": 0, "Command": 0, "Stance": 0};
 
 // Unit panels are panels with row(s) of buttons
-var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", "Barter", "Trading", "Construction", "Research", "Stance", "Command"];
+var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", "Barter", "Trading", "Construction", "Ability", "Research", "Stance", "Command"];
 
 // Indexes of resources to sell and buy on barter panel
 var g_barterSell = 0;
@@ -178,6 +179,11 @@
 				numberOfItems =  24;
 			break;
 
+		case ABILITY:
+			if (numberOfItems > 24)
+				numberOfItems = 24;
+			break;
+
 		case COMMAND:
 			if (numberOfItems > 6)
 				numberOfItems = 6;
@@ -194,7 +200,7 @@
 		var item = items[i];
 		var entType = ((guiName == "Queue")? item.template : item);
 		var template;
-		if (guiName != "Formation" && guiName != "Command" && guiName != "Stance")
+		if (guiName != "Formation" && guiName != "Command" && guiName != "Stance" && guiName != "Ability")
 		{
 			template = GetTemplateData(entType);
 			if (!template)
@@ -273,6 +279,23 @@
 
 				break;
 
+			case ABILITY:
+				// TODO read tooltips from some file or template based on 'item'
+				var tooltip;
+				switch(item)
+				{
+					case "heal":
+						tooltip = "Heal units";
+						break;
+					case "promote":
+						tooltip = "Promote this unit";
+						break;
+					default:
+						tooltip = "No tooltip defined";
+					break;
+				}
+				break;
+
 			case COMMAND:
 				// here, "item" is an object with properties .name (command name), .tooltip and .icon (relative to session/icons/single)
 				if (item.name == "unload-all")
@@ -342,6 +365,10 @@
 			icon.sprite = "stretched:session/icons/single/" + item.icon;
 
 		}
+		else if (guiName == "Ability")
+		{
+			icon.sprite = "stretched:session/icons/single/"+item+".png";
+		}
 		else if (template.icon)
 		{
 			icon.sprite = "stretched:session/portraits/" + template.icon;
@@ -534,6 +561,16 @@
 			setupUnitBarterPanel(entState);
 		}
 
+		if (entState.Ability)
+		{
+			var abilities = [];
+			if (entState.Ability.Healer)
+				abilities.push("heal");
+			if (entState.Ability.Promote)
+				abilities.push("promote");
+			setupUnitPanel("Ability", usedPanels, entState, abilities, function (item) { performCommand(entState.id, item); });
+		}
+
 		if (entState.buildEntities && entState.buildEntities.length)
 		{
 			setupUnitPanel("Construction", usedPanels, entState, entState.buildEntities, startBuildingPlacement);
Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js
===================================================================
--- binaries/data/mods/public/simulation/components/GarrisonHolder.js	(revision 11284)
+++ binaries/data/mods/public/simulation/components/GarrisonHolder.js	(working copy)
@@ -308,7 +308,8 @@
 			var cmpHealth = Engine.QueryInterface(entity, IID_Health);
 			if (cmpHealth)
 			{
-				if (cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints())
+				// We do not want to heal unhealable units
+				if (!cmpHealth.IsUnhealable() && cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints())
 					cmpHealth.Increase(this.healRate);
 			}
 		}
Index: binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/GuiInterface.js	(revision 11284)
+++ binaries/data/mods/public/simulation/components/GuiInterface.js	(working copy)
@@ -155,6 +155,7 @@
 		ret.hitpoints = cmpHealth.GetHitpoints();
 		ret.maxHitpoints = cmpHealth.GetMaxHitpoints();
 		ret.needsRepair = cmpHealth.IsRepairable() && (cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints());
+		ret.needsHeal = !cmpHealth.IsUnhealable() && (cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints());
 	}
 
 	var cmpAttack = Engine.QueryInterface(ent, IID_Attack);
@@ -273,6 +274,27 @@
 		ret.barterMarket = { "prices": cmpBarter.GetPrices() };
 	}
 
+	// Abilities
+	var cmpHeal = Engine.QueryInterface(ent, IID_Heal);
+	// Check if we have abilities
+	if (cmpHeal || (cmpHeal && cmpPromotion))
+		ret.Ability = [];
+	if (cmpHeal)
+	{
+		ret.Ability.Healer = { 
+			"unhealableClasses": cmpHeal.GetUnhealableClasses(),
+			"healableClasses": cmpHeal.GetHealableClasses(),
+		};
+	}
+
+	// TODO remove this; This is just used to test/demonstrate the extensibility
+	// of the Ability system
+	// promoteAbility (just for healers)
+	if (cmpPromotion && cmpHeal)
+	{
+		ret.Ability.Promote = true ;
+	}
+
 	var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
 	ret.visibility = cmpRangeManager.GetLosVisibility(ent, player, false);
 
Index: binaries/data/mods/public/simulation/components/Heal.js
===================================================================
--- binaries/data/mods/public/simulation/components/Heal.js	(revision 0)
+++ binaries/data/mods/public/simulation/components/Heal.js	(working copy)
@@ -0,0 +1,91 @@
+function Heal() {}
+
+Heal.prototype.Schema = 
+	"<a:help>Controls the healing abilities of the unit.</a:help>" +
+	"<a:example>" +
+		"<Range>20</Range>" +
+		"<HP>5</HP>" +
+		"<Rate>2000</Rate>" +
+		"<UnhealableClasses datatype=\"tokens\">Cavalry</UnhealableClasses>" +
+		"<HealableClasses datatype=\"tokens\">Support Infantry</HealableClasses>" +
+	"</a:example>" +
+	"<element name='Range' a:help='Range (in metres) where healing is possible'>" +
+		"<ref name='nonNegativeDecimal'/>" +
+	"</element>" +
+	"<element name='HP' a:help='Hitpoints healed per Rate'>" +
+		"<ref name='nonNegativeDecimal'/>" +
+	"</element>" +
+	"<element name='Rate' a:help='A heal is performed every Rate ms'>" +
+		"<ref name='nonNegativeDecimal'/>" +
+	"</element>" +
+	"<element name='UnhealableClasses' a:help='If the target has any of these classes it can not be healed (even if it has a class from HealableClasses)'>" +
+		"<attribute name='datatype'>" +
+			"<value>tokens</value>" +
+		"</attribute>" +
+		"<text/>" +
+	"</element>" +
+	"<element name='HealableClasses' a:help='The target must have one of these classes to be healable'>" +
+		"<attribute name='datatype'>" +
+			"<value>tokens</value>" +
+		"</attribute>" +
+		"<text/>" +
+	"</element>";
+
+Heal.prototype.Init = function()
+{
+};
+
+Heal.prototype.Serialize = null; // we have no dynamic state to save
+
+Heal.prototype.GetTimers = function()
+{
+	var prepare = 1000;
+	var repeat = +(this.template.Rate || 1000);
+	return { "prepare": prepare, "repeat": repeat };
+};
+
+Heal.prototype.GetRange = function()
+{
+	var max = +this.template.Range;
+	var min = 0;
+	return { "max": max, "min": min };
+};
+
+Heal.prototype.GetUnhealableClasses = function()
+{
+	var classes = this.template.UnhealableClasses._string;
+	// If we have no unhealable classes defined classes is undefined
+	return classes?classes.split(/\s+/):"";
+};
+
+Heal.prototype.GetHealableClasses = function()
+{
+	var classes = this.template.HealableClasses._string;
+	return classes.split(/\s+/);
+};
+
+/**
+ * Heal the target entity. This should only be called after a successful range 
+ * check, and should only be called after GetTimers().repeat msec has passed 
+ * since the last call to PerformHeal.
+ */
+Heal.prototype.PerformHeal = function(target)
+{
+	var cmpHealth = Engine.QueryInterface(target, IID_Health);
+	if (!cmpHealth)
+		return;
+	var targetState = cmpHealth.Increase(Math.max(0,this.template.HP));
+
+	// Add XP
+	var cmpLoot = Engine.QueryInterface(target, IID_Loot);
+	var cmpPromotion = Engine.QueryInterface(this.entity, IID_Promotion);
+	if (targetState.old && targetState.new && cmpLoot && cmpPromotion)
+	{
+		// HP healed * XP per HP
+		cmpPromotion.IncreaseXp((targetState.new-targetState.old)*(cmpLoot.GetXp()/cmpHealth.GetMaxHitpoints()));
+	}
+	//TODO we need a sound file
+//	PlaySound("heal_impact", this.entity);
+};
+
+Engine.RegisterComponentType(IID_Heal, "Heal", Heal);
Index: binaries/data/mods/public/simulation/components/Health.js
===================================================================
--- binaries/data/mods/public/simulation/components/Health.js	(revision 11284)
+++ binaries/data/mods/public/simulation/components/Health.js	(working copy)
@@ -25,7 +25,7 @@
 			"<value a:help='Remain in the world with 0 health'>remain</value>" +
 		"</choice>" +
 	"</element>" +
-	"<element name='Healable' a:help='Indicates that the entity can be healed by healer units'>" +
+	"<element name='Unhealable' a:help='Indicates that the entity can not be healed by healer units'>" +
 		"<data type='boolean'/>" +
 	"</element>" +
 	"<element name='Repairable' a:help='Indicates that the entity can be repaired by builder units'>" +
@@ -72,6 +72,11 @@
 	return (this.template.Repairable == "true");
 };
 
+Health.prototype.IsUnhealable = function()
+{
+	return (this.template.Unhealable == "true");
+};
+
 Health.prototype.Kill = function()
 {
 	this.Reduce(this.hitpoints);
@@ -131,12 +136,14 @@
 {
 	// If we're already dead, don't allow resurrection
 	if (this.hitpoints == 0)
-		return;
+		return false;
 
 	var old = this.hitpoints;
 	this.hitpoints = Math.min(this.hitpoints + amount, this.GetMaxHitpoints());
 
 	Engine.PostMessage(this.entity, MT_HealthChanged, { "from": old, "to": this.hitpoints });
+	// We return the old and the actual hp
+	return { "old": old, "new": this.hitpoints};
 };
 
 //// Private functions ////
Index: binaries/data/mods/public/simulation/components/Loot.js
===================================================================
--- binaries/data/mods/public/simulation/components/Loot.js	(revision 11284)
+++ binaries/data/mods/public/simulation/components/Loot.js	(working copy)
@@ -21,7 +21,7 @@
 
 Loot.prototype.GetXp = function()
 {
-	return this.template.xp;
+	return +(this.template.xp || 0);
 };
 
 Loot.prototype.GetResources = function()
Index: binaries/data/mods/public/simulation/components/UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/UnitAI.js	(revision 11284)
+++ binaries/data/mods/public/simulation/components/UnitAI.js	(working copy)
@@ -139,6 +139,11 @@
 	"HealthChanged": function(msg) {
 		// ignore
 	},
+	
+	// TODO: This is part of a really UGLY EVIL HACK
+	"GlobalHealthChanged": function() {
+		// ignore
+	},
 
 	"EntityRenamed": function(msg) {
 		// ignore
@@ -283,6 +288,43 @@
 		this.FinishOrder();
 	},
 
+	"Order.Heal": function(msg) {
+		// Check the target is alive
+		if (!this.TargetIsAlive(this.order.data.target))
+		{
+			this.FinishOrder();
+			return;
+		}
+
+		// Check if the target is in range
+		if (this.CheckTargetRange(this.order.data.target, IID_Heal))
+		{
+			this.StopMoving();
+			this.SetNextState("INDIVIDUAL.HEAL.HEALING");
+			return;
+		}
+
+		// If we can't reach the target, but are standing ground,
+		// then abandon this heal order
+		if (this.GetStance().respondStandGround && !this.order.data.force)
+		{
+			this.FinishOrder();
+			return;
+		}
+
+		// Try to move within heal range
+		if (this.MoveToTargetRange(this.order.data.target, IID_Heal))
+		{
+			// We've started walking to the given point
+			this.SetNextState("INDIVIDUAL.HEAL.APPROACHING");
+			return;
+		}
+
+		// We can't reach the target, and can't move towards it,
+		// so abandon this heal order
+		this.FinishOrder();
+	},
+
 	"Order.Gather": function(msg) {
 		
 		// If the target is still alive, we need to kill it first
@@ -410,6 +452,13 @@
 			cmpFormation.Disband();
 		},
 
+		"Order.Heal": function(msg) {
+			// TODO: see notes in Order.Attack
+			var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
+			cmpFormation.CallMemberFunction("Heal", [msg.data.target, false]);
+			cmpFormation.Disband();
+		},
+
 		"Order.Repair": function(msg) {
 			// TODO: see notes in Order.Attack
 			var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
@@ -548,13 +597,25 @@
 				// So we'll set a timer here and only report the idle event if we
 				// remain idle
 				this.StartTimer(1000);
+				
+				// TODO: We need to set up a Query that watches own and ally units in LOS
+				// and calls something if they loose health (or change it to simplify)
+				// to replace the really UGLY EVIL HACK using GlobalHealthChanged as that can
+				// have a performance impact as it gets called for each healer for every entity
+				// in the whole map.
+				
+				// If a unit can heal and attack we first want to heal wounded units,
+				// so check if we are a healer and find whether there's anybody nearby to heal.
+				// If anyone approaches later it'll be handled via LosRangeUpdate.)
+				if (this.IsHealer() && this.FindNewHealTargets())
+					return true; // (abort the FSM transition since we may have already switched state)
 
 				// If we entered the idle state we must have nothing better to do,
 				// so immediately check whether there's anybody nearby to attack.
 				// (If anyone approaches later, it'll be handled via LosRangeUpdate.)
 				if (this.FindNewTargets())
 					return true; // (abort the FSM transition since we may have already switched state)
-
+				
 				// Nobody to attack - stay in idle
 				return false;
 			},
@@ -562,6 +623,8 @@
 			"leave": function() {
 				var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
 				rangeMan.DisableActiveQuery(this.losRangeQuery);
+				if (this.losHealRangeQuery)
+					rangeMan.DisableActiveQuery(this.losHealRangeQuery);
 
 				this.StopTimer();
 
@@ -571,8 +634,21 @@
 					Engine.PostMessage(this.entity, MT_UnitIdleChanged, { "idle": this.isIdle });
 				}
 			},
-
+			
+			// TODO: This is part of an really UGLY EVIL HACK
+			"GlobalHealthChanged": function() {
+				if (this.IsHealer())
+				{
+					this.FindNewHealTargets();
+				}
+			},
+			
 			"LosRangeUpdate": function(msg) {
+				if (this.IsHealer())
+				{
+					// Start healing one of the newly-seen own or ally units (if any)
+					this.FindNewHealTargets();
+				}
 				if (this.GetStance().targetVisibleEnemies)
 				{
 					// Start attacking one of the newly-seen enemy (if any)
@@ -1002,6 +1078,135 @@
 			},
 		},
 
+		"HEAL": {
+			"EntityRenamed": function(msg) {
+				if (this.order.data.target == msg.entity)
+					this.order.data.target = msg.newentity;
+			},
+
+			"Attacked": function(msg) {
+				// If we stand ground we will rather die than flee
+				if (!this.GetStance().respondStandGround)
+					this.Flee(msg.data.attacker, false);
+			},
+
+			"APPROACHING": {
+				"enter": function () {
+					this.SelectAnimation("move");
+					this.StartTimer(1000, 1000);
+				},
+
+				"leave": function() {
+					this.StopTimer();
+				},
+
+				"Timer": function(msg) {
+					if (this.ShouldAbandonChase(this.order.data.target, this.order.data.force))
+					{
+						this.StopMoving();
+						this.FinishOrder();
+
+						// Return to our original position
+						if (this.GetStance().respondHoldGround)
+							this.WalkToHeldPosition();
+					}
+				},
+
+				"MoveCompleted": function() {
+					this.SetNextState("HEALING");
+				},
+
+				"Attacked": function(msg) {
+					// If we stand ground we will rather die than flee
+					if (!this.GetStance().respondStandGround)
+						this.Flee(msg.data.attacker, false);
+				},
+			},
+
+			"HEALING": {
+				"enter": function() {
+					var cmpHeal = Engine.QueryInterface(this.entity, IID_Heal);
+					this.healTimers = cmpHeal.GetTimers();
+//					this.SelectAnimation("heal", false, 1.0, "heal"); // TODO needs animation
+//					this.SetAnimationSync(this.healTimers.prepare, this.healTimers.repeat);
+					this.StartTimer(this.healTimers.prepare, this.healTimers.repeat);
+					// TODO if .prepare is short, players can cheat by cycling heal/stop/heal
+					// to beat the .repeat time; should enforce a minimum time
+					// see comment in ATTACKING.enter
+					this.FaceTowardsTarget(this.order.data.target);
+				},
+
+				"leave": function() {
+					this.StopTimer();
+				},
+
+				"Timer": function(msg) {
+					var target = this.order.data.target;
+					// Check the target is still alive and healable
+					if (this.TargetIsAlive(target) && this.CanHeal(target))
+					{
+						// Check if we can still reach the target
+						if (this.CheckTargetRange(target, IID_Heal))
+						{
+							this.FaceTowardsTarget(target);
+							var cmpHeal = Engine.QueryInterface(this.entity, IID_Heal);
+							cmpHeal.PerformHeal(target);
+							return;
+						}
+						// Can't reach it - try to chase after it
+						if (this.ShouldChaseTargetedEntity(target, this.order.data.force))
+						{
+							if (this.MoveToTargetRange(target, IID_Heal))
+							{
+								this.SetNextState("HEAL.CHASING");
+								return;
+							}
+						}
+					}
+					// Can't reach it, healed to max hp or doesn't exist any more - give up
+					if (this.FinishOrder())
+						return;
+
+					// Heal another one
+					if (this.FindNewHealTargets())
+						return;
+					
+					// Return to our original position
+					if (this.GetStance().respondHoldGround)
+						this.WalkToHeldPosition();
+				},
+				"Attacked": function(msg) {
+					// If we stand ground we will rather die than flee
+					if (!this.GetStance().respondStandGround)
+						this.Flee(msg.data.attacker, false);
+				},
+			},
+			"CHASING": {
+				"enter": function () {
+					this.SelectAnimation("move");
+					this.StartTimer(1000, 1000);
+				},
+
+				"leave": function () {
+					this.StopTimer();
+				},
+				"Timer": function(msg) {
+					if (this.ShouldAbandonChase(this.order.data.target, this.order.data.force))
+					{
+						this.StopMoving();
+						this.FinishOrder();
+
+						// Return to our original position
+						if (this.GetStance().respondHoldGround)
+							this.WalkToHeldPosition();
+					}
+				},
+				"MoveCompleted": function () {
+					this.SetNextState("HEALING");
+				},
+			},  
+		},
+
 		// Returning to dropsite
 		"RETURNRESOURCE": {
 			"APPROACHING": {
@@ -1457,6 +1662,11 @@
 	return (this.template.NaturalBehaviour ? true : false);
 };
 
+UnitAI.prototype.IsHealer = function()
+{
+	return Engine.QueryInterface(this.entity, IID_Heal);
+};
+
 UnitAI.prototype.IsIdle = function()
 {
 	return this.isIdle;
@@ -1480,6 +1690,8 @@
 UnitAI.prototype.OnOwnershipChanged = function(msg)
 {
 	this.SetupRangeQuery();
+	if (this.IsHealer())
+		this.SetupHealRangeQuery();
 };
 
 UnitAI.prototype.OnDestroy = function()
@@ -1491,6 +1703,8 @@
 	var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
 	if (this.losRangeQuery)
 		rangeMan.DestroyActiveQuery(this.losRangeQuery);
+	if (this.losHealRangeQuery)
+		rangeMan.DestroyActiveQuery(this.losHealRangeQuery);
 };
 
 // Set up a range query for all enemy units within LOS range
@@ -1529,6 +1743,41 @@
 	rangeMan.EnableActiveQuery(this.losRangeQuery);
 };
 
+// Set up a range query for all own or ally units within LOS range
+// which can be healed.
+// This should be called whenever our ownership changes.
+UnitAI.prototype.SetupHealRangeQuery = function()
+{
+	var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+	var owner = cmpOwnership.GetOwner();
+
+	var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+	var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
+
+	if (this.losHealRangeQuery)
+		rangeMan.DestroyActiveQuery(this.losHealRangeQuery);
+
+	var players = [owner];
+
+	if (owner != -1)
+	{
+		// If unit not just killed, get ally players via diplomacy
+		var cmpPlayer = Engine.QueryInterface(playerMan.GetPlayerByID(owner), IID_Player);
+		var numPlayers = playerMan.GetNumPlayers();
+		for (var i = 1; i < numPlayers; ++i)
+		{
+			// Exclude gaia and enemies
+			if (cmpPlayer.IsAlly(i))
+				players.push(i);
+		}
+	}
+
+	var range = this.GetQueryRange(true);
+
+	this.losHealRangeQuery = rangeMan.CreateActiveQuery(this.entity, range.min, range.max, players, IID_Health);
+	rangeMan.EnableActiveQuery(this.losHealRangeQuery);
+};
+
 //// FSM linkage functions ////
 
 UnitAI.prototype.SetNextState = function(state)
@@ -1750,10 +1999,22 @@
 
 UnitAI.prototype.OnRangeUpdate = function(msg)
 {
-	if (msg.tag == this.losRangeQuery)
+	if (msg.tag == this.losRangeQuery || msg.tag == this.losHealRangeQuery)
 		UnitFsm.ProcessMessage(this, {"type": "LosRangeUpdate", "data": msg});
 };
 
+// really UGLY EVIL HACK
+// TODO This should be replaced with a c++ component that tracks all entities within a range and notifies
+// Healers if any of the entities receives a HealthChanged message.
+// If any entity changes health we call this, so this probably has a huge performance impact.
+UnitAI.prototype.OnGlobalHealthChanged = function(msg)
+{
+	if (this.IsHealer())
+	{
+		UnitFsm.ProcessMessage(this, {"type": "GlobalHealthChanged"});
+	}
+}
+
 //// Helper functions to be called by the FSM ////
 
 UnitAI.prototype.GetWalkSpeed = function()
@@ -1781,6 +2042,30 @@
 };
 
 /**
+ * Returns true if the target exists and the current hitpoints are at maximum.
+ */
+UnitAI.prototype.TargetIsAtMaxHitpoints = function(ent)
+{
+	var cmpHealth = Engine.QueryInterface(ent, IID_Health);
+	if (!cmpHealth)
+		return false;
+
+	return (cmpHealth.GetHitpoints() == cmpHealth.GetMaxHitpoints());
+};
+
+/**
+ * Returns true if the target exists and is unhealable.
+ */
+UnitAI.prototype.TargetIsUnhealable = function(ent)
+{
+	var cmpHealth = Engine.QueryInterface(ent, IID_Health);
+	if (!cmpHealth)
+		return false;
+
+	return cmpHealth.IsUnhealable();
+};
+
+/**
  * Returns true if the target exists and needs to be killed before
  * beginning to gather resources from it.
  */
@@ -2271,6 +2556,7 @@
 		case "Flee":
 		case "LeaveFoundation":
 		case "Attack":
+		case "Heal":
 		case "Gather":
 		case "ReturnResource":
 		case "Repair":
@@ -2394,6 +2680,17 @@
 	this.AddOrder("GatherNearPosition", { "type": type, "x": x, "z": z }, queued);
 }
 
+UnitAI.prototype.Heal = function(target, queued)
+{
+	if (!this.CanHeal(target))
+	{
+		this.WalkToTarget(target, queued);
+		return;
+	}
+	
+	this.AddOrder("Heal", { "target": target, "force": true }, queued);
+};
+
 UnitAI.prototype.ReturnResource = function(target, queued)
 {
 	if (!this.CanReturnResource(target, true))
@@ -2505,7 +2802,7 @@
 		this.stance = stance;
 	else
 		error("UnitAI: Setting to invalid stance '"+stance+"'");
-}
+};
 
 UnitAI.prototype.SwitchToStance = function(stance)
 {
@@ -2521,7 +2818,11 @@
 
 	// Reset the range query, since the range depends on stance
 	this.SetupRangeQuery();
-}
+	// Just if we are a healer
+	// TODO maybe move those two to a SetupRangeQuerys()
+	if (this.IsHealer())
+		this.SetupHealRangeQuery();
+};
 
 /**
  * Resets losRangeQuery, and if there are some targets in range that we can
@@ -2542,15 +2843,40 @@
 	return this.RespondToTargetedEntities(ents);
 };
 
-UnitAI.prototype.GetQueryRange = function()
+/**
+ * Resets losHealRangeQuery, and if there are some targets in range that we can heal
+ * then we start healing and this returns true; otherwise, returns false.
+ */
+UnitAI.prototype.FindNewHealTargets = function()
+{
+	if (!this.losHealRangeQuery)
+		return false;
+	
+	var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+	var ents = rangeMan.ResetActiveQuery(this.losHealRangeQuery);
+	
+	for each (var ent in ents)
+	{
+		if (this.CanHeal(ent))
+		{
+			this.PushOrderFront("Heal", { "target": ent, "force": false });
+			return true;
+		}
+	}
+	// We haven't found any target to heal
+	return false;
+};
+
+UnitAI.prototype.GetQueryRange = function(healer)
 {
 	var ret = { "min": 0, "max": 0 };
-	if (this.GetStance().respondStandGround)
+	// If we have a healer with passive stance we need to set some defaults (eg same as stand ground)
+	if (this.GetStance().respondStandGround || (healer && !this.GetStance().respondStandGround && !this.GetStance().respondChase && !this.GetStance().respondHoldGround))
 	{
-		var cmpRanged = Engine.QueryInterface(this.entity, IID_Attack);
+		var cmpRanged = Engine.QueryInterface(this.entity, healer?IID_Heal:IID_Attack);
 		if (!cmpRanged)
 			return ret;
-		var range = cmpRanged.GetRange(cmpRanged.GetBestAttack());
+		var range = healer?cmpRanged.GetRange():cmpRanged.GetRange(cmpRanged.GetBestAttack());
 		ret.min = range.min;
 		ret.max = range.max;
 	}
@@ -2564,10 +2890,10 @@
 	}
 	else if (this.GetStance().respondHoldGround)
 	{
-		var cmpRanged = Engine.QueryInterface(this.entity, IID_Attack);
+		var cmpRanged = Engine.QueryInterface(this.entity, healer?IID_Heal:IID_Attack);
 		if (!cmpRanged)
 			return ret;
-		var range = cmpRanged.GetRange(cmpRanged.GetBestAttack());
+		var range = healer?cmpRanged.GetRange():cmpRanged.GetRange(cmpRanged.GetBestAttack());
 		var cmpVision = Engine.QueryInterface(this.entity, IID_Vision);
 		if (!cmpVision)
 			return ret;
@@ -2663,6 +2989,66 @@
 	return true;
 };
 
+UnitAI.prototype.CanHeal = function(target)
+{
+	// Formation controllers should always respond to commands
+	// (then the individual units can make up their own minds)
+	if (this.IsFormationController())
+		return true;
+
+	// Verify that we're able to respond to Heal commands
+	var cmpHeal = Engine.QueryInterface(this.entity, IID_Heal);
+	if (!cmpHeal)
+		return false;
+
+	// Verify that the target is alive
+	if (!this.TargetIsAlive(target))
+		return false;
+
+	// Verify that the target is owned by the same player as the entity or of an ally
+	var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+	if (!cmpOwnership || !(IsOwnedByPlayer(cmpOwnership.GetOwner(), target) || IsOwnedByAllyOfPlayer(cmpOwnership.GetOwner(), target)))
+		return false;
+	
+	// Verify that the target is not unhealable
+	if (this.TargetIsUnhealable(target))
+	{
+		return false;
+	}
+	
+	// Verify that the target has no unhealable class
+	// We could also use cmpIdentity.GetClassesList but this way is cleaner
+	var cmpIdentity = Engine.QueryInterface(target, IID_Identity);
+	if (!cmpIdentity)
+		return false;
+	for each (var unhealableClass in cmpHeal.GetUnhealableClasses())
+	{
+		if (cmpIdentity.HasClass(unhealableClass) != -1)
+		{
+			return false;
+		}
+	}
+
+	// Verify that the target is a healable class
+	// We could also use cmpIdentity.GetClassesList but this way is cleaner
+	var healable = false;
+	for each (var healableClass in cmpHeal.GetHealableClasses())
+	{
+		if (cmpIdentity.HasClass(healableClass) != -1)
+		{
+			healable = true;
+		}
+	}
+	if (!healable)
+		return false;
+
+	// Check that the target is not at MaxHealth
+	if (this.TargetIsAtMaxHitpoints(target))
+		return false; 
+
+	return true;
+};
+
 UnitAI.prototype.CanReturnResource = function(target, checkCarriedResource)
 {
 	// Formation controllers should always respond to commands
Index: binaries/data/mods/public/simulation/components/interfaces/Heal.js
===================================================================
--- binaries/data/mods/public/simulation/components/interfaces/Heal.js	(revision 0)
+++ binaries/data/mods/public/simulation/components/interfaces/Heal.js	(working copy)
@@ -0,0 +1 @@
+Engine.RegisterInterface("Heal");
Index: binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js	(revision 11284)
+++ binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js	(working copy)
@@ -5,6 +5,7 @@
 Engine.LoadComponentScript("interfaces/DamageReceiver.js");
 Engine.LoadComponentScript("interfaces/Foundation.js");
 Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
+Engine.LoadComponentScript("interfaces/Heal.js");
 Engine.LoadComponentScript("interfaces/Health.js");
 Engine.LoadComponentScript("interfaces/Promotion.js");
 Engine.LoadComponentScript("interfaces/RallyPoint.js");
@@ -271,6 +272,7 @@
 	GetHitpoints: function() { return 50; },
 	GetMaxHitpoints: function() { return 60; },
 	IsRepairable: function() { return false; },
+	IsUnhealable: function() { return false; },
 });
 
 AddMock(10, IID_Identity, {
@@ -304,6 +306,7 @@
 	hitpoints: 50,
 	maxHitpoints: 60,
 	needsRepair: false,
+	needsHeal: true,
 	buildEntities: ["test1", "test2"],
 	barterMarket: {
 		prices: { "buy": {"food":150}, "sell": {"food":25} },
Index: binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_UnitAI.js	(revision 11284)
+++ binaries/data/mods/public/simulation/components/tests/test_UnitAI.js	(working copy)
@@ -4,6 +4,7 @@
 Engine.LoadComponentScript("interfaces/Attack.js");
 Engine.LoadComponentScript("interfaces/DamageReceiver.js");
 Engine.LoadComponentScript("interfaces/Formation.js");
+Engine.LoadComponentScript("interfaces/Heal.js");
 Engine.LoadComponentScript("interfaces/Health.js");
 Engine.LoadComponentScript("interfaces/ResourceSupply.js");
 Engine.LoadComponentScript("interfaces/Timer.js");
Index: binaries/data/mods/public/simulation/helpers/Commands.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Commands.js	(revision 11284)
+++ binaries/data/mods/public/simulation/helpers/Commands.js	(working copy)
@@ -66,6 +66,20 @@
 		});
 		break;
 
+	case "heal":
+		if (g_DebugCommands && !(IsOwnedByPlayer(player, cmd.target) || IsOwnedByAllyOfPlayer(player, cmd.target)))
+		{
+			// This check is for debugging only!
+			warn("Invalid command: heal target is not owned by an ally of or player "+player+" itself: "+uneval(cmd));
+		}
+
+		// See UnitAI.CanHeal for target checks
+		var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
+		GetFormationUnitAIs(entities).forEach(function(cmpUnitAI) {
+			cmpUnitAI.Heal(cmd.target, cmd.queued);
+		});
+		break;
+
 	case "repair":
 		// This covers both repairing damaged buildings, and constructing unfinished foundations
 		if (g_DebugCommands && !IsOwnedByAllyOfPlayer(player, cmd.target))
Index: binaries/data/mods/public/simulation/templates/template_structure.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/template_structure.xml	(working copy)
@@ -33,7 +33,7 @@
   <Health>
     <DeathType>corpse</DeathType>
     <RegenRate>0</RegenRate>
-    <Healable>false</Healable>
+    <Unhealable>true</Unhealable>
     <Repairable>true</Repairable>
   </Health>
   <Identity>
Index: binaries/data/mods/public/simulation/templates/template_unit.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/template_unit.xml	(working copy)
@@ -30,7 +30,7 @@
     <DeathType>corpse</DeathType>
     <Max>100</Max>
     <RegenRate>0</RegenRate>
-    <Healable>true</Healable>
+    <Unhealable>false</Unhealable>
     <Repairable>false</Repairable>
   </Health>
   <Identity>
Index: binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml	(working copy)
@@ -4,7 +4,7 @@
     <Max>100</Max>
     <DeathType>remain</DeathType>
     <RegenRate>1</RegenRate>
-    <Healable>false</Healable>
+    <Unhealable>true</Unhealable>
     <Repairable>false</Repairable>
   </Health>
   <Identity>
Index: binaries/data/mods/public/simulation/templates/template_unit_mechanical.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_mechanical.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/template_unit_mechanical.xml	(working copy)
@@ -7,7 +7,7 @@
     <SinkAccel>2.0</SinkAccel>
   </Decay>
   <Health>
-    <Healable>false</Healable>
+    <Unhealable>true</Unhealable>
     <Repairable>true</Repairable>
   </Health>
   <Identity>
Index: binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml	(working copy)
@@ -5,12 +5,19 @@
     <Pierce>2.0</Pierce>
     <Crush>2.0</Crush>
   </Armour>
-  <Auras>
+<!--  <Auras>
     <Heal>
       <Radius>20</Radius>
       <Speed>2000</Speed>
     </Heal>
-  </Auras>
+  </Auras>-->
+  <Heal>
+    <Range>30</Range>
+    <HP>5</HP>
+    <Rate>2000</Rate>
+    <UnhealableClasses datatype="tokens"/>
+    <HealableClasses datatype="tokens">Support Infantry Cavalry</HealableClasses>
+  </Heal>
   <Cost>
     <Resources>
       <metal>120</metal>
@@ -23,8 +30,11 @@
   <Identity>
     <Classes datatype="tokens">Healer</Classes>
     <GenericName>Healer</GenericName>
-    <Tooltip>Heal units within his Aura. (Not implemented yet)</Tooltip>
+    <Tooltip>Heal units.</Tooltip>
   </Identity>
+  <Promotion>
+    <RequiredXp>100</RequiredXp>
+  </Promotion>
   <Sound>
     <SoundGroups>
       <select>voice/hellenes/civ/civ_male_select.xml</select>
Index: binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml	(working copy)
@@ -36,7 +36,7 @@
     </Resources>
   </Cost>
   <Health>
-    <Healable>false</Healable>
+    <Unhealable>true</Unhealable>
   </Health>
   <Identity>
     <Classes datatype="tokens">Slave</Classes>
Index: binaries/data/mods/public/simulation/templates/units/cart_support_healer_b.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/units/cart_support_healer_b.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/units/cart_support_healer_b.xml	(working copy)
@@ -6,7 +6,11 @@
     <History>Tanit (also spelled TINITH, TINNIT, or TINT), chief goddess of Carthage, equivalent of Astarte. Although she seems to have had some connection with the heavens, she was also a mother goddess, and fertility symbols often accompany representations of her. She was probably the consort of Baal Hammon (or Amon), the chief god of Carthage, and was often given the attribute "face of Baal." Although Tanit did not appear at Carthage before the 5th century BC, she soon eclipsed the more established cult of Baal Hammon and, in the Carthaginian area at least, was frequently listed before him on the monuments. In the worship of Tanit and Baal Hammon, children, probably firstborn, were sacrificed. Ample evidence of the practice has been found west of Carthage in the precinct of Tanit, where a tofet (a sanctuary for the sacrifice of children) was discovered. Tanit was also worshipped on Malta, Sardinia, and in Spain. There is no other reason for giving the Carthaginians a priestess instead of a priest in 0 A.D., although Tanit was the most popular of their two main gods with the people. </History>
     <Tooltip>Heal units within her aura. (Not implemented yet)</Tooltip>
     <Icon>units/cart_support_healer.png</Icon>
+    <Rank>Basic</Rank>
   </Identity>
+  <Promotion>
+    <Entity>units/cart_support_healer_a</Entity>
+  </Promotion>
   <VisualActor>
     <Actor>units/carthaginians/healer.xml</Actor>
   </VisualActor>
Index: binaries/data/mods/public/simulation/templates/units/celt_support_healer_b.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/units/celt_support_healer_b.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/units/celt_support_healer_b.xml	(working copy)
@@ -5,7 +5,11 @@
     <SpecificName>Druides </SpecificName>
     <History>A druid may be one of many different professions; priest, historian, lawyer, judges, teachers, philosophers, poets, composers, musicians, astronomers, prophets, councillors, high craftsmen like a blacksmith, the classes of the 'men of art', and sometimes kings, chieftains, or other politicians. Druids were very hierarchal, with classes and ranks based on the length of their education and what fields they practiced. They learned their trades through mnemonics by way of poetry and songs, as writing was rarely used by Celts outside of prayers on votive objects, or lists of names for migratory records.</History>
     <Icon>units/celt_support_healer.png</Icon>
+    <Rank>Basic</Rank>
   </Identity>
+  <Promotion>
+    <Entity>units/celt_support_healer_a</Entity>
+  </Promotion>
   <VisualActor>
     <Actor>units/celts/healer.xml</Actor>
   </VisualActor>
Index: binaries/data/mods/public/simulation/templates/units/hele_support_healer_b.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/units/hele_support_healer_b.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/units/hele_support_healer_b.xml	(working copy)
@@ -5,7 +5,11 @@
     <SpecificName>Hiereús</SpecificName>
     <History>The art of medicine was widely practised in Classical Greece. Hippocrates was the first physician to separate religion and superstition from actual medicine, and many others followed his lead.</History>
     <Icon>units/hele_support_healer.png</Icon>
+    <Rank>Basic</Rank>
   </Identity>
+  <Promotion>
+    <Entity>units/hele_support_healer_a</Entity>
+  </Promotion>
   <VisualActor>
     <Actor>units/hellenes/healer.xml</Actor>
   </VisualActor>
Index: binaries/data/mods/public/simulation/templates/units/iber_support_healer_b.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/units/iber_support_healer_b.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/units/iber_support_healer_b.xml	(working copy)
@@ -5,7 +5,11 @@
     <SpecificName>Sacerdotisa de Ataekina</SpecificName>
     <History> To the best of our knowledge, only one 'temple'-like structure has been found on the Iberian Peninsula dating from the times and the Iberians worshiped their pantheon of gods at small home altars; however, a very special sculptured head and torso was found in a farmer's field around the turn of the 20th century of a personage who was obviously someone of great substance. As the two principal gods, of the many worshiped, were male Endovellikos and female Ataekina, we thought it would be nice to adopt The Lady of Elche as our priestess-healer representing Ataekina. We know from archelogy and the Romans that Ataekina was associated with spring, the changing of seasons, and nature in general. Ataekina also seems to have been associated with the cycle of birth-death-rebirth.</History>
     <Icon>units/iber_support_healer.png</Icon>
+    <Rank>Basic</Rank>
   </Identity>
+  <Promotion>
+    <Entity>units/iber_support_healer_a</Entity>
+  </Promotion>
   <VisualActor>
     <Actor>units/iberians/healer.xml</Actor>
   </VisualActor>
Index: binaries/data/mods/public/simulation/templates/units/pers_support_healer_b.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/units/pers_support_healer_b.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/units/pers_support_healer_b.xml	(working copy)
@@ -6,7 +6,11 @@
     <SpecificName>Maguš Mada</SpecificName>
     <History>Under both the Medes and later the Persian the tribe of the Magi or the Magians were the masters of religious and oral tradition, comparable to the Levites of the Bible. They were connected to Zoroastrianism, but likely tended to other Iranian cults as well. Aside from religious duties the Magians also functioned as the Great King's bureaucrats and kept his administration running.</History>
     <Icon>units/pers_support_healer.png</Icon>
+    <Rank>Basic</Rank>
   </Identity>
+  <Promotion>
+    <Entity>units/pers_support_healer_a</Entity>
+  </Promotion>
   <VisualActor>
     <Actor>units/persians/healer.xml</Actor>
   </VisualActor>
Index: binaries/data/mods/public/simulation/templates/units/rome_support_healer_b.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/units/rome_support_healer_b.xml	(revision 11284)
+++ binaries/data/mods/public/simulation/templates/units/rome_support_healer_b.xml	(working copy)
@@ -6,7 +6,11 @@
     <SpecificName>Pontifex Minoris</SpecificName>
     <History>During the Republic, the position of priest was elevated and required a lot of responsibilities, which is why priests were by no means chosen randomly. The position of Pontifex Maximus, the high priest of the Roman religion, was occupied by such prominent figures as Julius Caesar, Marcus Aemilius Lepidus and Augustus.</History>
     <Icon>units/rome_support_healer.png</Icon>
+    <Rank>Basic</Rank>
   </Identity>
+  <Promotion>
+    <Entity>units/rome_support_healer_a</Entity>
+  </Promotion>
   <VisualActor>
     <Actor>units/romans/healer.xml</Actor>
   </VisualActor>
Index: binaries/data/mods/public/art/textures/ui/session/icons/single/heal.png
===================================================================
Cannot display: file marked as binary type.
svn:mime-type = application/octet-stream
