Index: binaries/data/mods/public/simulation/components/Auras.js
===================================================================
--- binaries/data/mods/public/simulation/components/Auras.js	(revision 13803)
+++ binaries/data/mods/public/simulation/components/Auras.js	(working copy)
@@ -3,40 +3,411 @@
 Auras.prototype.Schema =
 	"<oneOrMore>" +
 		"<element>" +
-			"<choice>" +
-				"<name>Allure</name>" +
-				"<name>Infidelity</name>" +
-				"<name>Heal</name>" +
-				"<name>Courage</name>" +
-				"<name>Fear</name>" +
-			"</choice>" +
+			"<anyName/>" +
 			"<interleave>" +
-				"<element name='Radius'>" +
-					"<data type='nonNegativeInteger'/>" +
+				"<element name='Modification'>" +
+					"<interleave>" +
+						"<element name='Value'>" +
+							"<text/>" +
+						"</element>" +
+						"<optional>" +
+							"<element name='Add'>" +
+								"<data type='decimal'/>" +
+							"</element>" +
+						"</optional>" +
+						"<optional>" +
+							"<element name='Multiply'>" +
+								"<data type='decimal'/>" +
+							"</element>" +
+						"</optional>" +
+					"</interleave>" +
 				"</element>" +
 				"<optional>" +
-					"<element name='Bonus'>" +
-						"<data type='positiveInteger'/>" +
+					"<element name='AffectedPlayers'>" +
+						"<text/>" +
 					"</element>" +
 				"</optional>" +
-				"<optional>" +
-					"<element name='Time'>" +
+				"<element name='Classes'>" +
+					"<text/>" +
+				"</element>" +
+				"<choice>" +
+					"<element name='Radius'>" +
 						"<data type='nonNegativeInteger'/>" +
 					"</element>" +
-				"</optional>" +
-				"<optional>" +
-					"<element name='Speed'>" +
-						"<data type='positiveInteger'/>" +
+					"<element name='Formation'>" +
+						"<value/>" +
 					"</element>" +
-				"</optional>" +
+					"<element name='GarrisoningStructure'>" +
+						"<value/>" +
+					"</element>" +
+					"<element name='Template'>" +
+						"<value/>" +
+					"</element>" +
+				"</choice>" +
 			"</interleave>" +
 		"</element>" +
 	"</oneOrMore>";
 
-/*
- * TODO: this all needs to be designed and implemented
- */
 
 Auras.prototype.Serialize = null; // we have no dynamic state to save
 
