Index: binaries/data/mods/public/simulation/components/AuraManager.js
===================================================================
--- binaries/data/mods/public/simulation/components/AuraManager.js	(révision 19081)
+++ binaries/data/mods/public/simulation/components/AuraManager.js	(copie de travail)
@@ -7,10 +7,26 @@ AuraManager.prototype.Init = function()
 {
 	this.modificationsCache = new Map();
 	this.modifications = new Map();
 	this.templateModificationsCache = new Map();
 	this.templateModifications = new Map();
+
+	this.globalAuraGivers = [];
+};
+
+
+AuraManager.prototype.RegisterGlobalAuraGiver = function(ent)
+{
+	if (this.globalAuraGivers.indexOf(ent) == -1)
+		this.globalAuraGivers.push(ent);
+};
+
+AuraManager.prototype.UnregisterGlobalAuraGiver = function(ent)
+{
+	let idx = this.globalAuraGivers.indexOf(ent);
+	if (idx != -1)
+		this.globalAuraGivers.splice(idx, 1);
 };
 
 AuraManager.prototype.ensureExists = function(name, value, id, key, defaultData)
 {
 	var cacheName = name + "Cache";
@@ -228,6 +244,16 @@ AuraManager.prototype.ApplyTemplateModif
 		}
 	}
 	return value * multiply + add;
 };
 
+AuraManager.prototype.OnGlobalOwnershipChanged = function(msg)
+{
+	for (let ent of this.globalAuraGivers)
+	{
+		let cmpAuras = Engine.QueryInterface(ent, IID_Auras);
+		if (cmpAuras)
+			cmpAuras.RegisterGlobalOwnershipChanged(msg);
+	}
+};
+
 Engine.RegisterSystemComponentType(IID_AuraManager, "AuraManager", AuraManager);
Index: binaries/data/mods/public/simulation/components/Auras.js
===================================================================
--- binaries/data/mods/public/simulation/components/Auras.js	(révision 19081)
+++ binaries/data/mods/public/simulation/components/Auras.js	(copie de travail)
@@ -58,15 +58,13 @@ Auras.prototype.GetAffectedEntities = fu
 	return this[name].targetUnits;
 };
 
 Auras.prototype.GetRange = function(name)
 {
-	if (!this.IsRangeAura(name))
-		return undefined;
-	if (this.IsGlobalAura(name))
-		return -1; // -1 is infinite range
-	return +this.auras[name].radius;
+	if (this.IsRangeAura(name))
+		return +this.auras[name].radius;
+	return undefined;
 };
 
 Auras.prototype.GetClasses = function(name)
 {
 	return this.auras[name].affects;
@@ -152,12 +150,11 @@ Auras.prototype.IsGarrisonedUnitsAura =
 	return this.GetType(name) == "garrisonedUnits";
 };
 
 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;
