1 | | /** |
2 | | * This array holds the data to populate the general section with. |
3 | | * Data is in the form [Title, Tooltip, {ActionType:Action}, InputType]. |
4 | | */ |
5 | | var options = { |
6 | | "generalSetting": |
7 | | [ |
8 | | ["Windowed Mode", "Start 0 A.D. in windowed mode", {"config":"windowed"}, "boolean"], |
9 | | ["Background Pause", "Pause single player games when window loses focus", {"config":"pauseonfocusloss"}, "boolean"], |
10 | | ], |
11 | | "graphicsSetting": |
12 | | [ |
13 | | ["Prefer GLSL", "Use OpenGL 2.0 shaders (recommended)", {"renderer":"PreferGLSL"}, "boolean"], |
14 | | ["Shadows", "Enable shadows", {"renderer":"Shadows"}, "boolean"], |
15 | | ["Particles", "Enable particles", {"renderer":"Particles"}, "boolean"], |
16 | | ["Show Sky", "Render Sky", {"renderer":"ShowSky"}, "boolean"], |
17 | | ["Unit Silhouettes", "Show outlines of units behind buildings", {"renderer":"Silhouettes"}, "boolean"], |
18 | | ["Shadow Flitering", "Smooth shadows", {"renderer":"ShadowPCF"}, "boolean"], |
19 | | ["HQ Waviness", "Use real normals for ocean-wave rendering, instead of applying them as a flat texture", {"renderer":"WaterNormal"}, "boolean"], |
20 | | ["Real Water Depth", "Use actual water depth in rendering calculations", {"renderer":"WaterRealDepth"}, "boolean"], |
21 | | ["Water Reflections", "Allow water to reflect a mirror image", {"renderer":"WaterReflection"}, "boolean"], |
22 | | ["Water Refraction", "Use a real water refraction map and not transparency", {"renderer":"WaterRefraction"}, "boolean"], |
23 | | ["Shore Foam", "Show foam on water near shore depending on water waviness", {"renderer":"WaterFoam"}, "boolean"], |
24 | | ["Shore Waves", "Show breaking waves on water near shore (Requires HQ Waviness)", {"renderer":"WaterCoastalWaves"}, "boolean"], |
25 | | ["Water Shadows", "Cast shadows on water", {"renderer":"WaterShadow"}, "boolean"], |
26 | | ], |
27 | | "soundSetting": |
28 | | [ |
29 | | ["Master Gain", "Master audio gain", {"config":"sound.mastergain", "function":"Engine.SetMasterGain(Number(this.caption));"}, "number"], |
30 | | ["Music Gain", "In game music gain", {"config":"sound.musicgain", "function":"Engine.SetMusicGain(Number(this.caption));"}, "number"], |
31 | | ["Ambient Gain", "In game ambient sound gain", {"config":"sound.ambientgain", "function":"Engine.SetMusicGain(Number(this.caption));"}, "number"], |
32 | | ["Action Gain", "In game unit action sound gain", {"config":"sound.actiongain", "function":"Engine.SetMusicGain(Number(this.caption));"}, "number"], |
33 | | ["UI Gain", "UI sound gain", {"config":"sound.uigain", "function":"Engine.SetMusicGain(Number(this.caption));"}, "number"], |
34 | | ], |
35 | | "lobbySetting": |
36 | | [ |
37 | | ["Chat Backlog", "Number of backlogged messages to load when joining the lobby", {"config":"lobby.history"}, "number"], |
38 | | ["Chat Timestamp", "Show time that messages are posted in the lobby chat", {"config":"lobby.chattimestamp"}, "boolean"], |
39 | | ], |
40 | | }; |
41 | | |
42 | | function init() |
43 | | { |
44 | | // WARNING: We assume a strict formatting of the XML and do minimal checking. |
45 | | for each (var prefix in Object.keys(options)) |
46 | | { |
47 | | var lastSize; |
48 | | for (var i = 0; i < options[prefix].length; i++) |
49 | | { |
50 | | var body = Engine.GetGUIObjectByName(prefix + "[" + i + "]"); |
51 | | var label = Engine.GetGUIObjectByName(prefix + "Label[" + i + "]"); |
52 | | // Setup control. |
53 | | setupControl(options[prefix][i], i, prefix); |
54 | | // Setup label. |
55 | | label.caption = options[prefix][i][0]; |
56 | | label.tooltip = options[prefix][i][1]; |
57 | | // Move each element to the correct place. |
58 | | if (i > 0) |
59 | | { |
60 | | var newSize = new GUISize(); |
61 | | newSize.left = lastSize.left; |
62 | | newSize.rright = lastSize.rright; |
63 | | newSize.top = lastSize.bottom; |
64 | | newSize.bottom = newSize.top + 25; |
65 | | body.size = newSize; |
66 | | lastSize = newSize; |
67 | | } |
68 | | else |
69 | | { |
70 | | lastSize = body.size; |
71 | | } |
72 | | // Show element. |
73 | | body.hidden = false; |
74 | | } |
75 | | } |
76 | | } |
77 | | |
78 | | /** |
79 | | * Setup the apropriate control for a given option. |
80 | | * |
81 | | * @param option Structure containing the data to setup an option. |
82 | | * @param prefix Prefix to use when accessing control, for example "generalSetting" when the tickbox name is generalSettingTickbox[i]. |
83 | | */ |
84 | | function setupControl(option, i, prefix) |
85 | | { |
86 | | switch (option[3]) |
87 | | { |
88 | | case "boolean": |
89 | | var control = Engine.GetGUIObjectByName(prefix + "Tickbox[" + i + "]"); |
90 | | var checked; |
91 | | var onPress = function(){}; |
92 | | // Different option action load and save differently, so this switch is needed. |
93 | | for each (var action in Object.keys(option[2])) |
94 | | { |
95 | | switch (action) |
96 | | { |
97 | | case "config": |
98 | | // Load initial value if not yet loaded. |
99 | | if (!checked || typeof checked != boolean) |
100 | | checked = Engine.ConfigDB_GetValue("user", option[2][action]) === "true" ? true : false; |
101 | | // Hacky macro to create the callback. |
102 | | var callback = function(key) |
103 | | { |
104 | | return function() |
105 | | { |
106 | | Engine.ConfigDB_CreateValue("user", key, String(this.checked)); |
107 | | }; |
108 | | }(option[2][action]); |
109 | | // Merge the new callback with any existing callbacks. |
110 | | onPress = mergeFunctions(callback, onPress); |
111 | | break; |
112 | | case "renderer": |
113 | | // Load initial value if not yet loaded. |
114 | | if (!checked || typeof checked != boolean) |
115 | | checked = eval("Engine.Renderer_Get" + option[2][action] + "Enabled()"); |
116 | | // Hacky macro to create the callback. |
117 | | var callback = function(key) |
118 | | { |
119 | | return function() |
120 | | { |
121 | | eval("Engine.Renderer_Set" + key + "Enabled(" + this.checked + ")"); |
122 | | }; |
123 | | }(option[2][action]); |
124 | | // Merge the new callback with any existing callbacks. |
125 | | onPress = mergeFunctions(callback, onPress); |
126 | | break; |
127 | | case "function": |
128 | | // This allows for doing low-level actions, like hiding/showing UI elements. |
129 | | onPress = mergeFunctions(eval("function(){" + option[2][action] + "}"), onPress); |
130 | | break; |
131 | | default: |
132 | | warn("Unknown option source type '" + action + "'"); |
133 | | } |
134 | | } |
135 | | // Load final data to the control element. |
136 | | control.checked = checked; |
137 | | control.onPress = onPress; |
138 | | break; |
139 | | case "number": |
140 | | // TODO: Slider |
141 | | case "string": |
142 | | var control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]"); |
143 | | var caption; |
144 | | var onPress = function(){}; |
145 | | for each (var action in Object.keys(option[2])) |
146 | | { |
147 | | switch (action) |
148 | | { |
149 | | case "config": |
150 | | // Load initial value if not yet loaded. |
151 | | if (!checked || typeof checked != boolean) |
152 | | caption = Engine.ConfigDB_GetValue("user", option[2][action]);; |
153 | | // Hacky macro to create the callback. |
154 | | var callback = function(key) |
155 | | { |
156 | | return function() |
157 | | { |
158 | | Engine.ConfigDB_CreateValue("user", key, String(this.caption)); |
159 | | }; |
160 | | }(option[2][action]); |
161 | | // Merge the new callback with any existing callbacks. |
162 | | onPress = mergeFunctions(callback, onPress); |
163 | | break; |
164 | | case "function": |
165 | | // This allows for doing low-level actions, like hiding/showing UI elements. |
166 | | onPress = mergeFunctions(function(){eval(option[2][action])}, onPress); |
167 | | break; |
168 | | default: |
169 | | warn("Unknown option source type '" + action + "'"); |
170 | | } |
171 | | } |
172 | | control.caption = caption; |
173 | | control.onPress = onPress; |
174 | | break; |
175 | | default: |
176 | | warn("Unknown option type '" + options[3] + "', assuming string. Valid types are 'number', 'string', or 'bool'."); |
177 | | var control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]"); |
178 | | break; |
179 | | } |
180 | | control.hidden = false; |
181 | | control.tooltip = option[1]; |
182 | | return control; |
183 | | } |
184 | | |
185 | | /** |
186 | | * Merge two functions which don't expect arguments. |
187 | | * |
188 | | * @return Merged function. |
189 | | */ |
190 | | function mergeFunctions(function1, function2) |
191 | | { |
192 | | return function() |
193 | | { |
194 | | function1.apply(this); |
195 | | function2.apply(this); |
196 | | }; |
197 | | } |
| 1 | /** |
| 2 | * This array holds the data to populate the general section with. |
| 3 | * Data is in the form [Title, Tooltip, {ActionType:Action}, InputType]. |
| 4 | */ |
| 5 | var options = { |
| 6 | "generalSetting": |
| 7 | [ |
| 8 | ["Windowed Mode", "Start 0 A.D. in windowed mode", {"config":"windowed"}, "boolean"], |
| 9 | ["Background Pause", "Pause single player games when window loses focus", {"config":"pauseonfocusloss"}, "boolean"], |
| 10 | ["Show FPS", "Show FPS in the top right corner", {"config":"pauseonfocusloss"}, "boolean"], |
| 11 | ], |
| 12 | "graphicsSetting": |
| 13 | [ |
| 14 | ["Prefer GLSL", "Use OpenGL 2.0 shaders (recommended)", {"renderer":"PreferGLSL"}, "boolean"], |
| 15 | ["Shadows", "Enable shadows", {"renderer":"Shadows"}, "boolean"], |
| 16 | ["Particles", "Enable particles", {"renderer":"Particles"}, "boolean"], |
| 17 | ["Show Sky", "Render Sky", {"renderer":"ShowSky"}, "boolean"], |
| 18 | ["Unit Silhouettes", "Show outlines of units behind buildings", {"renderer":"Silhouettes"}, "boolean"], |
| 19 | ["Shadow Flitering", "Smooth shadows", {"renderer":"ShadowPCF"}, "boolean"], |
| 20 | ["HQ Waviness", "Use real normals for ocean-wave rendering, instead of applying them as a flat texture", {"renderer":"WaterNormal"}, "boolean"], |
| 21 | ["Real Water Depth", "Use actual water depth in rendering calculations", {"renderer":"WaterRealDepth"}, "boolean"], |
| 22 | ["Water Reflections", "Allow water to reflect a mirror image", {"renderer":"WaterReflection"}, "boolean"], |
| 23 | ["Water Refraction", "Use a real water refraction map and not transparency", {"renderer":"WaterRefraction"}, "boolean"], |
| 24 | ["Shore Foam", "Show foam on water near shore depending on water waviness", {"renderer":"WaterFoam"}, "boolean"], |
| 25 | ["Shore Waves", "Show breaking waves on water near shore (Requires HQ Waviness)", {"renderer":"WaterCoastalWaves"}, "boolean"], |
| 26 | ["Water Shadows", "Cast shadows on water", {"renderer":"WaterShadow"}, "boolean"], |
| 27 | ], |
| 28 | "soundSetting": |
| 29 | [ |
| 30 | ["Master Gain", "Master audio gain", {"config":"sound.mastergain", "function":"Engine.SetMasterGain(Number(this.caption));"}, "number"], |
| 31 | ["Music Gain", "In game music gain", {"config":"sound.musicgain", "function":"Engine.SetMusicGain(Number(this.caption));"}, "number"], |
| 32 | ["Ambient Gain", "In game ambient sound gain", {"config":"sound.ambientgain", "function":"Engine.SetMusicGain(Number(this.caption));"}, "number"], |
| 33 | ["Action Gain", "In game unit action sound gain", {"config":"sound.actiongain", "function":"Engine.SetMusicGain(Number(this.caption));"}, "number"], |
| 34 | ["UI Gain", "UI sound gain", {"config":"sound.uigain", "function":"Engine.SetMusicGain(Number(this.caption));"}, "number"], |
| 35 | ], |
| 36 | "lobbySetting": |
| 37 | [ |
| 38 | ["Chat Backlog", "Number of backlogged messages to load when joining the lobby", {"config":"lobby.history"}, "number"], |
| 39 | ["Chat Timestamp", "Show time that messages are posted in the lobby chat", {"config":"lobby.chattimestamp"}, "boolean"], |
| 40 | ], |
| 41 | }; |
| 42 | |
| 43 | function init() |
| 44 | { |
| 45 | // WARNING: We assume a strict formatting of the XML and do minimal checking. |
| 46 | for each (var prefix in Object.keys(options)) |
| 47 | { |
| 48 | var lastSize; |
| 49 | for (var i = 0; i < options[prefix].length; i++) |
| 50 | { |
| 51 | var body = Engine.GetGUIObjectByName(prefix + "[" + i + "]"); |
| 52 | var label = Engine.GetGUIObjectByName(prefix + "Label[" + i + "]"); |
| 53 | // Setup control. |
| 54 | setupControl(options[prefix][i], i, prefix); |
| 55 | // Setup label. |
| 56 | label.caption = options[prefix][i][0]; |
| 57 | label.tooltip = options[prefix][i][1]; |
| 58 | // Move each element to the correct place. |
| 59 | if (i > 0) |
| 60 | { |
| 61 | var newSize = new GUISize(); |
| 62 | newSize.left = lastSize.left; |
| 63 | newSize.rright = lastSize.rright; |
| 64 | newSize.top = lastSize.bottom; |
| 65 | newSize.bottom = newSize.top + 25; |
| 66 | body.size = newSize; |
| 67 | lastSize = newSize; |
| 68 | } |
| 69 | else |
| 70 | { |
| 71 | lastSize = body.size; |
| 72 | } |
| 73 | // Show element. |
| 74 | body.hidden = false; |
| 75 | } |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | /** |
| 80 | * Setup the apropriate control for a given option. |
| 81 | * |
| 82 | * @param option Structure containing the data to setup an option. |
| 83 | * @param prefix Prefix to use when accessing control, for example "generalSetting" when the tickbox name is generalSettingTickbox[i]. |
| 84 | */ |
| 85 | function setupControl(option, i, prefix) |
| 86 | { |
| 87 | switch (option[3]) |
| 88 | { |
| 89 | case "boolean": |
| 90 | var control = Engine.GetGUIObjectByName(prefix + "Tickbox[" + i + "]"); |
| 91 | var checked; |
| 92 | var onPress = function(){}; |
| 93 | // Different option action load and save differently, so this switch is needed. |
| 94 | for each (var action in Object.keys(option[2])) |
| 95 | { |
| 96 | switch (action) |
| 97 | { |
| 98 | case "config": |
| 99 | // Load initial value if not yet loaded. |
| 100 | if (!checked || typeof checked != boolean) |
| 101 | checked = Engine.ConfigDB_GetValue("user", option[2][action]) === "true" ? true : false; |
| 102 | // Hacky macro to create the callback. |
| 103 | var callback = function(key) |
| 104 | { |
| 105 | return function() |
| 106 | { |
| 107 | Engine.ConfigDB_CreateValue("user", key, String(this.checked)); |
| 108 | }; |
| 109 | }(option[2][action]); |
| 110 | // Merge the new callback with any existing callbacks. |
| 111 | onPress = mergeFunctions(callback, onPress); |
| 112 | break; |
| 113 | case "renderer": |
| 114 | // Load initial value if not yet loaded. |
| 115 | if (!checked || typeof checked != boolean) |
| 116 | checked = eval("Engine.Renderer_Get" + option[2][action] + "Enabled()"); |
| 117 | // Hacky macro to create the callback. |
| 118 | var callback = function(key) |
| 119 | { |
| 120 | return function() |
| 121 | { |
| 122 | eval("Engine.Renderer_Set" + key + "Enabled(" + this.checked + ")"); |
| 123 | }; |
| 124 | }(option[2][action]); |
| 125 | // Merge the new callback with any existing callbacks. |
| 126 | onPress = mergeFunctions(callback, onPress); |
| 127 | break; |
| 128 | case "function": |
| 129 | // This allows for doing low-level actions, like hiding/showing UI elements. |
| 130 | onPress = mergeFunctions(eval("function(){" + option[2][action] + "}"), onPress); |
| 131 | break; |
| 132 | default: |
| 133 | warn("Unknown option source type '" + action + "'"); |
| 134 | } |
| 135 | } |
| 136 | // Load final data to the control element. |
| 137 | control.checked = checked; |
| 138 | control.onPress = onPress; |
| 139 | break; |
| 140 | case "number": |
| 141 | // TODO: Slider |
| 142 | case "string": |
| 143 | var control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]"); |
| 144 | var caption; |
| 145 | var onPress = function(){}; |
| 146 | for each (var action in Object.keys(option[2])) |
| 147 | { |
| 148 | switch (action) |
| 149 | { |
| 150 | case "config": |
| 151 | // Load initial value if not yet loaded. |
| 152 | if (!checked || typeof checked != boolean) |
| 153 | caption = Engine.ConfigDB_GetValue("user", option[2][action]);; |
| 154 | // Hacky macro to create the callback. |
| 155 | var callback = function(key) |
| 156 | { |
| 157 | return function() |
| 158 | { |
| 159 | Engine.ConfigDB_CreateValue("user", key, String(this.caption)); |
| 160 | }; |
| 161 | }(option[2][action]); |
| 162 | // Merge the new callback with any existing callbacks. |
| 163 | onPress = mergeFunctions(callback, onPress); |
| 164 | break; |
| 165 | case "function": |
| 166 | // This allows for doing low-level actions, like hiding/showing UI elements. |
| 167 | onPress = mergeFunctions(function(){eval(option[2][action])}, onPress); |
| 168 | break; |
| 169 | default: |
| 170 | warn("Unknown option source type '" + action + "'"); |
| 171 | } |
| 172 | } |
| 173 | control.caption = caption; |
| 174 | control.onPress = onPress; |
| 175 | break; |
| 176 | default: |
| 177 | warn("Unknown option type '" + options[3] + "', assuming string. Valid types are 'number', 'string', or 'bool'."); |
| 178 | var control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]"); |
| 179 | break; |
| 180 | } |
| 181 | control.hidden = false; |
| 182 | control.tooltip = option[1]; |
| 183 | return control; |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Merge two functions which don't expect arguments. |
| 188 | * |
| 189 | * @return Merged function. |
| 190 | */ |
| 191 | function mergeFunctions(function1, function2) |
| 192 | { |
| 193 | return function() |
| 194 | { |
| 195 | function1.apply(this); |
| 196 | function2.apply(this); |
| 197 | }; |
| 198 | } |