Index: binaries/data/mods/public/simulation/components/AuraManager.js
===================================================================
--- binaries/data/mods/public/simulation/components/AuraManager.js	(revision 0)
+++ binaries/data/mods/public/simulation/components/AuraManager.js	(working copy)
@@ -0,0 +1,184 @@
+function AuraManager() {}
+
+AuraManager.prototype.Schema = 
+	"<a:component type='system'/><empty/>";
+
+AuraManager.prototype.Init = function()
+{
+	this.modificationCache = {};
+	this.modifications = {};
+	this.templateModificationCache = {};
+	this.templateModifications = {};
+};
+
+AuraManager.prototype.ApplyBonus = function(value, ent, data, key)
+{
+	if (!this.modifications[value])
+	{
+		this.modificationCache[value] = {};
+		this.modifications[value] = {};
+	}	
+	
+	if (!this.modifications[value][ent])
+	{
+		this.modifications[value][ent] = {};
+		this.modificationCache[value][ent] = { "add":0, "multiply":1};
+	}
+
+	if (!this.modifications[value][ent][key])
+		this.modifications[value][ent][key] = [];
+
+	this.modifications[value][ent][key].push(data);
+
+	if (this.modifications[value][ent][key].length > 1)
+		return;
+	// first time added this aura
+	if (data.multiply)
+		this.modificationCache[value][ent].multiply *= data.multiply;
+	
+	if (data.add)
+		this.modificationCache[value][ent].add += data.add;
+
+	// post message to the entity to notify it about the change
+	// TODO with player = -1, this works, but it's ugly. Find a solution
+	var component = value.split("/")[0];
+	Engine.PostMessage(ent, MT_TechnologyModification, { "component": component, "player": -1});
+};
+
+AuraManager.prototype.ApplyTemplateBonus = function(value, player, classes, data, key)
+{
+	if (!this.templateModifications[value])
+	{
+		this.templateModificationCache[value] = {};
+		this.templateModifications[value] = {};
+	}	
+	
+	if (!this.templateModifications[value][player])
+	{
+		this.templateModifications[value][player] = {};
+		this.templateModificationCache[value][player] = {};
+	}
+
+	if (!this.templateModifications[value][player][key])
+		this.templateModifications[value][player][key] = [];
+
+	this.templateModifications[value][player][key].push(data);
+
+	if (this.templateModifications[value][player][key].length > 1)
+		return;
+	
+	// first time added this aura
+	for each (var c in classes)
+	{
+		if (!this.templateModificationCache[value][player][c])
+			this.templateModificationCache[value][player][c] = [];
+
+		if (!this.templateModificationCache[value][player][c][key])
+			this.templateModificationCache[value][player][c][key] = { "add":0, "multiply":1, "numberOfAuras": 1};
+
+		if (data.multiply)
+			this.templateModificationCache[value][player][c][key].multiply *= data.multiply;
+		
+		if (data.add)
+			this.templateModificationCache[value][player][c][key].add += data.add;
+
+
+		// post message to notify about the change
+		var component = value.split("/")[0];
+		Engine.BroadcastMessage(MT_TechnologyModification, { "component": component, "player": player});
+	}
+};
+
+AuraManager.prototype.RemoveBonus = function(value, ent, key)
+{
+	if (!this.modifications[value] || 
+	      !this.modifications[value][ent] || 
+	      !this.modifications[value][ent][key] ||
+	      !this.modifications[value][ent][key].length)
+		return;
+	
+	// get the applied data to remove again
+	var data = this.modifications[value][ent][key].pop();
+
+	if (this.modifications[value][ent][key].length > 0)
+		return;
+	
+	// out of last aura of this kind, remove modifications
+	if (data.add)
+		this.modificationCache[value][ent].add -= data.add;
+
+	if (data.multiply)
+		this.modificationCache[value][ent].multiply /= data.multiply;
+
+	// post message to the entity to notify it about the change
+	// TODO with player = 0, this works, but it's ugly. Find a solution
+	var component = value.split("/")[0];
+	Engine.PostMessage(ent, MT_TechnologyModification, { "component": component, "player": 0});
+	
+	
+};
+
+AuraManager.prototype.RemoveTemplateBonus = function(value, player, classes, key)
+{
+	if (!this.templateModifications[value] || 
+	      !this.templateModifications[value][player] || 
+	      !this.templateModifications[value][player][key] || 
+	      !this.templateModifications[value][player][key].length)
+		return;
+
+	this.templateModifications[value][player][key].pop();
+
+	if (this.templateModifications[value][player][key].length > 0)
+		return;
+
+	for each (var c in classes)
+	{
+		this.templateModificationCache[value][player][c][key].multiply = 1;
+		this.templateModificationCache[value][player][c][key].add = 0;
+
+
+		// post message to notify about the change
+		var component = value.split("/")[0];
+		Engine.BroadcastMessage(MT_TechnologyModification, { "component": component, "player": player});
+	}
+};
+
+AuraManager.prototype.ApplyModifications = function(valueName, value, ent)
+{
+	if (!this.modificationCache[valueName] || !this.modificationCache[valueName][ent])
+		return value;
+
+	value *= this.modificationCache[valueName][ent].multiply;
+	value += this.modificationCache[valueName][ent].add;
+	return value;
+};
+
+AuraManager.prototype.ApplyTemplateModifications = function(valueName, value, player, template)
+{
+	if (!this.templateModificationCache[valueName] || !this.templateModificationCache[valueName][player])
+		return value;
+
+	var classes = template.Identity.Classes._string.split(/\s+/);
+
+	var keyList = [];
+
+	for (var c in this.templateModificationCache[valueName][player])
+	{
+		if (classes.indexOf(c) == -1)
+			continue; 
+
+		for (var key in this.templateModificationCache[valueName][player][c])
+		{
+			// don't add an aura with the same key twice
+			if (keyList.indexOf(key) != -1)
+				continue;
+
+			value *= this.templateModificationCache[valueName][player][c][key].multiply;
+			value += this.templateModificationCache[valueName][player][c][key].add;
+			keyList.push(key);
+		}
+	}
+	return value;
+};
+
+Engine.RegisterComponentType(IID_AuraManager, "AuraManager", AuraManager);
Index: binaries/data/mods/public/simulation/components/Auras.js
===================================================================
--- binaries/data/mods/public/simulation/components/Auras.js	(revision 13977)
+++ binaries/data/mods/public/simulation/components/Auras.js	(working copy)
@@ -2,41 +2,362 @@
 
 Auras.prototype.Schema =
 	"<oneOrMore>" +
