Index: binaries/data/mods/public/globalscripts/Technologies.js =================================================================== --- binaries/data/mods/public/globalscripts/Technologies.js +++ binaries/data/mods/public/globalscripts/Technologies.js @@ -44,6 +44,47 @@ } /** + * Derives modifications (to be applied to entities) from a given technology. + * + * @param {Object} techTemplate - The technology template to derive the modifications from. + * @return {Object} containing the relevant modifications. + */ +function DeriveModificationsFromTech(techTemplate) +{ + if (!techTemplate.modifications) + return {}; + + let techMods = {}; + let techAffects = []; + if (techTemplate.affects && techTemplate.affects.length) + for (let affected of techTemplate.affects) + techAffects.push(affected.split(/\s+/)); + else + techAffects.push([]); + + for (let mod of techTemplate.modifications) + { + let affects = techAffects.slice(); + if (mod.affects) + { + let specAffects = mod.affects.split(/\s+/); + for (let a in affects) + affects[a] = affects[a].concat(specAffects); + } + + let newModifier = { "affects": affects }; + for (let idx in mod) + if (idx !== "value" && idx !== "affects") + newModifier[idx] = mod[idx]; + + if (!techMods[mod.value]) + techMods[mod.value] = []; + techMods[mod.value].push(newModifier); + } + return techMods; +} + +/** * Returns whether the given modification applies to the entity containing the given class list */ function DoesModificationApply(modification, classes) Index: binaries/data/mods/public/globalscripts/Templates.js =================================================================== --- binaries/data/mods/public/globalscripts/Templates.js +++ binaries/data/mods/public/globalscripts/Templates.js @@ -80,17 +80,22 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources) { // Return data either from template (in tech tree) or sim state (ingame) - let getEntityValue = function(tech_type) { + // @param value_path - Route to the value within the template + // @param mod_key - Modification key, if not the same as the value_path + let getEntityValue = function(value_path, mod_key = null) { let current_value = template; - for (let property of tech_type.split("/")) + for (let property of value_path.split("/")) current_value = current_value[property] || 0; current_value = +current_value; - if (!player) - return current_value; + if (player) + return ApplyValueModificationsToTemplate(mod_key || value_path, current_value, player, template); - return ApplyValueModificationsToTemplate(tech_type, current_value, player, template); + if (typeof g_CurrentModifiers !== "undefined") + return GetTechModifiedProperty(g_CurrentModifiers, GetIdentityClasses(template.Identity), mod_key || value_path, current_value); + + return current_value; }; let ret = {}; @@ -299,7 +304,7 @@ "generic": template.Identity.GenericName }; ret.icon = template.Identity.Icon; - ret.tooltip = template.Identity.Tooltip; + ret.tooltip = template.Identity.Tooltip; ret.requiredTechnology = template.Identity.RequiredTechnology; ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity); } @@ -345,26 +350,33 @@ } /** + * Get basic information about a technology template. + * @param {object} template - A valid template as obtained by loading the tech JSON file. + * @param {string} civ - Civilization for which the specific name should be returned. + */ +function GetTechnologyBasicDataHelper(template, civ) +{ + return { + "name": { + "generic": template.genericName + }, + "icon": template.icon ? "technologies/" + template.icon : undefined, + "description": template.description, + "reqs": DeriveTechnologyRequirements(template, civ) + }; +} + +/** * Get information about a technology template. - * @param template A valid template as obtained by loading the tech JSON file. - * @param civ Civilization for which the specific name should be returned. - * @param resources An instance of the Resources prototype. + * @param {object} template - A valid template as obtained by loading the tech JSON file. + * @param {string} civ - Civilization for which the specific name should be returned. */ function GetTechnologyDataHelper(template, civ, resources) { - let ret = {}; + let ret = GetTechnologyBasicDataHelper(template, civ); - // Get specific name for this civ or else the generic specific name - let specific; if (template.specificName) - specific = template.specificName[civ] || template.specificName.generic; - - ret.name = { - "specific": specific, - "generic": template.genericName, - }; - - ret.icon = template.icon ? "technologies/" + template.icon : null; + ret.name.specific = template.specificName[civ] || template.specificName.generic; ret.cost = { "time": template.researchTime ? +template.researchTime : 0 }; for (let type of resources.GetCodes()) @@ -373,10 +385,6 @@ ret.tooltip = template.tooltip; ret.requirementsTooltip = template.requirementsTooltip || ""; - ret.reqs = DeriveTechnologyRequirements(template, civ); - - ret.description = template.description; - return ret; } Index: binaries/data/mods/public/gui/structree/helper.js =================================================================== --- binaries/data/mods/public/gui/structree/helper.js +++ binaries/data/mods/public/gui/structree/helper.js @@ -1,7 +1,13 @@ +const g_TechnologyPath = "simulation/data/technologies/"; +const g_AuraPath = "simulation/data/auras/"; + var g_TemplateData = {}; var g_TechnologyData = {}; var g_AuraData = {}; +// Must be defined after g_TechnologyData object is declared +const g_AutoResearchTechList = findAllAutoResearchedTechs(); + function loadTemplate(templateName) { if (!(templateName in g_TemplateData)) @@ -24,9 +30,9 @@ { if (!(templateName in g_TechnologyData)) { - var filename = "simulation/data/technologies/" + templateName + ".json"; - var data = Engine.ReadJSONFile(filename); - translateObjectKeys(data, ["genericName", "tooltip"]); + let filename = g_TechnologyPath + templateName + ".json"; + let data = Engine.ReadJSONFile(filename); + translateObjectKeys(data, ["genericName", "tooltip", "description"]); g_TechnologyData[templateName] = data; } @@ -38,7 +44,7 @@ { if (!(templateName in g_AuraData)) { - let filename = "simulation/data/auras/" + templateName + ".json"; + let filename = g_AuraPath + templateName + ".json"; let data = Engine.ReadJSONFile(filename); translateObjectKeys(data, ["auraName", "auraDescription"]); @@ -48,6 +54,50 @@ return g_AuraData[templateName]; } +function findAllAutoResearchedTechs() +{ + let techFiles = Engine.BuildDirEntList(g_TechnologyPath, "*.json", true); + let techList = []; + + for (let filename of techFiles) + { + // -5 to strip off the file extension + let templateName = filename.slice(g_TechnologyPath.length, -5); + let data = loadTechData(templateName); + + if (!data || !data.autoResearch) + continue; + + techList.push(templateName); + } + + return techList; +} + +function deriveAutoresearchedModifications() +{ + g_CurrentModifiers = {}; + for (let templateName of g_AutoResearchTechList) + { + let data = loadTechData(templateName); + let modifier = GetTechnologyBasicDataHelper(data, g_SelectedCiv); + + if (!modifier.reqs) + continue; + + modifier.modifications = data.modifications; + modifier.affects = data.affects; + + let derivedModifiers = DeriveModificationsFromTech(modifier); + for (let modPath in derivedModifiers) + { + if (!g_CurrentModifiers[modPath]) + g_CurrentModifiers[modPath] = []; + g_CurrentModifiers[modPath] = g_CurrentModifiers[modPath].concat(derivedModifiers[modPath]); + } + } +} + /** * This is needed because getEntityCostTooltip in tooltip.js needs to get * the template data of the different wallSet pieces. In the session this Index: binaries/data/mods/public/gui/structree/structree.js =================================================================== --- binaries/data/mods/public/gui/structree/structree.js +++ binaries/data/mods/public/gui/structree/structree.js @@ -8,6 +8,7 @@ var g_Lists = {}; var g_CivData = {}; var g_SelectedCiv = ""; +var g_CurrentModifiers = {}; var g_CallbackSet = false; var g_ResourceData = new Resources(); @@ -49,6 +50,8 @@ g_SelectedCiv = civCode; + deriveAutoresearchedModifications(); + // If a buildList already exists, then this civ has already been parsed if (g_CivData[g_SelectedCiv].buildList) { Index: binaries/data/mods/public/simulation/components/TechnologyManager.js =================================================================== --- binaries/data/mods/public/simulation/components/TechnologyManager.js +++ binaries/data/mods/public/simulation/components/TechnologyManager.js @@ -270,48 +270,18 @@ // store the modifications in an easy to access structure if (template.modifications) { - var affects = []; - if (template.affects && template.affects.length > 0) + let derivedModifiers = DeriveModificationsFromTech(template); + for (let modifierPath in derivedModifiers) { - for (let affect of template.affects) - { - // Put the list of classes into an array for convenient access - affects.push(affect.split(/\s+/)); - } - } - else - { - affects.push([]); - } - - // We add an item to this.modifications for every modification in the template.modifications array - for (var i in template.modifications) - { - var modification = template.modifications[i]; - if (!this.modifications[modification.value]) - this.modifications[modification.value] = []; - - var modAffects = affects.slice(); - if (modification.affects) - { - var extraAffects = modification.affects.split(/\s+/); - for (var a in modAffects) - modAffects[a] = modAffects[a].concat(extraAffects); - } - - var mod = {"affects": modAffects}; - - // copy the modification data into our new data structure - for (var j in modification) - if (j !== "value" && j !== "affects") - mod[j] = modification[j]; + if (!this.modifications[modifierPath]) + this.modifications[modifierPath] = []; + this.modifications[modifierPath] = this.modifications[modifierPath].concat(derivedModifiers[modifierPath]); - this.modifications[modification.value].push(mod); - var component = modification.value.split("/")[0]; + let component = modifierPath.split("/")[0]; if (!modifiedComponents[component]) modifiedComponents[component] = []; - modifiedComponents[component].push(modification.value); - this.modificationCache[modification.value] = {}; + modifiedComponents[component].push(modifierPath); + this.modificationCache[modifierPath] = {}; } }