Ticket #2596: ticket2596.2.patch
File ticket2596.2.patch, 23.0 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/gui/options/options.js
1 1 var g_hasCallback = false; 2 2 var g_controls; 3 /**4 * This array holds the data to populate the general section with.5 * Data is in the form [Title, Tooltip, {ActionType:Action}, InputType].6 */7 var options = {8 "generalSetting":9 [10 [translate("Windowed Mode"), translate("Start 0 A.D. in a window"), {"config":"windowed"}, "boolean"],11 [translate("Background Pause"), translate("Pause single player games when window loses focus"), {"config":"pauseonfocusloss"}, "boolean"],12 [translate("Disable Welcome Screen"), translate("If you disable this screen completely, you may miss important announcements.\nYou can still launch it using the main menu."), {"config":"splashscreendisable"}, "boolean"],13 [translate("Detailed Tooltips"), translate("Show detailed tooltips for trainable units in unit-producing buildings."), {"config":"showdetailedtooltips"}, "boolean"],14 [translate("FPS Overlay"), translate("Show frames per second in top right corner."), {"config":"overlay.fps"}, "boolean"],15 [translate("Realtime Overlay"), translate("Show current system time in top right corner."), {"config":"overlay.realtime"}, "boolean"],16 [translate("Gametime Overlay"), translate("Show current simulation time in top right corner."), {"config":"gui.session.timeelapsedcounter"}, "boolean"],17 [translate("Ceasefire Time Overlay"), translate("Always show the remaining ceasefire time."), {"config":"gui.session.ceasefirecounter"}, "boolean"],18 [translate("Persist Match Settings"), translate("Save and restore match settings for quick reuse when hosting another game"), {"config":"persistmatchsettings"}, "boolean"],19 ],20 "graphicsSetting":21 [22 [translate("Prefer GLSL"), translate("Use OpenGL 2.0 shaders (recommended)"), {"renderer":"PreferGLSL", "config":"preferglsl"}, "boolean"],23 [translate("Post Processing"), translate("Use screen-space postprocessing filters (HDR, Bloom, DOF, etc)"), {"renderer":"Postproc", "config":"postproc"}, "boolean"],24 [translate("Shadows"), translate("Enable shadows"), {"renderer":"Shadows", "config":"shadows"}, "boolean"],25 [translate("Particles"), translate("Enable particles"), {"renderer":"Particles", "config":"particles"}, "boolean"],26 [translate("Show Sky"), translate("Render Sky"), {"renderer":"ShowSky", "config":"showsky"}, "boolean"],27 [translate("Smooth LOS"), translate("Lift darkness and fog-of-war smoothly"), {"renderer":"SmoothLOS", "config":"smoothlos"}, "boolean"],28 [translate("Unit Silhouettes"), translate("Show outlines of units behind buildings"), {"renderer":"Silhouettes", "config":"silhouettes"}, "boolean"],29 [translate("Shadow Filtering"), translate("Smooth shadows"), {"renderer":"ShadowPCF", "config":"shadowpcf"}, "boolean"],30 [translate("Fast & Ugly Water"), translate("Use the lowest settings possible to render water. This makes other settings irrelevant."), {"renderer":"WaterUgly", "config":"waterugly"}, "boolean"],31 [translate("HQ Water Effects"), translate("Use higher-quality effects for water, rendering coastal waves, shore foam, and ships trails."), {"renderer":"WaterFancyEffects", "config":"waterfancyeffects"}, "boolean"],32 [translate("Real Water Depth"), translate("Use actual water depth in rendering calculations"), {"renderer":"WaterRealDepth", "config":"waterrealdepth"}, "boolean"],33 [translate("Water Reflections"), translate("Allow water to reflect a mirror image"), {"renderer":"WaterReflection", "config":"waterreflection"}, "boolean"],34 [translate("Water Refraction"), translate("Use a real water refraction map and not transparency"), {"renderer":"WaterRefraction", "config":"waterrefraction"}, "boolean"],35 [translate("Shadows on Water"), translate("Cast shadows on water"), {"renderer":"WaterShadows", "config":"watershadows"}, "boolean"],36 [translate("VSync"), translate("Run vertical sync to fix screen tearing. REQUIRES GAME RESTART"), {"config":"vsync"}, "boolean"],37 [translate("Limit FPS in Menus"), translate("Limit FPS to 50 in all menus, to save power."), {"config":"gui.menu.limitfps"}, "boolean"],38 [translate("Graphics quality"), translate("Graphics quality. REQUIRES GAME RESTART"), {"config":"materialmgr.quality", "min": "0", "max": "10"}, "number"],39 ],40 "soundSetting":41 [42 [translate("Master Gain"), translate("Master audio gain"), {"config":"sound.mastergain", "function":"Engine.SetMasterGain(Number(this.caption));", "min": "0"}, "number"],43 [translate("Music Gain"), translate("In game music gain"), {"config":"sound.musicgain", "function":"Engine.SetMusicGain(Number(this.caption));", "min": "0"}, "number"],44 [translate("Ambient Gain"), translate("In game ambient sound gain"), {"config":"sound.ambientgain", "function":"Engine.SetAmbientGain(Number(this.caption));", "min": "0"}, "number"],45 [translate("Action Gain"), translate("In game unit action sound gain"), {"config":"sound.actiongain", "function":"Engine.SetActionGain(Number(this.caption));", "min": "0"}, "number"],46 [translate("UI Gain"), translate("UI sound gain"), {"config":"sound.uigain", "function":"Engine.SetUIGain(Number(this.caption));", "min": "0"}, "number"],47 ],48 "lobbySetting":49 [50 [translate("Chat Backlog"), translate("Number of backlogged messages to load when joining the lobby"), {"config":"lobby.history", "min": "0"}, "number"],51 [translate("Chat Timestamp"), translate("Show time that messages are posted in the lobby chat"), {"config":"lobby.chattimestamp"}, "boolean"],52 ],53 };54 3 55 4 function init(data) 56 5 { … … 59 8 let revert = data && data.revert; 60 9 g_controls = []; 61 10 62 // WARNING: We assume a strict formatting of the XML and do minimal checking.63 for (let prefixof Object.keys(options))11 var options = Engine.ReadJSONFile("gui/options/options.json"); 12 for (let category of Object.keys(options)) 64 13 { 65 14 let lastSize; 66 for (let i = 0; i < options[ prefix].length; i++)15 for (let i = 0; i < options[category].length; ++i) 67 16 { 68 let body = Engine.GetGUIObjectByName( prefix+ "[" + i + "]");69 let label = Engine.GetGUIObjectByName( prefix+ "Label[" + i + "]");17 let body = Engine.GetGUIObjectByName(category + "[" + i + "]"); 18 let label = Engine.GetGUIObjectByName(category + "Label[" + i + "]"); 70 19 // Setup control. 71 setupControl(options[prefix][i], i, prefix, revert); 20 let option = options[category][i]; 21 setupControl(option, i, category, revert); 72 22 // Setup label. 73 label.caption = option s[prefix][i][0];74 label.tooltip = option s[prefix][i][1];23 label.caption = option.label ? translate(option.label) : translate("unknown"); 24 label.tooltip = option.tooltip ? translate(option.tooltip) : ""; 75 25 // Move each element to the correct place. 76 26 if (i > 0) 77 27 { … … 100 50 * @param option Structure containing the data to setup an option. 101 51 * @param prefix Prefix to use when accessing control, for example "generalSetting" when the tickbox name is generalSettingTickbox[i]. 102 52 */ 103 function setupControl(option, i, prefix, revert)53 function setupControl(option, i, category, revert) 104 54 { 105 55 var control; 106 var on Press;56 var onUpdate; 107 57 108 switch (option [3])58 switch (option.type) 109 59 { 110 60 case "boolean": 111 61 // More space for the label 112 let text = Engine.GetGUIObjectByName( prefix+ "Label[" + i + "]");62 let text = Engine.GetGUIObjectByName(category + "Label[" + i + "]"); 113 63 let size = text.size; 114 64 size.rright = 87; 115 65 text.size = size; 116 control = Engine.GetGUIObjectByName( prefix+ "Tickbox[" + i + "]");66 control = Engine.GetGUIObjectByName(category + "Tickbox[" + i + "]"); 117 67 var checked; 118 68 var keyRenderer; 119 69 var keyConfig; 120 70 var functionBody; 121 71 122 for (let action of Object.keys(option[2]))72 for (let param of Object.keys(option.parameters)) 123 73 { 124 switch ( action)74 switch (param) 125 75 { 126 76 case "config": 127 keyConfig = option [2].config;77 keyConfig = option.parameters.config; 128 78 if (checked === undefined || revert) 129 79 checked = Engine.ConfigDB_GetValue("user", keyConfig) === "true"; 130 80 else if ((Engine.ConfigDB_GetValue("user", keyConfig) === "true") !== checked) … … 131 81 Engine.ConfigDB_CreateValue("user", keyConfig, String(checked)); 132 82 break; 133 83 case "renderer": 134 keyRenderer = option[2].renderer; 84 keyRenderer = option.parameters.renderer; 85 if (!Engine["Renderer_Get" + keyRenderer + "Enabled"]) 86 { 87 warn(" invalid renderer key " + keyRenderer); 88 keyRenderer = undefined; 89 break; 90 } 135 91 if (checked === undefined) 136 92 checked = eval("Engine.Renderer_Get" + keyRenderer + "Enabled()"); 137 93 else if (eval("Engine.Renderer_Get" + keyRenderer + "Enabled()") !== checked) 138 94 eval("Engine.Renderer_Set" + keyRenderer + "Enabled(" + checked + ")"); 139 95 break; 140 case "function":141 // This allows for doing low-level actions, like hiding/showing UI elements.142 functionBody = option[2].function;143 break;144 96 default: 145 warn("Unknown option source type '" + action+ "'");97 warn("Unknown option source type '" + param + "'"); 146 98 } 147 99 } 148 100 149 on Press = function(keyRenderer, keyConfig, functionBody)101 onUpdate = function(keyRenderer, keyConfig) 150 102 { 151 103 return function() 152 104 { … … 154 106 eval("Engine.Renderer_Set" + keyRenderer + "Enabled(" + this.checked + ")"); 155 107 if (keyConfig) 156 108 Engine.ConfigDB_CreateValue("user", keyConfig, String(this.checked)); 157 if (functionBody)158 eval(functionBody);159 109 updateStatus(true); 160 110 }; 161 }(keyRenderer, keyConfig , functionBody);111 }(keyRenderer, keyConfig); 162 112 163 113 // Load final data to the control element. 164 114 control.checked = checked; 165 control.onPress = on Press;115 control.onPress = onUpdate; 166 116 break; 167 117 case "number": 168 118 // TODO: Slider 169 119 case "string": 170 control = Engine.GetGUIObjectByName( prefix+ "Input[" + i + "]");120 control = Engine.GetGUIObjectByName(category + "Input[" + i + "]"); 171 121 var caption; 172 122 var key; 173 123 var functionBody; … … 174 124 var minval; 175 125 var maxval; 176 126 177 for (let action of Object.keys(option[2]))127 for (let param of Object.keys(option.parameters)) 178 128 { 179 switch ( action)129 switch (param) 180 130 { 181 131 case "config": 182 key = option [2].config;132 key = option.parameters.config; 183 133 caption = Engine.ConfigDB_GetValue("user", key); 184 134 break; 185 135 case "function": 186 // This allows for doing low-level actions, like hiding/showing UI elements.187 functionBody = option[2].function;136 if (Engine[option.parameters.function]) 137 functionBody = option.parameters.function; 188 138 break; 189 139 case "min": 190 minval = option [2].min;140 minval = option.parameters.min; 191 141 break; 192 142 case "max": 193 maxval = option [2].max;143 maxval = option.parameters.max; 194 144 break; 195 145 default: 196 146 warn("Unknown option source type '" + action + "'"); … … 201 151 // - when the mouse leave the control (MouseLeave event) 202 152 // - or when saving or closing the window (registerChanges function) 203 153 // so we must ensure that something has indeed been modified 204 on Press= function(key, functionBody, minval, maxval)154 onUpdate = function(key, functionBody, minval, maxval) 205 155 { 206 156 return function() 207 157 { … … 213 163 return; 214 164 Engine.ConfigDB_CreateValue("user", key, this.caption); 215 165 if (functionBody) 216 eval(functionBody); 166 { 167 let val = +this.caption; 168 Engine[functionBody](val); 169 } 217 170 updateStatus(true); 218 171 }; 219 172 }(key, functionBody, minval, maxval); 220 173 221 174 control.caption = caption; 222 control.onPress = on Press;223 control.onMouseLeave = on Press;175 control.onPress = onUpdate; 176 control.onMouseLeave = onUpdate; 224 177 g_controls.push(control); 225 178 break; 179 case "dropdown": 180 control = Engine.GetGUIObjectByName(category + "Dropdown[" + i + "]"); 181 var caption; 182 var key; 183 var functionBody; 184 var minval; 185 var maxval; 186 187 for (let param of Object.keys(option.parameters)) 188 { 189 switch (param) 190 { 191 case "config": 192 key = option.parameters.config; 193 let val = Engine.ConfigDB_GetValue("user", key); 194 if (key === "materialmgr.quality") 195 val = val > 5 ? 2 : val > 2 ? 1 : 0; 196 control.selected = val; 197 break; 198 case "list": 199 control.list = option.parameters.list; 200 break; 201 default: 202 warn("Unknown option source type '" + action + "'"); 203 } 204 } 205 206 onUpdate = function(key) 207 { 208 return function() 209 { 210 let val = this.selected; 211 if (key === "materialmgr.quality") 212 val = val == 0 ? 2 : val == 1 ? 5 : 8; 213 Engine.ConfigDB_CreateValue("user", key, val); 214 updateStatus(true); 215 }; 216 }(key); 217 218 control.onSelectionChange = onUpdate; 219 break; 226 220 default: 227 warn("Unknown option type '" + option [3]+ "', assuming string. Valid types are 'number', 'string', or 'bool'.");228 control = Engine.GetGUIObjectByName( prefix+ "Input[" + i + "]");221 warn("Unknown option type '" + option.type + "', assuming string. Valid types are 'number', 'string', or 'bool'."); 222 control = Engine.GetGUIObjectByName(category + "Input[" + i + "]"); 229 223 break; 230 224 } 231 225 control.hidden = false; 232 control.tooltip = option [1];226 control.tooltip = option.tooltip ? translate(option.tooltip) : ""; 233 227 return control; 234 228 } 235 229 -
binaries/data/mods/public/gui/options/options.json
1 { 2 "generalSetting": 3 [ 4 { 5 "type": "boolean", 6 "label": "Windowed Mode", 7 "tooltip": "Start 0 A.D. in a window", 8 "parameters": { "config": "windowed" } 9 }, 10 { 11 "type": "boolean", 12 "label": "Background Pause", 13 "tooltip": "Pause single player games when window loses focus", 14 "parameters": { "config": "pauseonfocusloss" } 15 }, 16 { 17 "type": "boolean", 18 "label": "Disable Welcome Screen", 19 "tooltip": "If you disable this screen completely, you may miss important announcements.\nYou can still launch it using the main menu.", 20 "parameters": { "config": "splashscreendisable" } 21 }, 22 { 23 "type": "boolean", 24 "label": "Detailed Tooltips", 25 "tooltip": "Show detailed tooltips for trainable units in unit-producing buildings.", 26 "parameters": { "config": "showdetailedtooltips" } 27 }, 28 { 29 "type": "boolean", 30 "label": "FPS Overlay", 31 "tooltip": "Show frames per second in top right corner.", 32 "parameters": { "config": "overlay.fps" } 33 }, 34 { 35 "type": "boolean", 36 "label": "Realtime Overlay", 37 "tooltip": "Show current system time in top right corner.", 38 "parameters": { "config": "overlay.realtime" } 39 }, 40 { 41 "type": "boolean", 42 "label": "Gametime Overlay", 43 "tooltip": "Show current simulation time in top right corner.", 44 "parameters": { "config": "gui.session.timeelapsedcounter" } 45 }, 46 { 47 "type": "boolean", 48 "label": "Ceasefire Time Overlay", 49 "tooltip": "Always show the remaining ceasefire time.", 50 "parameters": { "config": "gui.session.ceasefirecounter" } 51 }, 52 { 53 "type": "boolean", 54 "label": "Persist Match Settings", 55 "tooltip": "Save and restore match settings for quick reuse when hosting another game", 56 "parameters": { "config": "persistmatchsettings" } 57 } 58 ], 59 "graphicsSetting": 60 [ 61 { 62 "type": "boolean", 63 "label": "Prefer GLSL", 64 "tooltip": "Use OpenGL 2.0 shaders (recommended)", 65 "parameters": { "renderer": "PreferGLSL", "config": "preferglsl" } 66 }, 67 { 68 "type": "boolean", 69 "label": "Post Processing", 70 "tooltip": "Use screen-space postprocessing filters (HDR, Bloom, DOF, etc)", 71 "parameters": { "renderer": "Postproc", "config": "postproc" } 72 }, 73 { 74 "type": "boolean", 75 "label": "Shadows", 76 "tooltip": "Enable shadows", 77 "parameters": { "renderer": "Shadows", "config": "shadows"} 78 }, 79 { 80 "type": "boolean", 81 "label": "Particles", 82 "tooltip": "Enable particles", 83 "parameters": { "renderer": "Particles", "config": "particles" } 84 }, 85 { 86 "type": "boolean", 87 "label": "Show Sky", 88 "tooltip": "Render Sky", 89 "parameters": { "renderer": "ShowSky", "config": "showsky" } 90 }, 91 { 92 "type": "boolean", 93 "label": "Smooth LOS", 94 "tooltip": "Lift darkness and fog-of-war smoothly", 95 "parameters": { "renderer": "SmoothLOS", "config": "smoothlos" } 96 }, 97 { 98 "type": "boolean", 99 "label": "Unit Silhouettes", 100 "tooltip": "Show outlines of units behind buildings", 101 "parameters": { "renderer": "Silhouettes", "config": "silhouettes" } 102 }, 103 { 104 "type": "boolean", 105 "label": "Shadow Filtering", 106 "tooltip": "Smooth shadows", 107 "parameters": { "renderer": "ShadowPCF", "config": "shadowpcf" } 108 }, 109 { 110 "type": "boolean", 111 "label": "Fast & Ugly Water", 112 "tooltip": "Use the lowest settings possible to render water. This makes other settings irrelevant.", 113 "parameters": { "renderer": "WaterUgly", "config": "waterugly" } 114 }, 115 { 116 "type": "boolean", 117 "label": "HQ Water Effects", 118 "tooltip": "Use higher-quality effects for water, rendering coastal waves, shore foam, and ships trails.", 119 "parameters": { "renderer": "WaterFancyEffects", "config": "waterfancyeffects" } 120 }, 121 { 122 "type": "boolean", 123 "label": "Real Water Depth", 124 "tooltip": "Use actual water depth in rendering calculations", 125 "parameters": { "renderer": "WaterRealDepth", "config": "waterrealdepth" } 126 }, 127 { 128 "type": "boolean", 129 "label": "Water Reflections", 130 "tooltip": "Allow water to reflect a mirror image", 131 "parameters": { "renderer": "WaterReflection", "config": "waterreflection" } 132 }, 133 { 134 "type": "boolean", 135 "label": "Water Refraction", 136 "tooltip": "Use a real water refraction map and not transparency", 137 "parameters": { "renderer": "WaterRefraction", "config": "waterrefraction" } 138 }, 139 { 140 "type": "boolean", 141 "label": "Shadows on Water", 142 "tooltip": "Cast shadows on water", 143 "parameters": { "renderer": "WaterShadows", "config": "watershadows" } 144 }, 145 { 146 "type": "boolean", 147 "label": "VSync", 148 "tooltip": "Run vertical sync to fix screen tearing. REQUIRES GAME RESTART", 149 "parameters": { "config": "vsync" } 150 }, 151 { 152 "type": "boolean", 153 "label": "Limit FPS in Menus", 154 "tooltip": "Limit FPS to 50 in all menus, to save power.", 155 "parameters": { "config": "gui.menu.limitfps" } 156 }, 157 { 158 "type": "dropdown", 159 "label": "Graphics quality", 160 "tooltip": "Graphics quality. REQUIRES GAME RESTART", 161 "parameters": { "list": [ "Low", "Medium", "High" ], "config": "materialmgr.quality" } 162 163 } 164 ], 165 "soundSetting": 166 [ 167 { 168 "type": "number", 169 "label": "Master Gain", 170 "tooltip": "Master audio gain", 171 "parameters": { "config": "sound.mastergain", "function": "SetMasterGain", "min": "0" } 172 }, 173 { 174 "type": "number", 175 "label": "Music Gain", 176 "tooltip": "In game music gain", 177 "parameters": { "config": "sound.musicgain", "function": "SetMusicGain", "min": "0" } 178 }, 179 { 180 "type": "number", 181 "label": "Ambient Gain", 182 "tooltip": "In game ambient sound gain", 183 "parameters": { "config": "sound.ambientgain", "function": "SetAmbientGain", "min": "0" } 184 }, 185 { 186 "type": "number", 187 "label": "Action Gain", 188 "tooltip": "In game unit action sound gain", 189 "parameters": { "config": "sound.actiongain", "function": "SetActionGain", "min": "0" } 190 }, 191 { 192 "type": "number", 193 "label": "UI Gain", 194 "tooltip": "UI sound gain", 195 "parameters": { "config": "sound.uigain", "function": "SetUIGain", "min": "0" } 196 } 197 ], 198 "lobbySetting": 199 [ 200 { 201 "type": "number", 202 "label": "Chat Backlog", 203 "tooltip": "Number of backlogged messages to load when joining the lobby", 204 "parameters": { "config": "lobby.history", "min": "0" } 205 }, 206 { 207 "type": "boolean", 208 "label": "Chat Timestamp", 209 "tooltip": "Show time that messages are posted in the lobby chat", 210 "parameters": { "config": "lobby.chattimestamp" } 211 } 212 ] 213 } -
binaries/data/mods/public/gui/options/options.xml
26 26 <object name="generalSettingLabel[n]" size="0 0 65% 100%" type="text" style="ModernLabelText" text_align="left"/> 27 27 <object name="generalSettingTickbox[n]" size="90% 5 100% 100%+5" type="checkbox" style="ModernTickBox" hidden="true"/> 28 28 <object name="generalSettingInput[n]" size="70% 0 100%-8 100%" type="input" style="ModernInput" hidden="true"/> 29 <object name="generalSettingDropdown[n]" size="70% 0 100%-8 100%" type="dropdown" style="ModernDropDown" hidden="true"/> 29 30 </object> 30 31 </repeat> 31 32 </object> … … 38 39 <object name="graphicsSettingLabel[n]" size="0 0 65% 100%" type="text" style="ModernLabelText" text_align="left"/> 39 40 <object name="graphicsSettingTickbox[n]" size="90% 5 100% 100%+5" type="checkbox" style="ModernTickBox" hidden="true"/> 40 41 <object name="graphicsSettingInput[n]" size="70% 0 100%-8 100%" type="input" style="ModernInput" hidden="true"/> 42 <object name="graphicsSettingDropdown[n]" size="70% 0 100%-8 100%" type="dropdown" style="ModernDropDown" hidden="true"/> 41 43 </object> 42 44 </repeat> 43 45 </object> … … 50 52 <object name="soundSettingLabel[n]" size="0 0 65% 100%" type="text" style="ModernLabelText" text_align="left"/> 51 53 <object name="soundSettingTickbox[n]" size="90% 5 100% 100%+5" type="checkbox" style="ModernTickBox" hidden="true"/> 52 54 <object name="soundSettingInput[n]" size="70% 0 100%-8 100%" type="input" style="ModernInput" hidden="true"/> 55 <object name="soundSettingDropdown[n]" size="70% 0 100%-8 100%" type="dropdown" style="ModernDropDown" hidden="true"/> 53 56 </object> 54 57 </repeat> 55 58 </object> … … 62 65 <object name="lobbySettingLabel[n]" size="0 0 65% 100%" type="text" style="ModernLabelText" text_align="left"/> 63 66 <object name="lobbySettingTickbox[n]" size="90% 5 100% 100%+5" type="checkbox" style="ModernTickBox" hidden="true"/> 64 67 <object name="lobbySettingInput[n]" size="70% 0 100%-8 100%" type="input" style="ModernInput" hidden="true"/> 68 <object name="lobbySettingDropdown[n]" size="70% 0 100%-8 100%" type="dropdown" style="ModernDropDown" hidden="true"/> 65 69 </object> 66 70 </repeat> 67 71 </object> -
binaries/data/mods/public/l10n/messages.json
288 288 } 289 289 }, 290 290 { 291 "extractor": "json", 292 "filemasks": [ 293 "gui/options/**.json", 294 ], 295 "options": { 296 "keywords": [ 297 "label", 298 "tooltip", 299 "list" 300 ] 301 } 302 }, 303 { 291 304 "extractor": "txt", 292 305 "filemasks": [ 293 306 "gui/splashscreen/splashscreen.txt",