-		"<element>" +
-			"<choice>" +
-				"<name>Allure</name>" +
-				"<name>Infidelity</name>" +
-				"<name>Heal</name>" +
-				"<name>Courage</name>" +
-				"<name>Fear</name>" +
-			"</choice>" +
-			"<interleave>" +
-				"<element name='Radius'>" +
+		"<element a:help='Name of the aura JSON file to use, case-insensitive'>" +
+			"<anyName/>" +
+			"<optional>" +
+				"<element name='Radius' a:help='Define the radius this aura affects, if it is a range aura'>" +
 					"<data type='nonNegativeInteger'/>" +
 				"</element>" +
-				"<optional>" +
-					"<element name='Bonus'>" +
-						"<data type='positiveInteger'/>" +
-					"</element>" +
-				"</optional>" +
-				"<optional>" +
-					"<element name='Time'>" +
-						"<data type='nonNegativeInteger'/>" +
-					"</element>" +
-				"</optional>" +
-				"<optional>" +
-					"<element name='Speed'>" +
-						"<data type='positiveInteger'/>" +
-					"</element>" +
-				"</optional>" +
-			"</interleave>" +
+			"</optional>" +
+			"<element name='Type' a:help='Controls how this aura affects nearby units'>" +
+				"<choice>" +
+					"<value a:help='Affects units in the same formation'>formation</value>" +
+					"<value a:help='Affects units in a certain range'>range</value>" +
+					"<value a:help='Affects the structure or unit this unit is garrisoned in'>garrison</value>" +
+					"<value a:help='Affects all units while this unit is alive'>global</value>" +
+				"</choice>" +
+			"</element>" +
 		"</element>" +
 	"</oneOrMore>";
 