+	return this.GetType(name) == "range";
 };
 
 Auras.prototype.IsGlobalAura = function(name)
 {
 	return this.GetType(name) == "global";
@@ -202,24 +199,32 @@ Auras.prototype.Clean = function()
 		var affectedPlayers = this.GetAffectedPlayers(name);
 
 		if (!affectedPlayers.length)
 			continue;
 
-		if (!this.IsRangeAura(name))
+		if (this.IsGlobalAura(name))
 		{
-			this.ApplyBonus(name, targetUnitsClone[name]);
+			for (let player of affectedPlayers)
+			{
+				this.ApplyTemplateBonus(name, affectedPlayers);
+				// When only Player class affected, we do not need a rangeQuery as applicable only to player entity
+				// and templates TODO maybe add a new type "player"
+				if (this.GetClasses(name).length == 1 && this.GetClasses(name)[0] == "Player")
+				{
+					let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
+					let playerEnts = affectedPlayers.map(player => cmpPlayerManager.GetPlayerByID(player));
+					this.ApplyBonus(name, playerEnts);
+				}
+				else
+					this.ApplyBonus(name, cmpRangeManager.GetEntitiesByPlayer(player));
+			}
 			continue;
 		}
 
-		// When only Player class affected, we do not need a rangeQuery as applicable only to player entity
-		// and templates TODO maybe add a new type "player"
-		if (this.IsGlobalAura(name) && this.GetClasses(name).length == 1 && this.GetClasses(name)[0] == "Player")
+		if (!this.IsRangeAura(name))
 		{
-			this.ApplyTemplateBonus(name, affectedPlayers);
-			let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
-			let playerEnts = affectedPlayers.map(player => cmpPlayerManager.GetPlayerByID(player));
-			this.ApplyBonus(name, playerEnts);
+			this.ApplyBonus(name, targetUnitsClone[name]);
 			continue;
 		}
 
 		this[name].rangeQuery = cmpRangeManager.CreateActiveQuery(
 		    this.entity,
@@ -228,22 +233,10 @@ Auras.prototype.Clean = function()
 		    affectedPlayers,
 		    IID_Identity,
 		    cmpRangeManager.GetEntityFlagMask("normal")
 		);
 		cmpRangeManager.EnableActiveQuery(this[name].rangeQuery);
-
-		if (this.IsGlobalAura(name))
-		{
-			this.ApplyTemplateBonus(name, affectedPlayers);
-
-			// 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)
 {
@@ -272,10 +265,25 @@ Auras.prototype.OnGarrisonedUnitsChanged
 		this.ApplyBonus(name, msg.added);
 		this.RemoveBonus(name, msg.removed);
 	}
 };
 
+Auras.prototype.RegisterGlobalOwnershipChanged = function(msg)
+{
+	let auraNames = this.GetAuraNames().filter(n => this.IsGlobalAura(n));
+	for (let name of auraNames)
+	{
+		let affectedPlayers = this.GetAffectedPlayers(name);
+		let wasApplied = affectedPlayers.indexOf(msg.from) != -1;
+		let willBeApplied = affectedPlayers.indexOf(msg.to) != -1;
+		if (wasApplied && !willBeApplied)
+			this.RemoveBonus(name, [msg.entity]);
+		if (willBeApplied && !wasApplied)
+			this.ApplyBonus(name, [msg.entity]);
+	}
+};
+
 Auras.prototype.ApplyFormationBonus = function(memberList)
 {
 	var auraNames = this.GetAuraNames().filter(n => this.IsFormationAura(n));
 	for (let name of auraNames)
 		this.ApplyBonus(name, memberList);
@@ -297,10 +305,12 @@ Auras.prototype.ApplyTemplateBonus = fun
 		return;
 	var modifications = this.GetModifications(name);
 	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
 	var classes = this.GetClasses(name);
 
+	cmpAuraManager.RegisterGlobalAuraGiver(this.entity);
+
 	for (let mod of modifications)
 		for (let player of players)
 			cmpAuraManager.ApplyTemplateBonus(mod.value, player, classes, mod, this.GetModifierIdentifier(name));
 };
 
@@ -323,12 +333,14 @@ Auras.prototype.RemoveTemplateBonus = fu
 	if (!this[name].isApplied)
 		return;
 	if (!this.IsGlobalAura(name))
 		return;
 
-	var modifications = this.GetModifications(name);
 	var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+	cmpAuraManager.UnregisterGlobalAuraGiver(this.entity);
+
+	var modifications = this.GetModifications(name);
 	var classes = this.GetClasses(name);
 	var players = this.GetAffectedPlayers(name);
 
 	for (let mod of modifications)
 		for (let player of players)
Index: binaries/data/mods/public/simulation/components/tests/test_Auras.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Auras.js	(révision 19081)
+++ binaries/data/mods/public/simulation/components/tests/test_Auras.js	(copie de travail)
@@ -4,39 +4,41 @@ Engine.LoadComponentScript("interfaces/A
 Engine.LoadComponentScript("interfaces/AuraManager.js");
 Engine.LoadComponentScript("interfaces/TechnologyManager.js");
 Engine.LoadComponentScript("Auras.js");
 Engine.LoadComponentScript("AuraManager.js");
 
-let playerID = 1;
-let playerEnt = 10;
-let auraEnt = 20;
+let playerID = [0, 1, 2];
+let playerEnt = [10, 11, 12];
+let giverEnt = 20;
 let targetEnt = 30;
 let auraRange = 40;
 let template = { "Identity" : { "Classes" : { "_string" : "CorrectClass OtherClass" } } };
 
 function testAuras(name, test_function)
 {
 	ResetState();
 
 	AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
-		"GetPlayerByID": () => playerEnt,
-		"GetNumPlayers": () => 2,
+		"GetPlayerByID": idx => playerEnt[idx],
+		"GetNumPlayers": () => 3,
 	});
 
 	AddMock(SYSTEM_ENTITY, IID_RangeManager, {
 		"CreateActiveQuery": (ent, minRange, maxRange, players, iid, flags) => 1,
 		"EnableActiveQuery": id => {},
 		"ResetActiveQuery": id => {},
 		"DisableActiveQuery": id => {},
 		"DestroyActiveQuery": id => {},
 		"GetEntityFlagMask": identifier => {},
+		"GetEntitiesByPlayer": id => [30, 31, 32]
 	});
 
 	AddMock(SYSTEM_ENTITY, IID_DataTemplateManager, {
 		"GetAuraTemplate": (name) => {
 			let template = {
 				"type": name,
+				"affectedPlayers": ["Ally"],
 				"affects": ["CorrectClass"],
 				"modifications": [{ "value": "Component/Value", "add": 10 }],
 				"auraName": "name",
 				"auraDescription": "description"
 			};
@@ -44,68 +46,82 @@ function testAuras(name, test_function)
 				template.radius = auraRange;
 			return template;
 		}
 	});
 
-	AddMock(playerEnt, IID_Player, {
+	AddMock(playerEnt[1], IID_Player, {
 		"IsAlly": id => id == 1,
 		"IsEnemy": id => id != 1,
-		"GetPlayerID": () => 1,
+		"GetPlayerID": () => playerID[1],
 	});
 
 	AddMock(targetEnt, IID_Identity, {
 		"GetClassesList": () => ["CorrectClass", "OtherClass"],
 	});
 
-	AddMock(auraEnt, IID_Position, {
-		"GetPosition2D": () => new Vector2D(),
+	AddMock(giverEnt, IID_Position, {
+		"GetPosition2D": () => new Vector2D()
 	});
 
 	AddMock(targetEnt, IID_Position, {
-		"GetPosition2D": () => new Vector2D(),
+		"GetPosition2D": () => new Vector2D()
 	});
 
-	AddMock(auraEnt, IID_Ownership, {
-		"GetOwner": () => 1,
+	if (playerEnt.indexOf(giverEnt) == -1)
+	{
+		AddMock(giverEnt, IID_Ownership, {
+			"GetOwner": () => playerID[1]
+		});
+	}
+
+	AddMock(targetEnt, IID_Ownership, {
+		"GetOwner": () => playerID[1]
 	});
 
 	ConstructComponent(SYSTEM_ENTITY, "AuraManager", {});
-	let cmpAuras = ConstructComponent(auraEnt, "Auras", { "_string": name });
+	let cmpAuras = ConstructComponent(giverEnt, "Auras", { "_string": name });
 	test_function(name, cmpAuras);
 }
 
 testAuras("global", (name, cmpAuras) => {
-	cmpAuras.OnRangeUpdate({ "tag": 1, "added": [targetEnt], "removed": [] });
-	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);
-	TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 1, playerID, template), 11);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 5, playerID[1], template), 15);
+});
+
+giverEnt = 11;
+testAuras("global", (name, cmpAuras) => {
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 5, playerID[1], template), 15);
 });
 