+Auras.prototype.Init = function()
+{
+	var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
+	this.templateName = cmpTemplateManager.GetCurrentTemplateName(this.entity);
+};
+
+Auras.prototype.GetAuraTypes = function()
+{
+	return Object.keys(this.template);
+};
+
+Auras.prototype.GetRadius = function(type)
+{
+	if (!this.IsRangeAura(type))
+		return undefined;
+	if (this.IsTemplateAura(type))
+		return -1;
+	var radius = +this.template[type].Radius;
+	return ApplyTechModificationsToEntity("Auras/"+type+"/Radius",radius, this.entity);
+};
+
+Auras.prototype.GetClasses = function(type) 
+{ 
+	var string = this.template[type].Classes || ""; 
+	return string.split(/\s+/); 
+}; 
+
+Auras.prototype.GetModification = function(type)
+{
+	var ret = {};
+	ret.values = this.template[type].Modification.Value.split(/\s+/);
+	if (this.template[type].Modification.Add)
+	{
+		ret.add = +this.template[type].Modification.Add;
+		ret.add = ApplyTechModificationsToEntity("Auras/"+type+"/Modification/Add", ret.add, this.entity);
+	}
+	if (this.template[type].Modification.Multiply)
+	{
+		ret.multiply = +this.template[type].Modification.Multiply;
+		ret.multiply = ApplyTechModificationsToEntity("Auras/"+type+"/Modification/Multiply", ret.multiply, this.entity);
+	}
+	return ret;
+};
+
+Auras.prototype.GetAffectedPlayers = function(type)
+{
+	if (this.template[type].AffectedPlayers)
+		var affectedPlayers = this.template[type].AffectedPlayers.split(/\s+/);
+	else
+		var affectedPlayers = ["Player"];
+
+	var ret = [];
+
+	var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
+	warn(uneval(cmpPlayer));
+
+	if (!cmpPlayer)
+		return ret;
+
+	var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
+	var numPlayers = cmpPlayerManager.GetNumPlayers();
+	var enemies = [];
+	var mutualAllies = [];
+
+	for (var i = 0; i < numPlayers; ++i)
+	{
+		if (affectedPlayers.indexOf("Player") != -1 && cmpPlayer.GetPlayerID() == i)
+			ret.push(i);
+		else if (affectedPlayers.indexOf("Enemy") != -1 && cmpPlayer.IsEnemy(i))
+			ret.push(i);
+		else if (affectedPlayers.indexOf("MutualAlly") != -1 && cmpPlayer.IsMutualAlly(i))
+			ret.push(i);
+		else if (affectedPlayers.indexOf("Ally") != -1 && cmpPlayer.IsAlly(i))
+			ret.push(i);
+		else if (affectedPlayers.indexOf("Neutral") != -1 && cmpPlayer.IsNeutral(i))
+			ret.push(i);
+	}
+	// return and store the value
+	this[type].affectedPlayers = ret;
+	return ret; 
+};
+
+Auras.prototype.HasFormationAura = function()
+{
+	var auraTypes = this.GetAuraTypes();
+	for each (var type in auraTypes)
+	{
+		if (this.IsFormationAura(type))
+			return true;
+	}
+	return false;
+};
+
+Auras.prototype.HasGarrisonAura = function()
+{
+	var auraTypes = this.GetAuraTypes();
+	for each (var type in auraTypes)
+	{
+		if (this.IsGarrisonAura(type))
+			return true;
+	}
+	return false;
+};
+
+Auras.prototype.IsFormationAura = function(type)
+{
+	return 'Formation' in this.template[type];
+};
+
+Auras.prototype.IsGarrisonAura = function(type)
+{
+	return 'GarrisoningStructure' in this.template[type];
+};
+
+Auras.prototype.IsRangeAura = function(type)
+{
+	return 'Radius' in this.template[type] || "Template" in this.template[type];
+};
+
+Auras.prototype.IsTemplateAura = function(type)
+{
+	return "Template" in this.template[type];
+};
+
+/**
+ * clean all bonuses. Remove the old ones and re-apply the new ones
+ */
+Auras.prototype.Clean = function()
+{
+	var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+	var auraTypes = this.GetAuraTypes();
+	// remove all bonuses
+	for each (var type in auraTypes)
+	{
+		if (!this[type])
+			continue;
+
+		if (this.IsTemplateAura(type))
+			this.RemoveTemplateBonus(type);
+		
+		for each(var ent in this[type].targetUnits)
+			this.RemoveBonus(type, ent);
+
+		if (this[type].rangeQuery)
+			cmpRangeManager.DestroyActiveQuery(this[type].rangeQuery);
+	}
+
+	for each (var type in auraTypes)
+	{
+		// initialise range query
+		this[type] = {};
+		this[type].targetUnits = [];
+		var affectedPlayers = this.GetAffectedPlayers(type);
+		
+		if (!affectedPlayers.length)
+			continue;
+
+		if (this.IsTemplateAura(type))
+			this.ApplyTemplateBonus(type, affectedPlayers);
+
+		if (!this.IsRangeAura(type))
+			continue;
+		warn("add range query");
+		this[type].rangeQuery = cmpRangeManager.CreateActiveQuery(
+		    this.entity, 
+		    0, 
+		    this.GetRadius(type),
+		    affectedPlayers,
+		    IID_Identity,
+		    cmpRangeManager.GetEntityFlagMask("normal")
+		);
+		cmpRangeManager.EnableActiveQuery(this[type].rangeQuery);
+		// add self to your own query for consistency with templates
+		this.OnRangeUpdate({"tag":this[type].rangeQuery, "added":[this.entity], "removed":[]});
+	}
+};
+
+Auras.prototype.OnRangeUpdate = function(msg)
+{
+	var auraTypes = this.GetAuraTypes();
+	for each (var t in auraTypes)
+	{
+		if (msg.tag == this[t].rangeQuery)
+		{
+			var type = t;
+			break;
+		} 
+	}
+
+	if (!type) 
+		return;
+	
+	var targetUnits = this[type].targetUnits;
+	var classes = this.GetClasses(type);
+	
+	if (msg.added.length > 0)
+	{
+		for each (var e in msg.added)
+		{
+			var cmpIdentity = Engine.QueryInterface(e, IID_Identity);
+			var targetClasses = cmpIdentity.GetClassesList(); 
+
+			if (targetClasses.some(function(c){return classes.indexOf(c) > -1;})) 
+			{
+				targetUnits.push(e);
+				this.ApplyBonus(type,e);
+			}
+		}
+	}
+
+	if (msg.removed.length > 0)
+	{
+		for each (var e in msg.removed)
+		{
+			targetUnits.splice(targetUnits.indexOf(e), 1);
+			this.RemoveBonus(type,e);
+		}
+	}
+
+};
+
+Auras.prototype.ApplyFormationBonus = function(memberList)
+{
+	var auraTypes = this.GetAuraTypes();
+	for each (var type in auraTypes)
+	{
+		if (!this.IsFormationAura(type))
+			continue;
+		var classes = this.GetClasses(type);
+		
+		for each (var ent in memberList)
+		{
+			var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
+			var targetClasses = cmpIdentity.GetClassesList();
+			if (targetClasses.some(function(c){return classes.indexOf(c) > -1;})) 
+			{
+				this[type].targetUnits.push(ent);
+				this.ApplyBonus(type,ent);
+			}
+		}
+	}
+};
+
+Auras.prototype.ApplyGarrisonBonus = function(structure)
+{
+	var auraTypes = this.GetAuraTypes();
+	for each (var type in auraTypes)
+	{
+		if (!this.IsGarrisonAura(type))
+			continue;
+		var classes = this.GetClasses(type);
+
+		
+		var cmpIdentity = Engine.QueryInterface(structure, IID_Identity);
+		var targetClasses = cmpIdentity.GetClassesList();
+		if (targetClasses.some(function(c){return classes.indexOf(c) > -1;})) 
+		{
+			this[type].targetUnits.push(structure);
+			this.ApplyBonus(type,structure);
+		}
+	}
+};
+
+Auras.prototype.ApplyTemplateBonus = function(type, players)
+{
+	if (!this.IsTemplateAura(type))
+		return;
+	var modification = this.GetModification(type);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+	var classes = this.GetClasses(type);
+
+	for each (var value in modification.values)
+		for each (var player in players)
+			cmpAuraManager.ApplyTemplateBonus(value, player, classes, modification, this.templateName+"/"+type+"/"+value);	
+};
+
+Auras.prototype.RemoveFormationBonus = function(memberList)
+{
+	var auraTypes = this.GetAuraTypes();
+	for each (var type in auraTypes)
+	{
+		if (!this.IsFormationAura(type))
+			continue;
+
+		for each (var ent in memberList)
+		{
+			this.RemoveBonus(type,ent);
+			this[type].targetUnits.splice(this[type].targetUnits.indexOf(ent), 1);
+		}
+	}
+};
+
+Auras.prototype.RemoveGarrisonBonus = function(structure)
+{
+	var auraTypes = this.GetAuraTypes();
+	for each (var type in auraTypes)
+	{
+		if (!this.IsGarrisonAura(type))
+			continue;
+
+		this.RemoveBonus(type,structure);
+		this[type].targetUnits.splice(this[type].targetUnits.indexOf(structure), 1);
+	}
+};
+
+Auras.prototype.RemoveTemplateBonus = function(type)
+{
+	if (!this.IsTemplateAura(type))
+		return;
+
+	var modification = this.GetModification(type);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+	var classes = this.GetClasses(type);
+
+	for each (var value in modification.values)
+		for each (var player in this[type].affectedPlayers)
+			cmpAuraManager.RemoveTemplateBonus(value, player, classes, this.templateName+"/"+type+"/"+value);
+};
+
+Auras.prototype.ApplyBonus = function(type,ent)
+{
+	var modification = this.GetModification(type);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+	
+	for each (value in modification.values)
+		cmpAuraManager.ApplyBonus(value, ent,modification,this.templateName+"/"+type+"/"+value);	
+
+};
+
+Auras.prototype.RemoveBonus = function(type,ent)
+{
+	var modification = this.GetModification(type);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+
+	for each (value in modification.values)
+		cmpAuraManager.RemoveBonus(value, ent, this.templateName+"/"+type+"/"+value);	
+
+};
+
+Auras.prototype.OnOwnershipChanged = function(msg)
+{
+	warn("ownership" +uneval(msg));
+	this.Clean();
+};
+
+Auras.prototype.OnDiplomacyChanged = function(msg)
+{
+	warn("diplo" +uneval(msg));
+	var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
+	if (cmpOwnership && cmpOwnership.GetOwner() == msg.player)
+		this.Clean();
+};
+
+Auras.prototype.OnTechnologyModification = function(msg)
+{
+	if (msg.component =="Auras")
+		this.Clean();
+};
+
 Engine.RegisterComponentType(IID_Auras, "Auras", Auras);