-/*
- * TODO: this all needs to be designed and implemented
+Auras.prototype.Init = function()
+{
+	var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
+	this.templateName = cmpTemplateManager.GetCurrentTemplateName(this.entity);
+	var auraNames = this.GetAuraNames();
+	this.auras = {};
+	var cmpTechnologyTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TechnologyTemplateManager);
+	for each (var name in auraNames)
+		this.auras[name] = cmpTechnologyTemplateManager.GetAuraTemplate(name);
+};
+
+Auras.prototype.GetAuraNames = function()
+{
+	return Object.keys(this.template);
+};
+
+Auras.prototype.GetRange = function(name)
+{
+	if (!this.IsRangeAura(name))
+		return undefined;
+	if (this.IsGlobalAura(name))
+		return -1; // -1 is infinite range
+	return +this.template[name].Radius;
+};
+
+Auras.prototype.GetClasses = function(name)
+{
+	return this.auras[name].affects;
+};
+
+Auras.prototype.GetModifications = function(name)
+{
+	return this.auras[name].modifications;
+};
+
+Auras.prototype.GetAffectedPlayers = function(name)
+{
+	if (this.auras[name].affectedPlayers)
+		var affectedPlayers = this.auras[name].affectedPlayers;
+	else
+		var affectedPlayers = ["Player"];
+
+	var ret = [];
+
+	var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
+
+	if (!cmpPlayer)
+		return ret;
+
+	var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
+	var numPlayers = cmpPlayerManager.GetNumPlayers();
+
+	for (var i = 0; i < numPlayers; ++i)
+	{
+		for each (var p in affectedPlayers)
+		{
+			if (p == "Player" ? cmpPlayer.GetPlayerID() == i : cmpPlayer["Is" + p](i))
+			{
+				ret.push(i);
+				break;
+			}
+		}
+	}
+	return ret;
+};
+
+Auras.prototype.HasFormationAura = function()
+{
+	return this.GetAuraNames().some(this.IsFormationAura.bind(this));
+};
+
+Auras.prototype.HasGarrisonAura = function()
+{
+	return this.GetAuraNames().some(this.IsGarrisonAura.bind(this));
+};
+
+Auras.prototype.GetType = function(name)
+{
+	return this.template[name].Type;
+};
+
+Auras.prototype.IsFormationAura = function(name)
+{
+	return this.GetType(name) == "Formation";
+};
+
+Auras.prototype.IsGarrisonAura = function(name)
+{
+	return this.GetType(name) == "GarrisoningStructure";
+};
+
+Auras.prototype.IsRangeAura = function(name)
+{
+	// A global aura is also treated as a range aura with infinite range.
+	return ["range", "global"].indexOf(this.GetType(name)) != -1;
+};
+
+Auras.prototype.IsGlobalAura = function(name)
+{
+	return this.GetType(name) == "global";
+};
+
+/**
+ * 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 auraNames = this.GetAuraNames();
+	// remove all bonuses
+	for each (var name in auraNames)
+	{
+		if (!this[name])
+			continue;
 
-Auras.prototype.Serialize = null; // we have no dynamic state to save
+		if (this.IsGlobalAura(name))
+			this.RemoveTemplateBonus(name);
 
+		for each(var ent in this[name].targetUnits)
+			this.RemoveBonus(name, ent);
+
+		if (this[name].rangeQuery)
+			cmpRangeManager.DestroyActiveQuery(this[name].rangeQuery);
+	}
+
+	for each (var name in auraNames)
+	{
+		// initialise range query
+		this[name] = {};
+		this[name].targetUnits = [];
+		var affectedPlayers = this.GetAffectedPlayers(name);
+
+		if (!affectedPlayers.length)
+			continue;
+
+		if (this.IsGlobalAura(name))
+			this.ApplyTemplateBonus(name, affectedPlayers);
+
+		if (!this.IsRangeAura(name))
+			continue;
+		this[name].rangeQuery = cmpRangeManager.CreateActiveQuery(
+		    this.entity,
+		    0,
+		    this.GetRange(name),
+		    affectedPlayers,
+		    IID_Identity,
+		    cmpRangeManager.GetEntityFlagMask("normal")
+		);
+		cmpRangeManager.EnableActiveQuery(this[name].rangeQuery);
+		// Add self to your own query for consistency with templates.
+		this.OnRangeUpdate({"tag":this[name].rangeQuery, "added":[this.entity], "removed":[]});
+	}
+};
+
+Auras.prototype.GiveMembersWithValidClass = function(auraName, entityList)
+{
+	var validClasses = this.GetClasses(auraName);
+	var r = [];
+	for each (var ent in entityList)
+	{
+		var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
+		var targetClasses = cmpIdentity.GetClassesList();
+		for each (var classCollection in validClasses)
+		{
+			if (classCollection.split(/\s+/).every(function(c) {return targetClasses.indexOf(c) > -1}))
+			{
+				r.push(ent);
+				break;
+			}
+		}
+	}
+	return r;
+}
+
+Auras.prototype.OnRangeUpdate = function(msg)
+{
+	var auraNames = this.GetAuraNames();
+	for each (var n in auraNames)
+	{
+		if (msg.tag == this[n].rangeQuery)
+		{
+			var name = n;
+			break;
+		}
+	}
+
+	if (!name)
+		return;
+
+	var targetUnits = this[name].targetUnits;
+	var classes = this.GetClasses(name);
+
+	if (msg.added.length > 0)
+	{
+		var validList = this.GiveMembersWithValidClass(name, msg.added);
+		for each (var e in validList)
+		{
+			targetUnits.push(e);
+			this.ApplyBonus(name, e);
+		}
+	}
+
+	if (msg.removed.length > 0)
+	{
+		for each (var e in msg.removed)
+		{
+			targetUnits.splice(targetUnits.indexOf(e), 1);
+			this.RemoveBonus(name, e);
+		}
+	}
+
+};
+
+Auras.prototype.ApplyFormationBonus = function(memberList)
+{
+	var auraNames = this.GetAuraNames();
+	for each (var name in auraNames)
+	{
+		if (!this.IsFormationAura(name))
+			continue;
+
+		var validList = this.GiveMembersWithValidClass(name, memberList);
+		for each (var ent in validList)
+		{
+			targetUnits.push(e);
+			this.ApplyBonus(name,e);
+		}
+	}
+};
+
+Auras.prototype.ApplyGarrisonBonus = function(structure)
+{
+	var auraNames = this.GetAuraNames();
+	for each (var name in auraNames)
+	{
+		if (!this.IsGarrisonAura(name))
+			continue;
+
+		var validList = this.GiveMembersWithValidClass(name, [structure]);
+		if (validList.length)
+		{
+			targetUnits.push(validList[0]);
+			this.ApplyBonus(name,validList[0]);
+		}
+	}
+};
+
+Auras.prototype.ApplyTemplateBonus = function(name, players)
+{
+	if (!this.IsGlobalAura(name))
+		return;
+	var modifications = this.GetModifications(name);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+	var classes = this.GetClasses(name);
+
+	for each (var mod in modifications)
+		for each (var player in players)
+			cmpAuraManager.ApplyTemplateBonus(mod.value, player, classes, mod, this.templateName + "/" + name + "/" + mod.value);
+};
+
+Auras.prototype.RemoveFormationBonus = function(memberList)
+{
+	var auraNames = this.GetAuraNames();
+	for each (var name in auraName)
+	{
+		if (!this.IsFormationAura(name))
+			continue;
+
+		for each (var ent in memberList)
+		{
+			this.RemoveBonus(name,ent);
+			this[name].targetUnits.splice(this[name].targetUnits.indexOf(ent), 1);
+		}
+	}
+};
+
+Auras.prototype.RemoveGarrisonBonus = function(structure)
+{
+	var auraNames = this.GetAuraNames();
+	for each (var name in auraNames)
+	{
+		if (!this.IsGarrisonAura(name))
+			continue;
+
+		this.RemoveBonus(name,structure);
+		this[name].targetUnits.splice(this[name].targetUnits.indexOf(structure), 1);
+	}
+};
+
+Auras.prototype.RemoveTemplateBonus = function(name)
+{
+	if (!this.IsGlobalAura(name))
+		return;
+
+	var modifications = this.GetModifications(name);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+	var classes = this.GetClasses(name);
+
+	for each (var mod in modifications)
+		for each (var player in this.GetAffectedPlayers())
+			cmpAuraManager.RemoveTemplateBonus(mod.value, player, classes, this.templateName + "/" + name + "/" + mod.value);
+};
+
+Auras.prototype.ApplyBonus = function(name, ent)
+{
+	var modifications = this.GetModifications(name);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+
+	for each (mod in modifications)
+		cmpAuraManager.ApplyBonus(mod.value, ent, mod, this.templateName + "/" + name + "/" + mod.value);
+
+};
+
+Auras.prototype.RemoveBonus = function(name, ent)
+{
+	var modifications = this.GetModifications(name);
+	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+
+	for each (mod in modifications)
+		cmpAuraManager.RemoveBonus(mod.value, ent, this.templateName + "/" + name + "/" + mod.value);
+};
+
+Auras.prototype.OnOwnershipChanged = function(msg)
+{
+	this.Clean();
+};
+
+Auras.prototype.OnDiplomacyChanged = function(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/EndGameManager.js
===================================================================
--- binaries/data/mods/public/simulation/components/EndGameManager.js	(revision 13977)
+++ binaries/data/mods/public/simulation/components/EndGameManager.js	(working copy)
@@ -19,6 +19,7 @@
 	// Allied victory means allied players can win if victory conditions are met for each of them
 	// Would be false for a "last man standing" game (when diplomacy is fully implemented)
 	this.alliedVictory = true;
+	this.activePlayers = [];
 };
 
 EndGameManager.prototype.SetGameType = function(newGameType)
@@ -31,103 +32,56 @@
 	this.alliedVictory = flag;
 };
 
-/**
- * Begin checking the end-game conditions.
- * Must be called once, after calling SetGameType.
- */
-EndGameManager.prototype.Start = function()
+EndGameManager.prototype.OnUpdate = function()
 {
-	if (this.gameType != "endless")
+	if (this.gameType == "endless")
+		return;
+	// initialise the activePlayers array on the start of the game 
+	if (!this.activePlayers.length)
 	{
-		var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
-		this.timer = cmpTimer.SetTimeout(this.entity, IID_EndGameManager, "ProgressTimeout", g_ProgressInterval, {});
+		this.UpdatePlayerStates();
+		return;
 	}
-};
 
