Index: ps/trunk/binaries/data/mods/public/gui/common/tooltips.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/common/tooltips.js
+++ ps/trunk/binaries/data/mods/public/gui/common/tooltips.js
@@ -185,15 +185,16 @@
function attackRateDetails(interval, projectiles)
{
- // ToDo: Get the name of a projectile from the template.
-
- if (!interval || projectiles == 0)
+ if (!interval)
return "";
+ if (projectiles === 0)
+ return translate("Garrison to fire arrows");
+
let attackRateString = getSecondsString(interval / 1000);
let header = headerFont(translate("Interval:"));
- if (+projectiles > 1)
+ if (projectiles && +projectiles > 1)
{
header = headerFont(translate("Rate:"));
let projectileString = sprintf(translatePlural("%(projectileCount)s %(projectileName)s", "%(projectileCount)s %(projectileName)s", projectiles), {
@@ -258,7 +259,7 @@
return Object.keys(damageTemplate).filter(dmgType => damageTemplate[dmgType]).map(
dmgType => sprintf(translate("%(damage)s %(damageType)s"), {
- "damage": damageTemplate[dmgType].toFixed(1),
+ "damage": (+damageTemplate[dmgType]).toFixed(1),
"damageType": unitFont(translateWithContext("damage type", dmgType))
})).join(commaFont(translate(", ")));
}
@@ -269,11 +270,21 @@
return "";
return sprintf(translate("%(amount)s %(name)s"), {
- "amount": captureTemplate.toFixed(1),
+ "amount": (+captureTemplate).toFixed(1),
"name": unitFont(translateWithContext("damage type", "Capture"))
});
}
+function giveStatusDetails(giveStatusTemplate)
+{
+ if (!giveStatusTemplate)
+ return "";
+
+ return sprintf(translate("gives %(name)s"), {
+ "name": Object.keys(giveStatusTemplate).map(x => unitFont(translateWithContext("status effect", x))).join(', '),
+ });
+}
+
function attackEffectsDetails(attackTypeTemplate)
{
if (!attackTypeTemplate)
@@ -281,7 +292,8 @@
let effects = [
captureDetails(attackTypeTemplate.Capture || undefined),
- damageDetails(attackTypeTemplate.Damage || undefined)
+ damageDetails(attackTypeTemplate.Damage || undefined),
+ giveStatusDetails(attackTypeTemplate.GiveStatus || undefined)
];
return effects.filter(effect => effect).join(commaFont(translate(", ")));
}
@@ -309,11 +321,19 @@
if (template.buildingAI)
projectiles = template.buildingAI.arrowCount || template.buildingAI.defaultArrowCount;
- tooltips.push(sprintf(translate("%(attackLabel)s: %(effects)s, %(range)s, %(rate)s"), {
+ // Show the effects of status effects below
+ let statusEffectsDetails = [];
+ if (attackTypeTemplate.GiveStatus)
+ for (let status in attackTypeTemplate.GiveStatus)
+ statusEffectsDetails.push("\n " + getStatusEffectsTooltip(status, attackTypeTemplate.GiveStatus[status]));
+ statusEffectsDetails = statusEffectsDetails.join("");
+
+ tooltips.push(sprintf(translate("%(attackLabel)s: %(effects)s, %(range)s, %(rate)s%(statusEffects)s"), {
"attackLabel": attackLabel,
"effects": attackEffectsDetails(attackTypeTemplate),
"range": rangeDetails(attackTypeTemplate),
- "rate": attackRateDetails(attackTypeTemplate.repeatTime, projectiles)
+ "rate": attackRateDetails(attackTypeTemplate.repeatTime, projectiles),
+ "statusEffects": statusEffectsDetails
}));
}
return tooltips.join("\n");
@@ -351,6 +371,23 @@
return tooltips.join("\n");
}
+function getStatusEffectsTooltip(name, template)
+{
+ let durationString = "";
+ 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),
+ });
+
+ return sprintf(translate("%(statusName)s: %(effects)s, %(rate)s%(durationString)s"), {
+ "statusName": headerFont(translateWithContext("status effect", name)),
+ "effects": attackEffectsDetails(template),
+ "rate": attackRateDetails(+template.Interval),
+ "durationString": durationString
+ });
+}
+
function getGarrisonTooltip(template)
{
if (!template.garrisonHolder)
Index: ps/trunk/binaries/data/mods/public/gui/session/selection_details.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/selection_details.js
+++ ps/trunk/binaries/data/mods/public/gui/session/selection_details.js
@@ -93,6 +93,26 @@
Engine.GetGUIObjectByName("rankIcon").tooltip = "";
}
+ if (entState.statusEffects)
+ {
+ let statusIcons = Engine.GetGUIObjectByName("statusEffectsIcons").children;
+ let i = 0;
+ for (let effectName in entState.statusEffects)
+ {
+ let effect = entState.statusEffects[effectName];
+ statusIcons[i].hidden = false;
+ statusIcons[i].sprite = "stretched:session/icons/status_effects/" + (effect.Icon || "default") + ".png";
+ statusIcons[i].tooltip = getStatusEffectsTooltip(effectName, effect);
+ let size = statusIcons[i].size;
+ size.top = i * 18;
+ size.bottom = i * 18 + 16;
+ statusIcons[i].size = size;
+ i++;
+ }
+ for (; i < statusIcons.length; ++i)
+ statusIcons[i].hidden = true;
+ }
+
let showHealth = entState.hitpoints;
let showResource = entState.resourceSupply;
Index: ps/trunk/binaries/data/mods/public/gui/session/selection_panels_middle/single_details_area.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/selection_panels_middle/single_details_area.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/selection_panels_middle/single_details_area.xml
@@ -82,9 +82,18 @@
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js
+++ ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -291,6 +291,10 @@
"template": cmpUpgrade.GetUpgradingTo()
};
+ let cmpStatusEffects = Engine.QueryInterface(ent, IID_StatusEffectsReceiver);
+ if (cmpStatusEffects)
+ ret.statusEffects = cmpStatusEffects.GetActiveStatuses();
+
let cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue);
if (cmpProductionQueue)
ret.production = {
Index: ps/trunk/binaries/data/mods/public/simulation/components/StatusEffectsReceiver.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/StatusEffectsReceiver.js
+++ ps/trunk/binaries/data/mods/public/simulation/components/StatusEffectsReceiver.js
@@ -5,6 +5,11 @@
this.activeStatusEffects = {};
};
+StatusEffectsReceiver.prototype.GetActiveStatuses = function()
+{
+ return this.activeStatusEffects;
+};
+
// Called by attacking effects.
StatusEffectsReceiver.prototype.GiveStatus = function(effectData, attacker, attackerOwner, bonusMultiplier)
{
@@ -23,23 +28,23 @@
this.activeStatusEffects[statusName] = {};
let status = this.activeStatusEffects[statusName];
- status.duration = +data.Duration;
- status.interval = +data.Interval;
- status.damage = +data.Damage;
- status.timeElapsed = 0;
- status.firstTime = true;
+ 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);
+ status.Timer = cmpTimer.SetInterval(this.entity, IID_StatusEffectsReceiver, "ExecuteEffect", 0, +status.Interval, statusName);
};
-StatusEffectsReceiver.prototype.RemoveStatus = function(statusName) {
+StatusEffectsReceiver.prototype.RemoveStatus = function(statusName)
+{
if (!this.activeStatusEffects[statusName])
return;
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
- cmpTimer.CancelTimer(this.activeStatusEffects[statusName].timer);
- this.activeStatusEffects[statusName] = undefined;
+ cmpTimer.CancelTimer(this.activeStatusEffects[statusName].Timer);
+ delete this.activeStatusEffects[statusName];
};
StatusEffectsReceiver.prototype.ExecuteEffect = function(statusName, lateness)
@@ -48,17 +53,17 @@
if (!status)
return;
- if (status.firstTime)
+ if (status.FirstTime)
{
- status.firstTime = false;
- status.timeElapsed += lateness;
+ status.FirstTime = false;
+ status.TimeElapsed += lateness;
}
else
- status.timeElapsed += status.interval + lateness;
+ status.TimeElapsed += status.Interval + lateness;
- Attacking.HandleAttackEffects(statusName, { "Damage": { [statusName]: status.damage } }, this.entity, -1, -1);
+ Attacking.HandleAttackEffects(statusName, status, this.entity, -1, -1);
- if (status.timeElapsed >= status.duration)
+ if (status.Duration && status.TimeElapsed >= +status.Duration)
this.RemoveStatus(statusName);
};
Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
+++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
@@ -31,6 +31,7 @@
Engine.LoadComponentScript("interfaces/Trader.js");
Engine.LoadComponentScript("interfaces/Timer.js");
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
+Engine.LoadComponentScript("interfaces/StatusEffectsReceiver.js");
Engine.LoadComponentScript("interfaces/UnitAI.js");
Engine.LoadComponentScript("interfaces/Upgrade.js");
Engine.LoadComponentScript("interfaces/BuildingAI.js");
Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_StatusEffectsReceiver.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_StatusEffectsReceiver.js
+++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_StatusEffectsReceiver.js
@@ -28,7 +28,9 @@
cmpStatusReceiver.AddStatus(statusName, {
"Duration": 20000,
"Interval": 10000,
- "Damage": 1
+ "Damage": {
+ [statusName]: 1
+ }
});
cmpTimer.OnUpdate({ "turnLength": 1 });
@@ -65,12 +67,16 @@
"Burn": {
"Duration": 20000,
"Interval": 10000,
- "Damage": 10
+ "Damage": {
+ "Burn": 10
+ }
},
"Poison": {
"Duration": 3000,
"Interval": 1000,
- "Damage": 1
+ "Damage": {
+ "Poison": 1
+ }
}
});
@@ -102,7 +108,9 @@
cmpStatusReceiver.AddStatus(statusName, {
"Duration": 20000,
"Interval": 10000,
- "Damage": 1
+ "Damage": {
+ [statusName]: 1
+ }
});
cmpTimer.OnUpdate({ "turnLength": 1 });
Index: ps/trunk/binaries/data/mods/public/simulation/helpers/Attacking.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/helpers/Attacking.js
+++ ps/trunk/binaries/data/mods/public/simulation/helpers/Attacking.js
@@ -5,38 +5,44 @@
/**
* Builds a RelaxRNG schema of possible attack effects.
- * Currently harcoded to "Damage", "Capture" and "StatusEffects".
+ * See globalscripts/AttackEffects.js for possible elements.
* Attacks may also have a "Bonuses" element.
*
* @return {string} - RelaxNG schema string
*/
+const DamageSchema = "" +
+ "" +
+ "" +
+ "" +
+ // Armour requires Foundation to not be a damage type.
+ "Foundation" +
+ "" +
+ "" +
+ "" +
+ "";
+
Attacking.prototype.BuildAttackEffectsSchema = function()
{
return "" +
"" +
"" +
"" +
- "" +
- "" +
- "" +
- // Armour requires Foundation to not be a damage type.
- "Foundation" +
- "" +
- "" +
- "" +
- "" +
+ DamageSchema +
"" +
"" +
"" +
"" +
- "" +
+ "" +
"" +
"" +
"" +
"" +
+ "" +
+ "" +
+ "" +
"" +
"" +
- "" +
+ "" + DamageSchema + "" +
"" +
"" +
"" +
@@ -79,8 +85,8 @@
if (template.Capture)
ret.Capture = ApplyValueModificationsToEntity(valueModifRoot + "/Capture", +(template.Capture || 0), entity);
- if (template.StatusEffects)
- ret.StatusEffects = template.StatusEffects;
+ if (template.GiveStatus)
+ ret.GiveStatus = template.GiveStatus;
if (template.Bonuses)
ret.Bonuses = template.Bonuses;