Index: binaries/data/mods/public/simulation/components/Cost.js
===================================================================
--- binaries/data/mods/public/simulation/components/Cost.js
+++ binaries/data/mods/public/simulation/components/Cost.js
@@ -44,9 +44,7 @@
Cost.prototype.GetBuildTime = function()
{
- var cmpPlayer = QueryOwnerInterface(this.entity);
- var buildTime = (+this.template.BuildTime) * cmpPlayer.cheatTimeMultiplier;
- return ApplyValueModificationsToEntity("Cost/BuildTime", buildTime, this.entity);
+ return ApplyValueModificationsToEntity("Cost/BuildTime", +this.template.BuildTime, this.entity);
};
Cost.prototype.GetResourceCosts = function(owner)
Index: binaries/data/mods/public/simulation/components/ModifiersManager.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/ModifiersManager.js
@@ -0,0 +1,251 @@
+function ModifiersManager() {}
+
+ModifiersManager.prototype.Schema =
+ "";
+
+ModifiersManager.prototype.Serialize = function()
+{
+ // The cache will be affected by property reads from the GUI and other places so we shouldn't
+ // serialize it.
+
+ var ret = {};
+ for (var i in this)
+ {
+ if (this.hasOwnProperty(i))
+ ret[i] = this[i];
+ }
+ ret.cachedValues = new Map();
+ return ret;
+};
+
+ModifiersManager.prototype.Init = function()
+{
+ // TODO:
+ // add a way to show an icon for a given modification ID.
+
+ // By property name only.
+ this.globalModifiers = new Map();
+ // By property name and entity.
+ this.localModifiers = new Map();
+
+ // By entity
+ this.cachedValues = new Map();
+};
+
+// Wrapper for AddGlobalModifier, to set multiple modifiers with the same ID and priority easily
+ModifiersManager.prototype.AddGlobalModifiers = function(modificationID, priority, modificationArray)
+{
+ for (let propertyName in modificationArray)
+ this.AddGlobalModifier(propertyName, modificationID, priority, modificationArray[propertyName]);
+}
+
+// Wrapper for RemoveGlobalModifier, to remove any modifier with this ID
+ModifiersManager.prototype.RemoveGlobalModifiers = function(modificationID)
+{
+ for (let propertyName of this.globalModifiers)
+ this.RemoveGlobalModifier(propertyName[0], modificationID);
+}
+
+// Wrapper for HasGlobalModifier, will return true if there is at least one modifier with this ID for any property.
+ModifiersManager.prototype.HasAnyGlobalModifierWithID = function(modificationID)
+{
+ for (let propertyName of this.globalModifiers)
+ if (this.HasGlobalModifier(propertyName[0], modificationID))
+ return true;
+ return false;
+}
+
+ModifiersManager.prototype.UpdateGlobalModifier = function(propertyName, modificationID, priority, modification)
+{
+ warn("this function is TODO");
+}
+
+ModifiersManager.prototype.AddGlobalModifier = function(propertyName, modificationID, priority, modification)
+{
+ if (!this.globalModifiers.get(propertyName))
+ this.globalModifiers.set(propertyName, {"version": 0, "modifications": []});
+
+ let modifier = this.globalModifiers.get(propertyName);
+
+ // check whether we already have that modifier
+ let existing = modifier.modifications.filter(modification => { return modification.ID == modificationID; });
+
+ if (existing.length > 1)
+ {
+ error("Code bug: two global modifiers have the same modificationID " + modificationID);
+ return;
+ }
+
+ if (existing.length)
+ ++existing[0].count;
+ else
+ {
+ // create a new modifier at the correct position.
+ let index = 0;
+ // TODO: do a binary search if this ever becomes a performance problem.
+ for (index = 0; index < modifier.modifications.length; ++index)
+ // in case of equal priority, insert in chronological order.
+ if (modifier.modifications[index].priority > priority)
+ break;
+ modifier.modifications.splice(index, 0, {"ID": modificationID, "priority": priority, "count": 1, "effect": modification});
+ }
+
+ // bump version to invalidate caches
+ ++modifier.version;
+
+ this.SendGlobalModificationMessages(propertyName);
+}
+
+ModifiersManager.prototype.RemoveGlobalModifier = function(propertyName, modificationID)
+{
+ if (!this.globalModifiers.get(propertyName))
+ return;
+
+ let modifier = this.globalModifiers.get(propertyName);
+
+ // remove modifier.
+ let size = modifier.modifications.length;
+ let element = modifier.modifications.filter(modification => { return modification.ID == modificationID; });
+
+ if (!element.length || --element[0].count)
+ return;
+
+ modifier.modifications = modifier.modifications.filter(modification => { return modification.count; });
+
+ // bump version to invalidate caches
+ ++modifier.version;
+
+ this.SendGlobalModificationMessages(propertyName);
+}
+
+ModifiersManager.prototype.SendGlobalModificationMessages = function(propertyName)
+{
+ // send messages
+ let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
+ if (!cmpPlayer || cmpPlayer.GetPlayerID() === undefined)
+ return;
+ let playerID = cmpPlayer.GetPlayerID();
+
+ // TODO: would be nice to do this optionally in a meta-component with several property names or something.
+ Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, { "player": playerID, "component": propertyName.split("/")[0], "valueNames": [propertyName]});
+ // AIInterface wants the entities potentially affected. TODO: improve on this
+ let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
+ let ents = cmpRangeManager.GetEntitiesByPlayer(playerID);
+ Engine.BroadcastMessage(MT_ValueModification, { "entities": ents, "component": propertyName.split("/")[0], "valueNames": [propertyName]});
+
+}
+
+ModifiersManager.prototype.HasGlobalModifier = function(propertyName, modificationID)
+{
+ if (!this.globalModifiers.get(propertyName))
+ return false;
+
+ return this.globalModifiers.get(propertyName).modifications.some(modification => { return modification.ID == modificationID; });
+}
+
+// Caching layer in front of ApplyModificationsWorker
+// Note: be careful with the type of curValue, if it should be a numerical
+// value and is derived from template data, you must convert the string
+// from the template to a number using the + operator, before calling
+// this function!
+ModifiersManager.prototype.ApplyModifications = function(propertyName, originalValue, ent)
+{
+ let value = originalValue;
+ // sanity check
+ if (Array.isArray(originalValue))
+ value = originalValue.slice();
+ else if (typeof originalValue == "object")
+ {
+ error("ModifiersManager ApplyModifications called with an object");
+ return;
+ }
+
+ if (!this.cachedValues.get(ent))
+ this.cachedValues.set(ent, new Map());
+ if (!this.cachedValues.get(ent).get(propertyName))
+ this.cachedValues.get(ent).set(propertyName, { "version": 0, "value": value});
+
+ let propertyValue = this.cachedValues.get(ent).get(propertyName);
+
+ // global modifiers
+ if (this.globalModifiers.get(propertyName))
+ if (propertyValue.version < this.globalModifiers.get(propertyName).version)
+ {
+ let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
+ if (!cmpIdentity)
+ return originalValue;
+
+ let modifications = {};
+ modifications[propertyName] = []; // TODO: change this once GetTechModifiedProperty is updated I guess.
+ for (let modifier of this.globalModifiers.get(propertyName).modifications)
+ modifications[propertyName].push(modifier.effect);
+
+ let newValue = GetTechModifiedProperty(modifications, cmpIdentity.GetClassesList(), propertyName, value);
+
+ this.cachedValues.get(ent).get(propertyName).version = this.globalModifiers.get(propertyName).version;
+ this.cachedValues.get(ent).get(propertyName).value = newValue;
+ }
+
+ // TODO: local modifiers go here.
+
+ return this.cachedValues.get(ent).get(propertyName).value;
+};
+
+// Alternative version of ApplyModifications, applies to templates instead of entities
+ModifiersManager.prototype.ApplyModificationsTemplate = function(propertyName, originalValue, template)
+{
+ if (!template || !template.Identity || !this.globalModifiers.has(propertyName))
+ return originalValue;
+
+ let modifications = {};
+ modifications[propertyName] = []; // TODO: change this once GetTechModifiedProperty is updated I guess.
+ for (let modifier of this.globalModifiers.get(propertyName).modifications)
+ modifications[propertyName].push(modifier.effect);
+
+ return GetTechModifiedProperty(modifications, GetIdentityClasses(template.Identity), propertyName, originalValue);
+};
+
+ModifiersManager.prototype.OnGlobalOwnershipChanged = function(msg)
+{
+ // Send ValueModification messages to new entities.
+ // TODO: this is quite wasteful, we should cache templates affected by technologies and 360 quickscope it.
+
+ let playerID = (Engine.QueryInterface(this.entity, IID_Player)).GetPlayerID();
+ if (msg.to != playerID)
+ return;
+
+ let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
+ let template = cmpTemplateManager.GetCurrentTemplateName(msg.entity);
+
+ // TODO : save existing modifiers if from !== -1 in a clever way.
+ if (msg.from != -1)
+ return;
+
+ let cmpIdentity = Engine.QueryInterface(msg.entity, IID_Identity);
+ if (!cmpIdentity)
+ return;
+
+ let classes = cmpIdentity.GetClassesList();
+
+ // local modifiers will be added by the relevant components, so no need to check for them here.
+ let modifiedComponents = {};
+ for (let property of this.globalModifiers)
+ {
+ // We only need to find one one tech per component for a match
+ var modifications = property[1].modifications;
+ var component = property[0].split("/")[0];
+ for (let modif of modifications)
+ if (DoesModificationApply(modif.effect, classes))
+ {
+ if (!modifiedComponents[component])
+ modifiedComponents[component] = [];
+ modifiedComponents[component].push(property[0]);
+ }
+ }
+
+ // Send message(s) to the entity so it knows about researched techs
+ for (let component in modifiedComponents)
+ Engine.PostMessage(msg.entity, MT_ValueModification, { "entities": [msg.entity], "component": component, "valueNames": modifiedComponents[component] });
+}
+
+Engine.RegisterComponentType(IID_ModifiersManager, "ModifiersManager", ModifiersManager);
Index: binaries/data/mods/public/simulation/components/Pack.js
===================================================================
--- binaries/data/mods/public/simulation/components/Pack.js
+++ binaries/data/mods/public/simulation/components/Pack.js
@@ -98,8 +98,7 @@
{
let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
- return ApplyValueModificationsToEntity("Pack/Time", +this.template.Time, this.entity) *
- cmpPlayer.GetCheatTimeMultiplier();
+ return ApplyValueModificationsToEntity("Pack/Time", +this.template.Time, this.entity);
};
Pack.prototype.GetElapsedTime = function()
Index: binaries/data/mods/public/simulation/components/Player.js
===================================================================
--- binaries/data/mods/public/simulation/components/Player.js
+++ binaries/data/mods/public/simulation/components/Player.js
@@ -40,7 +40,6 @@
this.gatherRateMultiplier = 1;
this.tradeRateMultiplier = 1;
this.cheatsEnabled = false;
- this.cheatTimeMultiplier = 1;
this.panelEntities = [];
this.resourceNames = {};
this.disabledTemplates = {};
@@ -755,16 +754,6 @@
return this.cheatsEnabled;
};
-Player.prototype.SetCheatTimeMultiplier = function(time)
-{
- this.cheatTimeMultiplier = time;
-};
-
-Player.prototype.GetCheatTimeMultiplier = function()
-{
- return this.cheatTimeMultiplier;
-};
-
Player.prototype.TributeResource = function(player, amounts)
{
var cmpPlayer = QueryPlayerIDInterface(player);
Index: binaries/data/mods/public/simulation/components/ProductionQueue.js
===================================================================
--- binaries/data/mods/public/simulation/components/ProductionQueue.js
+++ binaries/data/mods/public/simulation/components/ProductionQueue.js
@@ -343,7 +343,7 @@
}
let techCostMultiplier = this.GetTechCostMultiplier();
- let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier();
+ let time = techCostMultiplier.time * template.researchTime;
let cost = {};
for (let res in template.cost)
@@ -512,7 +512,7 @@
var batchTimeModifier = ApplyValueModificationsToEntity("ProductionQueue/BatchTimeModifier", +this.template.BatchTimeModifier, this.entity);
// TODO: work out what equation we should use here.
- return Math.pow(batchSize, batchTimeModifier) * cmpPlayer.GetCheatTimeMultiplier();
+ return Math.pow(batchSize, batchTimeModifier);
};
ProductionQueue.prototype.OnOwnershipChanged = function(msg)
Index: binaries/data/mods/public/simulation/components/ResourceGatherer.js
===================================================================
--- binaries/data/mods/public/simulation/components/ResourceGatherer.js
+++ binaries/data/mods/public/simulation/components/ResourceGatherer.js
@@ -248,10 +248,6 @@
if (rate == 0 && type.generic)
rate = this.GetGatherRate(type.generic);
- let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
- let cheatMultiplier = cmpPlayer ? cmpPlayer.GetCheatTimeMultiplier() : 1;
- rate = rate / cheatMultiplier;
-
if ("Mirages" in cmpResourceSupply)
return rate;
Index: binaries/data/mods/public/simulation/components/TechnologyManager.js
===================================================================
--- binaries/data/mods/public/simulation/components/TechnologyManager.js
+++ binaries/data/mods/public/simulation/components/TechnologyManager.js
@@ -3,37 +3,12 @@
TechnologyManager.prototype.Schema =
"";
-TechnologyManager.prototype.Serialize = function()
-{
- // The modifications cache will be affected by property reads from the GUI and other places so we shouldn't
- // serialize it.
-
- var ret = {};
- for (var i in this)
- {
- if (this.hasOwnProperty(i))
- ret[i] = this[i];
- }
- ret.modificationCache = {};
- return ret;
-};
-
TechnologyManager.prototype.Init = function()
{
this.researchedTechs = {}; // technologies which have been researched
this.researchQueued = {}; // technologies which are queued for research
this.researchStarted = {}; // technologies which are being researched currently (non-queued)
- // This stores the modifications to unit stats from researched technologies
- // Example data: {"ResourceGatherer/Rates/food.grain": [
- // {"multiply": 1.15, "affects": ["FemaleCitizen", "Infantry Swordsman"]},
- // {"add": 2}
- // ]}
- this.modifications = {};
- this.modificationCache = {}; // Caches the values after technologies have been applied
- // e.g. { "Attack/Melee/Hack" : {5: {"origValue": 8, "newValue": 10}, 7: {"origValue": 9, "newValue": 12}, ...}, ...}
- // where 5 and 7 are entity id's
-
this.classCounts = {}; // stores the number of entities of each Class
this.typeCountsByClass = {}; // stores the number of entities of each type for each class i.e.
// {"someClass": {"unit/spearman": 2, "unit/cav": 5} "someOtherClass":...}
@@ -197,31 +172,6 @@
this.typeCountsByClass[cls][template] += 1;
}
}
-
- // Newly created entity, check if any researched techs might apply
- // (only do this for new entities because even if an entity is converted or captured,
- // we want it to maintain whatever technologies previously applied)
- if (msg.from == -1)
- {
- var modifiedComponents = {};
- for (var name in this.modifications)
- {
- // We only need to find one one tech per component for a match
- var modifications = this.modifications[name];
- var component = name.split("/")[0];
- for (let modif of modifications)
- if (DoesModificationApply(modif, classes))
- {
- if (!modifiedComponents[component])
- modifiedComponents[component] = [];
- modifiedComponents[component].push(name);
- }
- }
-
- // Send mesage(s) to the entity so it knows about researched techs
- for (var component in modifiedComponents)
- Engine.PostMessage(msg.entity, MT_ValueModification, { "entities": [msg.entity], "component": component, "valueNames": modifiedComponents[component] });
- }
}
if (msg.from == playerID)
{
@@ -247,8 +197,6 @@
}
}
}
-
- this.clearModificationCache(msg.entity);
}
};
@@ -265,24 +213,24 @@
return;
}
- var modifiedComponents = {};
this.researchedTechs[tech] = template;
// store the modifications in an easy to access structure
if (template.modifications)
{
- let derivedModifiers = DeriveModificationsFromTech(template);
- for (let modifierPath in derivedModifiers)
+ let priorityLevel = template.priority || 5;
+ let supersedes = template.supersedes || undefined;
+ while (supersedes)
{
- if (!this.modifications[modifierPath])
- this.modifications[modifierPath] = [];
- this.modifications[modifierPath] = this.modifications[modifierPath].concat(derivedModifiers[modifierPath]);
-
- let component = modifierPath.split("/")[0];
- if (!modifiedComponents[component])
- modifiedComponents[component] = [];
- modifiedComponents[component].push(modifierPath);
- this.modificationCache[modifierPath] = {};
+ ++priorityLevel;
+ let supertemplate = this.GetTechnologyTemplate(supersedes);
+ supersedes = supertemplate.supersedes || undefined;
}
+
+ let cmpModManager = Engine.QueryInterface(this.entity, IID_ModifiersManager);
+ let derivedModifiers = DeriveModificationsFromTech(template);
+ for (let modifierPath in derivedModifiers)
+ for (let modifier of derivedModifiers[modifierPath])
+ cmpModManager.AddGlobalModifier(modifierPath, "tech/"+tech, priorityLevel, modifier);
}
if (template.replaces && template.replaces.length > 0)
@@ -323,51 +271,13 @@
// always send research finished message
Engine.PostMessage(this.entity, MT_ResearchFinished, {"player": playerID, "tech": tech});
-
+ /*
for (var component in modifiedComponents)
{
Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, { "player": playerID, "component": component, "valueNames": modifiedComponents[component]});
Engine.BroadcastMessage(MT_ValueModification, { "entities": ents, "component": component, "valueNames": modifiedComponents[component]});
}
-};
-
-// Clears the cached data for an entity from the modifications cache
-TechnologyManager.prototype.clearModificationCache = function(ent)
-{
- for (var valueName in this.modificationCache)
- delete this.modificationCache[valueName][ent];
-};
-
-// Caching layer in front of ApplyModificationsWorker
-// Note: be careful with the type of curValue, if it should be a numerical
-// value and is derived from template data, you must convert the string
-// from the template to a number using the + operator, before calling
-// this function!
-TechnologyManager.prototype.ApplyModifications = function(valueName, curValue, ent)
-{
- if (!this.modificationCache[valueName])
- this.modificationCache[valueName] = {};
-
- if (!this.modificationCache[valueName][ent] || this.modificationCache[valueName][ent].origValue != curValue)
- {
- let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
- if (!cmpIdentity)
- return curValue;
- this.modificationCache[valueName][ent] = {
- "origValue": curValue,
- "newValue": GetTechModifiedProperty(this.modifications, cmpIdentity.GetClassesList(), valueName, curValue)
- };
- }
-
- return this.modificationCache[valueName][ent].newValue;
-};
-
-// Alternative version of ApplyModifications, applies to templates instead of entities
-TechnologyManager.prototype.ApplyModificationsTemplate = function(valueName, curValue, template)
-{
- if (!template || !template.Identity)
- return curValue;
- return GetTechModifiedProperty(this.modifications, GetIdentityClasses(template.Identity), valueName, curValue);
+ */
};
// Marks a technology as being queued for research
@@ -412,12 +322,6 @@
return undefined;
};
-// Get helper data for tech modifications
-TechnologyManager.prototype.GetTechModifications = function()
-{
- return this.modifications;
-};
-
// called by GUIInterface for PlayerData. AI use.
TechnologyManager.prototype.GetQueuedResearch = function()
{
Index: binaries/data/mods/public/simulation/components/Upgrade.js
===================================================================
--- binaries/data/mods/public/simulation/components/Upgrade.js
+++ binaries/data/mods/public/simulation/components/Upgrade.js
@@ -275,8 +275,7 @@
return 0;
let cmpPlayer = QueryPlayerIDInterface(this.owner, IID_Player);
- return ApplyValueModificationsToEntity("Upgrade/Time", +this.template[choice].Time, this.entity) *
- cmpPlayer.GetCheatTimeMultiplier();
+ return ApplyValueModificationsToEntity("Upgrade/Time", +this.template[choice].Time, this.entity);
};
Upgrade.prototype.GetElapsedTime = function()
Index: binaries/data/mods/public/simulation/components/interfaces/ModifiersManager.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/interfaces/ModifiersManager.js
@@ -0,0 +1 @@
+Engine.RegisterInterface("ModifiersManager");
Index: binaries/data/mods/public/simulation/components/tests/test_Attack.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Attack.js
+++ binaries/data/mods/public/simulation/components/tests/test_Attack.js
@@ -3,7 +3,7 @@
Engine.LoadComponentScript("interfaces/Auras.js");
Engine.LoadComponentScript("interfaces/AuraManager.js");
Engine.LoadComponentScript("interfaces/Capturable.js");
-Engine.LoadComponentScript("interfaces/TechnologyManager.js");
+Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("interfaces/Formation.js");
Engine.LoadComponentScript("interfaces/Attack.js");
Engine.LoadComponentScript("Attack.js");
Index: binaries/data/mods/public/simulation/components/tests/test_Auras.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Auras.js
+++ binaries/data/mods/public/simulation/components/tests/test_Auras.js
@@ -2,7 +2,7 @@
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/Auras.js");
Engine.LoadComponentScript("interfaces/AuraManager.js");
-Engine.LoadComponentScript("interfaces/TechnologyManager.js");
+Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("Auras.js");
Engine.LoadComponentScript("AuraManager.js");
Index: binaries/data/mods/public/simulation/components/tests/test_Capturable.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Capturable.js
+++ binaries/data/mods/public/simulation/components/tests/test_Capturable.js
@@ -5,7 +5,7 @@
Engine.LoadComponentScript("interfaces/Capturable.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
-Engine.LoadComponentScript("interfaces/TechnologyManager.js");
+Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("interfaces/TerritoryDecay.js");
Engine.LoadComponentScript("interfaces/Timer.js");
Engine.LoadComponentScript("Capturable.js");
Index: binaries/data/mods/public/simulation/components/tests/test_Damage.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Damage.js
+++ binaries/data/mods/public/simulation/components/tests/test_Damage.js
@@ -11,7 +11,7 @@
Engine.LoadComponentScript("interfaces/Player.js");
Engine.LoadComponentScript("interfaces/Promotion.js");
Engine.LoadComponentScript("interfaces/Sound.js");
-Engine.LoadComponentScript("interfaces/TechnologyManager.js");
+Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("interfaces/Timer.js");
Engine.LoadComponentScript("Attack.js");
Engine.LoadComponentScript("Damage.js");
Index: binaries/data/mods/public/simulation/components/tests/test_ModifiersManager.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/tests/test_ModifiersManager.js
@@ -0,0 +1,67 @@
+Engine.LoadComponentScript("interfaces/AuraManager.js");
+Engine.LoadComponentScript("interfaces/ModifiersManager.js");
+Engine.LoadComponentScript("ModifiersManager.js");
+Engine.LoadHelperScript("Player.js");
+Engine.LoadHelperScript("ValueModification.js");
+
+let cmpModManager = ConstructComponent(2, "ModifiersManager", {});
+
+cmpModManager.Init();
+
+AddMock(2, IID_AuraManager, {
+ "ApplyModifications": function(a, value, b) { return value; },
+ "ApplyTemplateModifications": function(a, value, b) { return value; },
+});
+AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
+ "GetPlayerByID": () => 2,
+});
+// create ownership, set to "1" for any entity used below,
+// otherwise QueryOwnerInterface fails
+let entitiesToTest = [5,6,7,8];
+for (let ent of entitiesToTest)
+{
+ AddMock(ent, IID_Ownership, {
+ "GetOwner": () => 1
+ });
+}
+// hack
+
+cmpModManager.AddGlobalModifier("Test_A", "Test_A_0", 4, {"affects":["Structure"], "add": 10 });
+cmpModManager.AddGlobalModifier("Test_A", "Test_A_1", 4, {"affects":["Infantry"], "add": 5 });
+cmpModManager.AddGlobalModifier("Test_A", "Test_A_2", 4, {"affects":["Unit"], "add": 3 });
+
+TS_ASSERT_EQUALS(cmpModManager.globalModifiers.get("Test_A").version, 3);
+
+AddMock(5, IID_Identity, {
+ "GetClassesList": function() { return "Structure"}
+});
+AddMock(6, IID_Identity, {
+ "GetClassesList": function() { return "Infantry"}
+});
+AddMock(7, IID_Identity, {
+ "GetClassesList": function() { return "Unit"}
+});
+AddMock(8, IID_Identity, {
+ "GetClassesList": function() { return "Structure Unit"}
+});
+
+TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Test_A", 5, 5), 15);
+TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Test_A", 5, 6), 10);
+TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Test_A", 5, 7), 8);
+TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Test_A", 5, 8), 18);
+
+TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Test_B", 5, 8), 5);
+
+cmpModManager.RemoveGlobalModifiers("Test_A_0");
+TS_ASSERT_EQUALS(cmpModManager.globalModifiers.get("Test_A").version, 4);
+TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Test_A", 5, 5), 5);
+
+cmpModManager.AddGlobalModifiers("Test_A_0", 4, {
+ "Test_A" : {"affects":["Structure"], "add": 10 },
+ "Test_B" : {"affects":["Structure"], "add": 8 },
+});
+
+TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Test_A", 5, 5), 15);
+TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Test_B", 5, 8), 13);
+
+// TODO: test ownership changes, updating.
\ No newline at end of file
Index: binaries/data/mods/public/simulation/components/tests/test_Pack.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Pack.js
+++ binaries/data/mods/public/simulation/components/tests/test_Pack.js
@@ -2,7 +2,7 @@
Engine.LoadHelperScript("Sound.js");
Engine.LoadHelperScript("Transform.js");
Engine.LoadHelperScript("ValueModification.js");
-Engine.LoadComponentScript("interfaces/TechnologyManager.js");
+Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("interfaces/AuraManager.js");
Engine.LoadComponentScript("interfaces/Capturable.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Index: binaries/data/mods/public/simulation/components/tests/test_Player.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Player.js
+++ binaries/data/mods/public/simulation/components/tests/test_Player.js
@@ -2,7 +2,7 @@
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/AuraManager.js");
Engine.LoadComponentScript("interfaces/Player.js");
-Engine.LoadComponentScript("interfaces/TechnologyManager.js");
+Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("Player.js");
Resources = {
Index: binaries/data/mods/public/simulation/components/tests/test_Technologies.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Technologies.js
+++ /dev/null
@@ -1,510 +0,0 @@
-// TODO: Move this to a folder of tests for GlobalScripts (once one is created)
-
-// No requirements set in template
-let template = {};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-
-/**
- * First, the basics:
- */
-
-// Technology Requirement
-template.requirements = { "tech": "expected_tech" };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["expected_tech"] }]);
-
-// Entity Requirement: Count of entities matching given class
-template.requirements = { "entity": { "class": "Village", "number": 5 } };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
-
-// Entity Requirement: Count of entities matching given class
-template.requirements = { "entity": { "class": "Village", "numberOfTypes": 5 } };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
-
-// Single `civ`
-template.requirements = { "civ": "athen" };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), false);
-
-// Single `notciv`
-template.requirements = { "notciv": "athen" };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), []);
-
-
-/**
- * Basic `all`s:
- */
-
-// Multiple techs
-template.requirements = { "all": [{ "tech": "tech_A" }, { "tech": "tech_B" }, { "tech": "tech_C" }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A", "tech_B", "tech_C"] }]);
-
-// Multiple entity definitions
-template.requirements = {
- "all": [
- { "entity": { "class": "class_A", "number": 5 } },
- { "entity": { "class": "class_B", "number": 5 } },
- { "entity": { "class": "class_C", "number": 5 } }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"),
- [{ "entities": [{ "class": "class_A", "number": 5, "check": "count" }, { "class": "class_B", "number": 5, "check": "count" }, { "class": "class_C", "number": 5, "check": "count" }] }]);
-
-// A `tech` and an `entity`
-template.requirements = { "all": [{ "tech": "tech_A" }, { "entity": { "class": "class_B", "number": 5, "check": "count" } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A"], "entities": [{ "class": "class_B", "number": 5, "check": "count" }] }]);
-
-// Multiple `civ`s
-template.requirements = { "all": [{ "civ": "civ_A"}, { "civ": "civ_B"}, { "civ": "civ_C"}] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_A"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_B"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_C"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_D"), false);
-
-// Multiple `notciv`s
-template.requirements = { "all": [{ "notciv": "civ_A"}, { "notciv": "civ_B"}, { "notciv": "civ_C"}] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_A"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_B"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_C"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_D"), []);
-
-// A `civ` with a tech/entity
-template.requirements = { "all": [{ "civ": "athen" }, { "tech": "expected_tech" }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["expected_tech"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), false);
-
-template.requirements = { "all": [{ "civ": "athen" }, { "entity": { "class": "Village", "number": 5 } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), false);
-
-template.requirements = { "all": [{ "civ": "athen" }, { "entity": { "class": "Village", "numberOfTypes": 5 } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), false);
-
-// A `notciv` with a tech/entity
-template.requirements = { "all": [{ "notciv": "athen" }, { "tech": "expected_tech" }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "techs": ["expected_tech"] }]);
-
-template.requirements = { "all": [{ "notciv": "athen" }, { "entity": { "class": "Village", "number": 5 } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
-
-template.requirements = { "all": [{ "notciv": "athen" }, { "entity": { "class": "Village", "numberOfTypes": 5 } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
-
-
-/**
- * Basic `any`s:
- */
-
-// Multiple techs
-template.requirements = { "any": [{ "tech": "tech_A" }, { "tech": "tech_B" }, { "tech": "tech_C" }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A"] }, { "techs": ["tech_B"] }, { "techs": ["tech_C"] }]);
-
-// Multiple entity definitions
-template.requirements = {
- "any": [
- { "entity": { "class": "class_A", "number": 5 } },
- { "entity": { "class": "class_B", "number": 5 } },
- { "entity": { "class": "class_C", "number": 5 } }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
- { "entities": [{ "class": "class_A", "number": 5, "check": "count" }] },
- { "entities": [{ "class": "class_B", "number": 5, "check": "count" }] },
- { "entities": [{ "class": "class_C", "number": 5, "check": "count" }] }
-]);
-
-// A tech or an entity
-template.requirements = { "any": [{ "tech": "tech_A" }, { "entity": { "class": "class_B", "number": 5, "check": "count" } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A"] }, { "entities": [{ "class": "class_B", "number": 5, "check": "count" }] }]);
-
-// Multiple `civ`s
-template.requirements = { "any": [{ "civ": "civ_A" }, { "civ": "civ_B" }, { "civ": "civ_C" }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_A"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_B"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_C"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_D"), false);
-
-// Multiple `notciv`s
-template.requirements = { "any": [{ "notciv": "civ_A" }, { "notciv": "civ_B" }, { "notciv": "civ_C" }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_A"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_B"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_C"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_D"), []);
-
-// A `civ` or a tech/entity
-template.requirements = { "any": [{ "civ": "athen" }, { "tech": "expected_tech" }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "techs": ["expected_tech"] }]);
-
-template.requirements = { "any": [{ "civ": "athen" }, { "entity": { "class": "Village", "number": 5 } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
-
-template.requirements = { "any": [{ "civ": "athen" }, { "entity": { "class": "Village", "numberOfTypes": 5 } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
-
-// A `notciv` or a tech
-template.requirements = { "any": [{ "notciv": "athen" }, { "tech": "expected_tech" }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "techs": ["expected_tech"] }]);
-
-template.requirements = { "any": [{ "notciv": "athen" }, { "entity": { "class": "Village", "number": 5 } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
-
-template.requirements = { "any": [{ "notciv": "athen" }, { "entity": { "class": "Village", "numberOfTypes": 5 } }] };
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
-
-
-/**
- * Complicated `all`s, part 1 - an `all` inside an `all`:
- */
-
-// Techs
-template.requirements = {
- "all": [
- { "all": [{ "tech": "tech_A" }, { "tech": "tech_B" }] },
- { "all": [{ "tech": "tech_C" }, { "tech": "tech_D" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A", "tech_B", "tech_C", "tech_D"] }]);
-
-// Techs and entities
-template.requirements = {
- "all": [
- { "all": [{ "tech": "tech_A" }, { "entity": { "class": "class_A", "number": 5 } }] },
- { "all": [{ "entity": { "class": "class_B", "numberOfTypes": 5 } }, { "tech": "tech_B" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{
- "techs": ["tech_A", "tech_B"],
- "entities": [{ "class": "class_A", "number": 5, "check": "count" }, { "class": "class_B", "number": 5, "check": "variants" }]
-}]);
-
-// Two `civ`s, without and with a tech
-template.requirements = {
- "all": [
- { "all": [{ "civ": "athen" }, { "civ": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
-
-template.requirements = {
- "all": [
- { "tech": "required_tech" },
- { "all": [{ "civ": "athen" }, { "civ": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
-
-// Two `notciv`s, without and with a tech
-template.requirements = {
- "all": [
- { "all": [{ "notciv": "athen" }, { "notciv": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), []);
-
-template.requirements = {
- "all": [
- { "tech": "required_tech" },
- { "all": [{ "notciv": "athen" }, { "notciv": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
-
-// Inner `all` has a tech and a `civ`/`notciv`
-template.requirements = {
- "all": [
- { "all": [{ "tech": "tech_A" }, { "civ": "maur" }] },
- { "tech": "tech_B" }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_B"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["tech_A", "tech_B"] }]);
-
-template.requirements = {
- "all": [
- { "all": [{ "tech": "tech_A" }, { "notciv": "maur" }] },
- { "tech": "tech_B" }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A", "tech_B"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["tech_B"] }]);
-
-
-/**
- * Complicated `all`s, part 2 - an `any` inside an `all`:
- */
-
-// Techs
-template.requirements = {
- "all": [
- { "any": [{ "tech": "tech_A" }, { "tech": "tech_B" }] },
- { "any": [{ "tech": "tech_C" }, { "tech": "tech_D" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
- { "techs": ["tech_A", "tech_C"] },
- { "techs": ["tech_A", "tech_D"] },
- { "techs": ["tech_B", "tech_C"] },
- { "techs": ["tech_B", "tech_D"] }
-]);
-
-// Techs and entities
-template.requirements = {
- "all": [
- { "any": [{ "tech": "tech_A" }, { "entity": { "class": "class_A", "number": 5 } }] },
- { "any": [{ "entity": { "class": "class_B", "numberOfTypes": 5 } }, { "tech": "tech_B" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
- { "techs": ["tech_A"], "entities": [{ "class": "class_B", "number": 5, "check": "variants" }] },
- { "techs": ["tech_A", "tech_B"] },
- { "entities": [{ "class": "class_A", "number": 5, "check": "count" }, { "class": "class_B", "number": 5, "check": "variants" }] },
- { "entities": [{ "class": "class_A", "number": 5, "check": "count" }], "techs": ["tech_B"] }
-]);
-
-// Two `civ`s, without and with a tech
-template.requirements = {
- "all": [
- { "any": [{ "civ": "athen" }, { "civ": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
-
-template.requirements = {
- "all": [
- { "tech": "required_tech" },
- { "any": [{ "civ": "athen" }, { "civ": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
-
-// Two `notciv`s, without and with a tech
-template.requirements = {
- "all": [
- { "any": [{ "notciv": "athen" }, { "notciv": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), []);
-
-template.requirements = {
- "all": [
- { "tech": "required_tech" },
- { "any": [{ "notciv": "athen" }, { "notciv": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
-
-
-/**
- * Complicated `any`s, part 1 - an `all` inside an `any`:
- */
-
-// Techs
-template.requirements = {
- "any": [
- { "all": [{ "tech": "tech_A" }, { "tech": "tech_B" }] },
- { "all": [{ "tech": "tech_C" }, { "tech": "tech_D" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
- { "techs": ["tech_A", "tech_B"] },
- { "techs": ["tech_C", "tech_D"] }
-]);
-
-// Techs and entities
-template.requirements = {
- "any": [
- { "all": [{ "tech": "tech_A" }, { "entity": { "class": "class_A", "number": 5 } }] },
- { "all": [{ "entity": { "class": "class_B", "numberOfTypes": 5 } }, { "tech": "tech_B" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
- { "techs": ["tech_A"], "entities": [{ "class": "class_A", "number": 5, "check": "count" }] },
- { "entities": [{ "class": "class_B", "number": 5, "check": "variants" }], "techs": ["tech_B"] }
-]);
-
-// Two `civ`s, without and with a tech
-template.requirements = {
- "any": [
- { "all": [{ "civ": "athen" }, { "civ": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
-
-template.requirements = {
- "any": [
- { "tech": "required_tech" },
- { "all": [{ "civ": "athen" }, { "civ": "spart" }] }
- ]
-};
-// Note: these requirements don't really make sense, as the `any` makes the `civ`s in the the inner `all` irrelevant.
-// We test it anyway as a precursor to later tests.
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
-
-// Two `notciv`s, without and with a tech
-template.requirements = {
- "any": [
- { "all": [{ "notciv": "athen" }, { "notciv": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), []);
-
-template.requirements = {
- "any": [
- { "tech": "required_tech" },
- { "all": [{ "notciv": "athen" }, { "notciv": "spart" }] }
- ]
-};
-// Note: these requirements have a result that might seen unexpected at first glance.
-// This is because the `notciv`s are rendered irrelevant by the `any`, and they have nothing else to operate on.
-// We test it anyway as a precursor for later tests.
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
-
-// Inner `all` has a tech and a `civ`/`notciv`
-template.requirements = {
- "any": [
- { "all": [{ "civ": "civA" }, { "tech": "tech1" }] },
- { "tech": "tech2" }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech1"] }, { "techs": ["tech2"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civB"), [{ "techs": ["tech2"] }]);
-
-template.requirements = {
- "any": [
- { "all": [{ "notciv": "civA" }, { "tech": "tech1" }] },
- { "tech": "tech2" }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech2"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civB"), [{ "techs": ["tech1"] }, { "techs": ["tech2"] }]);
-
-
-/**
- * Complicated `any`s, part 2 - an `any` inside an `any`:
- */
-
-// Techs
-template.requirements = {
- "any": [
- { "any": [{ "tech": "tech_A" }, { "tech": "tech_B" }] },
- { "any": [{ "tech": "tech_C" }, { "tech": "tech_D" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
- { "techs": ["tech_A"] },
- { "techs": ["tech_B"] },
- { "techs": ["tech_C"] },
- { "techs": ["tech_D"] }
-]);
-
-// Techs and entities
-template.requirements = {
- "any": [
- { "any": [{ "tech": "tech_A" }, { "entity": { "class": "class_A", "number": 5 } }] },
- { "any": [{ "entity": { "class": "class_B", "numberOfTypes": 5 } }, { "tech": "tech_B" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
- { "techs": ["tech_A"] },
- { "entities": [{ "class": "class_A", "number": 5, "check": "count" }] },
- { "entities": [{ "class": "class_B", "number": 5, "check": "variants" }] },
- { "techs": ["tech_B"] }
-]);
-
-// Two `civ`s, without and with a tech
-template.requirements = {
- "any": [
- { "any": [{ "civ": "athen" }, { "civ": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
-
-template.requirements = {
- "any": [
- { "tech": "required_tech" },
- { "any": [{ "civ": "athen" }, { "civ": "spart" }] }
- ]
-};
-// These requirements may not make sense, as the `civ`s are unable to restrict the requirements due to the outer `any`
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
-
-// Two `notciv`s, without and with a tech
-template.requirements = {
- "any": [
- { "any": [{ "notciv": "athen" }, { "notciv": "spart" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), []);
-
-template.requirements = {
- "any": [
- { "tech": "required_tech" },
- { "any": [{ "notciv": "athen" }, { "notciv": "spart" }] }
- ]
-};
-// These requirements may not make sense, as the `notciv`s are made irrelevant by the outer `any`
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
-
-
-/**
- * Further tests
- */
-
-template.requirements = {
- "all": [
- { "tech": "tech1" },
- { "any": [{ "civ": "civA" }, { "civ": "civB" }] },
- { "notciv": "civC" }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech1"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civC"), false);
-
-template.requirements = {
- "any": [
- { "all": [{ "civ": "civA" }, { "tech": "tech1" }] },
- { "all": [{ "civ": "civB" }, { "tech": "tech2" }] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech1"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civB"), [{ "techs": ["tech2"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civC"), false);
-
-template.requirements = {
- "any": [
- { "all": [{ "civ": "civA" }, { "tech": "tech1" }] },
- { "all": [
- { "any": [{ "civ": "civB" }, { "civ": "civC" }] },
- { "tech": "tech2" }
- ] }
- ]
-};
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech1"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civC"), [{ "techs": ["tech2"] }]);
-TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civD"), false);
Index: binaries/data/mods/public/simulation/components/tests/test_Technologies_effects.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/tests/test_Technologies_effects.js
@@ -0,0 +1,45 @@
+// TODO: Move this to a folder of tests for GlobalScripts (once one is created)
+
+
+// This tests the GetTechModifiedProperty function.
+
+let add = {
+ "Test_A": [{"add": 10, "affects": "Unit"}]
+}
+
+let add_add = {
+ "Test_A": [{"add": 10, "affects": "Unit"}, {"add": 5, "affects": "Unit"}]
+}
+
+let add_mul_add = {
+ "Test_A": [{"add": 10, "affects": "Unit"}, {"multiply": 2, "affects": "Unit"}, {"add": 5, "affects": "Unit"}]
+}
+
+let add_replace = {
+ "Test_A": [{"add": 10, "affects": "Unit"}, {"replace": 10, "affects": "Unit"}]
+}
+
+let replace_add = {
+ "Test_A": [{"replace": 10, "affects": "Unit"},{"add": 10, "affects": "Unit"}]
+}
+
+let replace_replace = {
+ "Test_A": [{"replace": 10, "affects": "Unit"},{"replace": 30, "affects": "Unit"}]
+}
+
+let replace_nonnum = {
+ "Test_A": [{"replace": "alpha", "affects": "Unit"}]
+}
+
+TS_ASSERT_EQUALS(GetTechModifiedProperty(add, "Unit", "Test_A", 5), 15);
+TS_ASSERT_EQUALS(GetTechModifiedProperty(add_add, "Unit", "Test_A", 5), 20);
+TS_ASSERT_EQUALS(GetTechModifiedProperty(add_add, "Other", "Test_A", 5), 5);
+
+
+TS_ASSERT_EQUALS(GetTechModifiedProperty(add_mul_add, "Unit", "Test_A", 5), 35);
+
+TS_ASSERT_EQUALS(GetTechModifiedProperty(add_replace, "Unit", "Test_A", 5), 10);
+TS_ASSERT_EQUALS(GetTechModifiedProperty(replace_replace, "Unit", "Test_A", 5), 30);
+
+TS_ASSERT_EQUALS(GetTechModifiedProperty(replace_nonnum, "Unit", "Test_A", "beta"), "alpha");
+
Index: binaries/data/mods/public/simulation/components/tests/test_Technologies_reqs.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/tests/test_Technologies_reqs.js
@@ -0,0 +1,510 @@
+// TODO: Move this to a folder of tests for GlobalScripts (once one is created)
+
+// No requirements set in template
+let template = {};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+
+/**
+ * First, the basics:
+ */
+
+// Technology Requirement
+template.requirements = { "tech": "expected_tech" };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["expected_tech"] }]);
+
+// Entity Requirement: Count of entities matching given class
+template.requirements = { "entity": { "class": "Village", "number": 5 } };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
+
+// Entity Requirement: Count of entities matching given class
+template.requirements = { "entity": { "class": "Village", "numberOfTypes": 5 } };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
+
+// Single `civ`
+template.requirements = { "civ": "athen" };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), false);
+
+// Single `notciv`
+template.requirements = { "notciv": "athen" };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), []);
+
+
+/**
+ * Basic `all`s:
+ */
+
+// Multiple techs
+template.requirements = { "all": [{ "tech": "tech_A" }, { "tech": "tech_B" }, { "tech": "tech_C" }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A", "tech_B", "tech_C"] }]);
+
+// Multiple entity definitions
+template.requirements = {
+ "all": [
+ { "entity": { "class": "class_A", "number": 5 } },
+ { "entity": { "class": "class_B", "number": 5 } },
+ { "entity": { "class": "class_C", "number": 5 } }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"),
+ [{ "entities": [{ "class": "class_A", "number": 5, "check": "count" }, { "class": "class_B", "number": 5, "check": "count" }, { "class": "class_C", "number": 5, "check": "count" }] }]);
+
+// A `tech` and an `entity`
+template.requirements = { "all": [{ "tech": "tech_A" }, { "entity": { "class": "class_B", "number": 5, "check": "count" } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A"], "entities": [{ "class": "class_B", "number": 5, "check": "count" }] }]);
+
+// Multiple `civ`s
+template.requirements = { "all": [{ "civ": "civ_A"}, { "civ": "civ_B"}, { "civ": "civ_C"}] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_A"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_B"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_C"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_D"), false);
+
+// Multiple `notciv`s
+template.requirements = { "all": [{ "notciv": "civ_A"}, { "notciv": "civ_B"}, { "notciv": "civ_C"}] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_A"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_B"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_C"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_D"), []);
+
+// A `civ` with a tech/entity
+template.requirements = { "all": [{ "civ": "athen" }, { "tech": "expected_tech" }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["expected_tech"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), false);
+
+template.requirements = { "all": [{ "civ": "athen" }, { "entity": { "class": "Village", "number": 5 } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), false);
+
+template.requirements = { "all": [{ "civ": "athen" }, { "entity": { "class": "Village", "numberOfTypes": 5 } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), false);
+
+// A `notciv` with a tech/entity
+template.requirements = { "all": [{ "notciv": "athen" }, { "tech": "expected_tech" }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "techs": ["expected_tech"] }]);
+
+template.requirements = { "all": [{ "notciv": "athen" }, { "entity": { "class": "Village", "number": 5 } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
+
+template.requirements = { "all": [{ "notciv": "athen" }, { "entity": { "class": "Village", "numberOfTypes": 5 } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
+
+
+/**
+ * Basic `any`s:
+ */
+
+// Multiple techs
+template.requirements = { "any": [{ "tech": "tech_A" }, { "tech": "tech_B" }, { "tech": "tech_C" }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A"] }, { "techs": ["tech_B"] }, { "techs": ["tech_C"] }]);
+
+// Multiple entity definitions
+template.requirements = {
+ "any": [
+ { "entity": { "class": "class_A", "number": 5 } },
+ { "entity": { "class": "class_B", "number": 5 } },
+ { "entity": { "class": "class_C", "number": 5 } }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
+ { "entities": [{ "class": "class_A", "number": 5, "check": "count" }] },
+ { "entities": [{ "class": "class_B", "number": 5, "check": "count" }] },
+ { "entities": [{ "class": "class_C", "number": 5, "check": "count" }] }
+]);
+
+// A tech or an entity
+template.requirements = { "any": [{ "tech": "tech_A" }, { "entity": { "class": "class_B", "number": 5, "check": "count" } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A"] }, { "entities": [{ "class": "class_B", "number": 5, "check": "count" }] }]);
+
+// Multiple `civ`s
+template.requirements = { "any": [{ "civ": "civ_A" }, { "civ": "civ_B" }, { "civ": "civ_C" }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_A"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_B"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_C"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_D"), false);
+
+// Multiple `notciv`s
+template.requirements = { "any": [{ "notciv": "civ_A" }, { "notciv": "civ_B" }, { "notciv": "civ_C" }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_A"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_B"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_C"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civ_D"), []);
+
+// A `civ` or a tech/entity
+template.requirements = { "any": [{ "civ": "athen" }, { "tech": "expected_tech" }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "techs": ["expected_tech"] }]);
+
+template.requirements = { "any": [{ "civ": "athen" }, { "entity": { "class": "Village", "number": 5 } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
+
+template.requirements = { "any": [{ "civ": "athen" }, { "entity": { "class": "Village", "numberOfTypes": 5 } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
+
+// A `notciv` or a tech
+template.requirements = { "any": [{ "notciv": "athen" }, { "tech": "expected_tech" }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "techs": ["expected_tech"] }]);
+
+template.requirements = { "any": [{ "notciv": "athen" }, { "entity": { "class": "Village", "number": 5 } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "count" }] }]);
+
+template.requirements = { "any": [{ "notciv": "athen" }, { "entity": { "class": "Village", "numberOfTypes": 5 } }] };
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "spart"), [{ "entities": [{ "class": "Village", "number": 5, "check": "variants" }] }]);
+
+
+/**
+ * Complicated `all`s, part 1 - an `all` inside an `all`:
+ */
+
+// Techs
+template.requirements = {
+ "all": [
+ { "all": [{ "tech": "tech_A" }, { "tech": "tech_B" }] },
+ { "all": [{ "tech": "tech_C" }, { "tech": "tech_D" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A", "tech_B", "tech_C", "tech_D"] }]);
+
+// Techs and entities
+template.requirements = {
+ "all": [
+ { "all": [{ "tech": "tech_A" }, { "entity": { "class": "class_A", "number": 5 } }] },
+ { "all": [{ "entity": { "class": "class_B", "numberOfTypes": 5 } }, { "tech": "tech_B" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{
+ "techs": ["tech_A", "tech_B"],
+ "entities": [{ "class": "class_A", "number": 5, "check": "count" }, { "class": "class_B", "number": 5, "check": "variants" }]
+}]);
+
+// Two `civ`s, without and with a tech
+template.requirements = {
+ "all": [
+ { "all": [{ "civ": "athen" }, { "civ": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
+
+template.requirements = {
+ "all": [
+ { "tech": "required_tech" },
+ { "all": [{ "civ": "athen" }, { "civ": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
+
+// Two `notciv`s, without and with a tech
+template.requirements = {
+ "all": [
+ { "all": [{ "notciv": "athen" }, { "notciv": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), []);
+
+template.requirements = {
+ "all": [
+ { "tech": "required_tech" },
+ { "all": [{ "notciv": "athen" }, { "notciv": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
+
+// Inner `all` has a tech and a `civ`/`notciv`
+template.requirements = {
+ "all": [
+ { "all": [{ "tech": "tech_A" }, { "civ": "maur" }] },
+ { "tech": "tech_B" }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_B"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["tech_A", "tech_B"] }]);
+
+template.requirements = {
+ "all": [
+ { "all": [{ "tech": "tech_A" }, { "notciv": "maur" }] },
+ { "tech": "tech_B" }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["tech_A", "tech_B"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["tech_B"] }]);
+
+
+/**
+ * Complicated `all`s, part 2 - an `any` inside an `all`:
+ */
+
+// Techs
+template.requirements = {
+ "all": [
+ { "any": [{ "tech": "tech_A" }, { "tech": "tech_B" }] },
+ { "any": [{ "tech": "tech_C" }, { "tech": "tech_D" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
+ { "techs": ["tech_A", "tech_C"] },
+ { "techs": ["tech_A", "tech_D"] },
+ { "techs": ["tech_B", "tech_C"] },
+ { "techs": ["tech_B", "tech_D"] }
+]);
+
+// Techs and entities
+template.requirements = {
+ "all": [
+ { "any": [{ "tech": "tech_A" }, { "entity": { "class": "class_A", "number": 5 } }] },
+ { "any": [{ "entity": { "class": "class_B", "numberOfTypes": 5 } }, { "tech": "tech_B" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
+ { "techs": ["tech_A"], "entities": [{ "class": "class_B", "number": 5, "check": "variants" }] },
+ { "techs": ["tech_A", "tech_B"] },
+ { "entities": [{ "class": "class_A", "number": 5, "check": "count" }, { "class": "class_B", "number": 5, "check": "variants" }] },
+ { "entities": [{ "class": "class_A", "number": 5, "check": "count" }], "techs": ["tech_B"] }
+]);
+
+// Two `civ`s, without and with a tech
+template.requirements = {
+ "all": [
+ { "any": [{ "civ": "athen" }, { "civ": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
+
+template.requirements = {
+ "all": [
+ { "tech": "required_tech" },
+ { "any": [{ "civ": "athen" }, { "civ": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
+
+// Two `notciv`s, without and with a tech
+template.requirements = {
+ "all": [
+ { "any": [{ "notciv": "athen" }, { "notciv": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), []);
+
+template.requirements = {
+ "all": [
+ { "tech": "required_tech" },
+ { "any": [{ "notciv": "athen" }, { "notciv": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
+
+
+/**
+ * Complicated `any`s, part 1 - an `all` inside an `any`:
+ */
+
+// Techs
+template.requirements = {
+ "any": [
+ { "all": [{ "tech": "tech_A" }, { "tech": "tech_B" }] },
+ { "all": [{ "tech": "tech_C" }, { "tech": "tech_D" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
+ { "techs": ["tech_A", "tech_B"] },
+ { "techs": ["tech_C", "tech_D"] }
+]);
+
+// Techs and entities
+template.requirements = {
+ "any": [
+ { "all": [{ "tech": "tech_A" }, { "entity": { "class": "class_A", "number": 5 } }] },
+ { "all": [{ "entity": { "class": "class_B", "numberOfTypes": 5 } }, { "tech": "tech_B" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
+ { "techs": ["tech_A"], "entities": [{ "class": "class_A", "number": 5, "check": "count" }] },
+ { "entities": [{ "class": "class_B", "number": 5, "check": "variants" }], "techs": ["tech_B"] }
+]);
+
+// Two `civ`s, without and with a tech
+template.requirements = {
+ "any": [
+ { "all": [{ "civ": "athen" }, { "civ": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
+
+template.requirements = {
+ "any": [
+ { "tech": "required_tech" },
+ { "all": [{ "civ": "athen" }, { "civ": "spart" }] }
+ ]
+};
+// Note: these requirements don't really make sense, as the `any` makes the `civ`s in the the inner `all` irrelevant.
+// We test it anyway as a precursor to later tests.
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
+
+// Two `notciv`s, without and with a tech
+template.requirements = {
+ "any": [
+ { "all": [{ "notciv": "athen" }, { "notciv": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), []);
+
+template.requirements = {
+ "any": [
+ { "tech": "required_tech" },
+ { "all": [{ "notciv": "athen" }, { "notciv": "spart" }] }
+ ]
+};
+// Note: these requirements have a result that might seen unexpected at first glance.
+// This is because the `notciv`s are rendered irrelevant by the `any`, and they have nothing else to operate on.
+// We test it anyway as a precursor for later tests.
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
+
+// Inner `all` has a tech and a `civ`/`notciv`
+template.requirements = {
+ "any": [
+ { "all": [{ "civ": "civA" }, { "tech": "tech1" }] },
+ { "tech": "tech2" }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech1"] }, { "techs": ["tech2"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civB"), [{ "techs": ["tech2"] }]);
+
+template.requirements = {
+ "any": [
+ { "all": [{ "notciv": "civA" }, { "tech": "tech1" }] },
+ { "tech": "tech2" }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech2"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civB"), [{ "techs": ["tech1"] }, { "techs": ["tech2"] }]);
+
+
+/**
+ * Complicated `any`s, part 2 - an `any` inside an `any`:
+ */
+
+// Techs
+template.requirements = {
+ "any": [
+ { "any": [{ "tech": "tech_A" }, { "tech": "tech_B" }] },
+ { "any": [{ "tech": "tech_C" }, { "tech": "tech_D" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
+ { "techs": ["tech_A"] },
+ { "techs": ["tech_B"] },
+ { "techs": ["tech_C"] },
+ { "techs": ["tech_D"] }
+]);
+
+// Techs and entities
+template.requirements = {
+ "any": [
+ { "any": [{ "tech": "tech_A" }, { "entity": { "class": "class_A", "number": 5 } }] },
+ { "any": [{ "entity": { "class": "class_B", "numberOfTypes": 5 } }, { "tech": "tech_B" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [
+ { "techs": ["tech_A"] },
+ { "entities": [{ "class": "class_A", "number": 5, "check": "count" }] },
+ { "entities": [{ "class": "class_B", "number": 5, "check": "variants" }] },
+ { "techs": ["tech_B"] }
+]);
+
+// Two `civ`s, without and with a tech
+template.requirements = {
+ "any": [
+ { "any": [{ "civ": "athen" }, { "civ": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), []);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), false);
+
+template.requirements = {
+ "any": [
+ { "tech": "required_tech" },
+ { "any": [{ "civ": "athen" }, { "civ": "spart" }] }
+ ]
+};
+// These requirements may not make sense, as the `civ`s are unable to restrict the requirements due to the outer `any`
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
+
+// Two `notciv`s, without and with a tech
+template.requirements = {
+ "any": [
+ { "any": [{ "notciv": "athen" }, { "notciv": "spart" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), false);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), []);
+
+template.requirements = {
+ "any": [
+ { "tech": "required_tech" },
+ { "any": [{ "notciv": "athen" }, { "notciv": "spart" }] }
+ ]
+};
+// These requirements may not make sense, as the `notciv`s are made irrelevant by the outer `any`
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "athen"), [{ "techs": ["required_tech"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "maur"), [{ "techs": ["required_tech"] }]);
+
+
+/**
+ * Further tests
+ */
+
+template.requirements = {
+ "all": [
+ { "tech": "tech1" },
+ { "any": [{ "civ": "civA" }, { "civ": "civB" }] },
+ { "notciv": "civC" }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech1"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civC"), false);
+
+template.requirements = {
+ "any": [
+ { "all": [{ "civ": "civA" }, { "tech": "tech1" }] },
+ { "all": [{ "civ": "civB" }, { "tech": "tech2" }] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech1"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civB"), [{ "techs": ["tech2"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civC"), false);
+
+template.requirements = {
+ "any": [
+ { "all": [{ "civ": "civA" }, { "tech": "tech1" }] },
+ { "all": [
+ { "any": [{ "civ": "civB" }, { "civ": "civC" }] },
+ { "tech": "tech2" }
+ ] }
+ ]
+};
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civA"), [{ "techs": ["tech1"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civC"), [{ "techs": ["tech2"] }]);
+TS_ASSERT_UNEVAL_EQUALS(DeriveTechnologyRequirements(template, "civD"), false);
Index: binaries/data/mods/public/simulation/components/tests/test_VisionSharing.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_VisionSharing.js
+++ binaries/data/mods/public/simulation/components/tests/test_VisionSharing.js
@@ -2,6 +2,7 @@
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/GarrisonHolder.js");
Engine.LoadComponentScript("interfaces/TechnologyManager.js");
+Engine.LoadComponentScript("interfaces/ModifiersManager.js");
Engine.LoadComponentScript("interfaces/AuraManager.js");
Engine.LoadComponentScript("interfaces/Timer.js");
Engine.LoadComponentScript("interfaces/VisionSharing.js");
@@ -116,6 +117,9 @@
AddMock(14, IID_TechnologyManager, {
"CanProduce": entity => false,
+});
+
+AddMock(14, IID_ModifiersManager, {
"ApplyModificationsTemplate": (valueName, curValue, template) => curValue
});
@@ -125,8 +129,12 @@
AddMock(14, IID_TechnologyManager, {
"CanProduce": entity => entity == "special/spy",
+});
+
+AddMock(14, IID_ModifiersManager, {
"ApplyModificationsTemplate": (valueName, curValue, template) => curValue
});
+
AddMock(14, IID_Player, {
"GetSpyCostMultiplier": () => 1,
"TrySubtractResources": costs => false
Index: binaries/data/mods/public/simulation/helpers/Cheat.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Cheat.js
+++ binaries/data/mods/public/simulation/helpers/Cheat.js
@@ -69,7 +69,23 @@
cmpProductionQueue.SpawnUnits(input.templates[i % input.templates.length], 1, null);
return;
case "fastactions":
- cmpPlayer.SetCheatTimeMultiplier((cmpPlayer.GetCheatTimeMultiplier() == 1) ? 0.01 : 1);
+ let cmpModManager = Engine.QueryInterface(playerEnt, IID_ModifiersManager);
+ if (!cmpModManager)
+ return;
+ if (cmpModManager.HasAnyGlobalModifierWithID("cheat/fastactions"))
+ {
+ warn("here");
+ cmpModManager.RemoveGlobalModifiers("cheat/fastactions")
+ }
+ else
+ cmpModManager.AddGlobalModifiers("cheat/fastactions", 1000, {
+ "Cost/BuildTime" : {"affects": [["Structure"], ["Unit"]], "multiply": 0.01},
+ "ResourceGatherer/BaseSpeed" : {"affects": [["Structure"], ["Unit"]], "multiply": 1000.0},
+ "Pack/Time" : {"affects": [["Structure"], ["Unit"]], "multiply": 0.01},
+ "Upgrade/Time" : {"affects": [["Structure"], ["Unit"]], "multiply": 0.01},
+ "ProductionQueue/TechCostMultiplier/time" : {"affects": [["Structure"], ["Unit"]], "multiply": 0.01}
+ }
+ );
return;
case "changespeed":
cmpPlayer.SetCheatTimeMultiplier(input.parameter);
Index: binaries/data/mods/public/simulation/helpers/ValueModification.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/ValueModification.js
+++ binaries/data/mods/public/simulation/helpers/ValueModification.js
@@ -3,9 +3,9 @@
function ApplyValueModificationsToEntity(tech_type, current_value, entity)
{
let value = current_value;
- let cmpTechnologyManager = QueryOwnerInterface(entity, IID_TechnologyManager);
- if (cmpTechnologyManager)
- value = cmpTechnologyManager.ApplyModifications(tech_type, current_value, entity);
+ let cmpModManager = QueryOwnerInterface(entity, IID_ModifiersManager);
+ if (cmpModManager)
+ value = cmpModManager.ApplyModifications(tech_type, current_value, entity);
let cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
if (!cmpAuraManager)
@@ -24,9 +24,9 @@
function ApplyValueModificationsToTemplate(tech_type, current_value, playerID, template)
{
let value = current_value;
- let cmpTechnologyManager = QueryPlayerIDInterface(playerID, IID_TechnologyManager);
- if (cmpTechnologyManager)
- value = cmpTechnologyManager.ApplyModificationsTemplate(tech_type, current_value, template);
+ let cmpModManager = QueryPlayerIDInterface(playerID, IID_ModifiersManager);
+ if (cmpModManager)
+ value = cmpModManager.ApplyModificationsTemplate(tech_type, current_value, template);
let cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
if (!cmpAuraManager)
Index: binaries/data/mods/public/simulation/templates/special/player.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/special/player.xml
+++ binaries/data/mods/public/simulation/templates/special/player.xml
@@ -57,6 +57,7 @@
Player
Player
+
unlock_shared_los
unlock_shared_dropsites