Index: ps/trunk/binaries/data/mods/public/simulation/components/AuraManager.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/AuraManager.js (revision 19091)
+++ ps/trunk/binaries/data/mods/public/simulation/components/AuraManager.js (revision 19092)
@@ -1,233 +1,258 @@
function AuraManager() {}
AuraManager.prototype.Schema =
"";
AuraManager.prototype.Init = function()
{
this.modificationsCache = new Map();
this.modifications = new Map();
this.templateModificationsCache = new Map();
this.templateModifications = new Map();
+
+ this.globalAuraSources = [];
+};
+
+AuraManager.prototype.RegisterGlobalAuraSource = function(ent)
+{
+ if (this.globalAuraSources.indexOf(ent) == -1)
+ this.globalAuraSources.push(ent);
+};
+
+AuraManager.prototype.UnregisterGlobalAuraSource = function(ent)
+{
+ let idx = this.globalAuraSources.indexOf(ent);
+ if (idx != -1)
+ this.globalAuraSources.splice(idx, 1);
};
AuraManager.prototype.ensureExists = function(name, value, id, key, defaultData)
{
var cacheName = name + "Cache";
var v = this[name].get(value);
if (!v)
{
v = new Map();
this[name].set(value, v);
this[cacheName].set(value, new Map());
}
var i = v.get(id);
if (!i)
{
i = new Map();
v.set(id, i);
this[cacheName].get(value).set(id, defaultData);
}
var k = i.get(key);
if (!k)
{
k = {};
i.set(key, k);
}
return k;
};
AuraManager.prototype.ApplyBonus = function(value, ents, newData, key)
{
for (let ent of ents)
{
var data = this.ensureExists("modifications", value, ent, key, { "add":0, "multiply":1 });
if (data.count)
{
// this aura is already applied and the bonus shouldn't be given twice,
// just count the number of times it is applied
data.count++;
continue;
}
// first time added this aura
data.multiply = newData.multiply;
data.add = newData.add;
data.count = 1;
if (data.add)
this.modificationsCache.get(value).get(ent).add += data.add;
if (data.multiply)
this.modificationsCache.get(value).get(ent).multiply *= data.multiply;
// post message to the entity to notify it about the change
Engine.PostMessage(ent, MT_ValueModification, {
"entities": [ent],
"component": value.split("/")[0],
"valueNames": [value]
});
}
};
AuraManager.prototype.ApplyTemplateBonus = function(value, player, classes, newData, key)
{
var data = this.ensureExists("templateModifications", value, player, key, new Map());
if (data.count)
{
// this aura is already applied and the bonus shouldn't be given twice,
// just count the number of times it is applied
data.count++;
return;
}
// first time added this aura
data.multiply = newData.multiply;
data.add = newData.add;
data.count = 1;
let cache = this.templateModificationsCache.get(value).get(player);
if (!cache.get(classes))
cache.set(classes, new Map());
if (!cache.get(classes).get(key))
cache.get(classes).set(key, { "add": 0, "multiply": 1 });
if (data.add)
cache.get(classes).get(key).add += data.add;
if (data.multiply)
cache.get(classes).get(key).multiply *= data.multiply;
Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, {
"player": player,
"component": value.split("/")[0],
"valueNames": [value]
});
};
AuraManager.prototype.RemoveBonus = function(value, ents, key)
{
var v = this.modifications.get(value);
if (!v)
return;
for (let ent of ents)
{
var e = v.get(ent);
if (!e)
continue;
var data = e.get(key);
if (!data || !data.count)
continue;
data.count--;
if (data.count > 0)
continue;
// out of last aura of this kind, remove modifications
if (data.add)
this.modificationsCache.get(value).get(ent).add -= data.add;
if (data.multiply)
this.modificationsCache.get(value).get(ent).multiply /= data.multiply;
// clean up the object
e.delete(key);
if (e.size == 0)
v.delete(ent);
// post message to the entity to notify it about the change
Engine.PostMessage(ent, MT_ValueModification, {
"entities": [ent],
"component": value.split("/")[0],
"valueNames": [value]
});
}
};
AuraManager.prototype.RemoveTemplateBonus = function(value, player, classes, key)
{
var v = this.templateModifications.get(value);
if (!v)
return;
var p = v.get(player);
if (!p)
return;
var data = p.get(key);
if (!data || !data.count)
return;
data.count--;
if (data.count > 0)
return;
this.templateModificationsCache.get(value).get(player).get(classes).delete(key);
if (this.templateModificationsCache.get(value).get(player).get(classes).size == 0)
this.templateModificationsCache.get(value).get(player).delete(classes);
// clean up the object
p.delete(key);
if (p.size == 0)
v.delete(player);
Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, {
"player": player,
"component": value.split("/")[0],
"valueNames": [value]
});
};
AuraManager.prototype.ApplyModifications = function(valueName, value, ent)
{
var v = this.modificationsCache.get(valueName);
if (!v)
return value;
var cache = v.get(ent);
if (!cache)
return value;
value *= cache.multiply;
value += cache.add;
return value;
};
AuraManager.prototype.ApplyTemplateModifications = function(valueName, value, player, template)
{
var v = this.templateModificationsCache.get(valueName);
if (!v)
return value;
var cache = v.get(player);
if (!cache)
return value;
if (!template || !template.Identity)
return value;
var classes = GetIdentityClasses(template.Identity);
var usedKeys = new Set();
var add = 0;
var multiply = 1;
for (let [className, mods] of cache)
{
if (!MatchesClassList(classes, className))
continue;
for (let [key, mod] of mods)
{
// don't add an aura with the same key twice
if (usedKeys.has(key))
continue;
add += mod.add;
multiply *= mod.multiply;
usedKeys.add(key);
}
}
return value * multiply + add;
};
+AuraManager.prototype.OnGlobalOwnershipChanged = function(msg)
+{
+ for (let ent of this.globalAuraSources)
+ {
+ let cmpAuras = Engine.QueryInterface(ent, IID_Auras);
+ if (cmpAuras)
+ cmpAuras.RegisterGlobalOwnershipChanged(msg);
+ }
+};
+
Engine.RegisterSystemComponentType(IID_AuraManager, "AuraManager", AuraManager);
Index: ps/trunk/binaries/data/mods/public/simulation/components/Auras.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/Auras.js (revision 19091)
+++ ps/trunk/binaries/data/mods/public/simulation/components/Auras.js (revision 19092)
@@ -1,426 +1,429 @@
function Auras() {}
Auras.prototype.Schema =
"" +
"tokens" +
"" +
"";
Auras.prototype.Init = function()
{
let cmpDataTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_DataTemplateManager);
this.auras = {};
this.affectedPlayers = {};
- let auraNames = this.GetAuraNames();
- for (let name of auraNames)
+ for (let name of this.GetAuraNames())
{
this.affectedPlayers[name] = [];
this.auras[name] = cmpDataTemplateManager.GetAuraTemplate(name);
}
// In case of autogarrisoning, this component can be called before ownership is set.
// So it needs to be completely initialised from the start.
this.Clean();
};
// We can modify identifier if we want stackable auras in some case.
Auras.prototype.GetModifierIdentifier = function(name)
{
if (this.auras[name].stackable)
return name + this.entity;
return name;
};
Auras.prototype.GetDescriptions = function()
{
- let auraNames = this.GetAuraNames();
var ret = {};
- for (let name of auraNames)
+ for (let name of this.GetAuraNames())
{
let aura = this.auras[name];
if (aura.auraName)
ret[aura.auraName] = aura.auraDescription || null;
}
return ret;
};
Auras.prototype.GetAuraNames = function()
{
return this.template._string.split(/\s+/);
};
Auras.prototype.GetOverlayIcon = function(name)
{
return this.auras[name].overlayIcon || "";
};
Auras.prototype.GetAffectedEntities = function(name)
{
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;
};
Auras.prototype.GetModifications = function(name)
{
return this.auras[name].modifications;
};
Auras.prototype.GetAffectedPlayers = function(name)
{
return this.affectedPlayers[name];
};
Auras.prototype.CalculateAffectedPlayers = function(name)
{
var affectedPlayers = this.auras[name].affectedPlayers || ["Player"];
this.affectedPlayers[name] = [];
var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
if (!cmpPlayer)
cmpPlayer = QueryOwnerInterface(this.entity);
if (!cmpPlayer)
return;
var numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
for (var i = 0; i < numPlayers; ++i)
{
for (let p of affectedPlayers)
{
if (p == "Player" ? cmpPlayer.GetPlayerID() == i : cmpPlayer["Is" + p](i))
{
this.affectedPlayers[name].push(i);
break;
}
}
}
};
Auras.prototype.CanApply = function(name)
{
if (!this.auras[name].requiredTechnology)
return true;
let cmpTechnologyManager = QueryOwnerInterface(this.entity, IID_TechnologyManager);
if (!cmpTechnologyManager)
return false;
return cmpTechnologyManager.IsTechnologyResearched(this.auras[name].requiredTechnology);
};
Auras.prototype.HasFormationAura = function()
{
return this.GetAuraNames().some(n => this.IsFormationAura(n));
};
Auras.prototype.HasGarrisonAura = function()
{
return this.GetAuraNames().some(n => this.IsGarrisonAura(n));
};
Auras.prototype.HasGarrisonedUnitsAura = function()
{
return this.GetAuraNames().some(n => this.IsGarrisonedUnitsAura(n));
};
Auras.prototype.GetType = function(name)
{
return this.auras[name].type;
};
Auras.prototype.IsFormationAura = function(name)
{
return this.GetType(name) == "formation";
};
Auras.prototype.IsGarrisonAura = function(name)
{
return this.GetType(name) == "garrison";
};
Auras.prototype.IsGarrisonedUnitsAura = function(name)
{
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";
};
/**
* 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();
let targetUnitsClone = {};
// remove all bonuses
for (let name of auraNames)
{
targetUnitsClone[name] = [];
if (!this[name])
continue;
if (this[name].targetUnits)
targetUnitsClone[name] = this[name].targetUnits.slice();
if (this.IsGlobalAura(name))
this.RemoveTemplateBonus(name);
this.RemoveBonus(name, this[name].targetUnits);
if (this[name].rangeQuery)
cmpRangeManager.DestroyActiveQuery(this[name].rangeQuery);
}
for (let name of auraNames)
{
// only calculate the affected players on re-applying the bonuses
// this makes sure the template bonuses are removed from the correct players
this.CalculateAffectedPlayers(name);
// initialise range query
this[name] = {};
this[name].targetUnits = [];
this[name].isApplied = this.CanApply(name);
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,
0,
this.GetRange(name),
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)
{
var match = this.GetClasses(auraName);
return entityList.filter(ent => {
let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), match);
});
};
Auras.prototype.OnRangeUpdate = function(msg)
{
- var auraNames = this.GetAuraNames().filter(n => this[n] && msg.tag == this[n].rangeQuery);
- for (let name of auraNames)
+ for (let name of this.GetAuraNames().filter(n => this[n] && msg.tag == this[n].rangeQuery))
{
this.ApplyBonus(name, msg.added);
this.RemoveBonus(name, msg.removed);
}
};
Auras.prototype.OnGarrisonedUnitsChanged = function(msg)
{
- var auraNames = this.GetAuraNames().filter(n => this.IsGarrisonedUnitsAura(n));
- for (let name of auraNames)
+ for (let name of this.GetAuraNames().filter(n => this.IsGarrisonedUnitsAura(n)))
{
this.ApplyBonus(name, msg.added);
this.RemoveBonus(name, msg.removed);
}
};
+Auras.prototype.RegisterGlobalOwnershipChanged = function(msg)
+{
+ for (let name of this.GetAuraNames().filter(n => this.IsGlobalAura(n)))
+ {
+ 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)
+ for (let name of this.GetAuraNames().filter(n => this.IsFormationAura(n)))
this.ApplyBonus(name, memberList);
};
Auras.prototype.ApplyGarrisonBonus = function(structure)
{
- var auraNames = this.GetAuraNames().filter(n => this.IsGarrisonAura(n));
- for (let name of auraNames)
+ for (let name of this.GetAuraNames().filter(n => this.IsGarrisonAura(n)))
this.ApplyBonus(name, [structure]);
};
Auras.prototype.ApplyTemplateBonus = function(name, players)
{
if (!this[name].isApplied)
return;
if (!this.IsGlobalAura(name))
return;
var modifications = this.GetModifications(name);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
var classes = this.GetClasses(name);
+ cmpAuraManager.RegisterGlobalAuraSource(this.entity);
+
for (let mod of modifications)
for (let player of players)
cmpAuraManager.ApplyTemplateBonus(mod.value, player, classes, mod, this.GetModifierIdentifier(name));
};
Auras.prototype.RemoveFormationBonus = function(memberList)
{
- var auraNames = this.GetAuraNames().filter(n => this.IsFormationAura(n));
- for (let name of auraNames)
+ for (let name of this.GetAuraNames().filter(n => this.IsFormationAura(n)))
this.RemoveBonus(name, memberList);
};
Auras.prototype.RemoveGarrisonBonus = function(structure)
{
- var auraNames = this.GetAuraNames().filter(n => this.IsGarrisonAura(n));
- for (let name of auraNames)
+ for (let name of this.GetAuraNames().filter(n => this.IsGarrisonAura(n)))
this.RemoveBonus(name, [structure]);
};
Auras.prototype.RemoveTemplateBonus = function(name)
{
if (!this[name].isApplied)
return;
if (!this.IsGlobalAura(name))
return;
- var modifications = this.GetModifications(name);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
+ cmpAuraManager.UnregisterGlobalAuraSource(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)
cmpAuraManager.RemoveTemplateBonus(mod.value, player, classes, this.GetModifierIdentifier(name));
};
Auras.prototype.ApplyBonus = function(name, ents)
{
var validEnts = this.GiveMembersWithValidClass(name, ents);
if (!validEnts.length)
return;
this[name].targetUnits = this[name].targetUnits.concat(validEnts);
if (!this[name].isApplied)
return;
var modifications = this.GetModifications(name);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
for (let mod of modifications)
cmpAuraManager.ApplyBonus(mod.value, validEnts, mod, this.GetModifierIdentifier(name));
// update status bars if this has an icon
if (!this.GetOverlayIcon(name))
return;
for (let ent of validEnts)
{
var cmpStatusBars = Engine.QueryInterface(ent, IID_StatusBars);
if (cmpStatusBars)
cmpStatusBars.AddAuraSource(this.entity, name);
}
};
Auras.prototype.RemoveBonus = function(name, ents)
{
var validEnts = this.GiveMembersWithValidClass(name, ents);
if (!validEnts.length)
return;
this[name].targetUnits = this[name].targetUnits.filter(v => validEnts.indexOf(v) == -1);
if (!this[name].isApplied)
return;
var modifications = this.GetModifications(name);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
for (let mod of modifications)
cmpAuraManager.RemoveBonus(mod.value, validEnts, this.GetModifierIdentifier(name));
// update status bars if this has an icon
if (!this.GetOverlayIcon(name))
return;
for (let ent of validEnts)
{
var cmpStatusBars = Engine.QueryInterface(ent, IID_StatusBars);
if (cmpStatusBars)
cmpStatusBars.RemoveAuraSource(this.entity, name);
}
};
Auras.prototype.OnOwnershipChanged = function(msg)
{
this.Clean();
};
Auras.prototype.OnDiplomacyChanged = function(msg)
{
var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
if (cmpPlayer && (cmpPlayer.GetPlayerID() == msg.player || cmpPlayer.GetPlayerID() == msg.otherPlayer) ||
IsOwnedByPlayer(msg.player, this.entity) ||
IsOwnedByPlayer(msg.otherPlayer, this.entity))
this.Clean();
};
Auras.prototype.OnGlobalResearchFinished = function(msg)
{
var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
if ((!cmpPlayer || cmpPlayer.GetPlayerID() != msg.player) && !IsOwnedByPlayer(msg.player, this.entity))
return;
- let auraNames = this.GetAuraNames();
- for (let name of auraNames)
+ for (let name of this.GetAuraNames())
{
let requiredTech = this.auras[name].requiredTechnology;
if (requiredTech && requiredTech == msg.tech)
{
this.Clean();
return;
}
}
};
Engine.RegisterComponentType(IID_Auras, "Auras", Auras);
Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Auras.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Auras.js (revision 19091)
+++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Auras.js (revision 19092)
@@ -1,111 +1,125 @@
Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/Auras.js");
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"
};
if (name == "range")
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"],
+ "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: ps/trunk/binaries/data/mods/public/simulation/data/auras/maur_hero_ashoka.json
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/data/auras/maur_hero_ashoka.json (revision 19091)
+++ ps/trunk/binaries/data/mods/public/simulation/data/auras/maur_hero_ashoka.json (revision 19092)
@@ -1,14 +1,17 @@
{
"type": "global",
"affects": ["Temple"],
"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": "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: ps/trunk/binaries/data/mods/public/simulation/data/auras/teambonuses/maur_player_teambonus.json
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/data/auras/teambonuses/maur_player_teambonus.json (nonexistent)
+++ ps/trunk/binaries/data/mods/public/simulation/data/auras/teambonuses/maur_player_teambonus.json (revision 19092)
@@ -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: ps/trunk/binaries/data/mods/public/simulation/templates/special/player_maur.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/special/player_maur.xml (nonexistent)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/special/player_maur.xml (revision 19092)
@@ -0,0 +1,4 @@
+
+
+ teambonuses/maur_player_teambonus
+