Adapt the civinfo page to read from templates
Instead of loading information about heroes, special buildings, et al., from the `{civ}.json` files, load the information desired from templates. Determination of "specialness" works as follows: * Heroes are detected via the `Hero` class. * Special Structures are detected via the `SpecialBuilding` or `Wonder` class. * Technologies are determined to be "special" when they can be researched by the currently selected civ, but are not open to be researched by every civ. * Team Bonuses are any applicable aura that reside in the appropriate folder. Accepted by: Freagarach Comments by: Stan Differential Revision: https://code.wildfiregames.com/D759 This was SVN commit r24492.
This commit is contained in:
parent
3ec8a91f30
commit
190d6e7cf5
@ -40,7 +40,7 @@ class CivInfoPage extends ReferencePage
|
||||
error(sprintf("Error loading civ data for \"%(code)s\"", { "code": civCode }));
|
||||
|
||||
// Update civ gameplay display
|
||||
this.gameplaySection.update(civInfo);
|
||||
this.gameplaySection.update(this.activeCiv, civInfo);
|
||||
|
||||
// Update civ history display
|
||||
this.historySection.update(civInfo);
|
||||
@ -81,24 +81,18 @@ class CivInfoPage extends ReferencePage
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a styled concatenation of the Name, History, and Description of the given object.
|
||||
*
|
||||
* @param obj {Object}
|
||||
* @returns {string}
|
||||
*/
|
||||
formatEntry(obj)
|
||||
formatEntry(name, tooltip, description)
|
||||
{
|
||||
if (!obj.Name)
|
||||
return "";
|
||||
let tooltip_icon = "";
|
||||
if (tooltip)
|
||||
tooltip_icon = '[icon="iconInfo" tooltip="' + escapeQuotation(tooltip) + '" tooltip_style="civInfoTooltip"]';
|
||||
|
||||
let history_icon = "";
|
||||
if (obj.History)
|
||||
history_icon = '[icon="iconInfo" tooltip="' + escapeQuotation(obj.History) + '" tooltip_style="civInfoTooltip"]';
|
||||
|
||||
let description = "";
|
||||
if (obj.Description)
|
||||
let description_text = "";
|
||||
if (description)
|
||||
// Translation: Description of an item in the CivInfo page, on a new line and indented.
|
||||
description = sprintf(translate('\n %(description)s'), { "description": obj.Description, });
|
||||
description_text = sprintf(translate('\n %(description)s'), { "description": description, });
|
||||
|
||||
return sprintf(
|
||||
// Translation: An entry in the CivInfo Page. The newline and indentation of the description is handled elsewhere.
|
||||
@ -107,9 +101,9 @@ class CivInfoPage extends ReferencePage
|
||||
// > A brief description of the aforementioned something.
|
||||
translate("• %(name)s %(info_icon)s%(description)s"),
|
||||
{
|
||||
"name": setStringTags(obj.Name, { "font": "sans-bold-14" }),
|
||||
"info_icon": history_icon,
|
||||
"description": description,
|
||||
"name": setStringTags(name, { "font": "sans-bold-14" }),
|
||||
"info_icon": tooltip_icon,
|
||||
"description": description_text,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ class GameplaySection
|
||||
this.TechnologiesSubsection = new TechnologiesSubsection(this.page);
|
||||
}
|
||||
|
||||
update(civInfo)
|
||||
update(civCode, civInfo)
|
||||
{
|
||||
this.CivGameplayHeading.caption =
|
||||
this.page.formatHeading(
|
||||
@ -19,10 +19,10 @@ class GameplaySection
|
||||
this.page.SectionHeaderSize
|
||||
);
|
||||
|
||||
this.BonusesSubsection.update(civInfo);
|
||||
this.TechnologiesSubsection.update(civInfo);
|
||||
this.StructuresSubsection.update(civInfo);
|
||||
this.HeroesSubsection.update(civInfo);
|
||||
this.BonusesSubsection.update(civCode, civInfo);
|
||||
this.TechnologiesSubsection.update(civCode);
|
||||
this.StructuresSubsection.update(civCode);
|
||||
this.HeroesSubsection.update(civCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,4 +4,67 @@ class Subsection
|
||||
{
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
getAuraCaptions(auraList, civCode)
|
||||
{
|
||||
let captions = [];
|
||||
for (let auraCode of auraList)
|
||||
{
|
||||
let aura = this.page.TemplateParser.getAura(auraCode);
|
||||
if (!aura.civ || aura.civ != civCode)
|
||||
continue;
|
||||
|
||||
captions.push(this.page.formatEntry(
|
||||
getEntityNames(aura),
|
||||
false,
|
||||
getDescriptionTooltip(aura)
|
||||
));
|
||||
}
|
||||
return captions;
|
||||
}
|
||||
|
||||
getEntityCaptions(entityList, classList, civCode)
|
||||
{
|
||||
let captions = [];
|
||||
for (let entityCode of entityList)
|
||||
{
|
||||
// Acquire raw template as we need to compare all classes an entity has, not just the visible ones.
|
||||
let template = this.page.TemplateLoader.loadEntityTemplate(entityCode, civCode);
|
||||
let classListFull = GetIdentityClasses(template.Identity);
|
||||
if (!MatchesClassList(classListFull, classList))
|
||||
continue;
|
||||
|
||||
let entity = this.page.TemplateParser.getEntity(entityCode, civCode);
|
||||
captions.push(this.page.formatEntry(
|
||||
getEntityNames(entity),
|
||||
getDescriptionTooltip(entity),
|
||||
getEntityTooltip(entity)
|
||||
));
|
||||
}
|
||||
return captions;
|
||||
}
|
||||
|
||||
getTechnologyCaptions(technologyList, civCode)
|
||||
{
|
||||
let captions = [];
|
||||
for (let techCode of technologyList)
|
||||
{
|
||||
let technology = this.page.TemplateParser.getTechnology(techCode, civCode);
|
||||
|
||||
// We deliberately pass an invalid civ code here.
|
||||
// If it returns with a value other than false, then
|
||||
// we know that this tech can be researched by any civ
|
||||
let genericReqs = this.page.TemplateParser.getTechnology(techCode, "anyciv").reqs;
|
||||
|
||||
if (!technology.reqs || genericReqs)
|
||||
continue;
|
||||
|
||||
captions.push(this.page.formatEntry(
|
||||
getEntityNames(technology),
|
||||
getDescriptionTooltip(technology),
|
||||
getEntityTooltip(technology)
|
||||
));
|
||||
}
|
||||
return captions;
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,21 @@ class BonusesSubsection extends Subsection
|
||||
this.CivBonuses = Engine.GetGUIObjectByName("civBonuses");
|
||||
}
|
||||
|
||||
update(civInfo)
|
||||
update(civCode, civInfo)
|
||||
{
|
||||
let civBonuses = civInfo.CivBonuses.map(bonus => this.page.formatEntry(bonus));
|
||||
// Not all civ bonuses can be represented by a single auto-researched technology (e.g.
|
||||
// Athenian "Silver Owls", Roman "Testudo Formation"). Thus we also display descriptions
|
||||
// of civ bonuses as written in the {civ}.json files.
|
||||
let civBonuses = this.getTechnologyCaptions(
|
||||
this.page.TemplateLoader.autoResearchTechList,
|
||||
civCode
|
||||
);
|
||||
for (let bonus of civInfo.CivBonuses)
|
||||
civBonuses.push(this.page.formatEntry(
|
||||
bonus.Name,
|
||||
bonus.History || false,
|
||||
bonus.Description || false
|
||||
));
|
||||
civBonuses.unshift(
|
||||
this.page.formatHeading(
|
||||
this.HeadingCivBonusCaption(civBonuses.length),
|
||||
@ -16,7 +28,10 @@ class BonusesSubsection extends Subsection
|
||||
)
|
||||
);
|
||||
|
||||
let teamBonuses = civInfo.TeamBonuses.map(bonus => this.page.formatEntry(bonus));
|
||||
let teamBonuses = this.getAuraCaptions(
|
||||
this.page.TemplateLoader.teamBonusAuraList,
|
||||
civCode
|
||||
);
|
||||
teamBonuses.unshift(
|
||||
this.page.formatHeading(
|
||||
this.HeadingTeamBonusCaption(teamBonuses.length),
|
||||
|
@ -6,14 +6,13 @@ class HeroesSubsection extends Subsection
|
||||
this.CivHeroes = Engine.GetGUIObjectByName("civHeroes");
|
||||
}
|
||||
|
||||
update(civInfo)
|
||||
update(civCode)
|
||||
{
|
||||
let heroes = [];
|
||||
for (let faction of civInfo.Factions)
|
||||
Array.prototype.push.apply(
|
||||
heroes,
|
||||
faction.Heroes.map(hero => this.page.formatEntry(hero))
|
||||
);
|
||||
let heroes = this.getEntityCaptions(
|
||||
this.page.TemplateLister.getTemplateLists(civCode).units.keys(),
|
||||
this.IdentifyingClassList,
|
||||
civCode
|
||||
);
|
||||
|
||||
heroes.unshift(
|
||||
this.page.formatHeading(
|
||||
@ -28,3 +27,6 @@ class HeroesSubsection extends Subsection
|
||||
|
||||
HeroesSubsection.prototype.HeadingCaption =
|
||||
count => translatePlural("Hero", "Heroes", count);
|
||||
|
||||
HeroesSubsection.prototype.IdentifyingClassList =
|
||||
["Hero"];
|
||||
|
@ -6,9 +6,14 @@ class StructuresSubsection extends Subsection
|
||||
this.CivStructures = Engine.GetGUIObjectByName("civStructures");
|
||||
}
|
||||
|
||||
update(civInfo)
|
||||
update(civCode)
|
||||
{
|
||||
let structures = civInfo.Structures.map(bonus => this.page.formatEntry(bonus));
|
||||
let structures = this.getEntityCaptions(
|
||||
this.page.TemplateLister.getTemplateLists(civCode).structures.keys(),
|
||||
this.IdentifyingClassList,
|
||||
civCode
|
||||
);
|
||||
|
||||
structures.unshift(
|
||||
this.page.formatHeading(
|
||||
this.HeadingCaption(structures.length),
|
||||
@ -22,3 +27,6 @@ class StructuresSubsection extends Subsection
|
||||
|
||||
StructuresSubsection.prototype.HeadingCaption =
|
||||
count => translatePlural("Special Structure", "Special Structures", count);
|
||||
|
||||
StructuresSubsection.prototype.IdentifyingClassList =
|
||||
[["SpecialBuilding"], ["Wonder"]];
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object type="image" sprite="ModernDarkBoxGold" size="33%+5 70%+5 75%-5 100%">
|
||||
<object type="image" sprite="ModernDarkBoxGold" size="33%+5 60%+5 75%-5 100%">
|
||||
<object
|
||||
name="civStructures"
|
||||
type="text"
|
||||
|
@ -6,14 +6,12 @@ class TechnologiesSubsection extends Subsection
|
||||
this.CivTechs = Engine.GetGUIObjectByName("civTechs");
|
||||
}
|
||||
|
||||
update(civInfo)
|
||||
update(civCode)
|
||||
{
|
||||
let techs = [];
|
||||
for (let faction of civInfo.Factions)
|
||||
Array.prototype.push.apply(
|
||||
techs,
|
||||
faction.Technologies.map(tech => this.page.formatEntry(tech))
|
||||
);
|
||||
let techs = this.getTechnologyCaptions(
|
||||
this.page.TemplateLister.getTemplateLists(civCode).techs.keys(),
|
||||
civCode
|
||||
);
|
||||
|
||||
techs.unshift(
|
||||
this.page.formatHeading(
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object type="image" sprite="ModernDarkBoxGold" size="33%+5 45 75%-5 70%-5">
|
||||
<object type="image" sprite="ModernDarkBoxGold" size="33%+5 45 75%-5 60%-5">
|
||||
<object
|
||||
name="civTechs"
|
||||
type="text"
|
||||
|
@ -16,6 +16,7 @@ class TemplateLoader
|
||||
* Partly-composed data.
|
||||
*/
|
||||
this.autoResearchTechList = this.findAllAutoResearchedTechs();
|
||||
this.teamBonusAuraList = this.findAllTeamBonusAuras();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,6 +197,33 @@ class TemplateLoader
|
||||
return techList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through and loads all team bonus auras.
|
||||
*
|
||||
* We make an assumption in this method: that all team bonus auras are
|
||||
* in a single folder.
|
||||
*
|
||||
* Team bonuses must have a "civ" attribute to indicate what civ they
|
||||
* belong to.
|
||||
*
|
||||
* @return {array} List of teambonus auras
|
||||
*/
|
||||
findAllTeamBonusAuras()
|
||||
{
|
||||
let auraList = [];
|
||||
let path = this.AuraPath + TemplateLoader.prototype.AuraTeamBonusSubpath;
|
||||
for (let templateName of listFiles(path, ".json", true))
|
||||
{
|
||||
let filename = TemplateLoader.prototype.AuraTeamBonusSubpath + templateName;
|
||||
let data = this.loadAuraTemplate(filename);
|
||||
if (!data || !data.civ)
|
||||
continue;
|
||||
|
||||
auraList.push(filename);
|
||||
}
|
||||
return auraList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -252,6 +280,7 @@ class TemplateLoader
|
||||
* It might be nice if we could get these from somewhere, instead of having them hardcoded here.
|
||||
*/
|
||||
TemplateLoader.prototype.AuraPath = "simulation/data/auras/";
|
||||
TemplateLoader.prototype.AuraTeamBonusSubpath = "teambonuses/";
|
||||
TemplateLoader.prototype.TechnologyPath = "simulation/data/technologies/";
|
||||
|
||||
TemplateLoader.prototype.DefaultCiv = "gaia";
|
||||
|
@ -10,6 +10,7 @@ class TemplateParser
|
||||
/**
|
||||
* Parsed Data Stores
|
||||
*/
|
||||
this.auras = {};
|
||||
this.entities = {};
|
||||
this.techs = {};
|
||||
this.phases = {};
|
||||
@ -18,6 +19,24 @@ class TemplateParser
|
||||
this.phaseList = [];
|
||||
}
|
||||
|
||||
getAura(auraName)
|
||||
{
|
||||
if (auraName in this.auras)
|
||||
return this.auras[auraName];
|
||||
|
||||
if (!AuraTemplateExists(auraName))
|
||||
return null;
|
||||
|
||||
let template = this.TemplateLoader.loadAuraTemplate(auraName);
|
||||
let parsed = GetAuraDataHelper(template);
|
||||
|
||||
if (template.civ)
|
||||
parsed.civ = template.civ;
|
||||
|
||||
this.auras[auraName] = parsed;
|
||||
return this.auras[auraName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse a structure, unit, resource, etc from its entity template file.
|
||||
*
|
||||
|
@ -26,3 +26,8 @@ function TechnologyTemplateExists(templateName)
|
||||
{
|
||||
return Engine.FileExists(g_Page.TemplateLoader.TechnologyPath + templateName + ".json");
|
||||
}
|
||||
|
||||
function AuraTemplateExists(templateName)
|
||||
{
|
||||
return Engine.FileExists(g_Page.TemplateLoader.AuraPath + templateName + ".json");
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Warship"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "athen",
|
||||
"modifications": [
|
||||
{ "value": "Cost/BuildTime", "multiply": 0.75 }
|
||||
],
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Healer"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "brit",
|
||||
"modifications": [
|
||||
{ "value": "Cost/Resources/food", "multiply": 0.8 },
|
||||
{ "value": "Cost/Resources/wood", "multiply": 0.8 },
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Trade"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "cart",
|
||||
"modifications": [
|
||||
{ "value": "Market/InternationalBonus", "add": 0.1 }
|
||||
],
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Forge"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "gaul",
|
||||
"modifications": [
|
||||
{ "value": "ProductionQueue/TechCostMultiplier/food", "multiply": 0.85 },
|
||||
{ "value": "ProductionQueue/TechCostMultiplier/wood", "multiply": 0.85 },
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Citizen Javelineer"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "iber",
|
||||
"modifications": [
|
||||
{ "value": "Cost/Resources/food", "multiply": 0.9 },
|
||||
{ "value": "Cost/Resources/wood", "multiply": 0.9 },
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Elephant"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "kush",
|
||||
"modifications": [
|
||||
{ "value": "Cost/BuildTime", "multiply": 0.8 },
|
||||
{ "value": "Cost/Resources/food", "multiply": 0.8 },
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "player",
|
||||
"affects": ["Player"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "mace",
|
||||
"modifications": [
|
||||
{ "value": "Player/BarterMultiplier/Sell/food", "multiply": 1.2 },
|
||||
{ "value": "Player/BarterMultiplier/Sell/wood", "multiply": 1.2 },
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Temple"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "maur",
|
||||
"modifications": [
|
||||
{ "value": "Cost/BuildTime", "multiply": 0.5 },
|
||||
{ "value": "Cost/Resources/wood", "multiply": 0.5 },
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Trader !Ship"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "pers",
|
||||
"modifications": [
|
||||
{ "value": "Trader/GainMultiplier", "multiply": 1.15 }
|
||||
],
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "player",
|
||||
"affects": ["Player"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "ptol",
|
||||
"modifications": [
|
||||
{ "value": "ResourceTrickle/Rates/food", "add": 1 }
|
||||
],
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Citizen Infantry"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "rome",
|
||||
"modifications": [
|
||||
{ "value": "Cost/BuildTime", "multiply": 0.9 }
|
||||
],
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["CivilCentre"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "sele",
|
||||
"modifications": [
|
||||
{ "value": "Cost/Resources/food", "multiply": 0.8 },
|
||||
{ "value": "Cost/Resources/wood", "multiply": 0.8 },
|
||||
|
@ -2,6 +2,7 @@
|
||||
"type": "global",
|
||||
"affects": ["Citizen Infantry Spearman"],
|
||||
"affectedPlayers": ["ExclusiveMutualAlly"],
|
||||
"civ": "spart",
|
||||
"modifications": [
|
||||
{ "value": "Health/Max", "multiply": 1.1 }
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user