-EndGameManager.prototype.OnDestroy = function()
-{
-	if (this.timer)
-	{
-		var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
-		cmpTimer.CancelTimer(this.timer);
-	}
-};
+	if (!this.activePlayers.every(function(v){return v.GetConquestCriticalEntitiesCount()}))
+		this.UpdatePlayerStates();
+}
 
-EndGameManager.prototype.ProgressTimeout = function(data)
+EndGameManager.prototype.UpdatePlayerStates = function()
 {
-	this.UpdatePlayerStates();
-	
-	// Repeat the timer
-	var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
-	this.timer = cmpTimer.SetTimeout(this.entity, IID_EndGameManager, "ProgressTimeout", g_ProgressInterval, data);
-};
+	if (this.gameType == "endless")
+		return;
 
-EndGameManager.prototype.UpdatePlayerStates = function()
-{
 	var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
-	switch (this.gameType)
+	var numPlayers = cmpPlayerManager.GetNumPlayers();
+	this.activePlayers = [];
+
+	// get all the active players (or won). Defeat players without the needed entities
+	for (var i = 1; i < numPlayers; ++i)
 	{
-	case "conquest":
+		var playerEntity = cmpPlayerManager.GetPlayerByID(i);
+		var cmpPlayer = Engine.QueryInterface(playerEntity, IID_Player);
+		if (cmpPlayer.GetState() == "defeated")
+			continue;
+		if (cmpPlayer.GetConquestCriticalEntitiesCount())
+			this.activePlayers.push(cmpPlayer);
+		else
+			Engine.PostMessage(playerEntity, MT_PlayerDefeated);
+	}
 
-		// Ignore gaia
-		var numPlayers = cmpPlayerManager.GetNumPlayers() - 1;
-		var cmpPlayers = new Array(numPlayers);
-		
-		// If a player is currently active but has no suitable units left,
-		// mark that player as defeated
-		for (var i = 0; i < numPlayers; i++)
-		{
-			var playerEntityId = cmpPlayerManager.GetPlayerByID(i+1);
-			cmpPlayers[i] = Engine.QueryInterface(playerEntityId, IID_Player);
-			if (cmpPlayers[i].GetState() == "active")
-			{
-				if (cmpPlayers[i].GetConquestCriticalEntitiesCount() == 0)
-				{	// Defeated - notify AIs by sending playerId
-					Engine.PostMessage(playerEntityId, MT_PlayerDefeated, { "playerId": i } );
-				}
-			}
-		}
+	if (!this.alliedVictory && this.activePlayers.length > 1)
+		return;
 
-		var onlyAlliesLeft = true;
-		var allies = [];
-		for (var i = 0; i < numPlayers && onlyAlliesLeft; i++)
-		{
-			if (cmpPlayers[i].GetState() == "active")
-			{	//Active player
-				for (var j = 0; j < numPlayers && onlyAlliesLeft; j++)
-				{
-					if (cmpPlayers[j].GetState() == "active"
-						&& (cmpPlayers[i].IsEnemy(j+1) || cmpPlayers[j].IsEnemy(i+1)
-						    || cmpPlayers[i].IsNeutral(j+1) || cmpPlayers[j].IsNeutral(i+1)))
-					{	// Only need to find an active non-allied player
-						onlyAlliesLeft = false;
-					}
-				}
-				
-				if (onlyAlliesLeft)
-					allies.push(i);
-			}
-		}
+	for each (var cmpPlayer in this.activePlayers)
+	{
+		if (!this.activePlayers.every(function(v){return cmpPlayer == v || cmpPlayer.IsMutualAlly(v.GetPlayerID())}))
+			return;
+	}
 
-		// If only allies left and allied victory set (or only one player left)
-		if (onlyAlliesLeft && (this.alliedVictory || allies.length == 1))
-		{
-			for each (var p in allies)
-			{
-				cmpPlayers[p].SetState("won");
-			}
-
-			// Reveal the map to all players
-			var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
-			cmpRangeManager.SetLosRevealAll(-1, true);
-		}
-
-		break;
-
-	default:
-		error("Invalid game type "+this.gameType);
-		break;
-	}
+	var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+	cmpRangeManager.SetLosRevealAll(-1, true);
+	for each (var cmpPlayer in this.activePlayers)
+		cmpPlayer.SetState("won");
 };
 
 Engine.RegisterComponentType(IID_EndGameManager, "EndGameManager", EndGameManager);
