Index: binaries/data/mods/public/globalscripts/ModificationTemplates.js
===================================================================
--- binaries/data/mods/public/globalscripts/ModificationTemplates.js
+++ binaries/data/mods/public/globalscripts/ModificationTemplates.js
@@ -43,3 +43,155 @@
global.AuraTemplates = new ModificationTemplates("simulation/data/auras/");
global.TechnologyTemplates = new ModificationTemplates("simulation/data/technologies/");
}
+
+/**
+ * Derives modifications (to be applied to entities) from a given aura/technology.
+ *
+ * @param {Object} techTemplate - The aura/technology template to derive the modifications from.
+ * @return {Object} containing the relevant modifications.
+ */
+function DeriveModificationsFromTech(techTemplate)
+{
+ if (!techTemplate.modifications)
+ return {};
+
+ let techMods = {};
+ let techAffects = [];
+ if (techTemplate.affects && techTemplate.affects.length)
+ for (let affected of techTemplate.affects)
+ techAffects.push(affected.split(/\s+/));
+ else
+ techAffects.push([]);
+
+ for (let mod of techTemplate.modifications)
+ {
+ let affects = techAffects.slice();
+ if (mod.affects)
+ {
+ let specAffects = mod.affects.split(/\s+/);
+ for (let a in affects)
+ affects[a] = affects[a].concat(specAffects);
+ }
+
+ let newModifier = { "affects": affects };
+ for (let idx in mod)
+ if (idx !== "value" && idx !== "affects")
+ newModifier[idx] = mod[idx];
+
+ if (!techMods[mod.value])
+ techMods[mod.value] = [];
+ techMods[mod.value].push(newModifier);
+ }
+ return techMods;
+}
+
+/**
+ * Derives modifications (to be applied to entities) from a provided array
+ * of aura/technology template data.
+ *
+ * @param {array} techsDataArray
+ * @return {object} containing the combined relevant modifications of all
+ * the technologies.
+ */
+function DeriveModificationsFromTechnologies(techsDataArray)
+{
+ let derivedModifiers = {};
+ for (let technology of techsDataArray)
+ {
+ if (!technology.reqs)
+ continue;
+
+ let modifiers = DeriveModificationsFromTech(technology);
+ for (let modPath in modifiers)
+ {
+ if (!derivedModifiers[modPath])
+ derivedModifiers[modPath] = [];
+ derivedModifiers[modPath] = derivedModifiers[modPath].concat(modifiers[modPath]);
+ }
+ }
+ return derivedModifiers;
+}
+
+/**
+ * Common definition of the XML schema for in-template modifications.
+ */
+const ModificationSchema =
+"" +
+ "" +
+ "" +
+ "tokens" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "tokens" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+"";
+
+const ModificationsSchema =
+"" +
+ "" +
+ "" +
+ "" +
+ ModificationSchema +
+ "" +
+ "" +
+"";
+
+/**
+ * Derives a single modification (to be applied to entities) from a given XML template.
+ *
+ * @param {Object} techTemplate - The XML template node to derive the modification from.
+ * @return {Object} containing the relevant modification.
+ */
+function DeriveModificationFromXMLTemplate(template)
+{
+ let effect = {};
+ if (template.Add)
+ effect.add = +template.Add;
+ if (template.Multiply)
+ effect.multiply = +template.Multiply;
+ if (template.Replace)
+ effect.replace = template.Replace;
+ effect.affects = template.Affects ? template.Affects._string.split(/\s/) : effect.affects = [];
+
+ let ret = {};
+ template.Paths._string.split(/\s/).forEach(path => (ret[path] = [effect]));
+ return ret;
+}
+
+/**
+ * Derives all modifications (to be applied to entities) from a given XML template.
+ *
+ * @param {Object} techTemplate - The XML template node to derive the modifications from.
+ * @return {Object} containing the combined modifications.
+ */
+function DeriveModificationsFromXMLTemplate(template)
+{
+ let ret = {};
+ for (let name in template)
+ {
+ let modification = DeriveModificationFromXMLTemplate(template[name]);
+ for (let path in modification)
+ {
+ if (!ret[path])
+ ret[path] = [];
+ ret[path] = ret[path].concat(modification[path]);
+ }
+ }
+ return ret;
+}
Index: binaries/data/mods/public/globalscripts/Technologies.js
===================================================================
--- binaries/data/mods/public/globalscripts/Technologies.js
+++ binaries/data/mods/public/globalscripts/Technologies.js
@@ -39,74 +39,6 @@
return originalValue;
}
-/**
- * Derives modifications (to be applied to entities) from a given technology.
- *
- * @param {Object} techTemplate - The technology template to derive the modifications from.
- * @return {Object} containing the relevant modifications.
- */
-function DeriveModificationsFromTech(techTemplate)
-{
- if (!techTemplate.modifications)
- return {};
-
- let techMods = {};
- let techAffects = [];
- if (techTemplate.affects && techTemplate.affects.length)
- for (let affected of techTemplate.affects)
- techAffects.push(affected.split(/\s+/));
- else
- techAffects.push([]);
-
- for (let mod of techTemplate.modifications)
- {
- let affects = techAffects.slice();
- if (mod.affects)
- {
- let specAffects = mod.affects.split(/\s+/);
- for (let a in affects)
- affects[a] = affects[a].concat(specAffects);
- }
-
- let newModifier = { "affects": affects };
- for (let idx in mod)
- if (idx !== "value" && idx !== "affects")
- newModifier[idx] = mod[idx];
-
- if (!techMods[mod.value])
- techMods[mod.value] = [];
- techMods[mod.value].push(newModifier);
- }
- return techMods;
-}
-
-/**
- * Derives modifications (to be applied to entities) from a provided array
- * of technology template data.
- *
- * @param {array} techsDataArray
- * @return {object} containing the combined relevant modifications of all
- * the technologies.
- */
-function DeriveModificationsFromTechnologies(techsDataArray)
-{
- let derivedModifiers = {};
- for (let technology of techsDataArray)
- {
- if (!technology.reqs)
- continue;
-
- let modifiers = DeriveModificationsFromTech(technology);
- for (let modPath in modifiers)
- {
- if (!derivedModifiers[modPath])
- derivedModifiers[modPath] = [];
- derivedModifiers[modPath] = derivedModifiers[modPath].concat(modifiers[modPath]);
- }
- }
- return derivedModifiers;
-}
-
/**
* Returns whether the given modification applies to the entity containing the given class list
*/
Index: binaries/data/mods/public/globalscripts/Templates.js
===================================================================
--- binaries/data/mods/public/globalscripts/Templates.js
+++ binaries/data/mods/public/globalscripts/Templates.js
@@ -180,7 +180,9 @@
effects.Damage[damageType] = getEntityValue(path + "/Damage/" + damageType);
}
- // TODO: status effects
+ if (temp.GiveStatus)
+ effects.GiveStatus = temp.GiveStatus;
+
return effects;
};
Index: binaries/data/mods/public/gui/common/tooltips.js
===================================================================
--- binaries/data/mods/public/gui/common/tooltips.js
+++ binaries/data/mods/public/gui/common/tooltips.js
@@ -377,13 +377,28 @@
if (template.Duration)
durationString = sprintf(translate(", %(durName)s: %(duration)s"), {
"durName": headerFont(translate("Duration")),
- "duration": getSecondsString((template.TimeElapsed ? +template.Duration - template.TimeElapsed : +template.Duration) / 1000),
+ "duration": getSecondsString((template._timeElapsed ? +template.Duration - template._timeElapsed : +template.Duration) / 1000),
});
- return sprintf(translate("%(statusName)s: %(effects)s, %(rate)s%(durationString)s"), {
+ let intervalString = "";
+ if (template.Interval)
+ intervalString = sprintf(translate(", %(interval)s"), {
+ "interval": attackRateDetails(+template.Interval)
+ });
+
+ let tooltipString = "";
+ if (template.Tooltip)
+ tooltipString = translate(template.Tooltip);
+
+ let attackEffectsString = "";
+ if (template.Damage || template.Capture)
+ attackEffectsString = attackEffectsDetails(template);
+
+ return sprintf(translate("%(statusName)s: %(tooltip)s%(effects)s%(rate)s%(durationString)s"), {
"statusName": headerFont(translateWithContext("status effect", name)),
- "effects": attackEffectsDetails(template),
- "rate": attackRateDetails(+template.Interval),
+ "tooltip": tooltipString,
+ "effects": attackEffectsString,
+ "rate": intervalString,
"durationString": durationString
});
}
Index: binaries/data/mods/public/simulation/components/StatusEffectsReceiver.js
===================================================================
--- binaries/data/mods/public/simulation/components/StatusEffectsReceiver.js
+++ binaries/data/mods/public/simulation/components/StatusEffectsReceiver.js
@@ -24,26 +24,58 @@
StatusEffectsReceiver.prototype.AddStatus = function(statusName, data)
{
if (this.activeStatusEffects[statusName])
+ {
+ // TODO: implement different behaviour when receiving the same status multiple times.
+ // For now, these are ignored.
return;
+ }
this.activeStatusEffects[statusName] = {};
let status = this.activeStatusEffects[statusName];
Object.assign(status, data);
- status.Interval = +data.Interval;
- status.TimeElapsed = 0;
- status.FirstTime = true;
- let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
- status.Timer = cmpTimer.SetInterval(this.entity, IID_StatusEffectsReceiver, "ExecuteEffect", 0, +status.Interval, statusName);
+ if (status.Modifiers)
+ {
+ let modifications = DeriveModificationsFromXMLTemplate(status.Modifiers);
+ warn(uneval(modifications));
+ let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
+ cmpModifiersManager.AddModifiers(statusName, modifications, this.entity);
+ }
+
+ // We want an interval to update the GUI to show how much time of the status effect
+ // is left even if the status effect itself has no interval.
+ if (status.Duration && !status.Interval)
+ status.Interval = 1000;
+
+ if (status.Interval)
+ {
+ if (status.Duration)
+ {
+ status._timeElapsed = 0;
+ status._firstTime = true;
+ }
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ status._timer = cmpTimer.SetInterval(this.entity, IID_StatusEffectsReceiver, "ExecuteEffect", 0, +status.Interval, statusName);
+ }
};
StatusEffectsReceiver.prototype.RemoveStatus = function(statusName)
{
- if (!this.activeStatusEffects[statusName])
+ let statusEffect = this.activeStatusEffects[statusName];
+ if (!statusEffect)
return;
- let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
- cmpTimer.CancelTimer(this.activeStatusEffects[statusName].Timer);
+ if (statusEffect.Modifiers)
+ {
+ let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
+ cmpModifiersManager.RemoveAllModifiers(statusName, this.entity);
+ }
+
+ if (statusEffect._timer)
+ {
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ cmpTimer.CancelTimer(statusEffect._timer);
+ }
delete this.activeStatusEffects[statusName];
};
@@ -53,17 +85,20 @@
if (!status)
return;
- if (status.FirstTime)
+ if (status.Duration)
{
- status.FirstTime = false;
- status.TimeElapsed += lateness;
+ if (status._firstTime)
+ {
+ status._firstTime = false;
+ status._timeElapsed += lateness;
+ }
+ else
+ status._timeElapsed += +status.Interval + lateness;
}
- else
- status.TimeElapsed += status.Interval + lateness;
+ if (status.Damage || status.Capture)
+ Attacking.HandleAttackEffects(statusName, status, this.entity, INVALID_ENTITY, INVALID_PLAYER);
- Attacking.HandleAttackEffects(statusName, status, this.entity, -1, -1);
-
- if (status.Duration && status.TimeElapsed >= +status.Duration)
+ if (status.Duration && status._timeElapsed >= +status.Duration)
this.RemoveStatus(statusName);
};
Index: binaries/data/mods/public/simulation/helpers/Attacking.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Attacking.js
+++ binaries/data/mods/public/simulation/helpers/Attacking.js
@@ -3,6 +3,55 @@
*/
function Attacking() {}
+const DirectEffectsSchema =
+ "" +
+ "" +
+ "" +
+ "" +
+ // Armour requires Foundation to not be a damage type.
+ "Foundation" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+
+const StatusEffectsSchema =
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ DirectEffectsSchema +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ ModificationsSchema +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+
/**
* Builds a RelaxRNG schema of possible attack effects.
* See globalscripts/AttackEffects.js for possible elements.
@@ -10,43 +59,13 @@
*
* @return {string} - RelaxNG schema string
*/
-const DamageSchema = "" +
- "" +
- "" +
- "" +
- // Armour requires Foundation to not be a damage type.
- "Foundation" +
- "" +
- "" +
- "" +
- "";
-
Attacking.prototype.BuildAttackEffectsSchema = function()
{
return "" +
"" +
"" +
- "" +
- DamageSchema +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" + DamageSchema + "" +
- "" +
- "" +
- "" +
- "" +
+ DirectEffectsSchema +
+ StatusEffectsSchema +
"" +
"" +
"" +
@@ -250,13 +269,16 @@
Object.assign(targetState, cmpReceiver[receiver.method](attackData[effectType], attacker, attackerOwner, bonusMultiplier));
}
+ if (targetState.killed)
+ this.TargetKilled(attacker, target, attackerOwner);
+
+ if (attacker == INVALID_ENTITY)
+ return;
+
let cmpPromotion = Engine.QueryInterface(attacker, IID_Promotion);
if (cmpPromotion && targetState.xp)
cmpPromotion.IncreaseXp(targetState.xp);
- if (targetState.killed)
- this.TargetKilled(attacker, target, attackerOwner);
-
Engine.PostMessage(target, MT_Attacked, {
"type": attackType,
"target": target,
Index: binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_archer.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_archer.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_archer.xml
@@ -11,6 +11,31 @@
6.0
0
+
+
+ Some bogus bonus tooltip describing the effect of the modifiers. This speeds up the entity but halves the health and resource gathering speed.
+ 10000
+
+
+ UnitMotion/WalkSpeed
+ Unit
+ 20
+
+
+ Health/Max ResourceGatherer/BaseSpeed
+ Unit Structure
+ 0.5
+
+
+
+
+ 10000
+ 1000
+
+ 1
+
+
+
72.0
0.0
600