Index: binaries/data/mods/public/globalscripts/StatusEffects.js
===================================================================
--- binaries/data/mods/public/globalscripts/StatusEffects.js
+++ binaries/data/mods/public/globalscripts/StatusEffects.js
@@ -10,7 +10,7 @@
{
this.statusEffectData = {};
- let files = Engine.ListDirectoryFiles("simulation/data/template_helpers/status_effects", "*.json", false);
+ let files = Engine.ListDirectoryFiles("simulation/data/status_effects", "*.json", false);
for (let filename of files)
{
let data = Engine.ReadJSONFile(filename);
@@ -23,22 +23,46 @@
continue;
}
- this.statusEffectData[data.code] = data;
+ this.statusEffectData[data.code] = {
+ "applierTooltip": data.applierTooltip || "",
+ "code": data.code,
+ "icon": data.icon || "default",
+ "statusName": data.statusName || "data.code",
+ "receiverTooltip": data.receiverTooltip || ""
+ };
}
}
/**
- * @returns the default data for @param code status effects, augmented with the given template data,
- * or simply @param templateData if the code is not found in JSON files.
+ * @param {string} code - The code of the Status Effect.
+ * @return {Object} - The JSON data corresponding to the code.
*/
- augment(code, templateData)
+ getData(code)
{
- if (!templateData && this.statusEffectData[code])
+ if (this.statusEffectData[code])
return this.statusEffectData[code];
- if (this.statusEffectData[code])
- return Object.assign({}, this.statusEffectData[code], templateData);
+ warn("No status effects data found for: " + code + ".");
+ return {};
+ }
- return templateData;
+ getApplierTooltip(code)
+ {
+ return this.getData(code).applierTooltip;
+ }
+
+ getIcon(code)
+ {
+ return this.getData(code).icon;
+ }
+
+ getName(code)
+ {
+ return this.getData(code).statusName;
+ }
+
+ getReceiverTooltip(code)
+ {
+ return this.getData(code).receiverTooltip;
}
}
Index: binaries/data/mods/public/globalscripts/Templates.js
===================================================================
--- binaries/data/mods/public/globalscripts/Templates.js
+++ binaries/data/mods/public/globalscripts/Templates.js
@@ -174,8 +174,15 @@
}
if (template.Resistance.Entity.Capture)
ret.resistance.Capture = getEntityValue("Resistance/Entity/Capture");
-
- // ToDo: Resistance against StatusEffects.
+ if (template.Resistance.Entity.ApplyStatus)
+ {
+ ret.resistance.ApplyStatus = {};
+ for (let statusEffect in template.Resistance.Entity.ApplyStatus)
+ ret.resistance.ApplyStatus[statusEffect] = {
+ "blockChance": getEntityValue("Resistance/Entity/ApplyStatus/" + statusEffect + "/BlockChance"),
+ "duration": getEntityValue("Resistance/Entity/ApplyStatus/" + statusEffect + "/Duration")
+ };
+ }
}
}
Index: binaries/data/mods/public/globalscripts/tests/test_statusEffects.js
===================================================================
--- binaries/data/mods/public/globalscripts/tests/test_statusEffects.js
+++ binaries/data/mods/public/globalscripts/tests/test_statusEffects.js
@@ -1,13 +1,13 @@
let statusEffects = {
"test_A": {
"code": "test_a",
- "StatusName": "A",
- "StatusTooltip": "TTA"
+ "statusName": "A",
+ "applierTooltip": "TTA"
},
"test_B": {
"code": "test_b",
- "StatusName": "B",
- "StatusTooltip": "TTB"
+ "statusName": "B",
+ "applierTooltip": "TTB"
}
};
@@ -16,16 +16,21 @@
let sem = new StatusEffectsMetadata();
-// Template data takes precedence over generic data.
-TS_ASSERT_UNEVAL_EQUALS(sem.augment("test_a"), {
- "code": "test_a", "StatusName": "A", "StatusTooltip": "TTA"
+TS_ASSERT_UNEVAL_EQUALS(sem.getData("test_a"), {
+ "applierTooltip": "TTA",
+ "code": "test_a",
+ "icon": "default",
+ "statusName": "A",
+ "receiverTooltip": ""
});
-TS_ASSERT_UNEVAL_EQUALS(sem.augment("test_b"), {
- "code": "test_b", "StatusName": "B", "StatusTooltip": "TTB"
-});
-TS_ASSERT_UNEVAL_EQUALS(sem.augment("test_a", { "StatusName": "test" }), {
- "code": "test_a", "StatusName": "test", "StatusTooltip": "TTA"
-});
-TS_ASSERT_UNEVAL_EQUALS(sem.augment("test_c", { "StatusName": "test" }), {
- "StatusName": "test"
+TS_ASSERT_UNEVAL_EQUALS(sem.getData("test_b"), {
+ "applierTooltip": "TTB",
+ "code": "test_b",
+ "icon": "default",
+ "statusName": "B",
+ "receiverTooltip": ""
});
+TS_ASSERT_UNEVAL_EQUALS(sem.getApplierTooltip("test_a"), "TTA");
+TS_ASSERT_UNEVAL_EQUALS(sem.getIcon("test_b"), "default");
+TS_ASSERT_UNEVAL_EQUALS(sem.getName("test_a"), "A");
+TS_ASSERT_UNEVAL_EQUALS(sem.getReceiverTooltip("test_b"), "");
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
@@ -181,7 +181,8 @@
if (template.resistance.Capture)
details.push(getCaptureResistanceTooltip(template.resistance.Capture));
- // TODO: Status effects resistance.
+ if (template.resistance.ApplyStatus)
+ details.push(getStatusEffectsResistanceTooltip(template.resistance.ApplyStatus));
return sprintf(translate("%(label)s\n%(details)s"), {
"label": headerFont(translate("Resistance:")),
@@ -230,6 +231,48 @@
});
}
+function getStatusEffectsResistanceTooltip(resistanceTypeTemplate)
+{
+ if (!resistanceTypeTemplate)
+ return "";
+ return sprintf(translate("%(label)s %(details)s"), {
+ "label": headerFont(translate("Status Effects:")),
+ "details":
+ Object.keys(resistanceTypeTemplate).map(
+ statusEffect => {
+ if (resistanceTypeTemplate[statusEffect].blockChance == 1)
+ return sprintf(translate("Blocks %(name)s"), {
+ "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect)))
+ });
+
+ if (resistanceTypeTemplate[statusEffect].blockChance == 0)
+ return sprintf(translate("%(name)s %(details)s"), {
+ "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect))),
+ "details": sprintf(translate("Duration reduction: %(durationReduction)s%%"), {
+ "durationReduction": (100 - resistanceTypeTemplate[statusEffect].duration * 100)
+ })
+ });
+
+ if (resistanceTypeTemplate[statusEffect].duration == 1)
+ return sprintf(translate("%(name)s %(details)s"), {
+ "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect))),
+ "details": sprintf(translate("Blocks: %(blockPercentage)s%%"), {
+ "blockPercentage": resistanceTypeTemplate[statusEffect].blockChance * 100
+ })
+ });
+
+ return sprintf(translate("%(name)s %(details)s"), {
+ "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect))),
+ "details": sprintf(translate("Blocks: %(blockPercentage)s%%, Duration reduction: %(durationReduction)s%%"), {
+ "blockPercentage": resistanceTypeTemplate[statusEffect].blockChance * 100,
+ "durationReduction": (100 - resistanceTypeTemplate[statusEffect].duration * 100)
+ })
+ });
+ }
+ ).join(commaFont(translate(", ")))
+ });
+}
+
function attackRateDetails(interval, projectiles)
{
if (!interval)
@@ -346,10 +389,9 @@
return "";
return sprintf(translate("gives %(name)s"), {
- "name": Object.keys(applyStatusTemplate).map(x => {
- let template = g_StatusEffectsMetadata.augment(x, applyStatusTemplate[x]);
- return unitFont(translateWithContext("status effect", template.StatusName));
- }).join(commaFont(translate(", "))),
+ "name": Object.keys(applyStatusTemplate).map(x =>
+ unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(x)))
+ ).join(commaFont(translate(", "))),
});
}
@@ -395,10 +437,7 @@
let statusEffectsDetails = [];
if (attackTypeTemplate.ApplyStatus)
for (let status in attackTypeTemplate.ApplyStatus)
- {
- let status_template = g_StatusEffectsMetadata.augment(status, attackTypeTemplate.ApplyStatus[status]);
- statusEffectsDetails.push("\n" + g_Indent + g_Indent + getStatusEffectsTooltip(status_template, true));
- }
+ statusEffectsDetails.push("\n" + g_Indent + g_Indent + getStatusEffectsTooltip(status, attackTypeTemplate.ApplyStatus[status], true));
statusEffectsDetails = statusEffectsDetails.join("");
tooltips.push(sprintf(translate("%(attackLabel)s: %(effects)s, %(range)s, %(rate)s%(statusEffects)s%(splash)s"), {
@@ -420,14 +459,10 @@
/**
* @param applier - if true, return the tooltip for the Applier. If false, Receiver is returned.
*/
-function getStatusEffectsTooltip(template, applier)
+function getStatusEffectsTooltip(statusCode, template, applier)
{
let tooltipAttributes = [];
- if (applier && template.ApplierTooltip)
- tooltipAttributes.push(translate(template.ApplierTooltip));
- else if (!applier && template.ReceiverTooltip)
- tooltipAttributes.push(translate(template.ReceiverTooltip));
-
+ let statusData = g_StatusEffectsMetadata.getData(statusCode);
if (template.Damage || template.Capture)
tooltipAttributes.push(attackEffectsDetails(template));
@@ -437,14 +472,19 @@
if (template.Duration)
tooltipAttributes.push(getStatusEffectDurationTooltip(template));
+ if (applier && statusData.applierTooltip)
+ tooltipAttributes.push(translate(statusData.applierTooltip));
+ else if (!applier && statusData.receiverTooltip)
+ tooltipAttributes.push(translate(statusData.receiverTooltip));
+
if (applier)
return sprintf(translate("%(statusName)s: %(statusInfo)s %(stackability)s"), {
- "statusName": headerFont(translateWithContext("status effect", template.StatusName)),
+ "statusName": headerFont(translateWithContext("status effect", statusData.statusName)),
"statusInfo": tooltipAttributes.join(commaFont(translate(", "))),
"stackability": getStatusEffectStackabilityTooltip(template)
});
return sprintf(translate("%(statusName)s: %(statusInfo)s"), {
- "statusName": headerFont(translateWithContext("status effect", template.StatusName)),
+ "statusName": headerFont(translateWithContext("status effect", statusData.statusName)),
"statusInfo": tooltipAttributes.join(commaFont(translate(", ")))
});
}
Index: binaries/data/mods/public/gui/session/selection_details.js
===================================================================
--- binaries/data/mods/public/gui/session/selection_details.js
+++ binaries/data/mods/public/gui/session/selection_details.js
@@ -98,12 +98,12 @@
statusEffectsSection.hidden = false;
let statusIcons = statusEffectsSection.children;
let i = 0;
- for (let effectName in entState.statusEffects)
+ for (let effectCode in entState.statusEffects)
{
- let effect = entState.statusEffects[effectName];
+ let effect = entState.statusEffects[effectCode];
statusIcons[i].hidden = false;
- statusIcons[i].sprite = "stretched:session/icons/status_effects/" + (effect.Icon || "default") + ".png";
- statusIcons[i].tooltip = getStatusEffectsTooltip(effect, false);
+ statusIcons[i].sprite = "stretched:session/icons/status_effects/" + g_StatusEffectsMetadata.getIcon(effect.baseCode) + ".png";
+ statusIcons[i].tooltip = getStatusEffectsTooltip(effect.baseCode, effect, false);
let size = statusIcons[i].size;
size.top = i * 18;
size.bottom = i * 18 + 16;
Index: binaries/data/mods/public/l10n/messages.json
===================================================================
--- binaries/data/mods/public/l10n/messages.json
+++ binaries/data/mods/public/l10n/messages.json
@@ -489,15 +489,6 @@
},
"options": {
"keywords": {
- "StatusName": {
- "customContext": "status effect"
- },
- "ApplierTooltip": {
- "customContext": "status effect"
- },
- "ReceiverTooltip": {
- "customContext": "status effect"
- },
"GenericName": {},
"SpecificName": {},
"History": {},
@@ -530,13 +521,13 @@
{
"extractor": "json",
"filemasks": [
- "simulation/data/template_helpers/status_effects/*.json"
+ "simulation/data/status_effects/*.json"
],
"options": {
"keywords": [
- "StatusName",
- "ApplierTooltip",
- "ReceiverTooltip"
+ "statusName",
+ "applierTooltip",
+ "receiverTooltip"
],
"context": "status effect"
}
Index: binaries/data/mods/public/simulation/components/Resistance.js
===================================================================
--- binaries/data/mods/public/simulation/components/Resistance.js
+++ binaries/data/mods/public/simulation/components/Resistance.js
@@ -2,7 +2,6 @@
/**
* Builds a RelaxRNG schema of possible attack effects.
- * ToDo: Resistance to StatusEffects.
*
* @return {string} - RelaxNG schema string.
*/
@@ -22,6 +21,23 @@
"" +
"" +
"" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
"" +
"";
};
@@ -122,6 +138,16 @@
if (template.Capture)
ret.Capture = ApplyValueModificationsToEntity("Resistance/" + entityForm + "/Capture", +this.template[entityForm].Capture, this.entity);
+ if (template.ApplyStatus)
+ {
+ ret.ApplyStatus = {};
+ for (let effect in template.ApplyStatus)
+ ret.ApplyStatus[effect] = {
+ "duration": ApplyValueModificationsToEntity("Resistance/" + entityForm + "/ApplyStatus/" + effect + "/Duration", +(template.ApplyStatus[effect].Duration || 1), this.entity),
+ "blockChance": ApplyValueModificationsToEntity("Resistance/" + entityForm + "/ApplyStatus/" + effect + "/BlockChance", +(template.ApplyStatus[effect].BlockChance || 0), this.entity)
+ };
+ }
+
return ret;
};
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
@@ -28,7 +28,7 @@
* @param {number} attackerOwner - The player ID of the attacker.
* @param {number} bonusMultiplier - A value to multiply the damage with (not implemented yet for SE).
*
- * @return {Object} - The names of the status effects which were processed.
+ * @return {Object} - The codes of the status effects which were processed.
*/
StatusEffectsReceiver.prototype.ApplyStatus = function(effectData, attacker, attackerOwner)
{
@@ -36,7 +36,7 @@
for (let effect in effectData)
this.AddStatus(effect, effectData[effect], attackerData);
- // TODO: implement loot / resistance.
+ // TODO: implement loot?
return { "inflictedStatuses": Object.keys(effectData) };
};
@@ -44,43 +44,46 @@
/**
* Adds a status effect to the entity.
*
- * @param {string} statusName - The name of the status effect.
+ * @param {string} statusCode - The code of the status effect.
* @param {Object} data - The various effects and timings.
* @param {Object} attackerData - The attacker and attackerOwner.
*/
-StatusEffectsReceiver.prototype.AddStatus = function(statusName, data, attackerData)
+StatusEffectsReceiver.prototype.AddStatus = function(baseCode, data, attackerData)
{
- if (this.activeStatusEffects[statusName])
+ let statusCode = baseCode;
+ if (this.activeStatusEffects[statusCode])
{
if (data.Stackability == "Ignore")
return;
if (data.Stackability == "Extend")
{
- this.activeStatusEffects[statusName].Duration += data.Duration;
+ this.activeStatusEffects[statusCode].Duration += data.Duration;
return;
}
if (data.Stackability == "Replace")
- this.RemoveStatus(statusName);
+ this.RemoveStatus(statusCode);
else if (data.Stackability == "Stack")
{
let i = 0;
let temp;
do
- temp = statusName + "_" + i++;
+ temp = statusCode + "_" + i++;
while (!!this.activeStatusEffects[temp]);
- statusName = temp;
+ statusCode = temp;
}
}
- this.activeStatusEffects[statusName] = {};
- let status = this.activeStatusEffects[statusName];
+ this.activeStatusEffects[statusCode] = {
+ "baseCode": baseCode
+ };
+ let status = this.activeStatusEffects[statusCode];
Object.assign(status, data);
if (status.Modifiers)
{
let modifications = DeriveModificationsFromXMLTemplate(status.Modifiers);
let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
- cmpModifiersManager.AddModifiers(statusName, modifications, this.entity);
+ cmpModifiersManager.AddModifiers(statusCode, modifications, this.entity);
}
// With neither an interval nor a duration, there is no point in starting a timer.
@@ -101,24 +104,24 @@
status.source = attackerData;
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
- status._timer = cmpTimer.SetInterval(this.entity, IID_StatusEffectsReceiver, "ExecuteEffect", 0, +(status.Interval || status._interval), statusName);
+ status._timer = cmpTimer.SetInterval(this.entity, IID_StatusEffectsReceiver, "ExecuteEffect", 0, +(status.Interval || status._interval), statusCode);
};
/**
* Removes a status effect from the entity.
*
- * @param {string} statusName - The status effect to be removed.
+ * @param {string} statusCode - The status effect to be removed.
*/
-StatusEffectsReceiver.prototype.RemoveStatus = function(statusName)
+StatusEffectsReceiver.prototype.RemoveStatus = function(statusCode)
{
- let statusEffect = this.activeStatusEffects[statusName];
+ let statusEffect = this.activeStatusEffects[statusCode];
if (!statusEffect)
return;
if (statusEffect.Modifiers)
{
let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
- cmpModifiersManager.RemoveAllModifiers(statusName, this.entity);
+ cmpModifiersManager.RemoveAllModifiers(statusCode, this.entity);
}
if (statusEffect._timer)
@@ -126,23 +129,23 @@
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
cmpTimer.CancelTimer(statusEffect._timer);
}
- delete this.activeStatusEffects[statusName];
+ delete this.activeStatusEffects[statusCode];
};
/**
* Called by the timers. Executes a status effect.
*
- * @param {string} statusName - The name of the status effect to be executed.
+ * @param {string} statusCode - The status effect to be executed.
* @param {number} lateness - The delay between the calling of the function and the actual execution (turn time?).
*/
-StatusEffectsReceiver.prototype.ExecuteEffect = function(statusName, lateness)
+StatusEffectsReceiver.prototype.ExecuteEffect = function(statusCode, lateness)
{
- let status = this.activeStatusEffects[statusName];
+ let status = this.activeStatusEffects[statusCode];
if (!status)
return;
if (status.Damage || status.Capture)
- Attacking.HandleAttackEffects(this.entity, statusName, status, status.source.entity, status.source.owner);
+ Attacking.HandleAttackEffects(this.entity, statusCode, status, status.source.entity, status.source.owner);
if (!status.Duration)
return;
@@ -156,7 +159,7 @@
status._timeElapsed += +(status.Interval || status._interval) + lateness;
if (status._timeElapsed >= +status.Duration)
- this.RemoveStatus(statusName);
+ this.RemoveStatus(statusCode);
};
Engine.RegisterComponentType(IID_StatusEffectsReceiver, "StatusEffectsReceiver", StatusEffectsReceiver);
Index: binaries/data/mods/public/simulation/components/tests/test_Resistance.js
===================================================================
--- binaries/data/mods/public/simulation/components/tests/test_Resistance.js
+++ binaries/data/mods/public/simulation/components/tests/test_Resistance.js
@@ -10,6 +10,7 @@
Engine.LoadComponentScript("interfaces/Promotion.js");
Engine.LoadComponentScript("interfaces/Resistance.js");
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
+Engine.LoadComponentScript("interfaces/StatusEffectsReceiver.js");
Engine.LoadComponentScript("Resistance.js");
class testResistance
@@ -26,9 +27,10 @@
Reset(schema = {})
{
this.cmpResistance = ConstructComponent(this.EntityID, "Resistance", schema);
- DeleteMock(this.EntityID, IID_Health);
DeleteMock(this.EntityID, IID_Capturable);
+ DeleteMock(this.EntityID, IID_Health);
DeleteMock(this.EntityID, IID_Identity);
+ DeleteMock(this.EntityID, IID_StatusEffectsReceiver);
}
TestInvulnerability()
@@ -148,6 +150,103 @@
TS_ASSERT_EQUALS(spy._called, 1);
}
+ TestStatusEffectsResistancesApplies()
+ {
+ // Test duration reduction.
+ let durationFactor = 0.5;
+ let statusName = "statusName";
+ this.Reset({
+ "Entity": {
+ "ApplyStatus": {
+ [statusName]: {
+ "Duration": durationFactor
+ }
+ }
+ }
+ });
+
+ let duration = 10;
+ let attackData = {
+ "ApplyStatus": {
+ [statusName]: {
+ "Duration": duration
+ }
+ }
+ };
+
+ let cmpStatusEffectsReceiver = AddMock(this.EntityID, IID_StatusEffectsReceiver, {
+ "ApplyStatus": (effectData, __, ___) => {
+ TS_ASSERT_EQUALS(effectData[statusName].Duration, duration * durationFactor);
+ return { "inflictedStatuses": Object.keys(effectData) };
+ }
+ });
+ let spy = new Spy(cmpStatusEffectsReceiver, "ApplyStatus");
+
+ Attacking.HandleAttackEffects(this.EntityID, "Test", attackData, this.AttackerID, this.EnemyID);
+ TS_ASSERT_EQUALS(spy._called, 1);
+
+ // Test blocking.
+ this.Reset({
+ "Entity": {
+ "ApplyStatus": {
+ [statusName]: {
+ "BlockChance": "1"
+ }
+ }
+ }
+ });
+
+ cmpStatusEffectsReceiver = AddMock(this.EntityID, IID_StatusEffectsReceiver, {
+ "ApplyStatus": (effectData, __, ___) => {
+ TS_ASSERT_UNEVAL_EQUALS(effectData, {});
+ return { "inflictedStatuses": Object.keys(effectData) };
+ }
+ });
+ spy = new Spy(cmpStatusEffectsReceiver, "ApplyStatus");
+
+ Attacking.HandleAttackEffects(this.EntityID, "Test", attackData, this.AttackerID, this.EnemyID);
+ TS_ASSERT_EQUALS(spy._called, 1);
+
+ // Test multiple resistances.
+ let reducedStatusName = "reducedStatus";
+ let blockedStatusName = "blockedStatus";
+ this.Reset({
+ "Entity": {
+ "ApplyStatus": {
+ [reducedStatusName]: {
+ "Duration": durationFactor
+ },
+ [blockedStatusName]: {
+ "BlockChance": "1"
+ }
+ }
+ }
+ });
+
+ attackData = {
+ "ApplyStatus": {
+ [reducedStatusName]: {
+ "Duration": duration
+ },
+ [blockedStatusName]: {
+ "Duration": duration
+ }
+ }
+ };
+
+ cmpStatusEffectsReceiver = AddMock(this.EntityID, IID_StatusEffectsReceiver, {
+ "ApplyStatus": (effectData, __, ___) => {
+ TS_ASSERT_EQUALS(effectData[reducedStatusName].Duration, duration * durationFactor);
+ TS_ASSERT_UNEVAL_EQUALS(Object.keys(effectData), [reducedStatusName]);
+ return { "inflictedStatuses": Object.keys(effectData) };
+ }
+ });
+ spy = new Spy(cmpStatusEffectsReceiver, "ApplyStatus");
+
+ Attacking.HandleAttackEffects(this.EntityID, "Test", attackData, this.AttackerID, this.EnemyID);
+ TS_ASSERT_EQUALS(spy._called, 1);
+ }
+
TestResistanceAndBonus()
{
let resistanceValue = 2;
@@ -246,5 +345,6 @@
cmp.TestBonus();
cmp.TestDamageResistanceApplies();
cmp.TestCaptureResistanceApplies();
+cmp.TestStatusEffectsResistancesApplies();
cmp.TestResistanceAndBonus();
cmp.TestMultipleEffects();
Index: binaries/data/mods/public/simulation/data/status_effects/anotherBogus.json
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/data/status_effects/anotherBogus.json
@@ -0,0 +1,5 @@
+{
+ "code": "AnotherBogus",
+ "statusName": "StatusEffect's name 3",
+ "applierTooltip": "Some bogus bonus tooltip describing the effect of the modifiers. This increases the armour permanently."
+}
Index: binaries/data/mods/public/simulation/data/status_effects/bogus.json
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/data/status_effects/bogus.json
@@ -0,0 +1,5 @@
+{
+ "code": "Bogus",
+ "statusName": "StatusEffect's name 1",
+ "applierTooltip": "Some bogus bonus tooltip describing the effect of the modifiers. This speeds up the entity but halves the health and resource gathering speed."
+}
Index: binaries/data/mods/public/simulation/data/status_effects/bogus2.json
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/data/status_effects/bogus2.json
@@ -0,0 +1,5 @@
+{
+ "code": "Bogus2",
+ "statusName": "StatusEffect's name 2",
+ "receiverTooltip": "You've been poissoned!"
+}
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
@@ -20,21 +20,9 @@
"" +
"" +
"" +
- "" +
+ "" +
"" +
"" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
- "" +
"" +
"" +
"" +
@@ -196,10 +184,32 @@
if (cmpHealth)
total /= 0.1 + 0.9 * cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints();
}
- else if (effectType == "ApplyStatus")
+ if (effectType != "ApplyStatus")
+ return total * bonusMultiplier;
+
+ if (!resistanceStrengths.ApplyStatus)
return effectData[effectType];
- return total * bonusMultiplier;
+ let result = {};
+ for (let statusEffect in effectData[effectType])
+ {
+ if (!resistanceStrengths.ApplyStatus[statusEffect])
+ {
+ result[statusEffect] = effectData[effectType][statusEffect];
+ continue;
+ }
+
+ if (randBool(resistanceStrengths.ApplyStatus[statusEffect].blockChance))
+ continue;
+
+ result[statusEffect] = effectData[effectType][statusEffect];
+
+ if (effectData[effectType][statusEffect].Duration)
+ result[statusEffect].Duration = effectData[effectType][statusEffect].Duration *
+ resistanceStrengths.ApplyStatus[statusEffect].duration;
+ }
+ return result;
+
};
/**
Index: binaries/data/mods/public/simulation/templates/template_structure.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure.xml
+++ binaries/data/mods/public/simulation/templates/template_structure.xml
@@ -111,6 +111,12 @@
1
1
+
+
+ 0.5
+ 1
+
+
Index: binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged.xml
@@ -7,6 +7,46 @@
1.5
0
+
+
+ Extend
+ 15000
+
+
+ UnitMotion/WalkSpeed
+ Unit
+ 20
+
+
+ Health/Max ResourceGatherer/BaseSpeed
+ Unit Structure
+ 0.5
+
+
+
+
+ Replace
+ 10000
+ 1000
+
+ 1
+
+
+
+ Stack
+ 1000
+
+ 1
+
+
+
+ Armour/Hack Armour/Pierce Armour/Crush
+ Unit
+ 20
+
+
+
+
10.0
0.0
750