Index: binaries/data/mods/public/maps/scripts/TriggerHelper.js
===================================================================
--- binaries/data/mods/public/maps/scripts/TriggerHelper.js
+++ binaries/data/mods/public/maps/scripts/TriggerHelper.js
@@ -121,7 +121,11 @@
for (let i = 0; i < count; ++i)
{
- let ent = Engine.AddEntity(template);
+ const upgradedTemplate = GetUpgradedTemplate(owner, template);
+ if (upgradedTemplate !== template)
+ warn(`tried to spawn template '${template}' but upgraded template ${upgradedTemplate} will be spawned instead. You might want to create a template that is not affected by this promotion.`);
+
+ let ent = Engine.AddEntity(upgradedTemplate);
let cmpEntPosition = Engine.QueryInterface(ent, IID_Position);
if (!cmpEntPosition)
{
Index: binaries/data/mods/public/simulation/components/EntRenameWatcher.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/EntRenameWatcher.js
@@ -0,0 +1,40 @@
+function EntRenameWatcher() {}
+
+EntRenameWatcher.prototype.Schema = "";
+
+EntRenameWatcher.prototype.Init = function()
+{
+ this.renames = new Map();
+}
+
+/**
+ * Return the current ID (after renames) of the entity ent
+ * @param ent - original Entity ID
+ */
+EntRenameWatcher.prototype.GetCurrentId = function(ent)
+{
+ let cid = this.renames.get(ent);
+ if (!cid)
+ return ent;
+ // Check if this renamed ID is itself renamed,
+ // if so update the original array (faster check next time)
+ let nid = this.renames.get(cid);
+ if (!nid)
+ return cid;
+ cid = nid;
+ while (true) {
+ let nid = this.renames.get(cid);
+ if (!nid)
+ break;
+ cid = nid;
+ }
+ this.renames.set(ent, cid);
+ return cid;
+};
+
+EntRenameWatcher.prototype.OnGlobalEntityRenamed = function(msg)
+{
+ this.renames.set(msg.entity, msg.newentity);
+};
+
+Engine.RegisterSystemComponentType(IID_EntRenameWatcher, "EntRenameWatcher", EntRenameWatcher);
Index: binaries/data/mods/public/simulation/components/Trainer.js
===================================================================
--- binaries/data/mods/public/simulation/components/Trainer.js
+++ binaries/data/mods/public/simulation/components/Trainer.js
@@ -554,7 +554,7 @@
return entMap;
}
- token = this.GetUpgradedTemplate(token);
+ token = GetUpgradedTemplate(cmpPlayer.GetPlayerID(), token);
entMap.set(rawToken, token);
updateAllQueuedTemplate(rawToken, token);
return entMap;
@@ -563,32 +563,6 @@
this.CalculateTrainCostMultiplier();
};
-/*
- * Returns the upgraded template name if necessary.
- */
-Trainer.prototype.GetUpgradedTemplate = function(templateName)
-{
- const cmpPlayer = QueryOwnerInterface(this.entity);
- if (!cmpPlayer)
- return templateName;
-
- const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
- let template = cmpTemplateManager.GetTemplate(templateName);
- while (template && template.Promotion !== undefined)
- {
- const requiredXp = ApplyValueModificationsToTemplate(
- "Promotion/RequiredXp",
- +template.Promotion.RequiredXp,
- cmpPlayer.GetPlayerID(),
- template);
- if (requiredXp > 0)
- break;
- templateName = template.Promotion.Entity;
- template = cmpTemplateManager.GetTemplate(templateName);
- }
- return templateName;
-};
-
Trainer.prototype.CalculateTrainCostMultiplier = function()
{
for (const res of Resources.GetCodes().concat(["time"]))
Index: binaries/data/mods/public/simulation/components/interfaces/EntRenameWatcher.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/interfaces/EntRenameWatcher.js
@@ -0,0 +1 @@
+Engine.RegisterInterface("EntRenameWatcher");
Index: binaries/data/mods/public/simulation/components/interfaces/Messages.js
===================================================================
--- binaries/data/mods/public/simulation/components/interfaces/Messages.js
+++ binaries/data/mods/public/simulation/components/interfaces/Messages.js
@@ -1,16 +1,3 @@
-/**
- * Message of the form { "entity": number, "newentity": number }
- * sent when one entity is changed to another:
- * - from Foundation component when a building construction is done
- * - from Formation component
- * - from Health component when an entity died and should remain as a resource
- * - from Promotion component when a unit is promoted
- * - from Mirage component when a fogged entity is re-discovered
- * - from SkirmishReplacer component when a skirmish entity has been replaced
- * - from Transform helper when an entity has been upgraded
- */
-Engine.RegisterMessageType("EntityRenamed");
-
/**
* Message of the form {}
* sent from InitGame for component map-dependent initialization.
Index: binaries/data/mods/public/simulation/components/tests/test_EntRenameWatcher.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/tests/test_EntRenameWatcher.js
@@ -0,0 +1,54 @@
+Engine.LoadComponentScript("interfaces/EntRenameWatcher.js");
+Engine.LoadComponentScript("EntRenameWatcher.js");
+
+
+// First test, regular order
+
+let cmpRenameWatcher = ConstructComponent(SYSTEM_ENTITY, "EntRenameWatcher");
+
+const entityA = 3476;
+const entityB = 857;
+const entityC = 7876;
+const invalid = INVALID_ENTITY;
+
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityA), entityA);
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(invalid), invalid);
+
+cmpRenameWatcher.OnGlobalEntityRenamed({
+ "entity": entityA,
+ "newentity": entityB,
+});
+
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityA), entityB);
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityB), entityB);
+
+cmpRenameWatcher.OnGlobalEntityRenamed({
+ "entity": entityB,
+ "newentity": entityC,
+});
+
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityA), entityC);
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityB), entityC);
+
+
+// First test, inverse order
+
+cmpRenameWatcher = ConstructComponent(SYSTEM_ENTITY, "EntRenameWatcher");
+
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityA), entityA);
+
+cmpRenameWatcher.OnGlobalEntityRenamed({
+ "entity": entityB,
+ "newentity": entityC,
+});
+
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityA), entityA);
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityB), entityC);
+
+cmpRenameWatcher.OnGlobalEntityRenamed({
+ "entity": entityA,
+ "newentity": entityB,
+});
+
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityA), entityC);
+TS_ASSERT_EQUALS(cmpRenameWatcher.GetCurrentId(entityB), entityC);
Index: binaries/data/mods/public/simulation/components/tests/test_Trainer.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Trainer.js
+++ binaries/data/mods/public/simulation/components/tests/test_Trainer.js
@@ -55,6 +55,16 @@
"GetCiv": () => "iber"
});
+let GetUpgradedTemplate = (_, template) => template === "units/iber/cavalry_javelineer_b" ? "units/iber/cavalry_javelineer_a" : template;
+Engine.RegisterGlobal("GetUpgradedTemplate", GetUpgradedTemplate);
+cmpTrainer.CalculateEntitiesMap();
+TS_ASSERT_UNEVAL_EQUALS(
+ cmpTrainer.GetEntitiesList(),
+ ["units/iber/cavalry_javelineer_a", "units/iber/infantry_swordsman_b", "units/iber/support_female_citizen"]
+);
+
+GetUpgradedTemplate = (_, template) => template;
+Engine.RegisterGlobal("GetUpgradedTemplate", GetUpgradedTemplate);
cmpTrainer.CalculateEntitiesMap();
TS_ASSERT_UNEVAL_EQUALS(
cmpTrainer.GetEntitiesList(),
Index: binaries/data/mods/public/simulation/helpers/Transform.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Transform.js
+++ binaries/data/mods/public/simulation/helpers/Transform.js
@@ -294,5 +294,30 @@
}
}
+/**
+ * @param {number} playerId - the player id to check technologies for.
+ * @param {string} templateName - the original template name.
+ * @returns the upgraded template name if it exists else the original template.
+ */
+function GetUpgradedTemplate(playerId, templateName)
+{
+ const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
+ let template = cmpTemplateManager.GetTemplate(templateName);
+ while (template && template.Promotion !== undefined)
+ {
+ const requiredXp = ApplyValueModificationsToTemplate(
+ "Promotion/RequiredXp",
+ +template.Promotion.RequiredXp,
+ playerId,
+ template);
+ if (requiredXp > 0)
+ break;
+ templateName = template.Promotion.Entity;
+ template = cmpTemplateManager.GetTemplate(templateName);
+ }
+ return templateName;
+};
+
+Engine.RegisterGlobal("GetUpgradedTemplate", GetUpgradedTemplate);
Engine.RegisterGlobal("ChangeEntityTemplate", ChangeEntityTemplate);
Engine.RegisterGlobal("ObstructionsBlockingTemplateChange", ObstructionsBlockingTemplateChange);
Index: binaries/data/mods/public/simulation/helpers/tests/test_Transform.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/helpers/tests/test_Transform.js
@@ -0,0 +1,41 @@
+Engine.LoadHelperScript("Transform.js");
+
+const template1 = "template_a";
+const template2 = "template_b";
+const template3 = "template_c";
+const template4 = "template_d";
+const affectedClasses = "CitizenSoldier";
+const playerId1 = 1;
+const playerId2 = 2;
+
+AddMock(SYSTEM_ENTITY, IID_TemplateManager, {
+ "GetTemplate": function (template) {
+ if (template === template1 || template === template4)
+ return {};
+
+ return {
+ "Identity": {
+ "Classes": { "_string": template === template3 ? "" : affectedClasses }
+ },
+ "Promotion": {
+ "Entity": template4,
+ "RequiredXp": "1000"
+ }
+ };
+ },
+});
+
+let applyValueModificationsToTemplate = function(_, current_value, playerID, template)
+{
+ return playerID === playerId1 && template.Identity.Classes._string === affectedClasses ? 0 : current_value;
+}
+
+Engine.RegisterGlobal("ApplyValueModificationsToTemplate", applyValueModificationsToTemplate);
+
+TS_ASSERT_EQUALS(GetUpgradedTemplate(playerId1, template1), template1);
+TS_ASSERT_EQUALS(GetUpgradedTemplate(playerId1, template2), template4);
+TS_ASSERT_EQUALS(GetUpgradedTemplate(playerId1, template3), template3);
+
+TS_ASSERT_EQUALS(GetUpgradedTemplate(playerId2, template1), template1);
+TS_ASSERT_EQUALS(GetUpgradedTemplate(playerId2, template2), template2);
+TS_ASSERT_EQUALS(GetUpgradedTemplate(playerId2, template3), template3);