+// Test the case when the aura giver is a player entity.
+giverEnt = 20;
 testAuras("range", (name, cmpAuras) => {
 	cmpAuras.OnRangeUpdate({ "tag": 1, "added": [targetEnt], "removed": [] });
-	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);
-	TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 1, playerID, template), 1);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 5, playerID[1], template), 5);
 	cmpAuras.OnRangeUpdate({ "tag": 1, "added": [], "removed": [targetEnt] });
-	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 1);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 5);
 });
 
 testAuras("garrisonedUnits", (name, cmpAuras) => {
 	cmpAuras.OnGarrisonedUnitsChanged({ "added" : [targetEnt], "removed": [] });
-	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15);
 	cmpAuras.OnGarrisonedUnitsChanged({ "added" : [], "removed": [targetEnt] });
-	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 1);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 5);
 });
 
 testAuras("garrison", (name, cmpAuras) => {
 	TS_ASSERT_EQUALS(cmpAuras.HasGarrisonAura(), true);
 	cmpAuras.ApplyGarrisonBonus(targetEnt);
-	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15);
 	cmpAuras.RemoveGarrisonBonus(targetEnt);
 	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 1);
 });
 
 testAuras("formation", (name, cmpAuras) => {
 	TS_ASSERT_EQUALS(cmpAuras.HasFormationAura(), true);
 	cmpAuras.ApplyFormationBonus([targetEnt]);
-	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15);
 	cmpAuras.RemoveFormationBonus([targetEnt]);
-	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 1);
+	TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 5);
 });
