1
0
forked from 0ad/0ad

Show correct cost/phase of template-variants in structree whilst maintaining correct build lists in viewer

("Variant" in this case means a template that is functionally the same
as its
base template - but is a different promotion level, requires a
technology to
unlock (that the base template doesn't), is an upgrade of its base, or
is a
trainable version.)

Should fix concern raised on b2842e8021.

Accepted by: Angen
Differential Revision: https://code.wildfiregames.com/D3347
This was SVN commit r25260.
This commit is contained in:
s0600204 2021-04-14 20:05:26 +00:00
parent 63224865d5
commit f57ac432e8
4 changed files with 99 additions and 34 deletions

View File

@ -36,17 +36,27 @@ class TemplateLister
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 @@ class TemplateLister
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);

View File

@ -121,7 +121,7 @@ class TemplateLoader
{
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 @@ class TemplateLoader
}
/**
* 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 @@ class TemplateLoader
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()];
for (let res in parentTemplate.Cost.Resources)
if (+parentTemplate.Cost.Resources[res])
return this.getBaseTemplateName(template["@parent"], civCode);
if (template.Identity.RequiredTechnology)
return [inheritedVariance[0], TemplateVariant.unlockedByTechnology, template.Identity.RequiredTechnology];
return templateName;
if (parentTemplate.Cost)
for (let res in parentTemplate.Cost.Resources)
if (+parentTemplate.Cost.Resources[res])
return [inheritedVariance[0], TemplateVariant.trainable];
warn("Template variance unknown: " + templateName);
return [templateName, TemplateVariant.unknown];
}
isPairTech(technologyCode)

View File

@ -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");

View File

@ -35,13 +35,7 @@ class ViewerPage extends ReferencePage
// 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 @@ class ViewerPage extends ReferencePage
// 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)));
}