Index: binaries/data/mods/public/globalscripts/Templates.js =================================================================== --- binaries/data/mods/public/globalscripts/Templates.js +++ binaries/data/mods/public/globalscripts/Templates.js @@ -390,6 +390,7 @@ ret.tooltip = template.Identity.Tooltip; ret.requiredTechnology = template.Identity.RequiredTechnology; ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity); + ret.nativeCiv = template.Identity.Civ; } if (template.UnitMotion) 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 @@ -2,7 +2,10 @@ "unit": { "font": "sans-10", "color": "orange" }, "header": { "font": "sans-bold-13" }, "body": { "font": "sans-13" }, - "comma": { "font": "sans-12" } + "comma": { "font": "sans-12" }, + "nameSpecificBig": { "font": "sans-bold-16" }, + "nameSpecificSmall": { "font": "sans-bold-12" }, + "nameGeneric": { "font": "sans-bold-16" } }; var g_AttackTypes = { @@ -110,6 +113,12 @@ }); } +/** + * Entity templates have a `Tooltip` tag in the Identity component. + * (The contents of which are copied to a `tooltip` attribute in globalscripts.) + * + * Technologies have a `tooltip` attribute. + */ function getEntityTooltip(template) { if (!template.tooltip) @@ -118,6 +127,35 @@ return bodyFont(template.tooltip); } +/** + * Technologies have a `description` attribute, and Auras have an `auraDescription` + * attribute, which becomes `description`. + * + * (For technologies, this happens in globalscripts.) + * + * (For auras, this happens either in the Auras component (for session gui) or + * reference/common/load.js (for Reference Suite gui)) + */ +function getDescriptionTooltip(template) +{ + if (!template.description) + return ""; + + return bodyFont(template.description); +} + +/** + * Entity templates have a `History` tag in the Identity component. + * (The contents of which are copied to a `history` attribute in globalscripts.) + */ +function getHistoryTooltip(template) +{ + if (!template.history) + return ""; + + return bodyFont(template.history); +} + function getHealthTooltip(template) { if (!template.health) @@ -569,7 +607,15 @@ } if (template.cost) - return getEntityCostComponentsTooltipString(template, entity, buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch).join(" "); + { + let costs = getEntityCostComponentsTooltipString(template, entity, buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch).join(" "); + if (costs) + // Translation: Label in tooltip showing cost of a unit, structure or technology. + return sprintf(translate("%(label)s %(costs)s"), { + "label": headerFont(translate("Cost:")), + "costs": costs + }); + } return ""; } @@ -717,15 +763,15 @@ function getEntityNamesFormatted(template) { if (!template.name.specific) - return '[font="sans-bold-16"]' + template.name.generic + "[/font]"; + return setStringTags(template.name.generic, g_TooltipTextFormats.nameSpecificBig); // Translation: Example: "Epibátēs Athēnaîos [font="sans-bold-16"](Athenian Marine)[/font]" 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]', + setStringTags(template.name.specific[0], g_TooltipTextFormats.nameSpecificBig) + + setStringTags(template.name.specific.slice(1).toUpperCase(), g_TooltipTextFormats.nameSpecificSmall), "genericName": template.name.generic, - "fontStart": '[font="sans-bold-16"]', + "fontStart": '[font="' + g_TooltipTextFormats.nameGeneric.font + '"]', "fontEnd": '[/font]' }); } @@ -776,3 +822,15 @@ "details": lootLabels.join(" ") }); } + +function showTemplateViewerOnRightClickTooltip() +{ + // Translation: Appears in a tooltip to indicate that right-clicking the corresponding GUI element will open the Template Details GUI page. + return translate("Right-click to view more information."); +} + +function showTemplateViewerOnClickTooltip() +{ + // Translation: Appears in a tooltip to indicate that clicking the corresponding GUI element will open the Template Details GUI page. + return translate("Click to view more information."); +} Index: binaries/data/mods/public/gui/page_viewer.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/page_viewer.xml @@ -0,0 +1,19 @@ + + + common/modern/setup.xml + common/modern/styles.xml + common/modern/sprites.xml + + common/setup_resources.xml + common/sprites.xml + common/styles.xml + + reference/common/sprites.xml + reference/common/styles.xml + + reference/viewer/styles.xml + reference/viewer/sprites.xml + reference/viewer/viewer.xml + + reference/common/setup.xml + Index: binaries/data/mods/public/gui/reference/common/core.js =================================================================== --- binaries/data/mods/public/gui/reference/common/core.js +++ binaries/data/mods/public/gui/reference/common/core.js @@ -1,4 +1,4 @@ -var g_SelectedCiv = ""; +var g_SelectedCiv = "gaia"; var g_CallbackSet = false; function closePage() @@ -94,6 +94,11 @@ if (!templateName || !Engine.TemplateExists(templateName)) return {}; + // If this is a non-promotion variant (ie. {civ}_support_female_citizen_house) + // then it is functionally equivalent to another unit being processed, so skip it. + if (getBaseTemplateName(templateName) != templateName) + return {}; + let template = loadTemplate(templateName); let templateLists = loadProductionQueue(template); @@ -144,7 +149,7 @@ { templateName = templateName.replace(/\{(civ|native)\}/g, g_SelectedCiv); if (Engine.TemplateExists(templateName)) - production.units.push(templateName); + production.units.push(getBaseTemplateName(templateName)); } if (template.ProductionQueue.Technologies && template.ProductionQueue.Technologies._string) @@ -182,3 +187,46 @@ return buildQueue; } + +/** + * Returns the name of a template's base form (without `_house`, `_trireme`, or similar), + * or the template's own name if the base is of a different promotion rank. + */ +function getBaseTemplateName(templateName) +{ + if (!templateName || !Engine.TemplateExists(templateName)) + return undefined; + + templateName = removeFiltersFromTemplateName(templateName); + let template = loadTemplate(templateName); + + if (dirname(template["@parent"]) != dirname(templateName)) + return templateName; + + let parentTemplate = loadTemplate(template["@parent"]); + + if (parentTemplate.Identity && parentTemplate.Identity.Rank && + parentTemplate.Identity.Rank != template.Identity.Rank) + return templateName; + + if (!parentTemplate.Cost) + return templateName; + + for (let res in parentTemplate.Cost.Resources) + if (parentTemplate.Cost.Resources[res] > 0) + return getBaseTemplateName(template["@parent"]); + + return templateName; +} + +function setViewerOnPress(guiObjectName, templateName) +{ + let viewerFunc = () => { + Engine.PushGuiPage("page_viewer.xml", { + "templateName": templateName, + "civ": g_SelectedCiv + }); + }; + Engine.GetGUIObjectByName(guiObjectName).onPress = viewerFunc; + Engine.GetGUIObjectByName(guiObjectName).onPressRight = viewerFunc; +} Index: binaries/data/mods/public/gui/reference/common/draw.js =================================================================== --- binaries/data/mods/public/gui/reference/common/draw.js +++ binaries/data/mods/public/gui/reference/common/draw.js @@ -4,13 +4,12 @@ var g_DrawLimits = {}; /** - * These functions are defined in gui/common/tooltips.js + * List of functions that get the statistics of any template or entity, + * formatted in such a way as to appear in a tooltip. + * + * The functions listed are defined in gui/common/tooltips.js */ -var g_TooltipFunctions = [ - getEntityNamesFormatted, - getEntityCostTooltip, - getEntityTooltip, - getAurasTooltip, +var g_StatsFunctions = [ getHealthTooltip, getHealerTooltip, getAttackTooltip, @@ -20,6 +19,7 @@ getProjectilesTooltip, getSpeedTooltip, getGatherTooltip, + getResourceSupplyTooltip, getPopulationBonusTooltip, getResourceTrickleTooltip, getLootTooltip @@ -37,3 +37,23 @@ { return textFunctions.map(func => func(template)).filter(tip => tip).join(joiner); } + +/** + * Returns the resources this entity supplies in the specified entity's tooltip + */ +function getResourceSupplyTooltip(template) +{ + if (!template.supply) + return ""; + + let supply = template.supply; + let type = supply.type[0] == "treasure" ? supply.type[1] : supply.type[0]; + + // Translation: Label in tooltip showing the resource type and quantity of a given resource supply. + return sprintf(translate("%(label)s %(component)s %(amount)s"), { + "label": headerFont(translate("Resource Supply:")), + "component": resourceIcon(type), + // Translation: Marks that a resource supply entity has an unending, infinite, supply of its resource. + "amount": Number.isFinite(+supply.amount) ? supply.amount : translate("∞") + }); +} Index: binaries/data/mods/public/gui/reference/common/helper.js =================================================================== --- binaries/data/mods/public/gui/reference/common/helper.js +++ binaries/data/mods/public/gui/reference/common/helper.js @@ -24,6 +24,7 @@ upgrade.entity = upgrade.entity.replace(/\{(civ|native)\}/g, g_SelectedCiv); let data = GetTemplateDataHelper(loadTemplate(upgrade.entity), null, g_AuraData, g_ResourceData, g_DamageTypes); + data.name.internal = upgrade.entity; data.cost = upgrade.cost; data.icon = upgrade.icon || data.icon; data.tooltip = upgrade.tooltip || data.tooltip; Index: binaries/data/mods/public/gui/reference/common/load.js =================================================================== --- binaries/data/mods/public/gui/reference/common/load.js +++ binaries/data/mods/public/gui/reference/common/load.js @@ -36,12 +36,16 @@ { // We need to clone the template because we want to perform some translations. let data = clone(Engine.GetTemplate(templateName)); - translateObjectKeys(data, ["GenericName", "SpecificName", "Tooltip"]); + translateObjectKeys(data, ["GenericName", "SpecificName", "Tooltip", "History"]); if (data.Auras) for (let auraID of data.Auras._string.split(/\s+/)) loadAuraData(auraID); + if (data.Identity.Civ != "gaia" && g_SelectedCiv != "gaia" && data.Identity.Civ != g_SelectedCiv) + warn("The \"" + templateName + "\" template has a defined civ of \"" + data.Identity.Civ + "\". " + + "This does not match the currently selected civ \"" + g_SelectedCiv + "\"."); + g_TemplateData[templateName] = data; } @@ -61,7 +65,7 @@ if (!(templateName in g_TechnologyData)) { let data = Engine.ReadJSONFile(g_TechnologyPath + templateName + ".json"); - translateObjectKeys(data, ["genericName", "tooltip"]); + translateObjectKeys(data, ["genericName", "tooltip", "description"]); g_TechnologyData[templateName] = data; } @@ -109,10 +113,18 @@ let parsed = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers); parsed.name.internal = templateName; + parsed.history = template.Identity.History; + parsed.production = loadProductionQueue(template); if (template.Builder) parsed.builder = loadBuildQueue(template); + if (template.Identity.Rank) + parsed.promotion = { + "current_rank": template.Identity.Rank, + "entity": template.Promotion && template.Promotion.Entity + }; + if (template.ResourceSupply) parsed.supply = { "type": template.ResourceSupply.Type.split("."), @@ -197,6 +209,7 @@ { let template = loadTechData(techName); let tech = GetTechnologyDataHelper(template, g_SelectedCiv, g_ResourceData); + tech.name.internal = techName; if (template.pair !== undefined) { Index: binaries/data/mods/public/gui/reference/structree/draw.js =================================================================== --- binaries/data/mods/public/gui/reference/structree/draw.js +++ binaries/data/mods/public/gui/reference/structree/draw.js @@ -1,3 +1,13 @@ +/** + * Functions used to collate the contents of a tooltip. + */ +var g_StructreeTooltipFunctions = [ + getEntityNamesFormatted, + getEntityCostTooltip, + getEntityTooltip, + getAurasTooltip +].concat(g_StatsFunctions); + /** * Draw the structree * @@ -44,11 +54,12 @@ "stretched:session/portraits/"+stru.icon; Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_icon").tooltip = - buildText(stru, g_TooltipFunctions); + compileTooltip(stru); Engine.GetGUIObjectByName("phase["+i+"]_struct["+s+"]_name").caption = translate(stru.name.specific); + setViewerOnPress("phase["+i+"]_struct["+s+"]_icon", stru.name.internal); thisEle.hidden = false; for (let r in g_DrawLimits[pha].prodQuant) @@ -154,8 +165,9 @@ trainer = g_ParsedData.units[trainer]; Engine.GetGUIObjectByName("trainer["+t+"]_icon").sprite = "stretched:session/portraits/"+trainer.icon; - Engine.GetGUIObjectByName("trainer["+t+"]_icon").tooltip = buildText(trainer, g_TooltipFunctions); + Engine.GetGUIObjectByName("trainer["+t+"]_icon").tooltip = compileTooltip(trainer); Engine.GetGUIObjectByName("trainer["+t+"]_name").caption = translate(trainer.name.specific); + setViewerOnPress("trainer["+t+"]_icon", trainer.name.internal); thisEle.hidden = false; let p = 0; @@ -242,11 +254,17 @@ } prodEle.sprite = "stretched:session/portraits/"+template.icon; - prodEle.tooltip = buildText(template, g_TooltipFunctions); + prodEle.tooltip = compileTooltip(template); prodEle.hidden = false; + setViewerOnPress(prodEle.name, template.name.internal); return true; } +function compileTooltip(template) +{ + return buildText(template, g_StructreeTooltipFunctions) + "\n" + showTemplateViewerOnClickTooltip(); +} + /** * Calculate row position offset (accounting for different number of prod rows per phase). * Index: binaries/data/mods/public/gui/reference/structree/rows.xml =================================================================== --- binaries/data/mods/public/gui/reference/structree/rows.xml +++ binaries/data/mods/public/gui/reference/structree/rows.xml @@ -6,14 +6,14 @@ - - + Index: binaries/data/mods/public/gui/reference/structree/structree.xml =================================================================== --- binaries/data/mods/public/gui/reference/structree/structree.xml +++ binaries/data/mods/public/gui/reference/structree/structree.xml @@ -96,12 +96,12 @@ - - + Index: binaries/data/mods/public/gui/reference/viewer/sprites.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/reference/viewer/sprites.xml @@ -0,0 +1,18 @@ + + + + + + + + Index: binaries/data/mods/public/gui/reference/viewer/styles.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/reference/viewer/styles.xml @@ -0,0 +1,14 @@ + + + +