Index: binaries/data/mods/public/simulation/data/auras/maur_hero_ashoka.json
===================================================================
--- binaries/data/mods/public/simulation/data/auras/maur_hero_ashoka.json	(révision 19081)
+++ binaries/data/mods/public/simulation/data/auras/maur_hero_ashoka.json	(copie de travail)
@@ -5,10 +5,13 @@
 		{ "value": "ProductionQueue/TechCostMultiplier/wood", "multiply": 0.5 },
 		{ "value": "ProductionQueue/TechCostMultiplier/food", "multiply": 0.5 },
 		{ "value": "ProductionQueue/TechCostMultiplier/metal", "multiply": 0.5 },
 		{ "value": "ProductionQueue/TechCostMultiplier/stone", "multiply": 0.5 },
 		{ "value": "ProductionQueue/TechCostMultiplier/time", "multiply": 0.5 }
+		{ "value": "Cost/BuildTime", "multiply": 0.5 },
+		{ "value": "Cost/Resources/stone", "multiply": 0.5 },
+		{ "value": "Cost/Resources/wood", "multiply": 0.5 }
 	],
-	"auraDescription": "All player temple technologies -50% cost and -50% research time.",
+	"auraDescription": "Temples and temple technologies -50% cost, in resources and time.",
 	"auraName": "Buddhism Aura",
 	"overlayIcon": "art/textures/ui/session/auras/build_bonus.png"
 }
Index: binaries/data/mods/public/simulation/data/auras/teambonuses/maur_player_teambonus.json
===================================================================
--- binaries/data/mods/public/simulation/data/auras/teambonuses/maur_player_teambonus.json	(nonexistent)
+++ binaries/data/mods/public/simulation/data/auras/teambonuses/maur_player_teambonus.json	(copie de travail)
@@ -0,0 +1,17 @@
+{
+	"type": "global",
+	"affects": ["Temple"],
+	"affectedPlayers": ["ExclusiveMutualAlly"],
+	"modifications": [
+		{ "value": "ProductionQueue/TechCostMultiplier/wood", "multiply": 0.5 },
+		{ "value": "ProductionQueue/TechCostMultiplier/food", "multiply": 0.5 },
+		{ "value": "ProductionQueue/TechCostMultiplier/metal", "multiply": 0.5 },
+		{ "value": "ProductionQueue/TechCostMultiplier/stone", "multiply": 0.5 },
+		{ "value": "ProductionQueue/TechCostMultiplier/time", "multiply": 0.5 },
+		{ "value": "Cost/BuildTime", "multiply": 0.5 },
+		{ "value": "Cost/Resources/stone", "multiply": 0.5 },
+		{ "value": "Cost/Resources/wood", "multiply": 0.5 }
+	],
+	"auraName": "Ashoka's Religious Support",
+	"auraDescription": "Allied temples and temple technologies -50% cost, in resources and time."
+}
Index: binaries/data/mods/public/simulation/templates/special/player_maur.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/special/player_maur.xml	(nonexistent)
+++ binaries/data/mods/public/simulation/templates/special/player_maur.xml	(copie de travail)
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Entity parent="special/player">
+  <Auras datatype="tokens">teambonuses/maur_player_teambonus</Auras>
+</Entity>
