Index: ps/trunk/binaries/data/mods/public/gui/reference/common/load.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/common/load.js (revision 21173) +++ ps/trunk/binaries/data/mods/public/gui/reference/common/load.js (revision 21174) @@ -1,286 +1,271 @@ /** * Paths to certain files. */ const g_TechnologyPath = "simulation/data/technologies/"; const g_AuraPath = "simulation/data/auras/"; /** * Raw Data Caches. */ var g_AuraData = {}; var g_TemplateData = {}; var g_TechnologyData = {}; var g_CivData = loadCivData(true, false); /** * Parsed Data Stores. */ var g_ParsedData = {}; var g_ResourceData = new Resources(); var g_DamageTypes = new DamageTypes(); // This must be defined after the g_TechnologyData cache object is declared. var g_AutoResearchTechList = findAllAutoResearchedTechs(); /** * Loads raw entity template. * * Loads from local cache if data present, else from file system. * * @param {string} templateName * @return {object} Object containing raw template data. */ function loadTemplate(templateName) { if (!(templateName in g_TemplateData)) { // We need to clone the template because we want to perform some translations. let data = clone(Engine.GetTemplate(templateName)); translateObjectKeys(data, ["GenericName", "SpecificName", "Tooltip"]); if (data.Auras) for (let auraID of data.Auras._string.split(/\s+/)) loadAuraData(auraID); g_TemplateData[templateName] = data; } return g_TemplateData[templateName]; } /** * Loads raw technology template. * * Loads from local cache if available, else from file system. * * @param {string} templateName * @return {object} Object containing raw template data. */ function loadTechData(templateName) { if (!(templateName in g_TechnologyData)) { let data = Engine.ReadJSONFile(g_TechnologyPath + templateName + ".json"); translateObjectKeys(data, ["genericName", "tooltip"]); g_TechnologyData[templateName] = data; } return g_TechnologyData[templateName]; } function techDataExists(templateName) { return Engine.FileExists("simulation/data/technologies/" + templateName + ".json"); } /** * Loads raw aura template. * * Loads from local cache if available, else from file system. * * @param {string} templateName * @return {object} Object containing raw template data. */ function loadAuraData(templateName) { if (!(templateName in g_AuraData)) { let data = Engine.ReadJSONFile(g_AuraPath + templateName + ".json"); translateObjectKeys(data, ["auraName", "auraDescription"]); g_AuraData[templateName] = data; } return g_AuraData[templateName]; } /** - * Load and parse unit from entity template. + * Load and parse a structure, unit, resource, etc from its entity template file. * - * @param {string} templateName - * @return Sanitized object about the requested unit or null if entity template doesn't exist. - */ -function loadUnit(templateName) -{ - if (!Engine.TemplateExists(templateName)) - return null; - - let template = loadTemplate(templateName); - let unit = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers); - - unit.production = loadProductionQueue(template); - unit.builder = loadBuildQueue(template); - - if (unit.upgrades) - unit.upgrades = getActualUpgradeData(unit.upgrades); - - return unit; -} - -/** - * Load and parse structure from entity template. - * - * @param {string} templateName - * @return {object} Sanitized data about the requested structure or null if entity template doesn't exist. + * @return {(object|null)} Sanitized object about the requested template or null if entity template doesn't exist. */ -function loadStructure(templateName) +function loadEntityTemplate (templateName) { if (!Engine.TemplateExists(templateName)) return null; let template = loadTemplate(templateName); - let structure = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers); + let parsed = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers); + parsed.name.internal = templateName; - structure.production = loadProductionQueue(template); + parsed.production = loadProductionQueue(template); + if (template.Builder) + parsed.builder = loadBuildQueue(template); + + if (template.ResourceSupply) + parsed.supply = { + "type": template.ResourceSupply.Type.split("."), + "amount": template.ResourceSupply.Amount, + }; - if (structure.upgrades) - structure.upgrades = getActualUpgradeData(structure.upgrades); + if (parsed.upgrades) + parsed.upgrades = getActualUpgradeData(parsed.upgrades); - if (structure.wallSet) + if (parsed.wallSet) { - structure.wallset = {}; + parsed.wallset = {}; - if (!structure.upgrades) - structure.upgrades = []; + if (!parsed.upgrades) + parsed.upgrades = []; // Note: An assumption is made here that wall segments all have the same armor and auras - let struct = loadStructure(structure.wallSet.templates.long); - structure.armour = struct.armour; - structure.auras = struct.auras; + let struct = loadEntityTemplate(parsed.wallSet.templates.long); + parsed.armour = struct.armour; + parsed.auras = struct.auras; // For technology cost multiplier, we need to use the tower - struct = loadStructure(structure.wallSet.templates.tower); - structure.techCostMultiplier = struct.techCostMultiplier; + struct = loadEntityTemplate(parsed.wallSet.templates.tower); + parsed.techCostMultiplier = struct.techCostMultiplier; let health; - for (let wSegm in structure.wallSet.templates) + for (let wSegm in parsed.wallSet.templates) { if (wSegm == "fort" || wSegm == "curves") continue; - let wPart = loadStructure(structure.wallSet.templates[wSegm]); - structure.wallset[wSegm] = wPart; + let wPart = loadEntityTemplate(parsed.wallSet.templates[wSegm]); + parsed.wallset[wSegm] = wPart; for (let research of wPart.production.techs) - structure.production.techs.push(research); + parsed.production.techs.push(research); if (wPart.upgrades) - structure.upgrades = structure.upgrades.concat(wPart.upgrades); + parsed.upgrades = parsed.upgrades.concat(wPart.upgrades); if (["gate", "tower"].indexOf(wSegm) != -1) continue; if (!health) { health = { "min": wPart.health, "max": wPart.health }; continue; } health.min = Math.min(health.min, wPart.health); health.max = Math.max(health.max, wPart.health); } - if (structure.wallSet.templates.curves) - for (let curve of structure.wallSet.templates.curves) + if (parsed.wallSet.templates.curves) + for (let curve of parsed.wallSet.templates.curves) { - let wPart = loadStructure(curve); + let wPart = loadEntityTemplate(curve); health.min = Math.min(health.min, wPart.health); health.max = Math.max(health.max, wPart.health); } if (health.min == health.max) - structure.health = health.min; + parsed.health = health.min; else - structure.health = sprintf(translate("%(health_min)s to %(health_max)s"), { + parsed.health = sprintf(translate("%(health_min)s to %(health_max)s"), { "health_min": health.min, "health_max": health.max }); } - return structure; + return parsed; } /** * Load and parse technology from json template. * * @param {string} templateName * @return {object} Sanitized data about the requested technology. */ function loadTechnology(techName) { let template = loadTechData(techName); let tech = GetTechnologyDataHelper(template, g_SelectedCiv, g_ResourceData); if (template.pair !== undefined) { tech.pair = template.pair; tech.reqs = mergeRequirements(tech.reqs, loadTechnologyPair(template.pair).reqs); } return tech; } /** * Crudely iterates through every tech JSON file and identifies those * that are auto-researched. * * @return {array} List of techs that are researched automatically */ function findAllAutoResearchedTechs() { let techList = []; for (let filename of Engine.ListDirectoryFiles(g_TechnologyPath, "*.json", true)) { // -5 to strip off the file extension let templateName = filename.slice(g_TechnologyPath.length, -5); let data = loadTechData(templateName); if (data && data.autoResearch) techList.push(templateName); } return techList; } /** * @param {string} phaseCode * @return {object} Sanitized object containing phase data */ function loadPhase(phaseCode) { let phase = loadTechnology(phaseCode); phase.actualPhase = phaseCode; if (phase.replaces !== undefined) phase.actualPhase = phase.replaces[0]; return phase; } /** * @param {string} pairCode * @return {object} Contains a list and the requirements of the techs in the pair */ function loadTechnologyPair(pairCode) { var pairInfo = loadTechData(pairCode); return { "techs": [ pairInfo.top, pairInfo.bottom ], "reqs": DeriveTechnologyRequirements(pairInfo, g_SelectedCiv) }; } /** * @param {string} modCode * @return {object} Sanitized object containing modifier tech data */ function loadModifierTech(modCode) { if (!Engine.FileExists("simulation/data/technologies/"+modCode+".json")) return {}; return loadTechData(modCode); } Index: ps/trunk/binaries/data/mods/public/gui/reference/structree/structree.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/structree/structree.js (revision 21173) +++ ps/trunk/binaries/data/mods/public/gui/reference/structree/structree.js (revision 21174) @@ -1,184 +1,184 @@ /** * Array of structure template names when given a civ and a phase name. */ var g_BuildList = {}; /** * Array of template names that can be trained from a unit, given a civ and unit template name. */ var g_TrainList = {}; /** * Initialize the page * * @param {object} data - Parameters passed from the code that calls this page into existence. */ function init(data = {}) { if (data.callback) g_CallbackSet = true; let civList = Object.keys(g_CivData).map(civ => ({ "name": g_CivData[civ].Name, "code": civ, })).sort(sortNameIgnoreCase); if (!civList.length) { closePage(); return; } g_ParsedData = { "units": {}, "structures": {}, "techs": {}, "phases": {} }; let civSelection = Engine.GetGUIObjectByName("civSelection"); civSelection.list = civList.map(c => c.name); civSelection.list_data = civList.map(c => c.code); civSelection.selected = data.civ ? civSelection.list_data.indexOf(data.civ) : 0; } /** * @param {string} civCode */ function selectCiv(civCode) { if (civCode === g_SelectedCiv || !g_CivData[civCode]) return; g_SelectedCiv = civCode; g_CurrentModifiers = deriveModifications(g_AutoResearchTechList); // If a buildList already exists, then this civ has already been parsed if (g_BuildList[g_SelectedCiv]) { draw(); drawPhaseIcons(); return; } let templateLists = compileTemplateLists(civCode); for (let u of templateLists.units.keys()) if (!g_ParsedData.units[u]) - g_ParsedData.units[u] = loadUnit(u); + g_ParsedData.units[u] = loadEntityTemplate(u); for (let s of templateLists.structures.keys()) if (!g_ParsedData.structures[s]) - g_ParsedData.structures[s] = loadStructure(s); + g_ParsedData.structures[s] = loadEntityTemplate(s); // Load technologies g_ParsedData.techs[civCode] = {}; for (let techcode of templateLists.techs.keys()) if (basename(techcode).startsWith("phase")) g_ParsedData.phases[techcode] = loadPhase(techcode); else g_ParsedData.techs[civCode][techcode] = loadTechnology(techcode); // Establish phase order g_ParsedData.phaseList = UnravelPhases(g_ParsedData.phases); // Load any required generic phases that aren't already loaded for (let phasecode of g_ParsedData.phaseList) if (!g_ParsedData.phases[phasecode]) g_ParsedData.phases[phasecode] = loadPhase(phasecode); // Group production and upgrade lists of structures by phase for (let structCode of templateLists.structures.keys()) { let structInfo = g_ParsedData.structures[structCode]; structInfo.phase = getPhaseOfTemplate(structInfo); let structPhaseIdx = g_ParsedData.phaseList.indexOf(structInfo.phase); // If this building is shared with another civ, // it may have already gone through the grouping process already if (!Array.isArray(structInfo.production.techs)) continue; // Sort techs by phase let newProdTech = {}; for (let prod of structInfo.production.techs) { let phase = getPhaseOfTechnology(prod); if (phase === false) continue; if (g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) phase = structInfo.phase; if (!(phase in newProdTech)) newProdTech[phase] = []; newProdTech[phase].push(prod); } // Sort units by phase let newProdUnits = {}; for (let prod of structInfo.production.units) { let phase = getPhaseOfTemplate(g_ParsedData.units[prod]); if (phase === false) continue; if (g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) phase = structInfo.phase; if (!(phase in newProdUnits)) newProdUnits[phase] = []; newProdUnits[phase].push(prod); } g_ParsedData.structures[structCode].production = { "techs": newProdTech, "units": newProdUnits }; // Sort upgrades by phase let newUpgrades = {}; if (structInfo.upgrades) for (let upgrade of structInfo.upgrades) { let phase = getPhaseOfTemplate(upgrade); if (g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) phase = structInfo.phase; if (!newUpgrades[phase]) newUpgrades[phase] = []; newUpgrades[phase].push(upgrade); } g_ParsedData.structures[structCode].upgrades = newUpgrades; } // Determine the buildList for the civ (grouped by phase) let buildList = {}; let trainerList = []; for (let pha of g_ParsedData.phaseList) buildList[pha] = []; for (let structCode of templateLists.structures.keys()) { let phase = g_ParsedData.structures[structCode].phase; buildList[phase].push(structCode); } for (let unitCode of templateLists.units.keys()) { let unitTemplate = g_ParsedData.units[unitCode]; if (!unitTemplate.production.units.length && !unitTemplate.production.techs.length && !unitTemplate.upgrades) continue; trainerList.push(unitCode); } g_BuildList[g_SelectedCiv] = buildList; g_TrainList[g_SelectedCiv] = trainerList; draw(); drawPhaseIcons(); }