Index: ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateLister.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateLister.js +++ ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateLister.js @@ -36,17 +36,27 @@ for (let templateBeingParsed of templatesThisIteration) { + let baseOfTemplateBeingParsed = this.TemplateLoader.getVariantBaseAndType(templateBeingParsed, civCode)[0]; let list = this.deriveTemplateListsFromTemplate(templateBeingParsed, civCode); for (let type in list) for (let templateName of list[type]) + { + if (type != "techs") + { + let templateVariance = this.TemplateLoader.getVariantBaseAndType(templateName, civCode); + if (templateVariance[1].passthru) + templateName = templateVariance[0]; + } + if (!templateLists[type].has(templateName)) { - templateLists[type].set(templateName, [templateBeingParsed]); + templateLists[type].set(templateName, [baseOfTemplateBeingParsed]); if (type != "techs") templatesToParse.push(templateName); } - else if (templateLists[type].get(templateName).indexOf(templateBeingParsed) == -1) - templateLists[type].get(templateName).push(templateBeingParsed); + else if (templateLists[type].get(templateName).indexOf(baseOfTemplateBeingParsed) == -1) + templateLists[type].get(templateName).push(baseOfTemplateBeingParsed); + } } } while (templatesToParse.length); @@ -111,11 +121,6 @@ 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 (this.TemplateLoader.getBaseTemplateName(templateName, civCode) != templateName) - return {}; - let template = this.TemplateLoader.loadEntityTemplate(templateName, civCode); let templateLists = this.TemplateLoader.deriveProductionQueue(template, civCode); Index: ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateLoader.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateLoader.js +++ ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateLoader.js @@ -121,7 +121,7 @@ { templateName = templateName.replace(/\{(civ|native)\}/g, civCode); if (Engine.TemplateExists(templateName)) - production.units.push(this.getBaseTemplateName(templateName, civCode)); + production.units.push(templateName); } let appendTechnology = (technologyName) => { @@ -225,10 +225,22 @@ } /** - * 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. + * A template may be a variant of another template, + * eg. `*_house`, `*_trireme`, or a promotion. + * + * This method returns an array containing: + * [0] - The template's basename + * [1] - The variant type + * [2] - Further information (if available) + * + * e.g.: + * units/athen/infantry_swordsman_e + * -> ["units/athen/infantry_swordsman_b", TemplateVariant.promotion, "elite"] + * + * units/brit/support_female_citizen_house + * -> ["units/brit/support_female_citizen", TemplateVariant.unlockedByTechnology, "unlock_female_house"] */ - getBaseTemplateName(templateName, civCode) + getVariantBaseAndType(templateName, civCode) { if (!templateName || !Engine.TemplateExists(templateName)) return undefined; @@ -237,29 +249,35 @@ let template = this.loadEntityTemplate(templateName, civCode); if (!dirname(templateName) || dirname(template["@parent"]) != dirname(templateName)) - return templateName; + return [templateName, TemplateVariant.base]; let parentTemplate = this.loadEntityTemplate(template["@parent"], civCode); + let inheritedVariance = this.getVariantBaseAndType(template["@parent"], civCode); - if (parentTemplate.Identity && ( - parentTemplate.Identity.Civ && parentTemplate.Identity.Civ != template.Identity.Civ || - parentTemplate.Identity.Rank && parentTemplate.Identity.Rank != template.Identity.Rank - )) - return templateName; + if (parentTemplate.Identity) + { + if (parentTemplate.Identity.Civ && parentTemplate.Identity.Civ != template.Identity.Civ) + return [templateName, TemplateVariant.base]; - if (!parentTemplate.Cost) - return templateName; + if (parentTemplate.Identity.Rank && parentTemplate.Identity.Rank != template.Identity.Rank) + return [inheritedVariance[0], TemplateVariant.promotion, template.Identity.Rank.toLowerCase()]; + } if (parentTemplate.Upgrade) for (let upgrade in parentTemplate.Upgrade) if (parentTemplate.Upgrade[upgrade].Entity) - return templateName; + return [inheritedVariance[0], TemplateVariant.upgrade, upgrade.toLowerCase()]; + + if (template.Identity.RequiredTechnology) + return [inheritedVariance[0], TemplateVariant.unlockedByTechnology, template.Identity.RequiredTechnology]; - for (let res in parentTemplate.Cost.Resources) - if (+parentTemplate.Cost.Resources[res]) - return this.getBaseTemplateName(template["@parent"], civCode); + if (parentTemplate.Cost) + for (let res in parentTemplate.Cost.Resources) + if (+parentTemplate.Cost.Resources[res]) + return [inheritedVariance[0], TemplateVariant.trainable]; - return templateName; + warn("Template variance unknown: " + templateName); + return [templateName, TemplateVariant.unknown]; } isPairTech(technologyCode) Index: ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateVariant.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateVariant.js +++ ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateVariant.js @@ -0,0 +1,37 @@ +/** + * Enum-type class that defines various template variant types. + */ +class TemplateVariant +{ + /** + * @param passthru Signifies if we should pass though to the base template when generating build lists. + */ + constructor(name, passthru=true) + { + this.name = name; + this.passthru = passthru; + + TemplateVariant[name] = this; + } + + static registerType(name, passthru=true) + { + TemplateVariant[name] = new TemplateVariant(name, passthru); + } + + toString() + { + return this.constructor.name + "." + this.name; + } +} + +/** + * Registered Template Variants. + * New variants add themselves as static properties to the main class. + */ +TemplateVariant.registerType("base"); +TemplateVariant.registerType("unknown"); +TemplateVariant.registerType("upgrade", false); +TemplateVariant.registerType("promotion", false); +TemplateVariant.registerType("unlockedByTechnology"); +TemplateVariant.registerType("trainable"); Index: ps/trunk/binaries/data/mods/public/gui/reference/viewer/ViewerPage.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/viewer/ViewerPage.js +++ ps/trunk/binaries/data/mods/public/gui/reference/viewer/ViewerPage.js @@ -35,13 +35,7 @@ // Attempt to get the civ code from the template, or, if // it's a technology, from the researcher's template. if (!isTech) - { - // Catch and redirect if template is a non-promotion variant of - // another (ie. units/{civ}_support_female_citizen_house). - templateName = this.TemplateLoader.getBaseTemplateName(templateName, this.TemplateLoader.DefaultCiv); - this.setActiveCiv(this.TemplateLoader.loadEntityTemplate(templateName, this.TemplateLoader.DefaultCiv).Identity.Civ); - } if (this.activeCiv == this.TemplateLoader.DefaultCiv && data.civ) this.setActiveCiv(data.civ); @@ -59,17 +53,28 @@ // We do that here, so we don't do it later in the tooltip callback functions, as that would be messier. if (this.activeCiv != this.TemplateLoader.DefaultCiv) { + let currentTemplateName = this.currentTemplate.name.internal; + if (!isTech) + { + // If template is a non-promotion, non-upgrade variant of another (e.g. + // units/{civ}/support_female_citizen_house), we wish to use the name of the base template, + // not that of the variant template, when interacting with the compiled Template Lists. + let templateVariance = this.TemplateLoader.getVariantBaseAndType(this.currentTemplate.name.internal, this.TemplateLoader.DefaultCiv); + if (templateVariance[1].passthru) + currentTemplateName = templateVariance[0]; + } + let templateLists = this.TemplateLister.getTemplateLists(this.activeCiv); - let builders = templateLists.structures.get(this.currentTemplate.name.internal); + let builders = templateLists.structures.get(currentTemplateName); if (builders && builders.length) this.currentTemplate.builtByListOfNames = builders.map(builder => getEntityNames(this.TemplateParser.getEntity(builder, this.activeCiv))); - let trainers = templateLists.units.get(this.currentTemplate.name.internal); + let trainers = templateLists.units.get(currentTemplateName); if (trainers && trainers.length) this.currentTemplate.trainedByListOfNames = trainers.map(trainer => getEntityNames(this.TemplateParser.getEntity(trainer, this.activeCiv))); - let researchers = templateLists.techs.get(this.currentTemplate.name.internal); + let researchers = templateLists.techs.get(currentTemplateName); if (researchers && researchers.length) this.currentTemplate.researchedByListOfNames = researchers.map(researcher => getEntityNames(this.TemplateParser.getEntity(researcher, this.activeCiv))); }