mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 10:03:43 +00:00
Tooltip overhaul.
Also contains a patch by fatherbushido for attackRateDetails and getAttackTooltip to not show something broken for buildingAI units that can capture, fixes #4061 (see #4000). Make tooltip functions uniform. Pass template everywhere instead of template.armour in getArmorTooltip rate in getRepairRateTooltip and getBuildRateTooltip and entState in attackRateDetails. Add an early return for every tooltip function. Use empty string instead of "Armor: (None)" for trees etc.. Don't prefix tooltip return values with "\n", but let the user of that function add them. Thus make tooltip concatenation much nicer (f.e. draw.js). Use a loop instead of duplicating per damage type in damageTypesToText. Add font functions to avoid duplicating tag code. Merge sprintf's and inline variables. Add few TODOs. Fix some strings: Use "%(specificName)s %(fontStart)s(%(genericName)s)%(fontEnd)s") instead of "(" + foo + ")" ... Use existing "%(percentage)s%%" instead of foo + "%" in armorLevelToPercentageString. Remove duplication by calling/introducing shared functions (getEntityTooltip, getHealthTooltip, getGatherTooltip, getVisibleEntityClassesFormatted), unused function damageTypeDetails which was also a duplicate of damageTypesToText, unused function damageValues, some warns that are equivalent to errors they attempt to cover up (getAttackTypeLabel, getCostComponentDisplayIcon, getEntityNames, getEntityNamesFormatted), some unused variables, "???" and translate("???"). Don't fix translate("Foo:") strings to avoid a lot of translation work. This was SVN commit r18454.
This commit is contained in:
@@ -10,62 +10,80 @@ const g_CostDisplayIcons = {
|
||||
const g_TooltipTextFormats = {
|
||||
"unit": ['[font="sans-10"][color="orange"]', '[/color][/font]'],
|
||||
"header": ['[font="sans-bold-13"]', '[/font]'],
|
||||
"body": ['[font="sans-13"]', '[/font]']
|
||||
"body": ['[font="sans-13"]', '[/font]'],
|
||||
"comma": ['[font="sans-12"]', '[/font]']
|
||||
};
|
||||
|
||||
function damageValues(dmg)
|
||||
{
|
||||
if (!dmg)
|
||||
return [0, 0, 0];
|
||||
const g_AttackTypes = {
|
||||
"Charge": translate("Charge Attack:"),
|
||||
"Melee": translate("Melee Attack:"),
|
||||
"Ranged": translate("Ranged Attack:"),
|
||||
"Capture": translate("Capture Attack:")
|
||||
};
|
||||
|
||||
return [dmg.hack || 0, dmg.pierce || 0, dmg.crush || 0];
|
||||
const g_DamageTypes = {
|
||||
"hack": translate("Hack"),
|
||||
"pierce": translate("Pierce"),
|
||||
"crush": translate("Crush"),
|
||||
};
|
||||
|
||||
function bodyFont(text)
|
||||
{
|
||||
return g_TooltipTextFormats.body[0] + text + g_TooltipTextFormats.body[1];
|
||||
}
|
||||
|
||||
function damageTypeDetails(dmg)
|
||||
function headerFont(text)
|
||||
{
|
||||
if (!dmg)
|
||||
return '[font="sans-12"]' + translate("(None)") + '[/font]';
|
||||
|
||||
let dmgArray = [];
|
||||
|
||||
if (dmg.hack)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s"), {
|
||||
"damage": dmg.hack.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Hack") + g_TooltipTextFormats.unit[1]
|
||||
}));
|
||||
|
||||
if (dmg.pierce)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s"), {
|
||||
"damage": dmg.pierce.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Pierce") + g_TooltipTextFormats.unit[1]
|
||||
}));
|
||||
|
||||
if (dmg.crush)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s"), {
|
||||
"damage": dmg.crush.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Crush") + g_TooltipTextFormats.unit[1]
|
||||
}));
|
||||
|
||||
return dmgArray.join(translate(", "));
|
||||
return g_TooltipTextFormats.header[0] + text + g_TooltipTextFormats.header[1];
|
||||
}
|
||||
|
||||
function attackRateDetails(entState, type)
|
||||
function unitFont(text)
|
||||
{
|
||||
return g_TooltipTextFormats.unit[0] + text + g_TooltipTextFormats.unit[1];
|
||||
}
|
||||
|
||||
function commaFont(text)
|
||||
{
|
||||
return g_TooltipTextFormats.comma[0] + text + g_TooltipTextFormats.comma[1];
|
||||
}
|
||||
|
||||
function getEntityTooltip(template)
|
||||
{
|
||||
if (!template.tooltip)
|
||||
return "";
|
||||
|
||||
return bodyFont(template.tooltip);
|
||||
}
|
||||
|
||||
function getHealthTooltip(template)
|
||||
{
|
||||
if (!template.health)
|
||||
return "";
|
||||
|
||||
return sprintf(translate("%(label)s %(details)s"), {
|
||||
"label": headerFont(translate("Health:")),
|
||||
"details": template.health
|
||||
});
|
||||
}
|
||||
|
||||
function attackRateDetails(template, type)
|
||||
{
|
||||
// Either one arrow shot by UnitAI,
|
||||
let time = entState.attack[type].repeatTime / 1000;
|
||||
let time = template.attack[type].repeatTime / 1000;
|
||||
let timeString = sprintf(translatePlural("%(time)s %(second)s", "%(time)s %(second)s", time), {
|
||||
"time": time,
|
||||
"second": g_TooltipTextFormats.unit[0] + translatePlural("second", "seconds", time) + g_TooltipTextFormats.unit[1]
|
||||
"second": unitFont(translatePlural("second", "seconds", time))
|
||||
});
|
||||
|
||||
// or multiple arrows shot by BuildingAI
|
||||
if (!entState.buildingAI)
|
||||
if (!template.buildingAI || type != "Ranged")
|
||||
return timeString;
|
||||
|
||||
let arrows = entState.buildingAI.arrowCount;
|
||||
let arrowString = sprintf(translatePlural("%(arrowcount)s %(arrow)s", "%(arrowcount)s %(arrow)s", arrows), {
|
||||
// Show either current rate from simulation or default count if the sim is not running
|
||||
let arrows = template.buildingAI.arrowCount || template.buildingAI.defaultArrowCount;
|
||||
let arrowString = sprintf(translatePlural("%(arrowcount)s %(arrows)s", "%(arrowcount)s %(arrows)s", arrows), {
|
||||
"arrowcount": arrows,
|
||||
"arrow": g_TooltipTextFormats.unit[0] + translatePlural("arrow", "arrows", arrows) + g_TooltipTextFormats.unit[1]
|
||||
"arrows": unitFont(translatePlural("arrow", "arrows", arrows))
|
||||
});
|
||||
|
||||
return sprintf(translate("%(arrowString)s / %(timeString)s"), {
|
||||
@@ -74,47 +92,35 @@ function attackRateDetails(entState, type)
|
||||
});
|
||||
}
|
||||
|
||||
// Converts an armor level into the actual reduction percentage
|
||||
/**
|
||||
* Converts an armor level into the actual reduction percentage
|
||||
*/
|
||||
function armorLevelToPercentageString(level)
|
||||
{
|
||||
return (100 - Math.round(Math.pow(0.9, level) * 100)) + "%";
|
||||
// return sprintf(translate("%(armorPercentage)s%"), { armorPercentage: (100 - Math.round(Math.pow(0.9, level) * 100)) }); // Not supported by our sprintf implementation.
|
||||
return sprintf(translate("%(percentage)s%%"), {
|
||||
"percentage": (100 - Math.round(Math.pow(0.9, level) * 100))
|
||||
});
|
||||
}
|
||||
|
||||
function getArmorTooltip(dmg)
|
||||
function getArmorTooltip(template)
|
||||
{
|
||||
let label = g_TooltipTextFormats.header[0] + translate("Armor:") + g_TooltipTextFormats.header[1];
|
||||
if (!dmg)
|
||||
return sprintf(translate("%(label)s %(details)s"), {
|
||||
"label": label,
|
||||
"details": '[font="sans-12"]' + translate("(None)") + '[/font]'
|
||||
});
|
||||
|
||||
let dmgArray = [];
|
||||
if (dmg.hack)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s %(armorPercentage)s"), {
|
||||
"damage": dmg.hack.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Hack") + g_TooltipTextFormats.unit[1],
|
||||
"armorPercentage": '[font="sans-10"]' + sprintf(translate("(%(armorPercentage)s)"), { "armorPercentage": armorLevelToPercentageString(dmg.hack) }) + '[/font]'
|
||||
}));
|
||||
|
||||
if (dmg.pierce)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s %(armorPercentage)s"), {
|
||||
"damage": dmg.pierce.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Pierce") + g_TooltipTextFormats.unit[1],
|
||||
"armorPercentage": '[font="sans-10"]' + sprintf(translate("(%(armorPercentage)s)"), { "armorPercentage": armorLevelToPercentageString(dmg.pierce) }) + '[/font]'
|
||||
}));
|
||||
|
||||
if (dmg.crush)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s %(armorPercentage)s"), {
|
||||
"damage": dmg.crush.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Crush") + g_TooltipTextFormats.unit[1],
|
||||
"armorPercentage": '[font="sans-10"]' + sprintf(translate("(%(armorPercentage)s)"), { "armorPercentage": armorLevelToPercentageString(dmg.crush) }) + '[/font]'
|
||||
}));
|
||||
if (!template.armour)
|
||||
return "";
|
||||
|
||||
return sprintf(translate("%(label)s %(details)s"), {
|
||||
"label": label,
|
||||
"details": dmgArray.join('[font="sans-12"]' + translate(", ") + '[/font]')
|
||||
"label": headerFont(translate("Armor:")),
|
||||
"details":
|
||||
Object.keys(template.armour).map(
|
||||
dmgType => sprintf(translate("%(damage)s %(damageType)s %(armorPercentage)s"), {
|
||||
"damage": template.armour[dmgType].toFixed(1),
|
||||
"damageType": unitFont(g_DamageTypes[dmgType]),
|
||||
"armorPercentage":
|
||||
'[font="sans-10"]' +
|
||||
sprintf(translate("(%(armorPercentage)s)"), {
|
||||
"armorPercentage": armorLevelToPercentageString(template.armour[dmgType])
|
||||
}) + '[/font]'
|
||||
})
|
||||
).join(commaFont(translate(", ")))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -123,74 +129,46 @@ function damageTypesToText(dmg)
|
||||
if (!dmg)
|
||||
return '[font="sans-12"]' + translate("(None)") + '[/font]';
|
||||
|
||||
let dmgArray = [];
|
||||
if (dmg.hack)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s"), {
|
||||
"damage": dmg.hack.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Hack") + g_TooltipTextFormats.unit[1]
|
||||
}));
|
||||
|
||||
if (dmg.pierce)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s"), {
|
||||
"damage": dmg.pierce.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Pierce") + g_TooltipTextFormats.unit[1]
|
||||
}));
|
||||
|
||||
if (dmg.crush)
|
||||
dmgArray.push(sprintf(translate("%(damage)s %(damageType)s"), {
|
||||
"damage": dmg.crush.toFixed(1),
|
||||
"damageType": g_TooltipTextFormats.unit[0] + translate("Crush") + g_TooltipTextFormats.unit[1]
|
||||
}));
|
||||
|
||||
return dmgArray.join('[font="sans-12"]' + translate(", ") + '[/font]');
|
||||
}
|
||||
|
||||
function getAttackTypeLabel(type)
|
||||
{
|
||||
if (type === "Charge") return translate("Charge Attack:");
|
||||
if (type === "Melee") return translate("Melee Attack:");
|
||||
if (type === "Ranged") return translate("Ranged Attack:");
|
||||
if (type === "Capture") return translate("Capture Attack:");
|
||||
|
||||
warn(sprintf("Internationalization: Unexpected attack type found with code ‘%(attackType)s’. This attack type must be internationalized.", { "attackType": type }));
|
||||
return translate("Attack:");
|
||||
return Object.keys(g_DamageTypes).filter(
|
||||
dmgType => dmg[dmgType]).map(
|
||||
dmgType => sprintf(translate("%(damage)s %(damageType)s"), {
|
||||
"damage": dmg[dmgType].toFixed(1),
|
||||
"damageType": unitFont(g_DamageTypes[dmgType])
|
||||
})).join(commaFont(translate(", ")));
|
||||
}
|
||||
|
||||
// TODO: should also show minRange and splash damage
|
||||
function getAttackTooltip(template)
|
||||
{
|
||||
let attacks = [];
|
||||
if (!template.attack)
|
||||
return "";
|
||||
|
||||
let rateLabel = g_TooltipTextFormats.header[0] + (template.buildingAI ? translate("Interval:") : translate("Rate:")) + g_TooltipTextFormats.header[1];
|
||||
|
||||
let attacks = [];
|
||||
for (let type in template.attack)
|
||||
{
|
||||
if (type == "Slaughter")
|
||||
continue; // Slaughter is not a real attack, so do not show it.
|
||||
continue; // Slaughter is used to kill animals, so do not show it.
|
||||
if (type == "Charge")
|
||||
continue; // Charging isn't implemented yet and shouldn't be displayed.
|
||||
|
||||
let rate = sprintf(translate("%(label)s %(details)s"), {
|
||||
"label": rateLabel,
|
||||
"label":
|
||||
headerFont(
|
||||
template.buildingAI && type == "Ranged" ?
|
||||
translate("Interval:") :
|
||||
translate("Rate:")),
|
||||
"details": attackRateDetails(template, type)
|
||||
});
|
||||
|
||||
let attackLabel = g_TooltipTextFormats.header[0] + getAttackTypeLabel(type) + g_TooltipTextFormats.header[1];
|
||||
if (type == "Capture")
|
||||
let attackLabel = headerFont(g_AttackTypes[type]);
|
||||
if (type == "Capture" || type != "Ranged")
|
||||
{
|
||||
attacks.push(sprintf(translate("%(attackLabel)s %(details)s, %(rate)s"), {
|
||||
"attackLabel": attackLabel,
|
||||
"details": template.attack[type].value,
|
||||
"rate": rate
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (type != "Ranged")
|
||||
{
|
||||
attacks.push(sprintf(translate("%(attackLabel)s %(details)s, %(rate)s"), {
|
||||
"attackLabel": attackLabel,
|
||||
"details": damageTypesToText(template.attack[type]),
|
||||
"details":
|
||||
type == "Capture" ?
|
||||
template.attack.Capture.value :
|
||||
damageTypesToText(template.attack[type]),
|
||||
"rate": rate
|
||||
}));
|
||||
continue;
|
||||
@@ -198,75 +176,56 @@ function getAttackTooltip(template)
|
||||
|
||||
let realRange = template.attack[type].elevationAdaptedRange;
|
||||
let range = Math.round(template.attack[type].maxRange);
|
||||
let rangeLabel = g_TooltipTextFormats.header[0] + translate("Range:") + g_TooltipTextFormats.header[1];
|
||||
let relativeRange = Math.round((realRange - range));
|
||||
let meters = g_TooltipTextFormats.unit[0] + translatePlural("meter", "meters", range) + g_TooltipTextFormats.unit[1];
|
||||
let relativeRange = realRange ? Math.round(realRange - range) : 0;
|
||||
|
||||
if (relativeRange) // show if it is non-zero
|
||||
attacks.push(sprintf(translate("%(attackLabel)s %(details)s, %(rangeLabel)s %(rangeString)s (%(relative)s), %(rate)s"), {
|
||||
"attackLabel": attackLabel,
|
||||
"details": damageTypesToText(template.attack[type]),
|
||||
"rangeLabel": rangeLabel,
|
||||
"rangeString": sprintf(
|
||||
translatePlural("%(range)s %(meters)s", "%(range)s %(meters)s", range), {
|
||||
"range": range,
|
||||
"meters": meters
|
||||
}),
|
||||
"relative": relativeRange > 0 ? "+" + relativeRange : relativeRange,
|
||||
"rate": rate
|
||||
}));
|
||||
else
|
||||
attacks.push(sprintf(translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(rangeString)s, %(rate)s"), {
|
||||
"attackLabel": attackLabel,
|
||||
"damageTypes": damageTypesToText(template.attack[type]),
|
||||
"rangeLabel": rangeLabel,
|
||||
"rangeString": sprintf(
|
||||
translatePlural("%(range)s %(meters)s", "%(range)s %(meters)s", range), {
|
||||
"range": range,
|
||||
"meters": meters
|
||||
}),
|
||||
rate: rate
|
||||
}));
|
||||
let rangeString = relativeRange ?
|
||||
translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(rangeString)s (%(relative)s), %(rate)s") :
|
||||
translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(rangeString)s, %(rate)s");
|
||||
|
||||
attacks.push(sprintf(rangeString, {
|
||||
"attackLabel": attackLabel,
|
||||
"damageTypes": damageTypesToText(template.attack[type]),
|
||||
"rangeLabel": translate("Range:"),
|
||||
"rangeString": sprintf(
|
||||
translatePlural("%(range)s %(meters)s", "%(range)s %(meters)s", range), {
|
||||
"range": range,
|
||||
"meters": unitFont(translatePlural("meter", "meters", range))
|
||||
}),
|
||||
"rate": rate,
|
||||
"relative": relativeRange > 0 ? "+" + relativeRange : relativeRange,
|
||||
}));
|
||||
}
|
||||
|
||||
return attacks.join("\n");
|
||||
}
|
||||
|
||||
function getRepairRateTooltip(rate)
|
||||
function getRepairRateTooltip(template)
|
||||
{
|
||||
return "\n" + sprintf(translate("%(repairRateLabel)s %(value)s %(health)s / %(second)s / %(worker)s"), {
|
||||
"repairRateLabel": g_TooltipTextFormats.header[0] + translate("Repair Rate:") + g_TooltipTextFormats.header[1],
|
||||
"value": Math.round(rate * 10) / 10,
|
||||
"health": g_TooltipTextFormats.unit[0] + translate("health") + g_TooltipTextFormats.unit[1],
|
||||
"second": g_TooltipTextFormats.unit[0] + translate("second") + g_TooltipTextFormats.unit[1],
|
||||
"worker": g_TooltipTextFormats.unit[0] + translate("worker") + g_TooltipTextFormats.unit[1]
|
||||
if (!template.repairRate)
|
||||
return "";
|
||||
|
||||
return sprintf(translate("%(repairRateLabel)s %(value)s %(health)s / %(second)s / %(worker)s"), {
|
||||
"repairRateLabel": headerFont(translate("Repair Rate:")),
|
||||
"value": Math.round(template.repairRate * 10) / 10,
|
||||
"health": unitFont(translate("health")),
|
||||
"second": unitFont(translate("second")),
|
||||
"worker": unitFont(translate("worker"))
|
||||
});
|
||||
}
|
||||
|
||||
function getBuildRateTooltip(rate)
|
||||
function getBuildRateTooltip(template)
|
||||
{
|
||||
return "\n" + sprintf(translate("%(buildRateLabel)s %(value)s %(health)s / %(second)s / %(worker)s"), {
|
||||
"buildRateLabel": g_TooltipTextFormats.header[0] + translate("Build Rate:") + g_TooltipTextFormats.header[1],
|
||||
"value": Math.round(rate * 10) / 10,
|
||||
"health": g_TooltipTextFormats.unit[0] + translate("health") + g_TooltipTextFormats.unit[1],
|
||||
"second": g_TooltipTextFormats.unit[0] + translate("second") + g_TooltipTextFormats.unit[1],
|
||||
"worker": g_TooltipTextFormats.unit[0] + translate("worker") + g_TooltipTextFormats.unit[1]
|
||||
if (!template.buildRate)
|
||||
return "";
|
||||
|
||||
return sprintf(translate("%(buildRateLabel)s %(value)s %(health)s / %(second)s / %(worker)s"), {
|
||||
"buildRateLabel": headerFont(translate("Build Rate:")),
|
||||
"value": Math.round(template.buildRate * 10) / 10,
|
||||
"health": unitFont(translate("health")),
|
||||
"second": unitFont(translate("second")),
|
||||
"worker": unitFont(translate("worker"))
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a cost component identifier as they are used internally
|
||||
* (e.g. "population", "food", etc.) to proper display names.
|
||||
*/
|
||||
function getCostComponentDisplayIcon(costComponentName)
|
||||
{
|
||||
if (costComponentName in g_CostDisplayIcons)
|
||||
return g_CostDisplayIcons[costComponentName];
|
||||
|
||||
warn(sprintf("The specified cost component, ‘%(component)s’, is not currently supported.", { "component": costComponentName }));
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the costs for a template by a given batch size.
|
||||
*/
|
||||
@@ -295,12 +254,28 @@ function getEntityCostComponentsTooltipString(template, trainNum, entity)
|
||||
for (let type in g_CostDisplayIcons)
|
||||
if (totalCosts[type])
|
||||
costs.push(sprintf(translate("%(component)s %(cost)s"), {
|
||||
"component": getCostComponentDisplayIcon(type),
|
||||
"component": g_CostDisplayIcons[type],
|
||||
"cost": totalCosts[type]
|
||||
}));
|
||||
|
||||
return costs;
|
||||
}
|
||||
function getGatherTooltip(template)
|
||||
{
|
||||
if (!template.gather)
|
||||
return "";
|
||||
|
||||
return sprintf(translate("%(label)s %(details)s"), {
|
||||
"label": headerFont(translate("Gather Rates:")),
|
||||
"details":
|
||||
Object.keys(template.gather).map(
|
||||
type => sprintf(translate("%(resourceIcon)s %(rate)s"), {
|
||||
"resourceIcon": g_CostDisplayIcons[type],
|
||||
"rate": template.gather[type]
|
||||
})
|
||||
).join(" ")
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of strings for a set of wall pieces. If the pieces share
|
||||
@@ -321,7 +296,6 @@ function getWallPieceTooltip(wallTypes)
|
||||
for (let i = 1; i < wallTypes.length; ++i)
|
||||
{
|
||||
for (let resource in wallTypes[i].cost)
|
||||
{
|
||||
// Break out of the same-type mode if this wall requires
|
||||
// resource types that the first didn't.
|
||||
if (wallTypes[i].cost[resource] && !resourceCount[resource])
|
||||
@@ -329,10 +303,8 @@ function getWallPieceTooltip(wallTypes)
|
||||
sameTypes = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (let resource in resourceCount)
|
||||
{
|
||||
if (wallTypes[i].cost[resource])
|
||||
resourceCount[resource].push(wallTypes[i].cost[resource]);
|
||||
else
|
||||
@@ -340,25 +312,17 @@ function getWallPieceTooltip(wallTypes)
|
||||
sameTypes = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sameTypes)
|
||||
{
|
||||
for (let resource in resourceCount)
|
||||
{
|
||||
let resourceMin = Math.min.apply(Math, resourceCount[resource]);
|
||||
let resourceMax = Math.max.apply(Math, resourceCount[resource]);
|
||||
|
||||
// Translation: This string is part of the resources cost string on
|
||||
// the tooltip for wall structures.
|
||||
out.push(sprintf(translate("%(resourceIcon)s %(minimum)s to %(resourceIcon)s %(maximum)s"), {
|
||||
"resourceIcon": getCostComponentDisplayIcon(resource),
|
||||
"minimum": resourceMin,
|
||||
"maximum": resourceMax
|
||||
"resourceIcon": g_CostDisplayIcons[resource],
|
||||
"minimum": Math.min.apply(Math, resourceCount[resource]),
|
||||
"maximum": Math.max.apply(Math, resourceCount[resource])
|
||||
}));
|
||||
}
|
||||
}
|
||||
else
|
||||
for (let i = 0; i < wallTypes.length; ++i)
|
||||
out.push(getEntityCostComponentsTooltipString(wallTypes[i]).join(", "));
|
||||
@@ -400,8 +364,8 @@ function getPopulationBonusTooltip(template)
|
||||
{
|
||||
let popBonus = "";
|
||||
if (template.cost && template.cost.populationBonus)
|
||||
popBonus = "\n" + sprintf(translate("%(label)s %(populationBonus)s"), {
|
||||
"label": g_TooltipTextFormats.header[0] + translate("Population Bonus:") + g_TooltipTextFormats.header[1],
|
||||
popBonus = sprintf(translate("%(label)s %(populationBonus)s"), {
|
||||
"label": headerFont(translate("Population Bonus:")),
|
||||
"populationBonus": template.cost.populationBonus
|
||||
});
|
||||
return popBonus;
|
||||
@@ -412,14 +376,17 @@ function getPopulationBonusTooltip(template)
|
||||
*/
|
||||
function getNeededResourcesTooltip(resources)
|
||||
{
|
||||
if (!resources)
|
||||
return "";
|
||||
|
||||
let formatted = [];
|
||||
for (let resource in resources)
|
||||
formatted.push(sprintf(translate("%(component)s %(cost)s"), {
|
||||
"component": '[font="sans-12"]' + getCostComponentDisplayIcon(resource) + '[/font]',
|
||||
"component": '[font="sans-12"]' + g_CostDisplayIcons[resource] + '[/font]',
|
||||
"cost": resources[resource]
|
||||
}));
|
||||
|
||||
return '\n\n[font="sans-bold-13"][color="red"]' + translate("Insufficient resources:") + '[/color][/font]\n' + formatted.join(" ");
|
||||
return '\n[font="sans-bold-13"][color="red"]' + translate("Insufficient resources:") + '[/color][/font]\n' + formatted.join(" ");
|
||||
}
|
||||
|
||||
function getSpeedTooltip(template)
|
||||
@@ -427,23 +394,22 @@ function getSpeedTooltip(template)
|
||||
if (!template.speed)
|
||||
return "";
|
||||
|
||||
let label = g_TooltipTextFormats.header[0] + translate("Speed:") + g_TooltipTextFormats.header[1];
|
||||
let speeds = [];
|
||||
|
||||
if (template.speed.walk)
|
||||
speeds.push(sprintf(translate("%(speed)s %(movementType)s"), {
|
||||
"speed": Math.round(template.speed.walk),
|
||||
"movementType": g_TooltipTextFormats.unit[0] + translate("Walk") + g_TooltipTextFormats.unit[1]
|
||||
"movementType": unitFont(translate("Walk"))
|
||||
}));
|
||||
|
||||
if (template.speed.run)
|
||||
speeds.push(sprintf(translate("%(speed)s %(movementType)s"), {
|
||||
"speed": Math.round(template.speed.run),
|
||||
"movementType": g_TooltipTextFormats.unit[0] + translate("Run") + g_TooltipTextFormats.unit[1]
|
||||
"movementType": unitFont(translate("Run"))
|
||||
}));
|
||||
|
||||
return sprintf(translate("%(label)s %(speeds)s"), {
|
||||
"label": label,
|
||||
"label": headerFont(translate("Speed:")),
|
||||
"speeds": speeds.join(translate(", "))
|
||||
});
|
||||
}
|
||||
@@ -453,25 +419,24 @@ function getHealerTooltip(template)
|
||||
if (!template.healer)
|
||||
return "";
|
||||
|
||||
let healer = [
|
||||
return [
|
||||
sprintf(translatePlural("%(label)s %(val)s %(unit)s", "%(label)s %(val)s %(unit)s", template.healer.HP), {
|
||||
"label": g_TooltipTextFormats.header[0] + translate("Heal:") + g_TooltipTextFormats.header[1],
|
||||
"label": headerFont(translate("Heal:")),
|
||||
"val": template.healer.HP,
|
||||
// Translation: Short for hit points (or health points) that are healed in one healing action
|
||||
"unit": g_TooltipTextFormats.unit[0] + translatePlural("HP", "HP", template.healer.HP) + g_TooltipTextFormats.unit[1]
|
||||
"unit": unitFont(translatePlural("HP", "HP", template.healer.HP))
|
||||
}),
|
||||
sprintf(translatePlural("%(label)s %(val)s %(unit)s", "%(label)s %(val)s %(unit)s", template.healer.Range), {
|
||||
"label": g_TooltipTextFormats.header[0] + translate("Range:") + g_TooltipTextFormats.header[1],
|
||||
"label": headerFont(translate("Range:")),
|
||||
"val": template.healer.Range,
|
||||
"unit": g_TooltipTextFormats.unit[0] + translatePlural("meter", "meters", template.healer.Range) + g_TooltipTextFormats.unit[1]
|
||||
"unit": unitFont(translatePlural("meter", "meters", template.healer.Range))
|
||||
}),
|
||||
sprintf(translatePlural("%(label)s %(val)s %(unit)s", "%(label)s %(val)s %(unit)s", template.healer.Rate/1000), {
|
||||
"label": g_TooltipTextFormats.header[0] + translate("Rate:") + g_TooltipTextFormats.header[1],
|
||||
"label": headerFont(translate("Rate:")),
|
||||
"val": template.healer.Rate/1000,
|
||||
"unit": g_TooltipTextFormats.unit[0] + translatePlural("second", "seconds", template.healer.Rate/1000) + g_TooltipTextFormats.unit[1]
|
||||
"unit": unitFont(translatePlural("second", "seconds", template.healer.Rate / 1000))
|
||||
})
|
||||
];
|
||||
return healer.join(translate(", "));
|
||||
].join(translate(", "));
|
||||
}
|
||||
|
||||
function getAurasTooltip(template)
|
||||
@@ -479,67 +444,50 @@ function getAurasTooltip(template)
|
||||
if (!template.auras)
|
||||
return "";
|
||||
|
||||
let txt = "";
|
||||
for (let aura in template.auras)
|
||||
txt += '\n' + sprintf(translate("%(auralabel)s %(aurainfo)s"), {
|
||||
"auralabel": g_TooltipTextFormats.header[0] + sprintf(translate("%(auraname)s:"), {
|
||||
let tooltips = Object.keys(template.auras).map(
|
||||
aura => sprintf(translate("%(auralabel)s %(aurainfo)s"), {
|
||||
"auralabel": headerFont(sprintf(translate("%(auraname)s:"), {
|
||||
"auraname": translate(template.auras[aura].name)
|
||||
}) + g_TooltipTextFormats.header[1],
|
||||
"aurainfo": g_TooltipTextFormats.body[0] + translate(template.auras[aura].description) + g_TooltipTextFormats.body[1]
|
||||
});
|
||||
return txt;
|
||||
})),
|
||||
"aurainfo": bodyFont(translate(template.auras[aura].description))
|
||||
}));
|
||||
return tooltips.join("\n");
|
||||
}
|
||||
|
||||
function getEntityNames(template)
|
||||
{
|
||||
if (template.name.specific)
|
||||
{
|
||||
if (template.name.generic && template.name.specific != template.name.generic)
|
||||
return sprintf(translate("%(specificName)s (%(genericName)s)"), {
|
||||
"specificName": template.name.specific,
|
||||
"genericName": template.name.generic
|
||||
});
|
||||
return template.name.specific;
|
||||
}
|
||||
if (template.name.generic)
|
||||
if (!template.name.specific)
|
||||
return template.name.generic;
|
||||
|
||||
warn("Entity name requested on an entity without a name, specific or generic.");
|
||||
return translate("???");
|
||||
}
|
||||
if (template.name.specific == template.name.generic)
|
||||
return template.name.specific;
|
||||
|
||||
return sprintf(translate("%(specificName)s (%(genericName)s)"), {
|
||||
"specificName": template.name.specific,
|
||||
"genericName": template.name.generic
|
||||
});
|
||||
|
||||
}
|
||||
function getEntityNamesFormatted(template)
|
||||
{
|
||||
let names = "";
|
||||
let generic = template.name.generic;
|
||||
let specific = template.name.specific;
|
||||
if (specific)
|
||||
{
|
||||
// drop caps for specific name
|
||||
names += '[font="sans-bold-16"]' + specific[0] + '[/font]' +
|
||||
'[font="sans-bold-12"]' + specific.slice(1).toUpperCase() + '[/font]';
|
||||
if (!template.name.specific)
|
||||
return '[font="sans-bold-16"]' + template.name.generic + "[/font]";
|
||||
|
||||
if (generic)
|
||||
names += '[font="sans-bold-16"] (' + generic + ')[/font]';
|
||||
}
|
||||
else if (generic)
|
||||
names = '[font="sans-bold-16"]' + generic + "[/font]";
|
||||
else
|
||||
names = "???";
|
||||
|
||||
return names;
|
||||
return sprintf(translate("%(specificName)s %(fontStart)s(%(genericName)s)%(fontEnd)s"), {
|
||||
"specificName":
|
||||
'[font="sans-bold-16"]' + template.name.specific[0] + '[/font]' +
|
||||
'[font="sans-bold-12"]' + template.name.specific.slice(1).toUpperCase() + '[/font]',
|
||||
"genericName": template.name.generic,
|
||||
"fontStart": '[font="sans-bold-16"]',
|
||||
"fontEnd": '[/font]'
|
||||
});
|
||||
}
|
||||
|
||||
function getVisibleEntityClassesFormatted(template)
|
||||
{
|
||||
let r = "";
|
||||
if (template.visibleIdentityClasses && template.visibleIdentityClasses.length)
|
||||
{
|
||||
r += '\n' + g_TooltipTextFormats.header[0] + translate("Classes:") + g_TooltipTextFormats.header[1];
|
||||
let classes = [];
|
||||
for (let c of template.visibleIdentityClasses)
|
||||
classes.push(translate(c));
|
||||
r += ' ' + g_TooltipTextFormats.body[0] + classes.join(translate(", ")) + g_TooltipTextFormats.body[1];
|
||||
}
|
||||
return r;
|
||||
if (!template.visibleIdentityClasses || !template.visibleIdentityClasses.length)
|
||||
return "";
|
||||
|
||||
return headerFont(translate("Classes:")) + ' ' +
|
||||
bodyFont(template.visibleIdentityClasses.map(c => translate(c)).join(translate(", ")));
|
||||
}
|
||||
|
||||
@@ -177,10 +177,10 @@ function displaySingle(entState)
|
||||
if (entState.resourceSupply)
|
||||
{
|
||||
let resources = entState.resourceSupply.isInfinite ? translate("∞") : // Infinity symbol
|
||||
sprintf(translate("%(amount)s / %(max)s"), {
|
||||
"amount": Math.ceil(+entState.resourceSupply.amount),
|
||||
"max": entState.resourceSupply.max
|
||||
});
|
||||
sprintf(translate("%(amount)s / %(max)s"), {
|
||||
"amount": Math.ceil(+entState.resourceSupply.amount),
|
||||
"max": entState.resourceSupply.max
|
||||
});
|
||||
|
||||
let resourceType = getResourceTypeDisplayName(entState.resourceSupply.type);
|
||||
|
||||
@@ -267,68 +267,41 @@ function displaySingle(entState)
|
||||
Engine.GetGUIObjectByName("resourceCarryingText").hidden = true;
|
||||
}
|
||||
|
||||
// Set Player details
|
||||
Engine.GetGUIObjectByName("specific").caption = specificName;
|
||||
Engine.GetGUIObjectByName("player").caption = playerName;
|
||||
Engine.GetGUIObjectByName("playerColorBackground").sprite = "color: " + playerColor;
|
||||
|
||||
if (genericName !== specificName)
|
||||
Engine.GetGUIObjectByName("generic").caption = sprintf(translate("(%(genericName)s)"), { "genericName": genericName });
|
||||
else
|
||||
Engine.GetGUIObjectByName("generic").caption = "";
|
||||
Engine.GetGUIObjectByName("generic").caption = genericName == specificName ? "" :
|
||||
sprintf(translate("(%(genericName)s)"), {
|
||||
"genericName": genericName
|
||||
});
|
||||
|
||||
if ("gaia" != playerState.civ)
|
||||
{
|
||||
Engine.GetGUIObjectByName("playerCivIcon").sprite = "stretched:grayscale:" + civEmblem;
|
||||
Engine.GetGUIObjectByName("player").tooltip = civName;
|
||||
}
|
||||
else
|
||||
{
|
||||
Engine.GetGUIObjectByName("playerCivIcon").sprite = "";
|
||||
Engine.GetGUIObjectByName("player").tooltip = "";
|
||||
}
|
||||
let isGaia = "gaia" == playerState.civ;
|
||||
Engine.GetGUIObjectByName("playerCivIcon").sprite = isGaia ? "" : "stretched:grayscale:" + civEmblem;
|
||||
Engine.GetGUIObjectByName("player").tooltip = isGaia ? "" : civName;
|
||||
|
||||
// Icon image
|
||||
// TODO: we should require all entities to have icons
|
||||
Engine.GetGUIObjectByName("icon").sprite = template.icon ? ("stretched:session/portraits/" + template.icon) : "bkFillBlack";
|
||||
|
||||
let armorString = getArmorTooltip(entState.armour);
|
||||
Engine.GetGUIObjectByName("attackAndArmorStats").tooltip = [
|
||||
getAttackTooltip,
|
||||
getArmorTooltip,
|
||||
getRepairRateTooltip,
|
||||
getBuildRateTooltip
|
||||
].map(func => func(entState)).filter(tip => tip).join("\n");
|
||||
|
||||
// Attack and Armor
|
||||
Engine.GetGUIObjectByName("attackAndArmorStats").tooltip = entState.attack ? (getAttackTooltip(entState) + "\n" + armorString) : armorString;
|
||||
|
||||
// Repair Rate
|
||||
if (entState.repairRate)
|
||||
Engine.GetGUIObjectByName("attackAndArmorStats").tooltip += getRepairRateTooltip(entState.repairRate);
|
||||
|
||||
// Build Rate
|
||||
if (entState.buildRate)
|
||||
Engine.GetGUIObjectByName("attackAndArmorStats").tooltip += getBuildRateTooltip(entState.buildRate);
|
||||
|
||||
// Icon Tooltip
|
||||
let iconTooltip = "";
|
||||
let iconTooltips = [];
|
||||
|
||||
if (genericName)
|
||||
iconTooltip = "[font=\"sans-bold-16\"]" + genericName + "[/font]";
|
||||
iconTooltips.push("[font=\"sans-bold-16\"]" + genericName + "[/font]");
|
||||
|
||||
if (template.visibleIdentityClasses && template.visibleIdentityClasses.length)
|
||||
{
|
||||
iconTooltip += "\n[font=\"sans-bold-13\"]" + translate("Classes:") + "[/font] ";
|
||||
iconTooltips = iconTooltips.concat([
|
||||
getVisibleEntityClassesFormatted,
|
||||
getAurasTooltip,
|
||||
getEntityTooltip
|
||||
].map(func => func(template)));
|
||||
|
||||
iconTooltip += "[font=\"sans-13\"]" +
|
||||
template.visibleIdentityClasses.map(c => translate(c)).join(translate(", ")) +
|
||||
"[/font]";
|
||||
}
|
||||
Engine.GetGUIObjectByName("iconBorder").tooltip = iconTooltips.filter(tip => tip).join("\n");
|
||||
|
||||
if (template.auras)
|
||||
iconTooltip += getAurasTooltip(template);
|
||||
|
||||
if (template.tooltip)
|
||||
iconTooltip += "\n[font=\"sans-13\"]" + template.tooltip + "[/font]";
|
||||
|
||||
Engine.GetGUIObjectByName("iconBorder").tooltip = iconTooltip;
|
||||
|
||||
// Unhide Details Area
|
||||
Engine.GetGUIObjectByName("detailsAreaSingle").hidden = false;
|
||||
Engine.GetGUIObjectByName("detailsAreaMultiple").hidden = true;
|
||||
}
|
||||
@@ -417,7 +390,7 @@ function displayMultiple(selection)
|
||||
let numberOfUnits = Engine.GetGUIObjectByName("numberOfUnits");
|
||||
numberOfUnits.caption = selection.length;
|
||||
numberOfUnits.tooltip = Object.keys(totalResourcesCarried).map(res =>
|
||||
getCostComponentDisplayIcon(res) + totalResourcesCarried[res]
|
||||
g_CostDisplayIcons[res] + totalResourcesCarried[res]
|
||||
).join(" ");
|
||||
|
||||
// Unhide Details Area
|
||||
|
||||
@@ -301,34 +301,31 @@ g_SelectionPanels.Construction = {
|
||||
"player": data.unitEntState.player
|
||||
});
|
||||
|
||||
let limits = getEntityLimitAndCount(data.playerState, data.item);
|
||||
|
||||
if (template.wallSet)
|
||||
template.auras = GetTemplateData(template.wallSet.templates.long).auras;
|
||||
|
||||
data.button.onPress = function () { startBuildingPlacement(data.item, data.playerState); };
|
||||
|
||||
let tooltip = getEntityNamesFormatted(template);
|
||||
tooltip += getVisibleEntityClassesFormatted(template);
|
||||
tooltip += getAurasTooltip(template);
|
||||
let tooltips = [
|
||||
getEntityNamesFormatted,
|
||||
getVisibleEntityClassesFormatted,
|
||||
getAurasTooltip,
|
||||
getEntityTooltip,
|
||||
getEntityCostTooltip,
|
||||
getPopulationBonusTooltip
|
||||
].map(func => func(template));
|
||||
|
||||
if (template.tooltip)
|
||||
tooltip += "\n[font=\"sans-13\"]" + template.tooltip + "[/font]";
|
||||
|
||||
tooltip += "\n" + getEntityCostTooltip(template);
|
||||
tooltip += getPopulationBonusTooltip(template);
|
||||
|
||||
tooltip += formatLimitString(limits.entLimit, limits.entCount, limits.entLimitChangers);
|
||||
let limits = getEntityLimitAndCount(data.playerState, data.item);
|
||||
tooltips.push(formatLimitString(limits.entLimit, limits.entCount, limits.entLimitChangers));
|
||||
|
||||
if (!technologyEnabled)
|
||||
tooltip += "\n" + sprintf(translate("Requires %(technology)s"), {
|
||||
tooltips.push(sprintf(translate("Requires %(technology)s"), {
|
||||
"technology": getEntityNames(GetTechnologyData(template.requiredTechnology))
|
||||
});
|
||||
}));
|
||||
|
||||
if (neededResources)
|
||||
tooltip += getNeededResourcesTooltip(neededResources);
|
||||
tooltips.push(getNeededResourcesTooltip(neededResources));
|
||||
|
||||
data.button.tooltip = tooltip;
|
||||
data.button.tooltip = tooltips.filter(tip => tip).join("\n");
|
||||
|
||||
let modifier = "";
|
||||
if (!technologyEnabled || limits.canBeAddedCount == 0)
|
||||
@@ -529,27 +526,26 @@ g_SelectionPanels.Gate = {
|
||||
{
|
||||
data.button.onPress = function() {data.item.callback(data.item); };
|
||||
|
||||
let tooltip = data.item.tooltip;
|
||||
let tooltips = [data.item.tooltip];
|
||||
if (data.item.template)
|
||||
{
|
||||
data.template = GetTemplateData(data.item.template);
|
||||
data.wallCount = data.selection.reduce(function (count, ent) {
|
||||
data.wallCount = data.selection.reduce(count, ent => {
|
||||
let state = GetEntityState(ent);
|
||||
if (hasClass(state, "LongWall") && !state.gate)
|
||||
++count;
|
||||
return count;
|
||||
}, 0);
|
||||
|
||||
tooltip += "\n" + getEntityCostTooltip(data.template, data.wallCount);
|
||||
tooltips.push(getEntityCostTooltip(data.template, data.wallCount));
|
||||
|
||||
data.neededResources = Engine.GuiInterfaceCall("GetNeededResources", {
|
||||
"cost": multiplyEntityCosts(data.template, data.wallCount)
|
||||
});
|
||||
|
||||
if (data.neededResources)
|
||||
tooltip += getNeededResourcesTooltip(data.neededResources);
|
||||
tooltips.push(getNeededResourcesTooltip(data.neededResources));
|
||||
}
|
||||
data.button.tooltip = tooltip;
|
||||
data.button.tooltip = tooltips.filter(tip => tip).join("\n");
|
||||
|
||||
data.button.enabled = controlsPlayer(data.unitEntState.player);
|
||||
let gateIcon;
|
||||
@@ -679,7 +675,7 @@ g_SelectionPanels.Queue = {
|
||||
{
|
||||
tooltip += "\n[color=\"red\"]" + translate("Insufficient population capacity:") + "\n[/color]";
|
||||
tooltip += sprintf(translate("%(population)s %(neededSlots)s"), {
|
||||
"population": getCostComponentDisplayIcon("population"),
|
||||
"population": g_CostDisplayIcons.population,
|
||||
"neededSlots": data.item.neededSlots
|
||||
});
|
||||
}
|
||||
@@ -783,25 +779,28 @@ g_SelectionPanels.Research = {
|
||||
let button = Engine.GetGUIObjectByName("unitResearchButton[" + position + "]");
|
||||
let icon = Engine.GetGUIObjectByName("unitResearchIcon[" + position + "]");
|
||||
|
||||
let tooltip = getEntityNamesFormatted(template);
|
||||
if (template.tooltip)
|
||||
tooltip += "\n[font=\"sans-13\"]" + template.tooltip + "[/font]";
|
||||
let tooltips = [
|
||||
getEntityNamesFormatted,
|
||||
getEntityTooltip,
|
||||
getEntityCostTooltip
|
||||
].map(func => func(template));
|
||||
|
||||
tooltip += "\n" + getEntityCostTooltip(template);
|
||||
if (!requirementsPassed)
|
||||
{
|
||||
tooltip += "\n" + template.requirementsTooltip;
|
||||
let tip = template.requirementsTooltip;
|
||||
if (template.classRequirements)
|
||||
{
|
||||
let player = data.unitEntState.player;
|
||||
let current = GetSimState().players[player].classCounts[template.classRequirements.class] || 0;
|
||||
let remaining = template.classRequirements.number - current;
|
||||
tooltip += " " + sprintf(translatePlural("Remaining: %(number)s to build.", "Remaining: %(number)s to build.", remaining), { "number": remaining });
|
||||
tip += " " + sprintf(translatePlural("Remaining: %(number)s to build.", "Remaining: %(number)s to build.", remaining), {
|
||||
"number": remaining
|
||||
});
|
||||
}
|
||||
tooltips.push(tip);
|
||||
}
|
||||
if (neededResources)
|
||||
tooltip += getNeededResourcesTooltip(neededResources);
|
||||
button.tooltip = tooltip;
|
||||
tooltips.push(getNeededResourcesTooltip(neededResources));
|
||||
button.tooltip = tooltips.filter(tip => tip).join("\n");
|
||||
|
||||
button.onPress = function () {
|
||||
addResearchToQueue(data.unitEntState.id, tech);
|
||||
@@ -988,47 +987,41 @@ g_SelectionPanels.Training = {
|
||||
|
||||
data.countDisplay.caption = trainNum > 1 ? trainNum : "";
|
||||
|
||||
let tooltip = "[font=\"sans-bold-16\"]" +
|
||||
colorizeHotkey("%(hotkey)s", "session.queueunit." + (data.i + 1)) +
|
||||
"[/font]";
|
||||
|
||||
tooltip += getEntityNamesFormatted(template);
|
||||
tooltip += getVisibleEntityClassesFormatted(template);
|
||||
tooltip += getAurasTooltip(template);
|
||||
|
||||
if (template.tooltip)
|
||||
tooltip += "\n[font=\"sans-13\"]" + template.tooltip + "[/font]";
|
||||
|
||||
tooltip += "\n" + getEntityCostTooltip(template, trainNum, data.unitEntState.id);
|
||||
let tooltips = [
|
||||
"[font=\"sans-bold-16\"]" +
|
||||
colorizeHotkey("%(hotkey)s", "session.queueunit." + (data.i + 1)) +
|
||||
"[/font]" + " " + getEntityNamesFormatted(template),
|
||||
getVisibleEntityClassesFormatted(template),
|
||||
getAurasTooltip(template),
|
||||
getEntityTooltip(template),
|
||||
getEntityCostTooltip(template, trainNum, data.unitEntState.id)
|
||||
];
|
||||
|
||||
let limits = getEntityLimitAndCount(data.playerState, data.item);
|
||||
tooltips.push(formatLimitString(limits.entLimit, limits.entCount, limits.entLimitChangers));
|
||||
|
||||
tooltip += formatLimitString(limits.entLimit, limits.entCount, limits.entLimitChangers);
|
||||
if (Engine.ConfigDB_GetValue("user", "showdetailedtooltips") === "true")
|
||||
{
|
||||
if (template.health)
|
||||
tooltip += "\n[font=\"sans-bold-13\"]" + translate("Health:") + "[/font] " + template.health;
|
||||
if (template.attack)
|
||||
tooltip += "\n" + getAttackTooltip(template);
|
||||
if (template.armour)
|
||||
tooltip += "\n" + getArmorTooltip(template.armour);
|
||||
if (template.speed)
|
||||
tooltip += "\n" + getSpeedTooltip(template);
|
||||
}
|
||||
tooltips.push(
|
||||
getHealthTooltip(template),
|
||||
getAttackTooltip(template),
|
||||
getArmorTooltip(template),
|
||||
getSpeedTooltip(template)
|
||||
);
|
||||
|
||||
tooltip += "[color=\"" + g_HotkeyColor + "\"]" +
|
||||
tooltips.push(
|
||||
"[color=\"" + g_HotkeyColor + "\"]" + " " +
|
||||
formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch) +
|
||||
"[/color]";
|
||||
"[/color]");
|
||||
|
||||
if (!technologyEnabled)
|
||||
{
|
||||
let techName = getEntityNames(GetTechnologyData(template.requiredTechnology));
|
||||
tooltip += "\n" + sprintf(translate("Requires %(technology)s"), { "technology": techName });
|
||||
}
|
||||
if (neededResources)
|
||||
tooltip += getNeededResourcesTooltip(neededResources);
|
||||
tooltips.push(sprintf(translate("Requires %(technology)s"), {
|
||||
"technology": getEntityNames(GetTechnologyData(template.requiredTechnology))
|
||||
}));
|
||||
|
||||
data.button.tooltip = tooltip;
|
||||
if (neededResources)
|
||||
tooltips.push(getNeededResourcesTooltip(neededResources));
|
||||
|
||||
data.button.tooltip = tooltips.filter(tip => tip).join("\n");
|
||||
|
||||
let modifier = "";
|
||||
if (!technologyEnabled || limits.canBeAddedCount == 0)
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
// Constants
|
||||
// Barter constants
|
||||
const BARTER_RESOURCE_AMOUNT_TO_SELL = 100;
|
||||
const BARTER_BUNCH_MULTIPLIER = 5;
|
||||
const BARTER_RESOURCES = ["food", "wood", "stone", "metal"];
|
||||
const BARTER_ACTIONS = ["Sell", "Buy"];
|
||||
|
||||
// Gate constants
|
||||
const GATE_ACTIONS = ["lock", "unlock"];
|
||||
|
||||
// ==============================================
|
||||
// BARTER HELPERS
|
||||
// Resources to sell on barter panel
|
||||
var g_BarterSell = "food";
|
||||
|
||||
// FORMATION HELPERS
|
||||
// Check if the selection can move into formation, and cache the result
|
||||
function canMoveSelectionIntoFormation(formationTemplate)
|
||||
{
|
||||
if (!(formationTemplate in g_canMoveIntoFormation))
|
||||
@@ -27,9 +18,6 @@ function canMoveSelectionIntoFormation(formationTemplate)
|
||||
return g_canMoveIntoFormation[formationTemplate];
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// STANCE HELPERS
|
||||
|
||||
function getStanceDisplayName(name)
|
||||
{
|
||||
switch (name)
|
||||
@@ -69,8 +57,6 @@ function getStanceTooltip(name)
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// TRAINING / CONSTRUCTION HELPERS
|
||||
/**
|
||||
* Format entity count/limit message for the tooltip
|
||||
*/
|
||||
@@ -79,17 +65,27 @@ function formatLimitString(trainEntLimit, trainEntCount, trainEntLimitChangers)
|
||||
if (trainEntLimit == undefined)
|
||||
return "";
|
||||
|
||||
var text = "\n\n" + sprintf(translate("Current Count: %(count)s, Limit: %(limit)s."), { "count": trainEntCount, "limit": trainEntLimit });
|
||||
var text = "\n" + sprintf(translate("Current Count: %(count)s, Limit: %(limit)s."), {
|
||||
"count": trainEntCount,
|
||||
"limit": trainEntLimit
|
||||
});
|
||||
|
||||
if (trainEntCount >= trainEntLimit)
|
||||
text = "[color=\"red\"]" + text + "[/color]";
|
||||
|
||||
for (var c in trainEntLimitChangers)
|
||||
{
|
||||
if (trainEntLimitChangers[c] > 0)
|
||||
text += "\n" + sprintf(translate("%(changer)s enlarges the limit with %(change)s."), { "changer": translate(c), "change": trainEntLimitChangers[c] });
|
||||
else if (trainEntLimitChangers[c] < 0)
|
||||
text += "\n" + sprintf(translate("%(changer)s lessens the limit with %(change)s."), { "changer": translate(c), "change": (-trainEntLimitChangers[c]) });
|
||||
if (!trainEntLimitChangers[c])
|
||||
continue;
|
||||
|
||||
let string = trainEntLimitChangers[c] > 0 ?
|
||||
translate("%(changer)s enlarges the limit with %(change)s.") :
|
||||
translate("%(changer)s lessens the limit with %(change)s.");
|
||||
|
||||
text += "\n" + sprintf(string, {
|
||||
"changer": translate(c),
|
||||
"change": trainEntLimitChangers[c]
|
||||
});
|
||||
}
|
||||
return text;
|
||||
}
|
||||
@@ -113,7 +109,6 @@ function formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize
|
||||
if (totalBatchTrainingCount < 2)
|
||||
return "";
|
||||
|
||||
var batchTrainingString = "";
|
||||
var fullBatchesString = "";
|
||||
if (buildingsCountToTrainFullBatch > 0)
|
||||
{
|
||||
@@ -126,34 +121,26 @@ function formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize
|
||||
fullBatchesString = fullBatchSize;
|
||||
}
|
||||
|
||||
var remainderBatchString = remainderBatch > 0 ? remainderBatch : "";
|
||||
var batchDetailsString = "";
|
||||
var action = "[font=\"sans-bold-13\"]" + translate("Shift-click") + "[/font]";
|
||||
|
||||
// We need to display the batch details part if there is either more than
|
||||
// one building with full batch or one building with the full batch and
|
||||
// another with a partial batch
|
||||
let batchString;
|
||||
if (buildingsCountToTrainFullBatch > 1 ||
|
||||
(buildingsCountToTrainFullBatch == 1 && remainderBatch > 0))
|
||||
buildingsCountToTrainFullBatch == 1 && remainderBatch > 0)
|
||||
{
|
||||
if (remainderBatch > 0)
|
||||
return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s (%(fullBatch)s + %(remainderBatch)s)."), {
|
||||
"action": action,
|
||||
"number": totalBatchTrainingCount,
|
||||
"fullBatch": fullBatchesString,
|
||||
"remainderBatch": remainderBatch
|
||||
}) + "[/font]";
|
||||
|
||||
return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s (%(fullBatch)s)."), {
|
||||
"action": action,
|
||||
"number": totalBatchTrainingCount,
|
||||
"fullBatch": fullBatchesString
|
||||
}) + "[/font]";
|
||||
batchString = translate("%(action)s to train %(number)s (%(fullBatch)s + %(remainderBatch)s).");
|
||||
else
|
||||
batchString = translate("%(action)s to train %(number)s (%(fullBatch)s).");
|
||||
}
|
||||
else
|
||||
batchString = translate("%(action)s to train %(number)s.");
|
||||
|
||||
return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s."), {
|
||||
"action": action,
|
||||
"number": totalBatchTrainingCount
|
||||
return "[font=\"sans-13\"]" + sprintf(batchString, {
|
||||
"action": "[font=\"sans-bold-13\"]" + translate("Shift-click") + "[/font]",
|
||||
"number": totalBatchTrainingCount,
|
||||
"fullBatch": fullBatchesString,
|
||||
"remainderBatch": remainderBatch
|
||||
}) + "[/font]";
|
||||
}
|
||||
|
||||
|
||||
@@ -824,22 +824,17 @@ function updateHeroes()
|
||||
|
||||
function createHeroTooltip(heroState, template)
|
||||
{
|
||||
let tooltip = "[font=\"sans-bold-16\"]" + template.name.specific + "[/font]" + "\n" +
|
||||
sprintf(translate("%(label)s %(current)s / %(max)s"), {
|
||||
"label": "[font=\"sans-bold-13\"]" + translate("Health:") + "[/font]",
|
||||
"current": Math.ceil(heroState.hitpoints),
|
||||
"max": Math.ceil(heroState.maxHitpoints)
|
||||
});
|
||||
|
||||
if (heroState.attack)
|
||||
tooltip += "\n" + getAttackTooltip(heroState);
|
||||
|
||||
tooltip += "\n" + getArmorTooltip(heroState.armour);
|
||||
|
||||
if (template.tooltip)
|
||||
tooltip += "\n" + template.tooltip;
|
||||
|
||||
return tooltip;
|
||||
return [
|
||||
"[font=\"sans-bold-16\"]" + template.name.specific + "[/font]" + "\n" +
|
||||
sprintf(translate("%(label)s %(current)s / %(max)s"), {
|
||||
"label": "[font=\"sans-bold-13\"]" + translate("Health:") + "[/font]",
|
||||
"current": Math.ceil(heroState.hitpoints),
|
||||
"max": Math.ceil(heroState.maxHitpoints)
|
||||
}),
|
||||
getAttackTooltip(heroState),
|
||||
getArmorTooltip(heroState),
|
||||
getEntityTooltip(heroState)
|
||||
].filter(tip => tip).join("\n");
|
||||
}
|
||||
|
||||
function displayHeroes()
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
var g_DrawLimits = {}; // GUI limits. Populated by predraw()
|
||||
|
||||
var g_TooltipFunctions = [
|
||||
getEntityNamesFormatted,
|
||||
getEntityCostTooltip,
|
||||
getEntityTooltip,
|
||||
getAurasTooltip,
|
||||
getHealthTooltip,
|
||||
getHealerTooltip,
|
||||
getAttackTooltip,
|
||||
getArmorTooltip,
|
||||
getSpeedTooltip,
|
||||
getGatherTooltip,
|
||||
getPopulationBonusTooltip
|
||||
];
|
||||
|
||||
/**
|
||||
* Draw the structree
|
||||
*
|
||||
@@ -363,54 +377,9 @@ function predraw()
|
||||
* Assemble a tooltip text
|
||||
*
|
||||
* @param template Information about a Unit, a Structure or a Technology
|
||||
*
|
||||
* @return The tooltip text, formatted.
|
||||
*/
|
||||
function assembleTooltip(template)
|
||||
{
|
||||
let txt = getEntityNamesFormatted(template);
|
||||
txt += '\n' + getEntityCostTooltip(template, 1);
|
||||
|
||||
if (template.tooltip)
|
||||
txt += '\n' + g_TooltipTextFormats.body[0] + translate(template.tooltip) + g_TooltipTextFormats.body[1];
|
||||
|
||||
if (template.auras)
|
||||
txt += getAurasTooltip(template);
|
||||
|
||||
if (template.health)
|
||||
txt += '\n' + sprintf(translate("%(label)s %(details)s"), {
|
||||
"label": g_TooltipTextFormats.header[0] + translate("Health:") + g_TooltipTextFormats.header[1],
|
||||
"details": template.health
|
||||
});
|
||||
|
||||
if (template.healer)
|
||||
txt += '\n' + getHealerTooltip(template);
|
||||
|
||||
if (template.attack)
|
||||
txt += '\n' + getAttackTooltip(template);
|
||||
|
||||
if (template.armour)
|
||||
txt += '\n' + getArmorTooltip(template.armour);
|
||||
|
||||
if (template.speed)
|
||||
txt += '\n' + getSpeedTooltip(template);
|
||||
|
||||
if (template.gather)
|
||||
{
|
||||
let rates = [];
|
||||
for (let type in template.gather)
|
||||
rates.push(sprintf(translate("%(resourceIcon)s %(rate)s"), {
|
||||
"resourceIcon": getCostComponentDisplayIcon(type),
|
||||
"rate": template.gather[type]
|
||||
}));
|
||||
|
||||
txt += '\n' + sprintf(translate("%(label)s %(details)s"), {
|
||||
"label": g_TooltipTextFormats.header[0] + translate("Gather Rates:") + g_TooltipTextFormats.header[1],
|
||||
"details": rates.join(" ")
|
||||
});
|
||||
}
|
||||
|
||||
txt += getPopulationBonusTooltip(template);
|
||||
|
||||
return txt;
|
||||
return g_TooltipFunctions.map(func => func(template)).filter(tip => tip).join("\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user