Ticket #3670: 3670_reqTooltips_v1-2.patch
File 3670_reqTooltips_v1-2.patch, 11.1 KB (added by , 7 years ago) |
---|
-
binaries/data/mods/public/globalscripts/Templates.js
diff --git a/binaries/data/mods/public/globalscripts/Templates.js b/binaries/data/mods/public/globalscripts/Templates.js index db54ca469..a782518d7 100644
a b function GetTechnologyDataHelper(template, civ, resources) 376 376 377 377 ret.description = template.description; 378 378 379 if (template.top) 380 ret.pair = [template.top, template.bottom]; 381 379 382 return ret; 380 383 } 381 384 -
binaries/data/mods/public/gui/common/tooltips.js
diff --git a/binaries/data/mods/public/gui/common/tooltips.js b/binaries/data/mods/public/gui/common/tooltips.js index 460c52061..00f28471d 100644
a b const g_TooltipTextFormats = { 2 2 "unit": ['[font="sans-10"][color="orange"]', '[/color][/font]'], 3 3 "header": ['[font="sans-bold-13"]', '[/font]'], 4 4 "body": ['[font="sans-13"]', '[/font]'], 5 "comma": ['[font="sans-12"]', '[/font]'] 5 "comma": ['[font="sans-12"]', '[/font]'], 6 "emphasis": ['[font="sans-bold-13"]', '[/font]'] 6 7 }; 7 8 8 9 const g_AttackTypes = { … … function commaFont(text) 42 43 return g_TooltipTextFormats.comma[0] + text + g_TooltipTextFormats.comma[1]; 43 44 } 44 45 46 function emphasisFont(text) 47 { 48 return g_TooltipTextFormats.emphasis[0] + text + g_TooltipTextFormats.emphasis[1]; 49 } 50 45 51 function getEntityTooltip(template) 46 52 { 47 53 if (!template.tooltip) … … function getRequiredTechnologyTooltip(technologyEnabled, requiredTechnology, civ 465 471 return ""; 466 472 467 473 return sprintf(translate("Requires %(technology)s"), { 468 "technology": getEntityNames(GetTechnologyData(requiredTechnology, civ))474 "technology": emphasisFont(getEntityNames(GetTechnologyData(requiredTechnology, civ))) 469 475 }); 470 476 } 471 477 -
binaries/data/mods/public/gui/session/selection_panels.js
diff --git a/binaries/data/mods/public/gui/session/selection_panels.js b/binaries/data/mods/public/gui/session/selection_panels.js index 74789e0cd..6a7b98265 100644
a b g_SelectionPanels.Research = { 828 828 ].map(func => func(template)); 829 829 830 830 if (!requirementsPassed) 831 { 832 let tip = template.requirementsTooltip; 833 let reqs = template.reqs; 834 for (let req of reqs) 835 { 836 if (!req.entities) 837 continue; 838 839 let entityCounts = []; 840 for (let entity of req.entities) 841 { 842 let current = 0; 843 switch (entity.check) 844 { 845 case "count": 846 current = playerState.classCounts[entity.class] || 0; 847 break; 848 849 case "variants": 850 current = playerState.typeCountsByClass[entity.class] ? 851 Object.keys(playerState.typeCountsByClass[entity.class]).length : 0; 852 break; 853 } 854 855 let remaining = entity.number - current; 856 if (remaining < 1) 857 continue; 858 859 entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { 860 "number": remaining, 861 "class": entity.class 862 })); 863 } 864 865 tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { 866 "entityCounts": entityCounts.join(translate(", ")) 867 }); 868 } 869 tooltips.push(tip); 870 } 831 tooltips.push(template.requirementsTooltip || deriveTechRequirementsTooltip(template.reqs, player)); 832 871 833 tooltips.push(getNeededResourcesTooltip(neededResources)); 872 834 button.tooltip = tooltips.filter(tip => tip).join("\n"); 873 835 -
binaries/data/mods/public/gui/session/selection_panels_helpers.js
diff --git a/binaries/data/mods/public/gui/session/selection_panels_helpers.js b/binaries/data/mods/public/gui/session/selection_panels_helpers.js index 6b9f507d6..1826f4046 100644
a b function formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize 144 144 }) + "[/font]"; 145 145 } 146 146 147 /** 148 * 149 * @param reqs {array} Civ-specific requirements 150 */ 151 function deriveTechRequirementsTooltip(reqs, player) 152 { 153 let optionalTexts = []; 154 let playerState = GetSimState().players[player]; 155 156 for (let req of reqs) 157 { 158 let requirementTexts = []; 159 160 if (req.techs) 161 { 162 let requiredTechs = []; 163 164 for (let tech of req.techs) 165 if (!playerState.researchedTechs[tech]) 166 { 167 if (tech.slice(0, 4) == "pair") 168 { 169 let pair = GetTechnologyData(tech).pair; 170 requiredTechs.push(sprintf(translate("%(firstTechOfPair)s or %(secondTechOfPair)s"), { 171 "firstTechOfPair": emphasisFont(getEntityNames(GetTechnologyData(pair[0]))), 172 "secondTechOfPair": emphasisFont(getEntityNames(GetTechnologyData(pair[1]))) 173 })); 174 } 175 else 176 requiredTechs.push(emphasisFont(getEntityNames(GetTechnologyData(tech)))); 177 } 178 179 if (requiredTechs.length) 180 { 181 if (requiredTechs.length == 1) 182 requirementTexts.push(requiredTechs[0]); 183 else 184 requirementTexts.push(sprintf(translate("%(listOfTechs)s and %(lastTechInList)s"), { 185 // Translation: This comma is used for separating first to penultimate elements in the list 186 "listOfTechs": requiredTechs.slice(0,-1).join(translate(", ")), 187 "lastTechInList": requiredTechs.slice(-1) 188 })); 189 } 190 } 191 192 if (req.entities) 193 { 194 let requiredEnts = []; 195 for (let entity of req.entities) 196 { 197 let current = 0; 198 switch (entity.check) 199 { 200 case "count": 201 current = playerState.classCounts[entity.class] || 0; 202 break; 203 204 case "variants": 205 current = playerState.typeCountsByClass[entity.class] ? 206 Object.keys(playerState.typeCountsByClass[entity.class]).length : 0; 207 break; 208 } 209 210 let remaining = entity.number - current; 211 if (remaining < 1) 212 continue; 213 214 let nameList = []; 215 for (let templateName of playerState.templatesByClass[entity.class]) 216 // We use the generic name only to keep the tooltip short 217 nameList.push(emphasisFont(GetTemplateData(templateName).name.generic)); 218 219 if (nameList.length == 1) 220 nameList = nameList[0]; 221 else 222 nameList = sprintf(translate("%(listOfEntityNames)s or %(lastEntityNameInList)s"), { 223 // Translation: This comma is used for separating first to penultimate elements in the list 224 "listOfEntityNames": nameList.slice(0,-1).join(translate(", ")), 225 "lastEntityNameInList": nameList.slice(-1) 226 }); 227 228 requiredEnts.push(sprintf(translate("%(number)s %(listOfTemplateNames)s (%(remaining)s remaining)"), { 229 "number": entity.number, 230 "listOfTemplateNames": nameList, 231 "remaining": remaining, 232 })); 233 } 234 if (requiredEnts.length) 235 requirementTexts.push(requiredEnts.join(translate(" and "))); 236 // Translation: This is used to join multiple technology requirements 237 } 238 239 optionalTexts.push(requirementTexts.join(translate(" and "))); 240 // Translation: This is used to join multiple technology requirements 241 } 147 242 243 return sprintf(translate("Requires %(requirementTexts)s"), { 244 // Translation: This is used to join multiple technology requirements 245 "requirementTexts": optionalTexts.join(translate("; or ")) 246 }); 247 } -
binaries/data/mods/public/simulation/components/GuiInterface.js
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index 04ced0a3e..31667a6c6 100644
a b GuiInterface.prototype.GetSimulationState = function() 106 106 "teamsLocked": cmpPlayer.GetLockTeams(), 107 107 "cheatsEnabled": cmpPlayer.GetCheatsEnabled(), 108 108 "disabledTemplates": cmpPlayer.GetDisabledTemplates(), 109 "templatesByClass": cmpPlayer.GetTemplateNamesByClass(), 109 110 "hasSharedDropsites": cmpPlayer.HasSharedDropsites(), 110 111 "hasSharedLos": cmpPlayer.HasSharedLos(), 111 112 "phase": phase, -
binaries/data/mods/public/simulation/components/Player.js
diff --git a/binaries/data/mods/public/simulation/components/Player.js b/binaries/data/mods/public/simulation/components/Player.js index 1c017bc30..747cd8f85 100644
a b Player.prototype.Init = function() 38 38 this.disabledTemplates = {}; 39 39 this.disabledTechnologies = {}; 40 40 this.startingTechnologies = []; 41 this.classedTemplates = undefined; 41 42 42 43 // Initial resources and trading goods probability in steps of 5 43 44 let resCodes = Resources.GetCodes(); … … Player.prototype.AddDisabledTemplate = function(template) 792 793 "type": "resetselectionpannel", 793 794 "players": [this.GetPlayerID()] 794 795 }); 796 this.classedTemplates = undefined; 795 797 }; 796 798 797 799 Player.prototype.RemoveDisabledTemplate = function(template) … … Player.prototype.RemoveDisabledTemplate = function(template) 804 806 "type": "resetselectionpannel", 805 807 "players": [this.GetPlayerID()] 806 808 }); 809 this.classedTemplates = undefined; 807 810 }; 808 811 809 812 Player.prototype.SetDisabledTemplates = function(templates) … … Player.prototype.SetDisabledTemplates = function(templates) 818 821 "type": "resetselectionpannel", 819 822 "players": [this.GetPlayerID()] 820 823 }); 824 this.classedTemplates = undefined; 821 825 }; 822 826 823 827 Player.prototype.GetDisabledTemplates = function() … … Player.prototype.SetStartingTechnologies = function(techs) 861 865 this.startingTechnologies = techs; 862 866 }; 863 867 868 Player.prototype.GetTemplateNamesByClass = function() 869 { 870 if (this.classedTemplates) 871 return this.classedTemplates; 872 873 // todo: find a better starting point 874 let cmpTechnologyManager = Engine.QueryInterface(this.entity, IID_TechnologyManager); 875 if (!cmpTechnologyManager) 876 return {}; 877 878 let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 879 let entsByClass = {}; 880 let toParse = Object.keys(cmpTechnologyManager.GetTypeCountsByClass().Structure); 881 let templateData = new Map(); 882 883 while (toParse.length) 884 { 885 let toParseNext = []; 886 887 for (let templateName of toParse) 888 { 889 if (!cmpTemplateManager.TemplateExists(templateName)) 890 continue; 891 892 let template = cmpTemplateManager.GetTemplate(templateName); 893 templateData.set(templateName, { 894 "parent": template["@parent"], 895 "classes": GetIdentityClasses(template.Identity) 896 }); 897 898 let entStrings = []; 899 if (template.ProductionQueue && template.ProductionQueue.Entities) 900 entStrings.push(template.ProductionQueue.Entities._string || ""); 901 902 if (template.Builder && template.Builder.Entities) 903 entStrings.push(template.Builder.Entities._string || ""); 904 905 for (let ent of entStrings.join(" ").replace(/\{civ\}/g, this.civ).split(/\s+/)) 906 if (ent && !templateData.has(ent) && toParseNext.indexOf(ent) < 0 && !this.disabledTemplates[ent]) 907 toParseNext.push(ent); 908 } 909 toParse = toParseNext; 910 } 911 912 for (let template of templateData) 913 { 914 // Crudely filter out *_house, *_trireme and *_barracks copies 915 if (templateData[template[1].parent]) 916 continue; 917 918 for (let cls of template[1].classes) 919 { 920 if (!entsByClass[cls]) 921 entsByClass[cls] = []; 922 entsByClass[cls].push(template[0]); 923 } 924 } 925 926 this.classedTemplates = entsByClass; 927 return this.classedTemplates; 928 } 929 864 930 Engine.RegisterComponentType(IID_Player, "Player", Player);