Index: binaries/data/mods/public/simulation/components/Formation.js
===================================================================
--- binaries/data/mods/public/simulation/components/Formation.js	(revision 13977)
+++ 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 13977)
+++ binaries/data/mods/public/simulation/components/GarrisonHolder.js	(working copy)
@@ -185,6 +185,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;
 };
@@ -228,6 +234,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/TechnologyTemplateManager.js
===================================================================
--- binaries/data/mods/public/simulation/components/TechnologyTemplateManager.js	(revision 13977)
+++ binaries/data/mods/public/simulation/components/TechnologyTemplateManager.js	(working copy)
@@ -9,6 +9,7 @@
 TechnologyTemplateManager.prototype.Init = function()
 {
 	this.allTechs = {};
+	this.allAuras = {};
 	var techNames = this.ListAllTechs();
 	for (var i in techNames)
 		this.GetTemplate(techNames[i]);
@@ -26,6 +27,18 @@
 	return this.allTechs[template];
 };
 
+TechnologyTemplateManager.prototype.GetAuraTemplate = function(template)
+{
+	if (!this.allAuras[template])
+	{
+		this.allAuras[template] = Engine.ReadJSONFile("auras/" + template + ".json");
+		if (! this.allAuras[template])
+			error("Failed to load aura \"" + template + "\"");
+	}
+	
+	return this.allAuras[template];
+};
+
 TechnologyTemplateManager.prototype.ListAllTechs = function()
 {
     return Engine.FindJSONFiles("technologies", true);
Index: binaries/data/mods/public/simulation/components/interfaces/AuraManager.js
===================================================================
--- binaries/data/mods/public/simulation/components/interfaces/AuraManager.js	(revision 0)
+++ binaries/data/mods/public/simulation/components/interfaces/AuraManager.js	(working copy)
@@ -0,0 +1 @@
+Engine.RegisterInterface("AuraManager");
Index: binaries/data/mods/public/simulation/components/tests/test_UnitAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_UnitAI.js	(revision 13977)
+++ 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/Setup.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Setup.js	(revision 13977)
+++ binaries/data/mods/public/simulation/helpers/Setup.js	(working copy)
@@ -41,7 +41,6 @@
 	{
 		cmpEndGameManager.SetGameType(settings.GameType);
 	}
-	cmpEndGameManager.Start();
 }
 
 Engine.RegisterGlobal("LoadMapSettings", LoadMapSettings);
