Index: binaries/data/mods/public/globalscripts/DamageTypes.js =================================================================== --- /dev/null +++ binaries/data/mods/public/globalscripts/DamageTypes.js @@ -0,0 +1,61 @@ +/** + * This class provides a cache for accessing damage types metadata stored in JSON files. + * Note that damage types need not be defined in JSON files to be handled in-game. + * This class must be initialised before using, as initialising it directly in globalscripts would + * introduce disk I/O every time e.g. a GUI page is loaded. + */ +class DamageTypesMetadata +{ + constructor() + { + this.damageTypeData = {}; + this.tooltipDamageTypes = []; + + for (let filename of Engine.ListDirectoryFiles("simulation/data/template_helpers/damage_types", "*.json", false)) + { + let data = Engine.ReadJSONFile(filename); + if (!data) + continue; + + if (data.code in this.damageTypeData) + { + error("Encountered two damage types with the code " + data.name); + continue; + } + + this.damageTypeData[data.code] = data; + + if (data.showInTooltips) + this.tooltipDamageTypes.push(data.code); + } + + this._sort = (a, b) => this.damageTypeData[a].order - this.damageTypeData[b].order; + this.tooltipDamageTypes.sort(this._sort); + } + + /** + * @returns a copy in sorted order. + */ + sort(damageTypes) + { + let sorted = damageTypes.slice(); + sorted.sort(this._sort); + return sorted; + } + + /** + * @returns the list of damage types to show in tooltips, ordered. + */ + getTooltipDamageTypes() + { + return this.tooltipDamageTypes; + } + + /** + * @returns the name of the @param code damage type, or @code if no metadata exists in JSON files. + */ + getName(code) + { + return this.damageTypeData[code] ? this.damageTypeData[code].name : code; + } +} Index: binaries/data/mods/public/globalscripts/StatusEffects.js =================================================================== --- /dev/null +++ binaries/data/mods/public/globalscripts/StatusEffects.js @@ -0,0 +1,59 @@ +/** + * This class provides a cache for accessing status effects metadata stored in JSON files. + * Note that status effects need not be defined in JSON files to be handled in-game. + * This class must be initialised before using, as initialising it directly in globalscripts would + * introduce disk I/O every time e.g. a GUI page is loaded. + */ +class StatusEffectsMetadata +{ + constructor() + { + this.statusEffectData = {}; + + for (let filename of Engine.ListDirectoryFiles("simulation/data/template_helpers/status_effects", "*.json", false)) + { + let data = Engine.ReadJSONFile(filename); + if (!data) + continue; + + if (data.code in this.statusEffectData) + { + error("Encountered two status effects with the code " + data.code); + continue; + } + + this.statusEffectData[data.code] = data; + } + + this._sort = (a, b) => this.damageTypeData[a].order - this.damageTypeData[b].order; + } + + /** + * @returns a copy in sorted order. + */ + sort(damageTypes) + { + let sorted = damageTypes.slice(); + sorted.sort(this._sort); + return sorted; + } + + /** + * @returns the default data for @param code status effects, augmented with the given template data, + * or simply @param templateData if the code is not found in JSON files. + */ + augment(code, templateData) + { + if (!this.statusEffectData[code]) + return templateData; + else if (!templateData && this.statusEffectData[code]) + return this.statusEffectData[code]; + else if (!this.statusEffectData[code] && !templateData) + { + error("Unknown status effect code " + code + " and no template data given."); + return {}; + } + + return Object.assign(this.statusEffectData[code], templateData); + } +} 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 @@ -13,6 +13,9 @@ return g_ResourceData.GetCodes().concat(["population", "populationBonus", "time"]); } +var g_DamageTypesMetadata = new DamageTypesMetadata(); +var g_StatusEffectsMetadata = new StatusEffectsMetadata(); + /** * If true, always shows whether the splash damage deals friendly fire. * Otherwise display the friendly fire tooltip only if it does. @@ -257,10 +260,10 @@ if (!damageTemplate) return ""; - return Object.keys(damageTemplate).filter(dmgType => damageTemplate[dmgType]).map( + return g_DamageTypesMetadata.getTooltipDamageTypes().filter(dmgType => !!damageTemplate[dmgType]).map( dmgType => sprintf(translate("%(damage)s %(damageType)s"), { "damage": (+damageTemplate[dmgType]).toFixed(1), - "damageType": unitFont(translateWithContext("damage type", dmgType)) + "damageType": unitFont(translateWithContext("damage type", g_DamageTypesMetadata.getName(dmgType))) })).join(commaFont(translate(", "))); } @@ -281,7 +284,8 @@ return ""; return sprintf(translate("gives %(name)s"), { - "name": Object.keys(giveStatusTemplate).map(x => unitFont(translateWithContext("status effect", x))).join(', '), + "name": Object.keys(giveStatusTemplate).map(x => + unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.augment(x, giveStatusTemplate[x]).Name))).join(', '), }); } @@ -371,8 +375,10 @@ return tooltips.join("\n"); } -function getStatusEffectsTooltip(name, template) +function getStatusEffectsTooltip(code, template) { + template = g_StatusEffectsMetadata.augment(code, template); + let durationString = ""; if (template.Duration) durationString = sprintf(translate(", %(durName)s: %(duration)s"), { @@ -395,7 +401,7 @@ attackEffectsString = attackEffectsDetails(template); return sprintf(translate("%(statusName)s: %(tooltip)s%(effects)s%(rate)s%(durationString)s"), { - "statusName": headerFont(translateWithContext("status effect", name)), + "statusName": headerFont(translateWithContext("status effect", template.Name)), "tooltip": tooltipString, "effects": attackEffectsString, "rate": intervalString, @@ -523,6 +529,9 @@ */ function getEntityCostComponentsTooltipString(template, entity, buildingsCountToTrainFullBatch = 1, fullBatchSize = 1, remainderBatch = 0) { + if (!template.cost) + return; + let totalCosts = multiplyEntityCosts(template, buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch); if (template.cost.time) totalCosts.time = Math.ceil(template.cost.time * (entity ? Engine.GuiInterfaceCall("GetBatchTime", { Index: binaries/data/mods/public/l10n/messages.json =================================================================== --- binaries/data/mods/public/l10n/messages.json +++ binaries/data/mods/public/l10n/messages.json @@ -623,6 +623,30 @@ ] } }, + { + "extractor": "json", + "filemasks": [ + "simulation/data/template_helpers/damage_types/*.json" + ], + "options": { + "keywords": [ + "name", + "description" + ] + } + }, + { + "extractor": "json", + "filemasks": [ + "simulation/data/template_helpers/status_effects/*.json" + ], + "options": { + "keywords": [ + "Name", + "Tooltip" + ] + } + }, { "extractor": "json", "filemasks": [ Index: binaries/data/mods/public/simulation/data/template_helpers/damage_types/crush.json =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/data/template_helpers/damage_types/crush.json @@ -0,0 +1,7 @@ +{ + "code": "Crush", + "name": "Crush", + "description": "Damage dealt from crushing, such as when ramming a gate.", + "order": 3, + "showInTooltips": true +} Index: binaries/data/mods/public/simulation/data/template_helpers/damage_types/hack.json =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/data/template_helpers/damage_types/hack.json @@ -0,0 +1,7 @@ +{ + "code": "Hack", + "name": "Hack", + "description": "Damage dealt from hacking, such as when fighting with swords.", + "order": 1, + "showInTooltips": true +} Index: binaries/data/mods/public/simulation/data/template_helpers/damage_types/pierce.json =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/data/template_helpers/damage_types/pierce.json @@ -0,0 +1,7 @@ +{ + "code": "Pierce", + "name": "Pierce", + "description": "Damage dealt from piercing, such as when being hit with an arrow.", + "order": 2, + "showInTooltips": true +} Index: binaries/data/mods/public/simulation/data/template_helpers/status_effects/AnotherBogus.json =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/data/template_helpers/status_effects/AnotherBogus.json @@ -0,0 +1,4 @@ +{ + "code": "AnotherBogus", + "Name": "AnotherBogus" +} Index: binaries/data/mods/public/simulation/helpers/Attacking.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Attacking.js +++ binaries/data/mods/public/simulation/helpers/Attacking.js @@ -25,6 +25,9 @@ "" + "" + "" + + "" + + "" + + "" + "" + "" + "" + Index: binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_archer.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_archer.xml +++ binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_archer.xml @@ -13,6 +13,7 @@ + Bogus Some bogus bonus tooltip describing the effect of the modifiers. This speeds up the entity but halves the health and resource gathering speed. 15000 @@ -29,6 +30,7 @@ + Bogus-Test2 10000 1000 @@ -73,6 +75,11 @@ 5 + + + units/athen_ship_fishing + + 1.1