Index: binaries/data/mods/public/simulation/components/Formation.js
===================================================================
--- binaries/data/mods/public/simulation/components/Formation.js	(revision 13803)
+++ binaries/data/mods/public/simulation/components/Formation.js	(working copy)
@@ -12,6 +12,7 @@
 	this.columnar = false; // whether we're travelling in column (vs box) formation
 	this.formationName = "Line Closed";
 	this.rearrange = true; // whether we should rearrange all formation members
+	this.formationMemebersWithAura = []; // Members with a formation aura
 };
 
 Formation.prototype.GetMemberCount = function()
@@ -86,6 +87,13 @@
 	{
 		var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
 		cmpUnitAI.SetFormationController(this.entity);
+		
+		var cmpAuras = Engine.QueryInterface(ent, IID_Auras);
+		if (cmpAuras && cmpAuras.HasFormationAura())
+		{
+			this.formationMemebersWithAura.push(ent);
+			cmpAuras.ApplyFormationBonus(ents);
+		}
 	}
 
 	// Locate this formation controller in the middle of its members
@@ -92,6 +100,7 @@
 	this.MoveToMembersCenter();
 
 	this.ComputeMotionParameters();
+
 };
 
 /**
@@ -109,6 +118,18 @@
 		cmpUnitAI.SetFormationController(INVALID_ENTITY);
 	}
 
+	for each (var ent in this.formationMemebersWithAura)
+	{
+		var cmpAuras = Engine.QueryInterface(ent, IID_Auras);
+		cmpAuras.RemoveFormationBonus(ents);
+
+		// the unit with the aura is also removed from the formation
+		if (ents.indexOf(ent) !== -1)
+			cmpAuras.RemoveFormationBonus(this.members);
+	}
+
+	this.formationMemebersWithAura = this.formationMemebersWithAura.filter(function(e) { return ents.indexOf(e) == -1; });
+
 	// If there's nobody left, destroy the formation
 	if (this.members.length == 0)
 	{
@@ -155,8 +176,16 @@
 		cmpUnitAI.SetFormationController(INVALID_ENTITY);
 	}
 
+	for each (var ent in this.formationMemebersWithAura)
+	{
+		var cmpAuras = Engine.QueryInterface(ent, IID_Auras);
+		cmpAuras.RemoveFormationBonus(this.members);
+	}
+
+
 	this.members = [];
 	this.inPosition = [];
+	this.formationMemebersWithAura = [];
 
 	Engine.DestroyEntity(this.entity);
 };
Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js
===================================================================
--- binaries/data/mods/public/simulation/components/GarrisonHolder.js	(revision 13803)
+++ binaries/data/mods/public/simulation/components/GarrisonHolder.js	(working copy)
@@ -189,6 +189,12 @@
 	if (cmpProductionQueue)
 		cmpProductionQueue.PauseProduction();
 
+	var cmpAura = Engine.QueryInterface(entity, IID_Auras);
+	if (cmpAura && cmpAura.HasGarrisonAura())
+	{
+		cmpAura.ApplyGarrisonBonus(this.entity);	
+	}
+
 	Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {});
 	return true;
 };
@@ -233,6 +239,13 @@
 	var cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
 	if (cmpProductionQueue)
 		cmpProductionQueue.UnpauseProduction();
+
+	var cmpAura = Engine.QueryInterface(entity, IID_Auras);
+	if (cmpAura && cmpAura.HasGarrisonAura())
+	{
+		cmpAura.RemoveGarrisonBonus(this.entity);	
+	}
+
 	
 	var cmpNewPosition = Engine.QueryInterface(entity, IID_Position);
 	cmpNewPosition.JumpTo(pos.x, pos.z);
Index: binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_UnitAI.js	(revision 13803)
+++ binaries/data/mods/public/simulation/components/tests/test_UnitAI.js	(working copy)
@@ -2,6 +2,7 @@
 Engine.LoadHelperScript("Entity.js");
 Engine.LoadHelperScript("Player.js");
 Engine.LoadComponentScript("interfaces/Attack.js");
+Engine.LoadComponentScript("interfaces/Auras.js");
 Engine.LoadComponentScript("interfaces/DamageReceiver.js");
 Engine.LoadComponentScript("interfaces/Formation.js");
 Engine.LoadComponentScript("interfaces/Heal.js");
Index: binaries/data/mods/public/simulation/helpers/Technology.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Technology.js	(revision 13805)
+++ binaries/data/mods/public/simulation/helpers/Technology.js	(working copy)
@@ -3,11 +3,15 @@
 function ApplyTechModificationsToEntity(tech_type, current_value, entity)
 {
 	var cmpTechMan = QueryOwnerInterface(entity, IID_TechnologyManager);
+	if (cmpTechMan)
+		var value = cmpTechMan.ApplyModificationsTemplate(tech_type, current_value, template);
+	else
+		var value = current_value;
 
-	if (!cmpTechMan)
-		return current_value;
-
-	return cmpTechMan.ApplyModifications(tech_type, current_value, entity);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+	if (!cmpAuraManager)
+	    return value;
+	return cmpAuraManager.ApplyModifications(tech_type, value, entity);
 }
 
 function ApplyTechModificationsToPlayer(tech_type, current_value, player_entity)
@@ -23,11 +27,15 @@
 function ApplyTechModificationsToTemplate(tech_type, current_value, playerID, template)
 {
 	var cmpTechMan = QueryPlayerIDInterface(playerID, IID_TechnologyManager);
+	if (cmpTechMan)
+		var value = cmpTechMan.ApplyModificationsTemplate(tech_type, current_value, template);
+	else
+		var value = current_value; 
 
-	if (!cmpTechMan)
-		return current_value;
-
-	return cmpTechMan.ApplyModificationsTemplate(tech_type, current_value, template);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager); 
+	if (!cmpAuraManager)
+		return value; 
+	return cmpAuraManager.ApplyTemplateModifications(tech_type, value, playerID, template);
 }
 
 Engine.RegisterGlobal("ApplyTechModificationsToEntity", ApplyTechModificationsToEntity);
Index: source/simulation2/Simulation2.cpp
===================================================================
--- source/simulation2/Simulation2.cpp	(revision 13803)
+++ source/simulation2/Simulation2.cpp	(working copy)
@@ -122,6 +122,7 @@
 				LOGERROR(L"Can't find component type " L##name); \
 			componentManager.AddComponent(SYSTEM_ENTITY, cid, noParam)
 
+			LOAD_SCRIPTED_COMPONENT("AuraManager");
 			LOAD_SCRIPTED_COMPONENT("AIInterface");
 			LOAD_SCRIPTED_COMPONENT("Barter");
 			LOAD_SCRIPTED_COMPONENT("EndGameManager");