Index: binaries/data/mods/public/simulation/helpers/Technology.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Technology.js	(revision 13977)
+++ 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, entity);
+	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: binaries/data/mods/public/simulation/templates/gaia/fauna_chicken.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/gaia/fauna_chicken.xml	(revision 13977)
+++ binaries/data/mods/public/simulation/templates/gaia/fauna_chicken.xml	(working copy)
@@ -15,7 +15,7 @@
   <ResourceSupply>
     <Amount>40</Amount>
     <Type>food.meat</Type>
-	<MaxGatherers>5</MaxGatherers>
+    <MaxGatherers>5</MaxGatherers>
   </ResourceSupply>
   <Sound>
     <SoundGroups>
Index: binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml	(revision 13977)
+++ binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml	(working copy)
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Entity parent="template_structure_civic">
   <Auras>
-    <Heal>
-      <Radius>40</Radius>
-      <Speed>1000</Speed>
-    </Heal>
+    <heal>
+      <Type>range</Type>
+      <Radius>10</Radius>
+    </heal>
   </Auras>
   <BuildRestrictions>
     <Category>Temple</Category>
Index: binaries/data/mods/public/simulation/templates/template_unit_fauna_herd.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_fauna_herd.xml	(revision 13977)
+++ binaries/data/mods/public/simulation/templates/template_unit_fauna_herd.xml	(working copy)
@@ -1,11 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Entity parent="template_unit_fauna">
-  <Auras>
-    <Infidelity>
-      <Radius>20</Radius>
-      <Time>0</Time>
-    </Infidelity>
-  </Auras>
   <Health>
     <DeathType>remain</DeathType>
   </Health>
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 13977)
+++ binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml	(working copy)
@@ -16,15 +16,6 @@
       <MaxRange>4.0</MaxRange>
     </Slaughter>
   </Attack>
-  <Auras>
-    <Allure>
-      <Radius>25</Radius>
-    </Allure>
-    <Infidelity>
-      <Radius>10</Radius>
-      <Time>10</Time>
-    </Infidelity>
-  </Auras>
   <Builder>
     <Rate>1.0</Rate>
     <Entities datatype="tokens">
Index: source/simulation2/Simulation2.cpp
===================================================================
--- source/simulation2/Simulation2.cpp	(revision 13958)
+++ source/simulation2/Simulation2.cpp	(working copy)
@@ -125,6 +125,7 @@
 				LOGERROR(L"Can't find component type " L##name); \
 			componentManager.AddComponent(systemEntity, cid, noParam)
 
+			LOAD_SCRIPTED_COMPONENT("AuraManager");
 			LOAD_SCRIPTED_COMPONENT("AIInterface");
 			LOAD_SCRIPTED_COMPONENT("Barter");
 			LOAD_SCRIPTED_COMPONENT("EndGameManager");
