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,247 @@
+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 SetGlobalModifier, to set multiple modifiers with the same ID and priority easily
+ModifiersManager.prototype.SetGlobalModifiers = function(modificationID, priority, modificationArray)
+{
+ for (let propertyName in modificationArray)
+ this.SetGlobalModifier(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.SetGlobalModifier = 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)
+ // update it.
+ existing.effect = modification;
+ 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, "effect": modification});
+ }
+
+ // bump version to invalidate caches
+ ++modifier.version;
+
+ // 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.RemoveGlobalModifier = function(propertyName, modificationID)
+{
+ if (!this.globalModifiers.get(propertyName))
+ return;
+
+ let modifier = this.globalModifiers.get(propertyName);
+
+ // remove modifier.
+ let size = modifier.modifications.length;
+ modifier.modifications = modifier.modifications.filter(modification => { return modification.ID != modificationID; });
+ if (modifier.modifications.length != size)
+ // bump version to invalidate caches
+ ++modifier.version;
+
+ // 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
@@ -35,7 +35,6 @@
this.gatherRateMultiplier = 1;
this.tradeRateMultiplier = 1;
this.cheatsEnabled = false;
- this.cheatTimeMultiplier = 1;
this.heroes = [];
this.resourceNames = {};
this.disabledTemplates = {};
@@ -751,16 +750,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,7 +213,6 @@
return;
}
- var modifiedComponents = {};
this.researchedTechs[tech] = template;
// store the modifications in an easy to access structure
if (template.modifications)
@@ -288,8 +235,6 @@
for (var i in template.modifications)
{
var modification = template.modifications[i];
- if (!this.modifications[modification.value])
- this.modifications[modification.value] = [];
var modAffects = affects.slice();
if (modification.affects)
@@ -306,12 +251,8 @@
if (j !== "value" && j !== "affects")
mod[j] = modification[j];
- this.modifications[modification.value].push(mod);
- var component = modification.value.split("/")[0];
- if (!modifiedComponents[component])
- modifiedComponents[component] = [];
- modifiedComponents[component].push(modification.value);
- this.modificationCache[modification.value] = {};
+ let cmpModManager = Engine.QueryInterface(this.entity, IID_ModifiersManager);
+ cmpModManager.SetGlobalModifier(modification.value, "tech/"+tech, 5, mod);
}
}
@@ -353,51 +294,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
@@ -442,12 +345,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
@@ -141,8 +141,7 @@
{
hasCosts = true;
let cmpPlayer = QueryPlayerIDInterface(this.owner, IID_Player);
- cost.time = ApplyValueModificationsToTemplate("Upgrade/Time", +choice.Time, this.owner, entType) *
- cmpPlayer.GetCheatTimeMultiplier();
+ cost.time = ApplyValueModificationsToTemplate("Upgrade/Time", +choice.Time, this.owner, entType);
}
ret.push({
"entity": entType,
@@ -276,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/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.SetGlobalModifiers("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)
@@ -26,9 +26,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