1 /*
2
3 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 and the "Aleph One" developers.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 This license is contained in the file "COPYING",
17 which is included with this source code; it is available online at
18 http://www.gnu.org/licenses/gpl.html
19
20 Feb 5, 2002 (Br'fin (Jeremy Parsons)):
21 Default to keyboard and mouse control under Carbon
22 for there are no InputSprockets
23
24 Apr 30, 2002 (Loren Petrich):
25 Converting to a MML-based preferences system
26
27 May 16, 2002 (Woody Zenfell):
28 Added UI/preferences elements for configurable mouse sensitivity
29 Support for "don't auto-recenter" behavior modifier
30 Routines to let other code disable/reenable/query behavior modification
31
32 Jul 21, 2002 (Loren Petrich):
33 AS had added some code to fix the OSX preferences behavior;
34 I modified it so that it would not be used in the Classic version
35
36 Apr 10-22, 2003 (Woody Zenfell):
37 Join hinting and autogathering have Preferences entries now
38 Being less obnoxious with unrecognized Prefs stuff
39 Macintosh Enviroprefs popup style can be set in Preferences file
40
41 May 22, 2003 (Woody Zenfell):
42 Support for preferences for multiple network game protocols; configurable local game port.
43
44 May 27, 2003 (Gregory Smith):
45 Preferences for speex netmic
46
47 August 27, 2003 (Woody Zenfell):
48 Preferences for netscript. Some reworking of index-based Mac FSSpec reading along the way.
49 */
50
51 /*
52 * preferences.cpp - Preferences handling
53 */
54
55 #include "cseries.h"
56 #include "FileHandler.h"
57
58 #include "map.h"
59 #include "shell.h" /* For the screen_mode structure */
60 #include "interface.h"
61 #include "SoundManager.h"
62
63 #include "preferences.h"
64 #include "wad.h"
65 #include "wad_prefs.h"
66 #include "game_errors.h"
67 #include "network.h" // for _ethernet, etc.
68 #include "find_files.h"
69 #include "game_wad.h" // for set_map_file
70 #include "screen.h"
71 #include "fades.h"
72 #include "extensions.h"
73 #include "Console.h"
74 #include "Plugins.h"
75
76 #include "InfoTree.h"
77 #include "StarGameProtocol.h"
78 #include "RingGameProtocol.h"
79
80 #include "tags.h"
81 #include "Logging.h"
82
83 #include <string.h>
84 #include <stdlib.h>
85
86 #include "sdl_dialogs.h"
87 #include "sdl_fonts.h"
88 #include "sdl_widgets.h"
89 #include "images.h"
90 #include "preference_dialogs.h"
91 #include "preferences_widgets_sdl.h"
92 #include "mouse.h"
93
94 #include "Music.h"
95 #include "HTTP.h"
96 #include "alephversion.h"
97
98 #include <cmath>
99 #include <sstream>
100 #include <boost/algorithm/hex.hpp>
101
102 #ifdef HAVE_UNISTD_H
103 #include <unistd.h>
104 #endif
105
106 #ifdef __WIN32__
107 #include <windows.h> // for GetUserName()
108 #endif
109
110 #include "joystick.h"
111
112 // 8-bit support is still here if you undefine this, but you'll need to fix it
113 #define TRUE_COLOR_ONLY 1
114
115 using namespace alephone;
116
117 static const char sPasswordMask[] = "reverof nohtaram";
118
119 static const char* sNetworkGameProtocolNames[] =
120 { // These should match up with _network_game_protocol_ring, etc.
121 "ring",
122 "star"
123 };
124
125 static const size_t NUMBER_OF_NETWORK_GAME_PROTOCOL_NAMES = sizeof(sNetworkGameProtocolNames) / sizeof(sNetworkGameProtocolNames[0]);
126
127
128 // Have the prefs been inited?
129 static bool PrefsInited = false;
130
131
132 // Global preferences data
133 struct graphics_preferences_data *graphics_preferences = NULL;
134 struct network_preferences_data *network_preferences = NULL;
135 struct player_preferences_data *player_preferences = NULL;
136 struct input_preferences_data *input_preferences = NULL;
137 SoundManager::Parameters *sound_preferences = NULL;
138 struct environment_preferences_data *environment_preferences = NULL;
139
140 // LP: fake portable-files stuff
memory_error()141 inline short memory_error() {return 0;}
142
143 static bool ethernet_active(void);
144 static std::string get_name_from_system(void);
145
146 // LP: getting rid of the (void *) mechanism as inelegant and non-type-safe
147 static void default_graphics_preferences(graphics_preferences_data *preferences);
148 static bool validate_graphics_preferences(graphics_preferences_data *preferences);
149 static void default_network_preferences(network_preferences_data *preferences);
150 static bool validate_network_preferences(network_preferences_data *preferences);
151 static void default_player_preferences(player_preferences_data *preferences);
152 static bool validate_player_preferences(player_preferences_data *preferences);
153 static void default_input_preferences(input_preferences_data *preferences);
154 static bool validate_input_preferences(input_preferences_data *preferences);
155 static void default_environment_preferences(environment_preferences_data *preferences);
156 static bool validate_environment_preferences(environment_preferences_data *preferences);
157
158 void parse_graphics_preferences(InfoTree root, std::string version);
159 void parse_player_preferences(InfoTree root, std::string version);
160 void parse_input_preferences(InfoTree root, std::string version);
161 void parse_sound_preferences(InfoTree root, std::string version);
162 void parse_network_preferences(InfoTree root, std::string version);
163 void parse_environment_preferences(InfoTree root, std::string version);
164
165 // Prototypes
166 static void player_dialog(void *arg);
167 static void online_dialog(void *arg);
168 static void graphics_dialog(void *arg);
169 static void sound_dialog(void *arg);
170 static void controls_dialog(void *arg);
171 static void environment_dialog(void *arg);
172 static void plugins_dialog(void *arg);
173 static void keyboard_dialog(void *arg);
174 //static void texture_options_dialog(void *arg);
175
176 /*
177 * Get user name
178 */
179
get_name_from_system()180 static std::string get_name_from_system()
181 {
182 #if defined(unix) || (defined (__APPLE__) && defined (__MACH__)) || defined(__NetBSD__) || defined(__OpenBSD__)
183
184 const char *login_name = getlogin();
185 std::string login = (login_name ? login_name : "");
186 if (login.length())
187 return login;
188
189 #elif defined(__WIN32__)
190
191 char login[17];
192 DWORD len = 17;
193
194 bool hasName = (GetUserName((LPSTR)login, &len) == TRUE);
195 if (hasName && strpbrk(login, "\\/:*?\"<>|") == NULL) // Ignore illegal names
196 return login;
197
198 #else
199 //#error get_name_from_system() not implemented for this platform
200 #endif
201
202 return "Bob User";
203 }
204
205
206 /*
207 * Ethernet always available
208 */
209
ethernet_active(void)210 static bool ethernet_active(void)
211 {
212 return true;
213 }
214
215
216 /*
217 * Main preferences dialog
218 */
219
handle_preferences(void)220 void handle_preferences(void)
221 {
222 // Save the existing preferences, in case we have to reload them
223 write_preferences();
224
225 // Create top-level dialog
226 dialog d;
227 vertical_placer *placer = new vertical_placer;
228 w_title *w_header = new w_title("PREFERENCES");
229 d.add(w_header);
230 w_button *w_player = new w_button("PLAYER", player_dialog, &d);
231 d.add(w_player);
232 w_button *w_online = new w_button("INTERNET", online_dialog, &d);
233 d.add(w_online);
234 w_button *w_graphics = new w_button("GRAPHICS", graphics_dialog, &d);
235 d.add(w_graphics);
236 w_button *w_sound = new w_button("SOUND", sound_dialog, &d);
237 d.add(w_sound);
238 w_button *w_controls = new w_button("CONTROLS", controls_dialog, &d);
239 d.add(w_controls);
240 w_button *w_environment = new w_button("ENVIRONMENT", environment_dialog, &d);
241 d.add(w_environment);
242
243 w_button *w_return = new w_button("RETURN", dialog_cancel, &d);
244 d.add(w_return);
245
246 placer->add(w_header);
247 placer->add(new w_spacer, true);
248 placer->add(w_player);
249 placer->add(w_online);
250 placer->add(w_graphics);
251 placer->add(w_sound);
252 placer->add(w_controls);
253 placer->add(w_environment);
254 placer->add(new w_spacer, true);
255 placer->add(w_return);
256
257 d.set_widget_placer(placer);
258
259 // Clear menu screen
260 clear_screen();
261
262 // Run dialog
263 d.run();
264
265 // Redraw main menu
266 display_main_menu();
267 }
268
269 class CrosshairPref : public Bindable<int>
270 {
271 public:
CrosshairPref(short & pref)272 CrosshairPref(short& pref) : m_pref(pref) { }
273
bind_export()274 virtual int bind_export() {
275 return (m_pref - 1);
276 }
277
bind_import(int value)278 virtual void bind_import(int value) {
279 m_pref = value + 1;
280 }
281
282 protected:
283 short& m_pref;
284 };
285
286 class ColorComponentPref : public Bindable<int>
287 {
288 public:
ColorComponentPref(uint16 & pref)289 ColorComponentPref(uint16& pref) : m_pref(pref) { }
290
bind_export()291 virtual int bind_export() {
292 return (m_pref >> 12);
293 }
294
bind_import(int value)295 virtual void bind_import(int value) {
296 m_pref = value << 12;
297 }
298
299 protected:
300 uint16& m_pref;
301 };
302
303 class OpacityPref : public Bindable<int>
304 {
305 public:
OpacityPref(float & pref)306 OpacityPref(float& pref) : m_pref(pref) { }
307
bind_export()308 virtual int bind_export() {
309 return (static_cast<int>(floor(m_pref * 16)));
310 }
311
bind_import(int value)312 virtual void bind_import(int value) {
313 m_pref = ((float) value / 16.0);
314 }
315 protected:
316 float& m_pref;
317 };
318
319 static const char *shape_labels[3] = {
320 "Cross", "Octagon", NULL
321 };
322
323 enum { kCrosshairWidget };
324
325 static std::unique_ptr<BinderSet> crosshair_binders;
326
327 struct update_crosshair_display
328 {
operator ()update_crosshair_display329 void operator()(dialog *d) {
330 crosshair_binders->migrate_all_first_to_second();
331 }
332 };
333
334 class w_crosshair_slider : public w_slider {
335 public:
w_crosshair_slider(int num_items,int sel)336 w_crosshair_slider(int num_items, int sel) : w_slider(num_items, sel) {
337 init_formatted_value();
338 }
339
formatted_value(void)340 virtual std::string formatted_value(void) {
341 std::ostringstream ss;
342 ss << (selection + 1);
343 return ss.str();
344 }
345 };
346
crosshair_dialog(void * arg)347 static void crosshair_dialog(void *arg)
348 {
349 CrosshairData OldCrosshairs = player_preferences->Crosshairs;
350 crosshair_binders.reset(new BinderSet);
351
352 dialog *parent = (dialog *) arg;
353 (void)parent;
354
355 dialog d;
356 vertical_placer *placer = new vertical_placer;
357 w_title *w_header = new w_title("CROSSHAIR SETTINGS");
358 placer->dual_add(w_header, d);
359 placer->add(new w_spacer, true);
360
361 placer->dual_add(new w_static_text("HUD plugins may override these settings."), d);
362 placer->add(new w_spacer, true);
363
364 w_crosshair_display *crosshair_w = new w_crosshair_display();
365 placer->dual_add(crosshair_w, d);
366
367 placer->add(new w_spacer, true);
368
369 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET));
370 table->col_flags(0, placeable::kAlignRight);
371
372 // Shape
373 w_select *shape_w = new w_select(0, shape_labels);
374 SelectSelectorWidget shapeWidget(shape_w);
375 Int16Pref shapePref(player_preferences->Crosshairs.Shape);
376 crosshair_binders->insert<int> (&shapeWidget, &shapePref);
377 table->dual_add(shape_w->label("Shape"), d);
378 table->dual_add(shape_w, d);
379
380 table->add_row(new w_spacer(), true);
381
382 // Thickness
383 w_slider* thickness_w = new w_crosshair_slider(7, 0);
384 SliderSelectorWidget thicknessWidget(thickness_w);
385 CrosshairPref thicknessPref(player_preferences->Crosshairs.Thickness);
386 crosshair_binders->insert<int> (&thicknessWidget, &thicknessPref);
387 table->dual_add(thickness_w->label("Width"), d);
388 table->dual_add(thickness_w, d);
389
390 // From Center
391 w_slider *from_center_w = new w_slider(15, 0);
392 SliderSelectorWidget fromCenterWidget(from_center_w);
393 Int16Pref fromCenterPref(player_preferences->Crosshairs.FromCenter);
394 crosshair_binders->insert<int> (&fromCenterWidget, &fromCenterPref);
395 table->dual_add(from_center_w->label("Gap"), d);
396 table->dual_add(from_center_w, d);
397
398 // Length
399 w_slider *length_w = new w_crosshair_slider(15, 0);
400 SliderSelectorWidget lengthWidget(length_w);
401 CrosshairPref lengthPref(player_preferences->Crosshairs.Length);
402 crosshair_binders->insert<int> (&lengthWidget, &lengthPref);
403 table->dual_add(length_w->label("Size"), d);
404 table->dual_add(length_w, d);
405
406 table->add_row(new w_spacer(), true);
407 table->dual_add_row(new w_static_text("Color"), d);
408
409 // Color
410 w_slider *red_w = new w_percentage_slider(16, 0);
411 SliderSelectorWidget redWidget(red_w);
412 ColorComponentPref redPref(player_preferences->Crosshairs.Color.red);
413 crosshair_binders->insert<int> (&redWidget, &redPref);
414 table->dual_add(red_w->label("Red"), d);
415 table->dual_add(red_w, d);
416
417 w_slider *green_w = new w_percentage_slider(16, 0);
418 SliderSelectorWidget greenWidget(green_w);;
419 ColorComponentPref greenPref(player_preferences->Crosshairs.Color.green);
420 crosshair_binders->insert<int> (&greenWidget, &greenPref);
421 table->dual_add(green_w->label("Green"), d);
422 table->dual_add(green_w, d);
423
424 w_slider *blue_w = new w_percentage_slider(16, 0);
425 SliderSelectorWidget blueWidget(blue_w);
426 ColorComponentPref bluePref(player_preferences->Crosshairs.Color.blue);
427 crosshair_binders->insert<int> (&blueWidget, &bluePref);
428 table->dual_add(blue_w->label("Blue"), d);
429 table->dual_add(blue_w, d);
430
431 table->add_row(new w_spacer(), true);
432 table->dual_add_row(new w_static_text("OpenGL Only (no preview)"), d);
433
434 w_slider *opacity_w = new w_percentage_slider(16, 0);
435 SliderSelectorWidget opacityWidget(opacity_w);
436 OpacityPref opacityPref(player_preferences->Crosshairs.Opacity);
437 crosshair_binders->insert<int> (&opacityWidget, &opacityPref);
438 table->dual_add(opacity_w->label("Opacity"), d);
439 table->dual_add(opacity_w, d);
440
441 placer->add(table, true);
442 placer->add(new w_spacer, true);
443
444 horizontal_placer *button_placer = new horizontal_placer;
445 w_button *w_accept = new w_button("ACCEPT", dialog_ok, &d);
446 button_placer->dual_add(w_accept, d);
447 w_button *w_cancel = new w_button("CANCEL", dialog_cancel, &d);
448 button_placer->dual_add(w_cancel, d);
449 placer->add(button_placer, true);
450
451 d.set_widget_placer(placer);
452 d.set_processing_function(update_crosshair_display());
453
454 crosshair_binders->migrate_all_second_to_first();
455
456 clear_screen();
457
458 if (d.run() == 0) // Accepted
459 {
460 crosshair_binders->migrate_all_first_to_second();
461 player_preferences->Crosshairs.PreCalced = false;
462 write_preferences();
463 }
464 else
465 {
466 player_preferences->Crosshairs = OldCrosshairs;
467 }
468
469 crosshair_binders.reset(0);
470 }
471
472 /*
473 * Player dialog
474 */
475
476 enum {
477 NAME_W
478 };
479
player_dialog(void * arg)480 static void player_dialog(void *arg)
481 {
482 // Create dialog
483 dialog d;
484 vertical_placer *placer = new vertical_placer;
485 placer->dual_add(new w_title("PLAYER SETTINGS"), d);
486 placer->add(new w_spacer());
487
488 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
489 table->col_flags(0, placeable::kAlignRight);
490 table->col_flags(1, placeable::kAlignLeft);
491
492 w_select *level_w = new w_select(player_preferences->difficulty_level, NULL /*level_labels*/);
493 level_w->set_labels_stringset(kDifficultyLevelsStringSetID);
494 table->dual_add(level_w->label("Difficulty"), d);
495 table->dual_add(level_w, d);
496
497 table->add_row(new w_spacer(), true);
498
499 table->dual_add_row(new w_static_text("Appearance"), d);
500
501 w_text_entry *name_w = new w_text_entry(PREFERENCES_NAME_LENGTH, player_preferences->name);
502 name_w->set_identifier(NAME_W);
503 name_w->set_enter_pressed_callback(dialog_try_ok);
504 name_w->set_value_changed_callback(dialog_disable_ok_if_empty);
505 name_w->enable_mac_roman_input();
506 table->dual_add(name_w->label("Name"), d);
507 table->dual_add(name_w, d);
508
509 w_player_color *pcolor_w = new w_player_color(player_preferences->color);
510 table->dual_add(pcolor_w->label("Color"), d);
511 table->dual_add(pcolor_w, d);
512
513 w_player_color *tcolor_w = new w_player_color(player_preferences->team);
514 table->dual_add(tcolor_w->label("Team"), d);
515 table->dual_add(tcolor_w, d);
516
517 table->add_row(new w_spacer(), true);
518
519 w_toggle *crosshairs_active_w = new w_toggle(player_preferences->crosshairs_active);
520 table->dual_add(crosshairs_active_w->label("Show crosshairs"), d);
521 table->dual_add(crosshairs_active_w, d);
522
523 placer->add(table, true);
524
525 placer->add(new w_spacer(), true);
526
527 w_button *crosshair_button = new w_button("CROSSHAIR SETTINGS", crosshair_dialog, &d);
528 placer->dual_add(crosshair_button, d);
529
530 placer->add(new w_spacer(), true);
531
532 horizontal_placer *button_placer = new horizontal_placer;
533
534 w_button* ok_button = new w_button("ACCEPT", dialog_ok, &d);
535 ok_button->set_identifier(iOK);
536 button_placer->dual_add(ok_button, d);
537 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
538
539 placer->add(button_placer, true);
540
541 d.set_widget_placer(placer);
542
543 // Clear screen
544 clear_screen();
545
546 // Run dialog
547 if (d.run() == 0) { // Accepted
548 bool changed = false;
549
550 const char *name = name_w->get_text();
551 if (strcmp(name, player_preferences->name)) {
552 strncpy(player_preferences->name, name, PREFERENCES_NAME_LENGTH);
553 player_preferences->name[PREFERENCES_NAME_LENGTH] = '\0';
554 changed = true;
555 }
556
557 int16 level = static_cast<int16>(level_w->get_selection());
558 assert(level >= 0);
559 if (level != player_preferences->difficulty_level) {
560 player_preferences->difficulty_level = level;
561 changed = true;
562 }
563
564 int16 color = static_cast<int16>(pcolor_w->get_selection());
565 assert(color >= 0);
566 if (color != player_preferences->color) {
567 player_preferences->color = color;
568 changed = true;
569 }
570
571 int16 team = static_cast<int16>(tcolor_w->get_selection());
572 assert(team >= 0);
573 if (team != player_preferences->team) {
574 player_preferences->team = team;
575 changed = true;
576 }
577
578 bool crosshair = crosshairs_active_w->get_selection();
579 if (crosshair != player_preferences->crosshairs_active) {
580 player_preferences->crosshairs_active = crosshair;
581 changed = true;
582 }
583
584 if (changed)
585 write_preferences();
586 }
587 }
588
589 /*
590 * Online (lhowon.org) dialog
591 */
592
593 const int iONLINE_USERNAME_W = 10;
594 const int iONLINE_PASSWORD_W = 11;
595 const int iSIGNUP_EMAIL_W = 20;
596 const int iSIGNUP_USERNAME_W = 21;
597 const int iSIGNUP_PASSWORD_W = 22;
598
proc_account_link(void * arg)599 static void proc_account_link(void *arg)
600 {
601 dialog *d = static_cast<dialog *>(arg);
602
603 HTTPClient conn;
604 HTTPClient::parameter_map params;
605 w_text_entry *username_w = static_cast<w_text_entry *>(d->get_widget_by_id(iONLINE_USERNAME_W));
606 w_text_entry *password_w = static_cast<w_text_entry *>(d->get_widget_by_id(iONLINE_PASSWORD_W));
607
608 params["username"] = username_w->get_text();
609 params["password"] = password_w->get_text();
610 params["salt"] = "";
611
612 std::string url = A1_METASERVER_SETTINGS_URL;
613 if (conn.Post(A1_METASERVER_LOGIN_URL, params))
614 {
615 std::string token = boost::algorithm::hex(conn.Response());
616 url += "?token=" + token;
617 }
618
619 toggle_fullscreen(false);
620 launch_url_in_browser(url.c_str());
621 d->draw();
622 }
623
signup_dialog_ok(void * arg)624 static void signup_dialog_ok(void *arg)
625 {
626 dialog *d = static_cast<dialog *>(arg);
627 w_text_entry *email_w = static_cast<w_text_entry *>(d->get_widget_by_id(iSIGNUP_EMAIL_W));
628 w_text_entry *login_w = static_cast<w_text_entry *>(d->get_widget_by_id(iSIGNUP_USERNAME_W));
629 w_password_entry *password_w = static_cast<w_password_entry *>(d->get_widget_by_id(iSIGNUP_PASSWORD_W));
630
631 // check that fields are filled out
632 if (strlen(email_w->get_text()) == 0)
633 {
634 alert_user("Please enter your email address.", infoError);
635 }
636 else if (strlen(login_w->get_text()) == 0)
637 {
638 alert_user("Please enter a username.", infoError);
639 }
640 else if (strlen(password_w->get_text()) == 0)
641 {
642 alert_user("Please enter a password.", infoError);
643 }
644 else
645 {
646 // send parameters to server
647 HTTPClient conn;
648 HTTPClient::parameter_map params;
649 params["email"] = email_w->get_text();
650 params["username"] = login_w->get_text();
651 params["password"] = password_w->get_text();
652
653 if (conn.Post(A1_METASERVER_SIGNUP_URL, params))
654 {
655 if (conn.Response() == "OK")
656 {
657 // account was created successfully, save username and password
658 strncpy(network_preferences->metaserver_login, login_w->get_text(), network_preferences_data::kMetaserverLoginLength);
659 strncpy(network_preferences->metaserver_password, password_w->get_text(), network_preferences_data::kMetaserverLoginLength);
660 write_preferences();
661 d->quit(0);
662 }
663 else
664 {
665 alert_user(conn.Response().c_str(), infoError);
666 }
667 }
668 else
669 {
670 alert_user("There was a problem contacting the server.", infoError);
671 }
672 }
673 }
674
signup_dialog(void * arg)675 static void signup_dialog(void *arg)
676 {
677 dialog d;
678 vertical_placer *placer = new vertical_placer;
679 placer->dual_add(new w_title("ACCOUNT SIGN UP"), d);
680 placer->add(new w_spacer());
681
682 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
683 table->col_flags(0, placeable::kAlignRight);
684 table->col_flags(1, placeable::kAlignLeft);
685
686 w_text_entry *email_w = new w_text_entry(256, "");
687 email_w->set_identifier(iSIGNUP_EMAIL_W);
688 table->dual_add(email_w->label("Email Address"), d);
689 table->dual_add(email_w, d);
690
691 w_text_entry *login_w = new w_text_entry(network_preferences_data::kMetaserverLoginLength, network_preferences->metaserver_login);
692 login_w->set_identifier(iSIGNUP_USERNAME_W);
693 table->dual_add(login_w->label("Username"), d);
694 table->dual_add(login_w, d);
695
696 w_password_entry *password_w = new w_password_entry(network_preferences_data::kMetaserverLoginLength, network_preferences->metaserver_password);
697 password_w->set_identifier(iSIGNUP_PASSWORD_W);
698 table->dual_add(password_w->label("Password"), d);
699 table->dual_add(password_w, d);
700
701 table->add_row(new w_spacer(), true);
702 placer->add(table, true);
703
704 horizontal_placer *button_placer = new horizontal_placer;
705
706 w_button* ok_button = new w_button("SIGN UP", signup_dialog_ok, &d);
707 ok_button->set_identifier(iOK);
708 button_placer->dual_add(ok_button, d);
709 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
710
711 placer->add(button_placer, true);
712
713 d.set_widget_placer(placer);
714
715 clear_screen();
716
717 if (d.run() == 0)
718 {
719 // account was successfully created, update parent fields with new account info
720 dialog *parent = static_cast<dialog *>(arg);
721 w_text_entry *login_w = static_cast<w_text_entry *>(parent->get_widget_by_id(iONLINE_USERNAME_W));
722 login_w->set_text(network_preferences->metaserver_login);
723 w_password_entry *password_w = static_cast<w_password_entry *>(parent->get_widget_by_id(iONLINE_PASSWORD_W));
724 password_w->set_text(network_preferences->metaserver_password);
725 }
726 }
727
online_dialog(void * arg)728 static void online_dialog(void *arg)
729 {
730 // Create dialog
731 dialog d;
732 vertical_placer *placer = new vertical_placer;
733 placer->dual_add(new w_title("INTERNET GAME SETUP"), d);
734 placer->add(new w_spacer());
735
736 tab_placer* tabs = new tab_placer();
737
738 std::vector<std::string> labels;
739 labels.push_back("ACCOUNT");
740 labels.push_back("PREGAME LOBBY");
741 labels.push_back("STATS");
742 w_tab *tab_w = new w_tab(labels, tabs);
743
744 placer->dual_add(tab_w, d);
745 placer->add(new w_spacer(), true);
746
747 vertical_placer *account = new vertical_placer();
748 table_placer *account_table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
749 account_table->col_flags(0, placeable::kAlignRight);
750 account_table->col_flags(1, placeable::kAlignLeft);
751
752 w_text_entry *login_w = new w_text_entry(network_preferences_data::kMetaserverLoginLength, network_preferences->metaserver_login);
753 login_w->set_identifier(iONLINE_USERNAME_W);
754 account_table->dual_add(login_w->label("Username"), d);
755 account_table->dual_add(login_w, d);
756
757 w_password_entry *password_w = new w_password_entry(network_preferences_data::kMetaserverLoginLength, network_preferences->metaserver_password);
758 password_w->set_identifier(iONLINE_PASSWORD_W);
759 account_table->dual_add(password_w->label("Password"), d);
760 account_table->dual_add(password_w, d);
761
762 w_hyperlink *account_link_w = new w_hyperlink("", "Visit my lhowon.org account page");
763 account_link_w->set_callback(proc_account_link, &d);
764 account_table->dual_add_row(account_link_w, d);
765
766 account_table->add_row(new w_spacer(), true);
767
768 w_button *signup_button = new w_button("SIGN UP", signup_dialog, &d);
769 account_table->dual_add_row(signup_button, d);
770
771 account_table->add_row(new w_spacer(), true);
772
773 account->add(account_table, true);
774
775 vertical_placer *lobby = new vertical_placer();
776 table_placer *lobby_table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
777 lobby_table->col_flags(0, placeable::kAlignRight);
778 lobby_table->col_flags(1, placeable::kAlignLeft);
779
780 w_text_entry *name_w = new w_text_entry(PREFERENCES_NAME_LENGTH, player_preferences->name);
781 name_w->set_identifier(NAME_W);
782 name_w->set_enter_pressed_callback(dialog_try_ok);
783 name_w->set_value_changed_callback(dialog_disable_ok_if_empty);
784 name_w->enable_mac_roman_input();
785 lobby_table->dual_add(name_w->label("Name"), d);
786 lobby_table->dual_add(name_w, d);
787
788 w_enabling_toggle *custom_colors_w = new w_enabling_toggle(network_preferences->use_custom_metaserver_colors);
789 lobby_table->dual_add(custom_colors_w->label("Custom Chat Colors"), d);
790 lobby_table->dual_add(custom_colors_w, d);
791
792 w_color_picker *primary_w = new w_color_picker(network_preferences->metaserver_colors[0]);
793 lobby_table->dual_add(primary_w->label("Primary"), d);
794 lobby_table->dual_add(primary_w, d);
795
796 w_color_picker *secondary_w = new w_color_picker(network_preferences->metaserver_colors[1]);
797 lobby_table->dual_add(secondary_w->label("Secondary"), d);
798 lobby_table->dual_add(secondary_w, d);
799
800 custom_colors_w->add_dependent_widget(primary_w);
801 custom_colors_w->add_dependent_widget(secondary_w);
802
803 w_toggle *mute_guests_w = new w_toggle(network_preferences->mute_metaserver_guests);
804 lobby_table->dual_add(mute_guests_w->label("Mute All Guest Chat"), d);
805 lobby_table->dual_add(mute_guests_w, d);
806
807 lobby_table->add_row(new w_spacer(), true);
808
809 w_toggle *join_meta_w = new w_toggle(network_preferences->join_metaserver_by_default);
810 lobby_table->dual_add(join_meta_w->label("Join Pregame Lobby by Default"), d);
811 lobby_table->dual_add(join_meta_w, d);
812
813 lobby_table->add_row(new w_spacer(), true);
814
815 lobby->add(lobby_table, true);
816
817 vertical_placer *stats = new vertical_placer();
818 stats->dual_add(new w_hyperlink(A1_LEADERBOARD_URL, "Visit the leaderboards"), d);
819 stats->add(new w_spacer(), true);
820
821 horizontal_placer *stats_box = new horizontal_placer();
822
823 w_toggle *allow_stats_w = new w_toggle(network_preferences->allow_stats);
824 stats_box->dual_add(allow_stats_w, d);
825 stats_box->dual_add(allow_stats_w->label("Send Stats to Lhowon.org"), d);
826
827 stats->add(stats_box, true);
828 stats->add(new w_spacer(), true);
829
830 stats->dual_add(new w_static_text("To compete on the leaderboards,"), d);
831 stats->dual_add(new w_static_text("you need an online account, and a"), d);
832 stats->dual_add(new w_static_text("Stats plugin installed and enabled."), d);
833
834 stats->add(new w_spacer(), true);
835 stats->dual_add(new w_button("PLUGINS", plugins_dialog, &d), d);
836
837 stats->add(new w_spacer(), true);
838
839 tabs->add(account, true);
840 tabs->add(lobby, true);
841 tabs->add(stats, true);
842
843 placer->add(tabs, true);
844 placer->add(new w_spacer(), true);
845
846 horizontal_placer *button_placer = new horizontal_placer;
847
848 w_button* ok_button = new w_button("ACCEPT", dialog_ok, &d);
849 ok_button->set_identifier(iOK);
850 button_placer->dual_add(ok_button, d);
851 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
852
853 placer->add(button_placer, true);
854
855 d.set_widget_placer(placer);
856
857 // Clear screen
858 clear_screen();
859
860 // Run dialog
861 if (d.run() == 0) { // Accepted
862 bool changed = false;
863
864 const char *name = name_w->get_text();
865 if (strcmp(name, player_preferences->name)) {
866 strncpy(player_preferences->name, name, PREFERENCES_NAME_LENGTH);
867 player_preferences->name[PREFERENCES_NAME_LENGTH] = '\0';
868 changed = true;
869 }
870
871 const char *metaserver_login = login_w->get_text();
872 if (strcmp(metaserver_login, network_preferences->metaserver_login)) {
873 strncpy(network_preferences->metaserver_login, metaserver_login, network_preferences_data::kMetaserverLoginLength-1);
874 network_preferences->metaserver_login[network_preferences_data::kMetaserverLoginLength-1] = '\0';
875 changed = true;
876 }
877
878 // clear password if login has been cleared
879 if (!strlen(metaserver_login)) {
880 if (strlen(network_preferences->metaserver_password)) {
881 network_preferences->metaserver_password[0] = '\0';
882 changed = true;
883 }
884 } else {
885 const char *metaserver_password = password_w->get_text();
886 if (strcmp(metaserver_password, network_preferences->metaserver_password)) {
887 strncpy(network_preferences->metaserver_password, metaserver_password, network_preferences_data::kMetaserverLoginLength-1);
888 network_preferences->metaserver_password[network_preferences_data::kMetaserverLoginLength-1] = '\0';
889 changed = true;
890 }
891 }
892
893 bool use_custom_metaserver_colors = custom_colors_w->get_selection();
894 if (use_custom_metaserver_colors != network_preferences->use_custom_metaserver_colors)
895 {
896 network_preferences->use_custom_metaserver_colors = use_custom_metaserver_colors;
897 changed = true;
898 }
899
900 if (use_custom_metaserver_colors)
901 {
902 rgb_color primary_color = primary_w->get_selection();
903 if (primary_color.red != network_preferences->metaserver_colors[0].red || primary_color.green != network_preferences->metaserver_colors[0].green || primary_color.blue != network_preferences->metaserver_colors[0].blue)
904 {
905 network_preferences->metaserver_colors[0] = primary_color;
906 changed = true;
907 }
908
909 rgb_color secondary_color = secondary_w->get_selection();
910 if (secondary_color.red != network_preferences->metaserver_colors[1].red || secondary_color.green != network_preferences->metaserver_colors[1].green || secondary_color.blue != network_preferences->metaserver_colors[1].blue) {
911 network_preferences->metaserver_colors[1] = secondary_color;
912 changed = true;
913 }
914
915 }
916
917 bool mute_metaserver_guests = mute_guests_w->get_selection() == 1;
918 if (mute_metaserver_guests != network_preferences->mute_metaserver_guests)
919 {
920 network_preferences->mute_metaserver_guests = mute_metaserver_guests;
921 changed = true;
922 }
923
924 bool join_meta = join_meta_w->get_selection() == 1;
925 if (join_meta != network_preferences->join_metaserver_by_default)
926 {
927 network_preferences->join_metaserver_by_default = join_meta;
928 changed = true;
929 }
930
931 bool allow_stats = allow_stats_w->get_selection() == 1;
932 if (allow_stats != network_preferences->allow_stats)
933 {
934 network_preferences->allow_stats = allow_stats;
935 Plugins::instance()->invalidate();
936 changed = true;
937 }
938
939
940 if (changed)
941 write_preferences();
942 }
943 }
944
945 /*
946 * Handle graphics dialog
947 */
948
949 #ifdef TRUE_COLOR_ONLY
950 static const char* depth_labels[3] = {
951 "16 Bit", "32 Bit", NULL
952 };
953 #else
954 static const char *depth_labels[4] = {
955 "8 Bit", "16 Bit", "32 Bit", NULL
956 };
957 #endif
958
959 static const char *resolution_labels[3] = {
960 "Low", "High", NULL
961 };
962
963 static const char *sw_alpha_blending_labels[4] = {
964 "Off", "Fast", "Nice", NULL
965 };
966
967 static const char *sw_sdl_driver_labels[5] = {
968 "Default", "None", "Direct3D", "OpenGL", NULL
969 };
970
971 static const char *gamma_labels[9] = {
972 "Darkest", "Darker", "Dark", "Normal", "Light", "Really Light", "Even Lighter", "Lightest", NULL
973 };
974
975 static const char* renderer_labels[] = {
976 "Software", "OpenGL", NULL
977 };
978
979 static const char* hud_scale_labels[] = {
980 "Normal", "Double", "Largest", NULL
981 };
982
983 static const char* term_scale_labels[] = {
984 "Normal", "Double", "Largest", NULL
985 };
986
987 static const char* mouse_accel_labels[] = {
988 "Off", "Classic", NULL
989 };
990
991 static const char* max_saves_labels[] = {
992 "20", "100", "500", "Unlimited", NULL
993 };
994 static const uint32 max_saves_values[] = {
995 20, 100, 500, 0
996 };
997
998
999 enum {
1000 iRENDERING_SYSTEM = 1000
1001 };
1002
build_stringvector_from_cstring_array(const char ** label_array)1003 static const vector<string> build_stringvector_from_cstring_array (const char** label_array)
1004 {
1005 std::vector<std::string> label_vector;
1006 for (int i = 0; label_array[i] != NULL; ++i)
1007 label_vector.push_back(std::string(label_array[i]));
1008
1009 return label_vector;
1010 }
1011
1012
software_rendering_options_dialog(void * arg)1013 static void software_rendering_options_dialog(void* arg)
1014 {
1015 // Create dialog
1016 dialog d;
1017 vertical_placer *placer = new vertical_placer;
1018 placer->dual_add(new w_title("SOFTWARE RENDERING OPTIONS"), d);
1019 placer->add(new w_spacer(), true);
1020
1021 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1022 table->col_flags(0, placeable::kAlignRight);
1023
1024 #ifdef TRUE_COLOR_ONLY
1025 w_select *depth_w = new w_select(graphics_preferences->screen_mode.bit_depth == 16 ? 0 : 1, depth_labels);
1026 #else
1027 w_select *depth_w = new w_select(graphics_preferences->screen_mode.bit_depth == 8 ? 0 : graphics_preferences->screen_mode.bit_depth == 16 ? 1 : 2, depth_labels);
1028 #endif
1029 table->dual_add(depth_w->label("Color Depth"), d);
1030 table->dual_add(depth_w, d);
1031
1032 w_toggle *resolution_w = new w_toggle(graphics_preferences->screen_mode.high_resolution, resolution_labels);
1033 table->dual_add(resolution_w->label("Resolution"), d);
1034 table->dual_add(resolution_w, d);
1035
1036 table->add_row(new w_spacer(), true);
1037
1038 w_select *sw_alpha_blending_w = new w_select(graphics_preferences->software_alpha_blending, sw_alpha_blending_labels);
1039 table->dual_add(sw_alpha_blending_w->label("Transparent Liquids"), d);
1040 table->dual_add(sw_alpha_blending_w, d);
1041
1042 w_select *sw_driver_w = new w_select(graphics_preferences->software_sdl_driver, sw_sdl_driver_labels);
1043 table->dual_add(sw_driver_w->label("Acceleration"), d);
1044 table->dual_add(sw_driver_w, d);
1045
1046 placer->add(table, true);
1047
1048 placer->add(new w_spacer(), true);
1049 horizontal_placer *button_placer = new horizontal_placer;
1050 button_placer->dual_add(new w_button("ACCEPT", dialog_ok, &d), d);
1051 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
1052 placer->add(button_placer, true);
1053
1054 d.set_widget_placer(placer);
1055 // Clear screen
1056 clear_screen();
1057
1058 // Run dialog
1059 if (d.run() == 0) { // Accepted
1060 bool changed = false;
1061
1062 #ifdef TRUE_COLOR_ONLY
1063 int depth = (depth_w->get_selection() == 0 ? 16 : 32);
1064 #else
1065 int depth = (depth_w->get_selection() == 0 ? 8 : depth_w->get_selection() == 1 ? 16 : 32);
1066 #endif
1067 if (depth != graphics_preferences->screen_mode.bit_depth) {
1068 graphics_preferences->screen_mode.bit_depth = depth;
1069 changed = true;
1070 // don't change mode now; it will be changed when the game starts
1071 }
1072
1073 bool hi_res = resolution_w->get_selection() != 0;
1074 if (hi_res != graphics_preferences->screen_mode.high_resolution) {
1075 graphics_preferences->screen_mode.high_resolution = hi_res;
1076 changed = true;
1077 }
1078
1079 if (sw_alpha_blending_w->get_selection() != graphics_preferences->software_alpha_blending)
1080 {
1081 graphics_preferences->software_alpha_blending = sw_alpha_blending_w->get_selection();
1082 changed = true;
1083 }
1084
1085 if (sw_driver_w->get_selection() != graphics_preferences->software_sdl_driver)
1086 {
1087 graphics_preferences->software_sdl_driver = sw_driver_w->get_selection();
1088 changed = true;
1089 }
1090
1091 if (changed)
1092 write_preferences();
1093 }
1094 }
1095
1096 // ZZZ addition: bounce to correct renderer-config box based on selected rendering system.
rendering_options_dialog_demux(void * arg)1097 static void rendering_options_dialog_demux(void* arg)
1098 {
1099 int theSelectedRenderer = get_selection_control_value((dialog*) arg, iRENDERING_SYSTEM) - 1;
1100
1101 switch(theSelectedRenderer) {
1102 case _no_acceleration:
1103 software_rendering_options_dialog(arg);
1104 break;
1105
1106 case _opengl_acceleration:
1107 OpenGLDialog::Create (theSelectedRenderer)->OpenGLPrefsByRunning ();
1108 break;
1109
1110 default:
1111 assert(false);
1112 break;
1113 }
1114 }
1115
build_resolution_labels()1116 std::vector<std::string> build_resolution_labels()
1117 {
1118 std::vector<std::string> result;
1119 bool first_mode = true;
1120 for (std::vector<std::pair<int, int> >::const_iterator it = Screen::instance()->GetModes().begin(); it != Screen::instance()->GetModes().end(); ++it)
1121 {
1122 std::ostringstream os;
1123 os << it->first << "x" << it->second;
1124 if (first_mode)
1125 {
1126 result.push_back("Automatic");
1127 first_mode = false;
1128 }
1129 result.push_back(os.str());
1130 }
1131
1132 return result;
1133 }
1134
graphics_dialog(void * arg)1135 static void graphics_dialog(void *arg)
1136 {
1137 dialog *parent = (dialog *)arg;
1138
1139 // Create dialog
1140 dialog d;
1141
1142 vertical_placer *placer = new vertical_placer;
1143 placer->dual_add(new w_title("GRAPHICS SETUP"), d);
1144 placer->add(new w_spacer(), true);
1145
1146 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1147 table->col_flags(0, placeable::kAlignRight);
1148
1149 w_select* renderer_w = new w_select(graphics_preferences->screen_mode.acceleration, renderer_labels);
1150 renderer_w->set_identifier(iRENDERING_SYSTEM);
1151 #ifndef HAVE_OPENGL
1152 renderer_w->set_selection(_no_acceleration);
1153 renderer_w->set_enabled(false);
1154 #endif
1155 table->dual_add(renderer_w->label("Rendering System"), d);
1156 table->dual_add(renderer_w, d);
1157
1158 w_select_popup *size_w = new w_select_popup();
1159 size_w->set_labels(build_resolution_labels());
1160 if (graphics_preferences->screen_mode.auto_resolution)
1161 size_w->set_selection(0);
1162 else
1163 size_w->set_selection(Screen::instance()->FindMode(graphics_preferences->screen_mode.width, graphics_preferences->screen_mode.height) + 1);
1164 table->dual_add(size_w->label("Screen Size"), d);
1165 table->dual_add(size_w, d);
1166
1167 w_toggle *high_dpi_w = NULL;
1168 high_dpi_w = new w_toggle(graphics_preferences->screen_mode.high_dpi);
1169 #if (defined(__APPLE__) && defined(__MACH__))
1170 // SDL's DPI support only enabled on macOS
1171 table->dual_add(high_dpi_w->label("Use High DPI"), d);
1172 table->dual_add(high_dpi_w, d);
1173 #endif
1174
1175 w_toggle *fixh_w = new w_toggle(!graphics_preferences->screen_mode.fix_h_not_v);
1176 table->dual_add(fixh_w->label("Limit Vertical View"), d);
1177 table->dual_add(fixh_w, d);
1178
1179 w_toggle *bob_w = new w_toggle(graphics_preferences->screen_mode.camera_bob);
1180 table->dual_add(bob_w->label("Camera Bobbing"), d);
1181 table->dual_add(bob_w, d);
1182
1183 w_select_popup *gamma_w = new w_select_popup();
1184 gamma_w->set_labels(build_stringvector_from_cstring_array(gamma_labels));
1185 gamma_w->set_selection(graphics_preferences->screen_mode.gamma_level);
1186 table->dual_add(gamma_w->label("Brightness"), d);
1187 table->dual_add(gamma_w, d);
1188
1189 table->add_row(new w_spacer(), true);
1190
1191 w_toggle *fullscreen_w = new w_toggle(!graphics_preferences->screen_mode.fullscreen);
1192 table->dual_add(fullscreen_w->label("Windowed Mode"), d);
1193 table->dual_add(fullscreen_w, d);
1194
1195 table->add_row(new w_spacer(), true);
1196 table->dual_add_row(new w_static_text("Heads-Up Display"), d);
1197 w_enabling_toggle *hud_w = new w_enabling_toggle(graphics_preferences->screen_mode.hud);
1198 table->dual_add(hud_w->label("Show HUD"), d);
1199 table->dual_add(hud_w, d);
1200
1201 w_select_popup *hud_scale_w = new w_select_popup();
1202 hud_scale_w->set_labels(build_stringvector_from_cstring_array(hud_scale_labels));
1203 hud_scale_w->set_selection(graphics_preferences->screen_mode.hud_scale_level);
1204 table->dual_add(hud_scale_w->label("HUD Size"), d);
1205 table->dual_add(hud_scale_w, d);
1206 hud_w->add_dependent_widget(hud_scale_w);
1207
1208 w_select_popup *term_scale_w = new w_select_popup();
1209 term_scale_w->set_labels(build_stringvector_from_cstring_array(term_scale_labels));
1210 term_scale_w->set_selection(graphics_preferences->screen_mode.term_scale_level);
1211 table->dual_add(term_scale_w->label("Terminal Size"), d);
1212 table->dual_add(term_scale_w, d);
1213
1214 w_toggle *map_w = new w_toggle(graphics_preferences->screen_mode.translucent_map);
1215 table->dual_add(map_w->label("Overlay Map"), d);
1216 table->dual_add(map_w, d);
1217
1218 placer->add(table, true);
1219
1220 placer->add(new w_spacer(), true);
1221 placer->dual_add(new w_button("RENDERING OPTIONS", rendering_options_dialog_demux, &d), d);
1222 placer->add(new w_spacer(), true);
1223
1224 #ifndef HAVE_OPENGL
1225 expand_app_variables(temporary, "This copy of $appName$ was built without OpenGL support.");
1226 placer->dual_add(new w_static_text(temporary), d);
1227 #endif
1228 placer->add(new w_spacer(), true);
1229
1230 horizontal_placer *button_placer = new horizontal_placer;
1231 button_placer->dual_add(new w_button("ACCEPT", dialog_ok, &d), d);
1232 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
1233
1234 placer->add(button_placer, true);
1235
1236 d.set_widget_placer(placer);
1237
1238 // Clear screen
1239 clear_screen();
1240
1241 // Run dialog
1242 if (d.run() == 0) { // Accepted
1243 bool changed = false;
1244
1245 bool fullscreen = fullscreen_w->get_selection() == 0;
1246 if (fullscreen != graphics_preferences->screen_mode.fullscreen) {
1247 graphics_preferences->screen_mode.fullscreen = fullscreen;
1248 changed = true;
1249 }
1250
1251 short renderer = static_cast<short>(renderer_w->get_selection());
1252 assert(renderer >= 0);
1253 if(renderer != graphics_preferences->screen_mode.acceleration) {
1254 graphics_preferences->screen_mode.acceleration = renderer;
1255 if (renderer) graphics_preferences->screen_mode.bit_depth = 32;
1256 changed = true;
1257 }
1258
1259 short resolution = static_cast<short>(size_w->get_selection());
1260 if (resolution == 0)
1261 {
1262 if (!graphics_preferences->screen_mode.auto_resolution) {
1263 graphics_preferences->screen_mode.auto_resolution = true;
1264 changed = true;
1265 }
1266 }
1267 else if (Screen::instance()->ModeWidth(resolution - 1) != graphics_preferences->screen_mode.width || Screen::instance()->ModeHeight(resolution - 1) != graphics_preferences->screen_mode.height || graphics_preferences->screen_mode.auto_resolution)
1268 {
1269 graphics_preferences->screen_mode.width = Screen::instance()->ModeWidth(resolution - 1);
1270 graphics_preferences->screen_mode.height = Screen::instance()->ModeHeight(resolution - 1);
1271 graphics_preferences->screen_mode.auto_resolution = false;
1272 changed = true;
1273 }
1274
1275 bool high_dpi = high_dpi_w->get_selection() != 0;
1276 if (high_dpi != graphics_preferences->screen_mode.high_dpi) {
1277 graphics_preferences->screen_mode.high_dpi = high_dpi;
1278 changed = true;
1279 }
1280
1281 short gamma = static_cast<short>(gamma_w->get_selection());
1282 if (gamma != graphics_preferences->screen_mode.gamma_level) {
1283 graphics_preferences->screen_mode.gamma_level = gamma;
1284 changed = true;
1285 }
1286
1287 bool fix_h_not_v = fixh_w->get_selection() == 0;
1288 if (fix_h_not_v != graphics_preferences->screen_mode.fix_h_not_v) {
1289 graphics_preferences->screen_mode.fix_h_not_v = fix_h_not_v;
1290 changed = true;
1291 }
1292
1293 bool hud = hud_w->get_selection() != 0;
1294 if (hud != graphics_preferences->screen_mode.hud)
1295 {
1296 graphics_preferences->screen_mode.hud = hud;
1297 changed = true;
1298 }
1299
1300 short hud_scale = static_cast<short>(hud_scale_w->get_selection());
1301 if (hud_scale != graphics_preferences->screen_mode.hud_scale_level)
1302 {
1303 graphics_preferences->screen_mode.hud_scale_level = hud_scale;
1304 changed = true;
1305 }
1306
1307 short term_scale = static_cast<short>(term_scale_w->get_selection());
1308 if (term_scale != graphics_preferences->screen_mode.term_scale_level)
1309 {
1310 graphics_preferences->screen_mode.term_scale_level = term_scale;
1311 changed = true;
1312 }
1313
1314 bool translucent_map = map_w->get_selection() != 0;
1315 if (translucent_map != graphics_preferences->screen_mode.translucent_map) {
1316 graphics_preferences->screen_mode.translucent_map = translucent_map;
1317 changed = true;
1318 }
1319
1320 bool camera_bob = bob_w->get_selection() != 0;
1321 if (camera_bob != graphics_preferences->screen_mode.camera_bob) {
1322 graphics_preferences->screen_mode.camera_bob = camera_bob;
1323 changed = true;
1324 }
1325
1326 if (changed) {
1327 write_preferences();
1328 change_screen_mode(&graphics_preferences->screen_mode, true);
1329 clear_screen(true);
1330 parent->layout();
1331 parent->draw(); // DirectX seems to need this
1332 }
1333 }
1334 }
1335
1336 /*
1337 * Sound dialog
1338 */
1339
1340 class w_toggle *stereo_w, *dynamic_w;
1341
1342 class w_stereo_toggle : public w_toggle {
1343 public:
w_stereo_toggle(bool selection)1344 w_stereo_toggle(bool selection) : w_toggle(selection) {}
1345
selection_changed(void)1346 void selection_changed(void)
1347 {
1348 // Turning off stereo turns off dynamic tracking
1349 w_toggle::selection_changed();
1350 if (selection == false)
1351 dynamic_w->set_selection(false);
1352 }
1353 };
1354
1355 class w_dynamic_toggle : public w_toggle {
1356 public:
w_dynamic_toggle(bool selection)1357 w_dynamic_toggle(bool selection) : w_toggle(selection) {}
1358
selection_changed(void)1359 void selection_changed(void)
1360 {
1361 // Turning on dynamic tracking turns on stereo
1362 w_toggle::selection_changed();
1363 if (selection == true)
1364 stereo_w->set_selection(true);
1365 }
1366 };
1367
1368 static const char *channel_labels[] = {"1", "2", "4", "8", "16", "32", NULL};
1369
1370 class w_volume_slider : public w_percentage_slider {
1371 public:
w_volume_slider(int vol)1372 w_volume_slider(int vol) : w_percentage_slider(NUMBER_OF_SOUND_VOLUME_LEVELS, vol) {}
~w_volume_slider()1373 ~w_volume_slider() {}
1374
item_selected(void)1375 void item_selected(void)
1376 {
1377 SoundManager::instance()->TestVolume(selection, _snd_adjust_volume);
1378 }
1379 };
1380
sound_dialog(void * arg)1381 static void sound_dialog(void *arg)
1382 {
1383 // Create dialog
1384 dialog d;
1385 vertical_placer *placer = new vertical_placer;
1386 placer->dual_add(new w_title("SOUND SETUP"), d);
1387 placer->add(new w_spacer(), true);
1388
1389 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1390 table->col_flags(0, placeable::kAlignRight);
1391
1392 static const char *quality_labels[3] = {"8 Bit", "16 Bit", NULL};
1393 w_toggle *quality_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _16bit_sound_flag), quality_labels);
1394 table->dual_add(quality_w->label("Quality"), d);
1395 table->dual_add(quality_w, d);
1396
1397 stereo_w = new w_stereo_toggle(sound_preferences->flags & _stereo_flag);
1398 table->dual_add(stereo_w->label("Stereo"), d);
1399 table->dual_add(stereo_w, d);
1400
1401 dynamic_w = new w_dynamic_toggle(TEST_FLAG(sound_preferences->flags, _dynamic_tracking_flag));
1402 table->dual_add(dynamic_w->label("Active Panning"), d);
1403 table->dual_add(dynamic_w, d);
1404
1405 w_toggle *ambient_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _ambient_sound_flag));
1406 table->dual_add(ambient_w->label("Ambient Sounds"), d);
1407 table->dual_add(ambient_w, d);
1408
1409 w_toggle *more_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _more_sounds_flag));
1410 table->dual_add(more_w->label("More Sounds"), d);
1411 table->dual_add(more_w, d);
1412
1413 w_toggle *button_sounds_w = new w_toggle(TEST_FLAG(input_preferences->modifiers, _inputmod_use_button_sounds));
1414 table->dual_add(button_sounds_w->label("Interface Button Sounds"), d);
1415 table->dual_add(button_sounds_w, d);
1416
1417 w_select *channels_w = new w_select(static_cast<int>(std::floor(std::log(static_cast<float>(sound_preferences->channel_count)) / std::log(2.0) + 0.5)), channel_labels);
1418 table->dual_add(channels_w->label("Channels"), d);
1419 table->dual_add(channels_w, d);
1420
1421 w_volume_slider *volume_w = new w_volume_slider(sound_preferences->volume);
1422 table->dual_add(volume_w->label("Volume"), d);
1423 table->dual_add(volume_w, d);
1424
1425 w_slider *music_volume_w = new w_percentage_slider(NUMBER_OF_SOUND_VOLUME_LEVELS, sound_preferences->music);
1426 table->dual_add(music_volume_w->label("Music Volume"), d);
1427 table->dual_add(music_volume_w, d);
1428
1429
1430 table->add_row(new w_spacer(), true);
1431 table->dual_add_row(new w_static_text("Network Microphone"), d);
1432
1433 w_toggle* mute_while_transmitting_w = new w_toggle(!sound_preferences->mute_while_transmitting);
1434 table->dual_add(mute_while_transmitting_w->label("Headset Mic Mode"), d);
1435 table->dual_add(mute_while_transmitting_w, d);
1436
1437 table->add_row(new w_spacer(), true);
1438 table->dual_add_row(new w_static_text("Experimental Sound Options"), d);
1439 w_toggle *zrd_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _zero_restart_delay));
1440 table->dual_add(zrd_w->label("Zero Restart Delay"), d);
1441 table->dual_add(zrd_w, d);
1442
1443 placer->add(table, true);
1444
1445 placer->add(new w_spacer(), true);
1446
1447 horizontal_placer *button_placer = new horizontal_placer;
1448 button_placer->dual_add(new w_button("ACCEPT", dialog_ok, &d), d);
1449 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
1450
1451 placer->add(button_placer, true);
1452
1453 d.set_widget_placer(placer);
1454 // Clear screen
1455 clear_screen();
1456
1457 // Run dialog
1458 if (d.run() == 0) { // Accepted
1459 bool changed = false;
1460
1461 uint16 flags = 0;
1462 if (quality_w->get_selection()) flags |= _16bit_sound_flag;
1463 if (stereo_w->get_selection()) flags |= _stereo_flag;
1464 if (dynamic_w->get_selection()) flags |= _dynamic_tracking_flag;
1465 if (ambient_w->get_selection()) flags |= _ambient_sound_flag;
1466 if (more_w->get_selection()) flags |= _more_sounds_flag;
1467 if (zrd_w->get_selection()) flags |= _zero_restart_delay;
1468
1469 if (flags != sound_preferences->flags) {
1470 sound_preferences->flags = flags;
1471 changed = true;
1472 }
1473
1474 flags = input_preferences->modifiers & ~_inputmod_use_button_sounds;
1475 if (button_sounds_w->get_selection()) flags |= _inputmod_use_button_sounds;
1476 if (flags != input_preferences->modifiers) {
1477 input_preferences->modifiers = flags;
1478 changed = true;
1479 }
1480
1481 int16 channel_count = 1 << (channels_w->get_selection() == UNONE ? 1 : channels_w->get_selection());
1482 if (channel_count != sound_preferences->channel_count) {
1483 sound_preferences->channel_count = channel_count;
1484 changed = true;
1485 }
1486
1487 int volume = volume_w->get_selection();
1488 if (volume != sound_preferences->volume) {
1489 sound_preferences->volume = volume;
1490 changed = true;
1491 }
1492
1493 int music_volume = music_volume_w->get_selection();
1494 if (music_volume != sound_preferences->music) {
1495 sound_preferences->music = music_volume;
1496 changed = true;
1497 }
1498
1499 bool mute_while_transmitting = !mute_while_transmitting_w->get_selection();
1500 if (mute_while_transmitting != sound_preferences->mute_while_transmitting)
1501 {
1502 sound_preferences->mute_while_transmitting = mute_while_transmitting;
1503 changed = true;
1504 }
1505
1506 if (changed) {
1507 // set_sound_manager_parameters(sound_preferences);
1508 SoundManager::instance()->SetParameters(*sound_preferences);
1509 write_preferences();
1510 }
1511 }
1512 }
1513
1514
1515 /*
1516 * Controls dialog
1517 */
1518
1519 const float kMinSensitivityLog = -3.0f;
1520 const float kMaxSensitivityLog = 3.0f;
1521 const float kSensitivityLogRange = kMaxSensitivityLog - kMinSensitivityLog;
1522
1523 class w_sens_slider : public w_slider {
1524 public:
w_sens_slider(int num_items,int sel)1525 w_sens_slider(int num_items, int sel) : w_slider(num_items, sel) {
1526 init_formatted_value();
1527 }
1528
formatted_value(void)1529 virtual std::string formatted_value(void) {
1530 std::ostringstream ss;
1531 float val = std::exp(selection * kSensitivityLogRange / 1000.0f + kMinSensitivityLog);
1532 if (val >= 1.f)
1533 ss.precision(4);
1534 else if (val >= 0.1f)
1535 ss.precision(3);
1536 else if (val >= 0.01f)
1537 ss.precision(2);
1538 else
1539 ss.precision(1);
1540 ss << std::showpoint << val;
1541 return ss.str();
1542 }
1543 };
1544
1545 class w_deadzone_slider : public w_slider {
1546 public:
w_deadzone_slider(int num_items,int sel)1547 w_deadzone_slider(int num_items, int sel) : w_slider(num_items, sel) {
1548 init_formatted_value();
1549 }
1550
formatted_value(void)1551 virtual std::string formatted_value(void) {
1552 std::ostringstream ss;
1553 ss << selection << "%";
1554 return ss.str();
1555 }
1556 };
1557
1558
1559 const int NUM_KEYS = 21;
1560
1561 static const char *action_name[NUM_KEYS] = {
1562 "Move Forward", "Move Backward", "Turn Left", "Turn Right", "Sidestep Left", "Sidestep Right",
1563 "Glance Left", "Glance Right", "Look Up", "Look Down", "Recenter View",
1564 "Previous Weapon", "Next Weapon", "Trigger", "2nd Trigger",
1565 "Turn -> Sidestep", "Run/Swim", "Move -> Look",
1566 "Action", "Auto Map", "Microphone"
1567 };
1568
1569 static key_binding_map default_key_bindings = {
1570 { 0, { SDL_SCANCODE_W,
1571 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_NEGATIVE + SDL_CONTROLLER_AXIS_LEFTY)
1572 } },
1573 { 1, { SDL_SCANCODE_S,
1574 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_POSITIVE + SDL_CONTROLLER_AXIS_LEFTY)
1575 } },
1576 { 2, { SDL_SCANCODE_LEFT,
1577 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_NEGATIVE + SDL_CONTROLLER_AXIS_RIGHTX)
1578 } },
1579 { 3, { SDL_SCANCODE_RIGHT,
1580 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_POSITIVE + SDL_CONTROLLER_AXIS_RIGHTX)
1581 } },
1582 { 4, { SDL_SCANCODE_A,
1583 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_NEGATIVE + SDL_CONTROLLER_AXIS_LEFTX)
1584 } },
1585 { 5, { SDL_SCANCODE_D,
1586 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_POSITIVE + SDL_CONTROLLER_AXIS_LEFTX)
1587 } },
1588 { 6, { SDL_SCANCODE_Q,
1589 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_DPAD_LEFT)
1590 } },
1591 { 7, { SDL_SCANCODE_E,
1592 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_DPAD_RIGHT)
1593 } },
1594 { 8, { SDL_SCANCODE_UP,
1595 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_NEGATIVE + SDL_CONTROLLER_AXIS_RIGHTY)
1596 } },
1597 { 9, { SDL_SCANCODE_DOWN,
1598 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_POSITIVE + SDL_CONTROLLER_AXIS_RIGHTY)
1599 } },
1600 { 10, { SDL_SCANCODE_V,
1601 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_RIGHTSTICK)
1602 } },
1603 { 11, { SDL_SCANCODE_F,
1604 static_cast<SDL_Scancode>(AO_SCANCODE_MOUSESCROLL_UP),
1605 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
1606 } },
1607 { 12, { SDL_SCANCODE_R,
1608 static_cast<SDL_Scancode>(AO_SCANCODE_MOUSESCROLL_DOWN),
1609 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)
1610 } },
1611 { 13, { SDL_SCANCODE_SPACE,
1612 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_MOUSE_BUTTON + SDL_BUTTON_LEFT - 1),
1613 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_POSITIVE + SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
1614 } },
1615 { 14, { SDL_SCANCODE_LSHIFT,
1616 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_MOUSE_BUTTON + SDL_BUTTON_RIGHT - 1),
1617 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_AXIS_POSITIVE + SDL_CONTROLLER_AXIS_TRIGGERLEFT)
1618 } },
1619 { 15, { SDL_SCANCODE_LALT
1620 } },
1621 { 16, { SDL_SCANCODE_LCTRL,
1622 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_LEFTSTICK)
1623 } },
1624 { 17, { SDL_SCANCODE_LGUI
1625 } },
1626 { 18, { SDL_SCANCODE_TAB,
1627 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_A)
1628 } },
1629 { 19, { SDL_SCANCODE_M,
1630 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_X)
1631 } },
1632 { 20, { SDL_SCANCODE_GRAVE,
1633 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_Y)
1634 } },
1635 };
1636
1637 static const char *shell_action_name[NUMBER_OF_SHELL_KEYS] = {
1638 "Inventory Left", "Inventory Right", "Switch Player View", "Volume Up", "Volume Down", "Zoom Map In", "Zoom Map Out", "Toggle FPS", "Chat/Console", "Network Stats"
1639 };
1640
1641 static key_binding_map default_shell_key_bindings = {
1642 { 0, { SDL_SCANCODE_LEFTBRACKET
1643 } },
1644 { 1, { SDL_SCANCODE_RIGHTBRACKET
1645 } },
1646 { 2, { SDL_SCANCODE_BACKSPACE
1647 } },
1648 { 3, { SDL_SCANCODE_PERIOD
1649 } },
1650 { 4, { SDL_SCANCODE_COMMA
1651 } },
1652 { 5, { SDL_SCANCODE_EQUALS,
1653 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_DPAD_UP)
1654 } },
1655 { 6, { SDL_SCANCODE_MINUS,
1656 static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + SDL_CONTROLLER_BUTTON_DPAD_DOWN)
1657 } },
1658 { 7, { SDL_SCANCODE_SLASH
1659 } },
1660 { 8, { SDL_SCANCODE_BACKSLASH
1661 } },
1662 { 9, { SDL_SCANCODE_1
1663 } },
1664 };
1665
1666 class w_prefs_key;
1667
1668 typedef std::multimap<int, w_prefs_key*> prefsKeyMap;
1669 typedef std::pair<int, w_prefs_key*> prefsKeyMapPair;
1670 static prefsKeyMap key_w;
1671 static prefsKeyMap shell_key_w;
1672
1673 class w_prefs_key : public w_key {
1674 public:
w_prefs_key(SDL_Scancode key,w_key::Type event_type)1675 w_prefs_key(SDL_Scancode key, w_key::Type event_type) : w_key(key, event_type) {}
1676
set_key(SDL_Scancode new_key)1677 void set_key(SDL_Scancode new_key)
1678 {
1679 // Key used for in-game function?
1680 int error = NONE;
1681 switch (new_key) {
1682 case SDL_SCANCODE_F1:
1683 case SDL_SCANCODE_F2:
1684 case SDL_SCANCODE_F3:
1685 case SDL_SCANCODE_F4:
1686 case SDL_SCANCODE_F5:
1687 case SDL_SCANCODE_F6:
1688 case SDL_SCANCODE_F7:
1689 case SDL_SCANCODE_F8:
1690 case SDL_SCANCODE_F9:
1691 case SDL_SCANCODE_F10:
1692 case SDL_SCANCODE_F11:
1693 case SDL_SCANCODE_F12:
1694 case SDL_SCANCODE_ESCAPE: // (ZZZ: for quitting)
1695 case AO_SCANCODE_JOYSTICK_ESCAPE:
1696 error = keyIsUsedAlready;
1697 break;
1698
1699 default:
1700 break;
1701 }
1702 if (error != NONE) {
1703 alert_user(infoError, strERRORS, error, 0);
1704 return;
1705 }
1706
1707 w_key::set_key(new_key);
1708 dirty = true;
1709 if (new_key == SDL_SCANCODE_UNKNOWN)
1710 return;
1711
1712 // Remove binding to this key from all other widgets
1713 for (auto it = key_w.begin(); it != key_w.end(); ++it) {
1714 if (it->second != this && it->second->get_key() == new_key) {
1715 it->second->set_key(SDL_SCANCODE_UNKNOWN);
1716 it->second->dirty = true;
1717 }
1718 }
1719 for (auto it = shell_key_w.begin(); it != shell_key_w.end(); ++it) {
1720 if (it->second != this && it->second->get_key() == new_key) {
1721 it->second->set_key(SDL_SCANCODE_UNKNOWN);
1722 it->second->dirty = true;
1723 }
1724 }
1725 }
1726 };
1727
load_default_keys(void * arg)1728 static void load_default_keys(void *arg)
1729 {
1730 for (int i = 0; i < NUM_KEYS; i++) {
1731 SDL_Scancode kcode = SDL_SCANCODE_UNKNOWN;
1732 SDL_Scancode mcode = SDL_SCANCODE_UNKNOWN;
1733 SDL_Scancode jcode = SDL_SCANCODE_UNKNOWN;
1734 for (auto it = default_key_bindings[i].begin(); it != default_key_bindings[i].end(); ++it) {
1735 SDL_Scancode code = *it;
1736 if (code == SDL_SCANCODE_UNKNOWN)
1737 continue;
1738 switch (w_key::event_type_for_key(code)) {
1739 case w_key::MouseButton:
1740 mcode = code;
1741 break;
1742 case w_key::JoystickButton:
1743 jcode = code;
1744 break;
1745 case w_key::KeyboardKey:
1746 default:
1747 kcode = code;
1748 break;
1749 }
1750 }
1751 auto range = key_w.equal_range(i);
1752 for (auto ik = range.first; ik != range.second; ++ik) {
1753 w_prefs_key *pk = ik->second;
1754 switch (pk->event_type) {
1755 case w_key::MouseButton:
1756 pk->set_key(mcode);
1757 break;
1758 case w_key::JoystickButton:
1759 pk->set_key(jcode);
1760 break;
1761 case w_key::KeyboardKey:
1762 default:
1763 pk->set_key(kcode);
1764 break;
1765 }
1766 }
1767 }
1768
1769 for (int i = 0; i < NUMBER_OF_SHELL_KEYS; i++) {
1770 SDL_Scancode kcode = SDL_SCANCODE_UNKNOWN;
1771 SDL_Scancode mcode = SDL_SCANCODE_UNKNOWN;
1772 SDL_Scancode jcode = SDL_SCANCODE_UNKNOWN;
1773 for (auto it = default_shell_key_bindings[i].begin(); it != default_shell_key_bindings[i].end(); ++it) {
1774 SDL_Scancode code = *it;
1775 if (code == SDL_SCANCODE_UNKNOWN)
1776 continue;
1777 switch (w_key::event_type_for_key(code)) {
1778 case w_key::MouseButton:
1779 mcode = code;
1780 break;
1781 case w_key::JoystickButton:
1782 jcode = code;
1783 break;
1784 case w_key::KeyboardKey:
1785 default:
1786 kcode = code;
1787 break;
1788 }
1789 }
1790 auto range = shell_key_w.equal_range(i);
1791 for (auto ik = range.first; ik != range.second; ++ik) {
1792 w_prefs_key *pk = ik->second;
1793 switch (pk->event_type) {
1794 case w_key::MouseButton:
1795 pk->set_key(mcode);
1796 break;
1797 case w_key::JoystickButton:
1798 pk->set_key(jcode);
1799 break;
1800 case w_key::KeyboardKey:
1801 default:
1802 pk->set_key(kcode);
1803 break;
1804 }
1805 }
1806 }
1807
1808 dialog *d = (dialog *)arg;
1809 d->draw();
1810 }
1811
unset_scancode(SDL_Scancode code)1812 static void unset_scancode(SDL_Scancode code)
1813 {
1814 for (int i = 0; i < NUM_KEYS; ++i)
1815 input_preferences->key_bindings[i].erase(code);
1816 for (int i = 0; i < NUMBER_OF_SHELL_KEYS; ++i)
1817 input_preferences->shell_key_bindings[i].erase(code);
1818 }
1819
1820 enum {
1821 KEYBOARD_TABS,
1822 TAB_KEYS,
1823 TAB_MORE_KEYS
1824 };
1825
1826 const std::vector<std::string> mouse_feel_labels = { "Classic", "Modern", "(custom)" };
1827 static w_select_popup *mouse_feel_w;
1828 static w_select_popup *mouse_feel_details_w;
1829 static w_toggle *mouse_raw_w;
1830 static w_toggle *mouse_vertical_w;
1831 static w_toggle *mouse_accel_w;
1832 static w_toggle *mouse_precision_w;
1833 static bool inside_callback = false; // prevent circular changes
1834
mouse_feel_details_changed(void * arg)1835 static void mouse_feel_details_changed(void *arg)
1836 {
1837 if (inside_callback)
1838 return;
1839 inside_callback = true;
1840 switch (mouse_feel_details_w->get_selection())
1841 {
1842 case 0:
1843 mouse_raw_w->set_selection(0);
1844 mouse_accel_w->set_selection(1);
1845 mouse_vertical_w->set_selection(1);
1846 mouse_precision_w->set_selection(1);
1847 break;
1848 case 1:
1849 mouse_raw_w->set_selection(1);
1850 mouse_accel_w->set_selection(0);
1851 mouse_vertical_w->set_selection(0);
1852 mouse_precision_w->set_selection(0);
1853 break;
1854 default:
1855 break;
1856 }
1857 inside_callback = false;
1858 }
1859
update_mouse_feel_details(void * arg)1860 static void update_mouse_feel_details(void *arg)
1861 {
1862 if (inside_callback)
1863 return;
1864 inside_callback = true;
1865 if (mouse_raw_w->get_selection() == 0 &&
1866 mouse_accel_w->get_selection() == 1 &&
1867 mouse_vertical_w->get_selection() == 1 &&
1868 mouse_precision_w->get_selection() == 1)
1869 {
1870 mouse_feel_details_w->set_selection(0);
1871 }
1872 else if (mouse_raw_w->get_selection() == 1 &&
1873 mouse_accel_w->get_selection() == 0 &&
1874 mouse_vertical_w->get_selection() == 0 &&
1875 mouse_precision_w->get_selection() == 0)
1876 {
1877 mouse_feel_details_w->set_selection(1);
1878 }
1879 else
1880 {
1881 mouse_feel_details_w->set_selection(2);
1882 }
1883 inside_callback = false;
1884 }
1885
update_mouse_feel(void * arg)1886 static void update_mouse_feel(void *arg)
1887 {
1888 if (input_preferences->raw_mouse_input == false &&
1889 input_preferences->mouse_accel_type == _mouse_accel_classic &&
1890 input_preferences->classic_vertical_aim == true &&
1891 input_preferences->extra_mouse_precision == false)
1892 {
1893 mouse_feel_w->set_selection(0);
1894 }
1895 else if (input_preferences->raw_mouse_input == true &&
1896 input_preferences->mouse_accel_type == _mouse_accel_none &&
1897 input_preferences->classic_vertical_aim == false &&
1898 input_preferences->extra_mouse_precision == true)
1899 {
1900 mouse_feel_w->set_selection(1);
1901 }
1902 else
1903 {
1904 mouse_feel_w->set_selection(2);
1905 }
1906 }
1907
apply_mouse_feel(int selection)1908 static bool apply_mouse_feel(int selection)
1909 {
1910 bool changed = false;
1911 switch (selection)
1912 {
1913 case 0:
1914 if (false != input_preferences->raw_mouse_input) {
1915 input_preferences->raw_mouse_input = false;
1916 changed = true;
1917 }
1918 if (_mouse_accel_classic != input_preferences->mouse_accel_type) {
1919 input_preferences->mouse_accel_type = _mouse_accel_classic;
1920 changed = true;
1921 }
1922 if (true != input_preferences->classic_vertical_aim) {
1923 input_preferences->classic_vertical_aim = true;
1924 changed = true;
1925 }
1926 if (false != input_preferences->extra_mouse_precision) {
1927 input_preferences->extra_mouse_precision = false;
1928 changed = true;
1929 }
1930 break;
1931 case 1:
1932 if (true != input_preferences->raw_mouse_input) {
1933 input_preferences->raw_mouse_input = true;
1934 changed = true;
1935 }
1936 if (_mouse_accel_none != input_preferences->mouse_accel_type) {
1937 input_preferences->mouse_accel_type = _mouse_accel_none;
1938 changed = true;
1939 }
1940 if (false != input_preferences->classic_vertical_aim) {
1941 input_preferences->classic_vertical_aim = false;
1942 changed = true;
1943 }
1944 if (true != input_preferences->extra_mouse_precision) {
1945 input_preferences->extra_mouse_precision = true;
1946 changed = true;
1947 }
1948 break;
1949 default:
1950 break;
1951 }
1952 return changed;
1953 }
1954
mouse_custom_dialog(void * arg)1955 static void mouse_custom_dialog(void *arg)
1956 {
1957 dialog d;
1958 vertical_placer *placer = new vertical_placer;
1959 placer->dual_add(new w_title("MOUSE ADVANCED"), d);
1960 placer->add(new w_spacer());
1961
1962 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1963 table->col_flags(0, placeable::kAlignRight);
1964
1965 float hSensitivity = ((float) input_preferences->sens_horizontal) / FIXED_ONE;
1966 if (hSensitivity <= 0.0f) hSensitivity = 1.0f;
1967 float hSensitivityLog = std::log(hSensitivity);
1968 int hSliderPosition =
1969 (int) ((hSensitivityLog - kMinSensitivityLog) * (1000.0f / kSensitivityLogRange) + 0.5f);
1970 w_sens_slider *mouse_h_sens_w = new w_sens_slider(1000, hSliderPosition);
1971 table->dual_add(mouse_h_sens_w->label("Horizontal Sensitivity"), d);
1972 table->dual_add(mouse_h_sens_w, d);
1973
1974 float vSensitivity = ((float) input_preferences->sens_vertical) / FIXED_ONE;
1975 if (vSensitivity <= 0.0f) vSensitivity = 1.0f;
1976 float vSensitivityLog = std::log(vSensitivity);
1977 int vSliderPosition =
1978 (int) ((vSensitivityLog - kMinSensitivityLog) * (1000.0f / kSensitivityLogRange) + 0.5f);
1979 w_sens_slider *mouse_v_sens_w = new w_sens_slider(1000, vSliderPosition);
1980 table->dual_add(mouse_v_sens_w->label("Vertical Sensitivity"), d);
1981 table->dual_add(mouse_v_sens_w, d);
1982
1983 w_toggle *mouse_v_invert_w = new w_toggle(input_preferences->modifiers & _inputmod_invert_mouse);
1984 mouse_v_invert_w->set_selection_changed_callback(update_mouse_feel_details);
1985 table->dual_add(mouse_v_invert_w->label("Invert Vertical Aim"), d);
1986 table->dual_add(mouse_v_invert_w, d);
1987
1988 table->add_row(new w_spacer(), true);
1989
1990 mouse_feel_details_w = new w_select_popup();
1991 mouse_feel_details_w->set_labels(mouse_feel_labels);
1992 mouse_feel_details_w->set_selection(mouse_feel_w->get_selection());
1993 mouse_feel_details_w->set_popup_callback(mouse_feel_details_changed, NULL);
1994 table->dual_add(mouse_feel_details_w->label("Mouse Feel"), d);
1995 table->dual_add(mouse_feel_details_w, d);
1996
1997 mouse_raw_w = new w_toggle(input_preferences->raw_mouse_input);
1998 mouse_raw_w->set_selection_changed_callback(update_mouse_feel_details);
1999 table->dual_add(mouse_raw_w->label("Raw Input Mode"), d);
2000 table->dual_add(mouse_raw_w, d);
2001
2002 mouse_accel_w = new w_toggle(input_preferences->mouse_accel_type == _mouse_accel_classic);
2003 mouse_accel_w->set_selection_changed_callback(update_mouse_feel_details);
2004 table->dual_add(mouse_accel_w->label("Acceleration"), d);
2005 table->dual_add(mouse_accel_w, d);
2006
2007 mouse_vertical_w = new w_toggle(input_preferences->classic_vertical_aim);
2008 mouse_vertical_w->set_selection_changed_callback(update_mouse_feel_details);
2009 table->dual_add(mouse_vertical_w->label("Adjust Vertical Speed"), d);
2010 table->dual_add(mouse_vertical_w, d);
2011
2012 mouse_precision_w = new w_toggle(!input_preferences->extra_mouse_precision);
2013 mouse_precision_w->set_selection_changed_callback(update_mouse_feel_details);
2014 table->dual_add(mouse_precision_w->label("Snap View to Weapon Aim"), d);
2015 table->dual_add(mouse_precision_w, d);
2016
2017 placer->add(table);
2018 placer->add(new w_spacer(), true);
2019
2020 horizontal_placer *button_placer = new horizontal_placer;
2021 button_placer->dual_add(new w_button("ACCEPT", dialog_ok, &d), d);
2022 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
2023 placer->add(button_placer, true);
2024
2025 d.set_widget_placer(placer);
2026 mouse_feel_details_changed(NULL);
2027
2028 // Run dialog
2029 if (d.run() == 0) { // Accepted
2030 bool changed = false;
2031
2032 int hPos = mouse_h_sens_w->get_selection();
2033 float hLog = kMinSensitivityLog + ((float) hPos) * (kSensitivityLogRange / 1000.0f);
2034 _fixed hNorm = _fixed(std::exp(hLog) * FIXED_ONE);
2035 if (hNorm != input_preferences->sens_horizontal) {
2036 input_preferences->sens_horizontal = hNorm;
2037 changed = true;
2038 }
2039
2040 int vPos = mouse_v_sens_w->get_selection();
2041 float vLog = kMinSensitivityLog + ((float) vPos) * (kSensitivityLogRange / 1000.0f);
2042 _fixed vNorm = _fixed(std::exp(vLog) * FIXED_ONE);
2043 if (vNorm != input_preferences->sens_vertical) {
2044 input_preferences->sens_vertical = vNorm;
2045 changed = true;
2046 }
2047
2048 uint16 flags = input_preferences->modifiers;
2049 if (mouse_v_invert_w->get_selection()) {
2050 flags |= _inputmod_invert_mouse;
2051 } else {
2052 flags &= ~_inputmod_invert_mouse;
2053 }
2054 if (flags != input_preferences->modifiers) {
2055 input_preferences->modifiers = flags;
2056 changed = true;
2057 }
2058
2059 if (mouse_raw_w->get_selection() != input_preferences->raw_mouse_input) {
2060 input_preferences->raw_mouse_input = mouse_raw_w->get_selection();
2061 changed = true;
2062 }
2063
2064 if (mouse_accel_w->get_selection() != input_preferences->mouse_accel_type) {
2065 input_preferences->mouse_accel_type = mouse_accel_w->get_selection();
2066 changed = true;
2067 }
2068
2069 bool vert = mouse_vertical_w->get_selection();
2070 if (vert != input_preferences->classic_vertical_aim) {
2071 input_preferences->classic_vertical_aim = vert;
2072 changed = true;
2073 }
2074
2075 bool precision = (mouse_precision_w->get_selection() == 0);
2076 if (precision != input_preferences->extra_mouse_precision) {
2077 input_preferences->extra_mouse_precision = precision;
2078 changed = true;
2079 }
2080
2081 if (changed) {
2082 write_preferences();
2083 }
2084 update_mouse_feel(NULL);
2085 }
2086 }
2087
2088
controller_details_dialog(void * arg)2089 static void controller_details_dialog(void *arg)
2090 {
2091 dialog d;
2092 vertical_placer *placer = new vertical_placer;
2093 placer->dual_add(new w_title("CONTROLLER ADVANCED"), d);
2094 placer->add(new w_spacer());
2095
2096 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
2097 table->col_flags(0, placeable::kAlignRight);
2098
2099 float joySensitivity = ((float) input_preferences->controller_sensitivity) / FIXED_ONE;
2100 if (joySensitivity <= 0.0f) joySensitivity = 1.0f;
2101 float joySensitivityLog = std::log(joySensitivity);
2102 int joySliderPosition =
2103 (int) ((joySensitivityLog - kMinSensitivityLog) * (1000.0f / kSensitivityLogRange) + 0.5f);
2104
2105 w_sens_slider* sens_joy_w = new w_sens_slider(1000, joySliderPosition);
2106 table->dual_add(sens_joy_w->label("Aiming Sensitivity"), d);
2107 table->dual_add(sens_joy_w, d);
2108
2109 int joyDeadzone = (int)((input_preferences->controller_deadzone / 655.36f) + 0.5f);
2110 w_deadzone_slider* dead_joy_w = new w_deadzone_slider(11, joyDeadzone);
2111 table->dual_add(dead_joy_w->label("Analog Dead Zone"), d);
2112 table->dual_add(dead_joy_w, d);
2113
2114 table->add_row(new w_spacer(), true);
2115 placer->add(table, true);
2116
2117 horizontal_placer *button_placer = new horizontal_placer;
2118 button_placer->dual_add(new w_button("ACCEPT", dialog_ok, &d), d);
2119 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
2120 placer->add(button_placer, true);
2121
2122 d.set_widget_placer(placer);
2123
2124 // Run dialog
2125 if (d.run() == 0) { // Accepted
2126 bool changed = false;
2127
2128 int sensPos = sens_joy_w->get_selection();
2129 float sensLog = kMinSensitivityLog + ((float) sensPos) * (kSensitivityLogRange / 1000.0f);
2130 _fixed sensNorm = _fixed(std::exp(sensLog) * FIXED_ONE);
2131 if (sensNorm != input_preferences->controller_sensitivity) {
2132 input_preferences->controller_sensitivity = sensNorm;
2133 changed = true;
2134 }
2135
2136 int deadPos = dead_joy_w->get_selection();
2137 int deadNorm = deadPos * 655.36f;
2138 if (deadNorm != input_preferences->controller_deadzone) {
2139 input_preferences->controller_deadzone = deadNorm;
2140 changed = true;
2141 }
2142
2143 if (changed) {
2144 write_preferences();
2145 }
2146 }
2147 }
2148
2149
controls_dialog(void * arg)2150 static void controls_dialog(void *arg)
2151 {
2152 // Clear array of key widgets (because w_prefs_key::set_key() scans it)
2153 key_w.clear();
2154 shell_key_w.clear();
2155
2156 // Create dialog
2157 dialog d;
2158 vertical_placer *placer = new vertical_placer;
2159 placer->dual_add(new w_title("CONTROLS"), d);
2160 placer->add(new w_spacer());
2161
2162 // create all key widgets
2163 for (int i = 0; i < NUM_KEYS; i++) {
2164 SDL_Scancode kcode = SDL_SCANCODE_UNKNOWN;
2165 SDL_Scancode mcode = SDL_SCANCODE_UNKNOWN;
2166 SDL_Scancode jcode = SDL_SCANCODE_UNKNOWN;
2167 for (std::set<SDL_Scancode>::const_iterator bit = input_preferences->key_bindings[i].begin(); bit != input_preferences->key_bindings[i].end(); ++bit) {
2168 SDL_Scancode code = *bit;
2169 if (code >= AO_SCANCODE_BASE_JOYSTICK_BUTTON && code < (AO_SCANCODE_BASE_JOYSTICK_BUTTON + NUM_SDL_JOYSTICK_BUTTONS)) {
2170 jcode = code;
2171 } else if (code >= AO_SCANCODE_BASE_MOUSE_BUTTON && code < (AO_SCANCODE_BASE_MOUSE_BUTTON + NUM_SDL_MOUSE_BUTTONS)) {
2172 mcode = code;
2173 } else {
2174 kcode = code;
2175 }
2176 }
2177 key_w.insert(prefsKeyMapPair(i, new w_prefs_key(kcode, w_key::KeyboardKey)));
2178 key_w.insert(prefsKeyMapPair(i, new w_prefs_key(mcode, w_key::MouseButton)));
2179 key_w.insert(prefsKeyMapPair(i, new w_prefs_key(jcode, w_key::JoystickButton)));
2180 }
2181 for (int i = 0; i < NUMBER_OF_SHELL_KEYS; i++) {
2182 SDL_Scancode kcode = SDL_SCANCODE_UNKNOWN;
2183 SDL_Scancode mcode = SDL_SCANCODE_UNKNOWN;
2184 SDL_Scancode jcode = SDL_SCANCODE_UNKNOWN;
2185 for (std::set<SDL_Scancode>::const_iterator bit = input_preferences->shell_key_bindings[i].begin(); bit != input_preferences->shell_key_bindings[i].end(); ++bit) {
2186 SDL_Scancode code = *bit;
2187 if (code >= AO_SCANCODE_BASE_JOYSTICK_BUTTON && code < (AO_SCANCODE_BASE_JOYSTICK_BUTTON + NUM_SDL_JOYSTICK_BUTTONS)) {
2188 jcode = code;
2189 } else if (code >= AO_SCANCODE_BASE_MOUSE_BUTTON && code < (AO_SCANCODE_BASE_MOUSE_BUTTON + NUM_SDL_MOUSE_BUTTONS)) {
2190 mcode = code;
2191 } else {
2192 kcode = code;
2193 }
2194 }
2195 shell_key_w.insert(prefsKeyMapPair(i, new w_prefs_key(kcode, w_key::KeyboardKey)));
2196 shell_key_w.insert(prefsKeyMapPair(i, new w_prefs_key(mcode, w_key::MouseButton)));
2197 shell_key_w.insert(prefsKeyMapPair(i, new w_prefs_key(jcode, w_key::JoystickButton)));
2198 }
2199
2200 tab_placer* tabs = new tab_placer();
2201
2202 std::vector<std::string> labels = { "AIM", "MOVE", "ACTIONS", "INTERFACE", "OTHER" };
2203 w_tab *tab_w = new w_tab(labels, tabs);
2204
2205 placer->dual_add(tab_w, d);
2206 placer->add(new w_spacer(), true);
2207
2208 vertical_placer *move = new vertical_placer();
2209 table_placer *move_table = new table_placer(4, get_theme_space(ITEM_WIDGET), true);
2210 move_table->col_flags(0, placeable::kAlignRight);
2211 move_table->col_flags(1, placeable::kAlignLeft);
2212 move_table->col_flags(2, placeable::kAlignLeft);
2213 move_table->col_flags(3, placeable::kAlignLeft);
2214 move_table->add(new w_spacer(), true);
2215 move_table->dual_add(new w_label("Keyboard"), d);
2216 move_table->dual_add(new w_label("Mouse"), d);
2217 move_table->dual_add(new w_label("Controller"), d);
2218
2219 std::vector<int> move_keys = { 0, 1, 4, 5, -1, 16, 15, 17 };
2220 for (auto it = move_keys.begin(); it != move_keys.end(); ++it) {
2221 if (*it < 0) {
2222 move_table->add_row(new w_spacer(), true);
2223 } else if (*it >= 100) {
2224 int i = *it - 100;
2225 move_table->dual_add(new w_label(shell_action_name[i]), d);
2226 auto range = shell_key_w.equal_range(i);
2227 for (auto ik = range.first; ik != range.second; ++ik) {
2228 move_table->dual_add(ik->second, d);
2229 }
2230 } else {
2231 int i = *it;
2232 move_table->dual_add(new w_label(action_name[i]), d);
2233 auto range = key_w.equal_range(i);
2234 for (auto ik = range.first; ik != range.second; ++ik) {
2235 if ((ik->second->event_type == w_key::MouseButton) &&
2236 (i == 0 || i == 1 || i == 4 || i == 5))
2237 move_table->dual_add(new w_label(""), d);
2238 else
2239 move_table->dual_add(ik->second, d);
2240 }
2241 }
2242 }
2243 move->add(move_table, true);
2244 move->add(new w_spacer(), true);
2245
2246 table_placer *move_options = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
2247 move_options->col_flags(0, placeable::kAlignRight);
2248
2249 w_toggle *always_run_w = new w_toggle(input_preferences->modifiers & _inputmod_interchange_run_walk);
2250 move_options->dual_add(always_run_w->label("Always Run"), d);
2251 move_options->dual_add(always_run_w, d);
2252
2253 w_toggle *always_swim_w = new w_toggle(TEST_FLAG(input_preferences->modifiers, _inputmod_interchange_swim_sink));
2254 move_options->dual_add(always_swim_w->label("Always Swim"), d);
2255 move_options->dual_add(always_swim_w, d);
2256
2257 move->add(move_options, true);
2258
2259 vertical_placer *look = new vertical_placer();
2260 table_placer *look_table = new table_placer(4, get_theme_space(ITEM_WIDGET), true);
2261 look_table->col_flags(0, placeable::kAlignRight);
2262 look_table->col_flags(1, placeable::kAlignLeft);
2263 look_table->col_flags(2, placeable::kAlignLeft);
2264 look_table->col_flags(3, placeable::kAlignLeft);
2265 look_table->add(new w_spacer(), true);
2266 look_table->dual_add(new w_label("Keyboard"), d);
2267 look_table->dual_add(new w_label("Mouse"), d);
2268 look_table->dual_add(new w_label("Controller"), d);
2269
2270 std::vector<int> look_keys = { 8, 9, 2, 3, -1, 6, 7, 10 };
2271 for (auto it = look_keys.begin(); it != look_keys.end(); ++it) {
2272 if (*it < 0) {
2273 look_table->add_row(new w_spacer(), true);
2274 } else if (*it >= 100) {
2275 int i = *it - 100;
2276 look_table->dual_add(new w_label(shell_action_name[i]), d);
2277 auto range = shell_key_w.equal_range(i);
2278 for (auto ik = range.first; ik != range.second; ++ik) {
2279 look_table->dual_add(ik->second, d);
2280 }
2281 } else {
2282 int i = *it;
2283 look_table->dual_add(new w_label(action_name[i]), d);
2284 auto range = key_w.equal_range(i);
2285 for (auto ik = range.first; ik != range.second; ++ik) {
2286 if (ik->second->event_type == w_key::MouseButton) {
2287 w_text_entry* txt = NULL;
2288 switch (i) {
2289 case 8:
2290 txt = new w_text_entry(12, "move up");
2291 break;
2292 case 9:
2293 txt = new w_text_entry(12, "move down");
2294 break;
2295 case 2:
2296 txt = new w_text_entry(12, "move left");
2297 break;
2298 case 3:
2299 txt = new w_text_entry(12, "move right");
2300 break;
2301 default:
2302 break;
2303 }
2304 if (txt) {
2305 txt->set_enabled(false);
2306 txt->set_min_width(50);
2307 look_table->dual_add(txt, d);
2308 continue;
2309 }
2310 }
2311 look_table->dual_add(ik->second, d);
2312 }
2313 }
2314 }
2315 look->add(look_table, true);
2316 look->add(new w_spacer(), true);
2317
2318 table_placer *look_options = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
2319 look_options->col_flags(0, placeable::kAlignRight);
2320
2321 w_toggle* auto_recenter_w = new w_toggle(!(input_preferences->modifiers & _inputmod_dont_auto_recenter));
2322 look_options->dual_add(auto_recenter_w->label("Auto-Recenter View"), d);
2323 look_options->dual_add(auto_recenter_w, d);
2324
2325 look_options->add_row(new w_spacer(), true);
2326
2327 table_placer *mouse_options = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
2328 mouse_options->col_flags(0, placeable::kAlignRight);
2329 mouse_options->col_flags(1, placeable::kAlignLeft);
2330
2331 w_toggle *enable_mouse_w = new w_toggle(input_preferences->input_device == _mouse_yaw_pitch);
2332 mouse_options->dual_add(enable_mouse_w->label("Mouse Aiming"), d);
2333 mouse_options->dual_add(enable_mouse_w, d);
2334
2335 mouse_feel_w = new w_select_popup();
2336 mouse_feel_w->set_labels(mouse_feel_labels);
2337 update_mouse_feel(NULL);
2338 mouse_options->dual_add(mouse_feel_w->label("Mouse Feel"), d);
2339 mouse_options->dual_add(mouse_feel_w, d);
2340
2341 mouse_options->add_row(new w_spacer(), true);
2342 mouse_options->dual_add_row(new w_button("MOUSE ADVANCED", mouse_custom_dialog, &d), d);
2343
2344 look_options->add(mouse_options, true);
2345
2346 table_placer *controller_options = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
2347 controller_options->col_flags(0, placeable::kAlignRight);
2348 controller_options->col_flags(1, placeable::kAlignLeft);
2349
2350 controller_options->dual_add_row(new w_label(""), d);
2351 std::vector<std::string> joystick_aiming_labels = { "Treat as Analog Stick", "Treat as D-Pad" };
2352 w_select_popup *joystick_aiming_w = new w_select_popup();
2353 joystick_aiming_w->set_labels(joystick_aiming_labels);
2354 joystick_aiming_w->set_selection(input_preferences->controller_analog ? 0 : 1);
2355 controller_options->dual_add(joystick_aiming_w->label("Controller Feel"), d);
2356 controller_options->dual_add(joystick_aiming_w, d);
2357
2358 controller_options->add_row(new w_spacer(), true);
2359 controller_options->dual_add_row(new w_button("CONTROLLER ADVANCED", controller_details_dialog, &d), d);
2360
2361 look_options->add(controller_options, true);
2362
2363 look->add(look_options, true);
2364
2365 vertical_placer *actions = new vertical_placer();
2366 table_placer *actions_table = new table_placer(4, get_theme_space(ITEM_WIDGET), true);
2367 actions_table->col_flags(0, placeable::kAlignRight);
2368 actions_table->col_flags(1, placeable::kAlignLeft);
2369 actions_table->col_flags(2, placeable::kAlignLeft);
2370 actions_table->col_flags(3, placeable::kAlignLeft);
2371 actions_table->add(new w_spacer(), true);
2372 actions_table->dual_add(new w_label("Keyboard"), d);
2373 actions_table->dual_add(new w_label("Mouse"), d);
2374 actions_table->dual_add(new w_label("Controller"), d);
2375
2376 std::vector<int> actions_keys = { 13, 14, 11, 12, -1, 18, -1, 20, 108 };
2377 for (auto it = actions_keys.begin(); it != actions_keys.end(); ++it) {
2378 if (*it < 0) {
2379 actions_table->add_row(new w_spacer(), true);
2380 } else if (*it >= 100) {
2381 int i = *it - 100;
2382 actions_table->dual_add(new w_label(shell_action_name[i]), d);
2383 auto range = shell_key_w.equal_range(i);
2384 for (auto ik = range.first; ik != range.second; ++ik) {
2385 actions_table->dual_add(ik->second, d);
2386 }
2387 } else {
2388 int i = *it;
2389 actions_table->dual_add(new w_label(action_name[i]), d);
2390 auto range = key_w.equal_range(i);
2391 for (auto ik = range.first; ik != range.second; ++ik) {
2392 actions_table->dual_add(ik->second, d);
2393 }
2394 }
2395 }
2396 actions->add(actions_table, true);
2397 actions->add(new w_spacer(), true);
2398
2399 table_placer *actions_options = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
2400 actions_options->col_flags(0, placeable::kAlignRight);
2401
2402 w_toggle *weapon_w = new w_toggle(!(input_preferences->modifiers & _inputmod_dont_switch_to_new_weapon));
2403 actions_options->dual_add(weapon_w->label("Auto-Switch Weapons"), d);
2404 actions_options->dual_add(weapon_w, d);
2405
2406 actions->add(actions_options, true);
2407
2408 actions->add(new w_spacer(), true);
2409 actions->dual_add(new w_static_text("Warning: Auto-Switch Weapons is always ON in"), d);
2410 actions->dual_add(new w_static_text("network play. Turning it OFF will also disable"), d);
2411 actions->dual_add(new w_static_text("film recording for single-player games."), d);
2412
2413
2414 vertical_placer *iface = new vertical_placer();
2415 table_placer *interface_table = new table_placer(4, get_theme_space(ITEM_WIDGET), true);
2416 interface_table->col_flags(0, placeable::kAlignRight);
2417 interface_table->col_flags(1, placeable::kAlignLeft);
2418 interface_table->col_flags(2, placeable::kAlignLeft);
2419 interface_table->col_flags(3, placeable::kAlignLeft);
2420 interface_table->add(new w_spacer(), true);
2421 interface_table->dual_add(new w_label("Keyboard"), d);
2422 interface_table->dual_add(new w_label("Mouse"), d);
2423 interface_table->dual_add(new w_label("Controller"), d);
2424
2425 std::vector<int> interface_keys = { 19, 105, 106, -1, 103, 104, -1, 100, 101, -1, 102, 107, 109, -1, -2 };
2426 for (auto it = interface_keys.begin(); it != interface_keys.end(); ++it) {
2427 if (*it == -2) {
2428 interface_table->dual_add(new w_label("Exit Game"), d);
2429 w_prefs_key *kb = new w_prefs_key(SDL_SCANCODE_ESCAPE, w_key::KeyboardKey);
2430 kb->set_enabled(false);
2431 interface_table->dual_add(kb, d);
2432 interface_table->dual_add(new w_label(""), d);
2433 w_prefs_key *cn = new w_prefs_key(AO_SCANCODE_JOYSTICK_ESCAPE, w_key::JoystickButton);
2434 cn->set_enabled(false);
2435 interface_table->dual_add(cn, d);
2436 } else if (*it < 0) {
2437 interface_table->add_row(new w_spacer(), true);
2438 } else if (*it >= 100) {
2439 int i = *it - 100;
2440 interface_table->dual_add(new w_label(shell_action_name[i]), d);
2441 auto range = shell_key_w.equal_range(i);
2442 for (auto ik = range.first; ik != range.second; ++ik) {
2443 interface_table->dual_add(ik->second, d);
2444 }
2445 } else {
2446 int i = *it;
2447 interface_table->dual_add(new w_label(action_name[i]), d);
2448 auto range = key_w.equal_range(i);
2449 for (auto ik = range.first; ik != range.second; ++ik) {
2450 interface_table->dual_add(ik->second, d);
2451 }
2452 }
2453 }
2454 iface->add(interface_table, true);
2455
2456 vertical_placer *other = new vertical_placer();
2457 other->dual_add(new w_static_text("These keyboard shortcuts cannot be changed."), d);
2458 other->add(new w_spacer());
2459
2460 table_placer *other_table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
2461 other_table->dual_add(new w_label("Main Menu"), d);
2462 other_table->dual_add(new w_label("In Game"), d);
2463
2464 table_placer *other_menu = new table_placer(2, get_theme_space(ITEM_WIDGET), false);
2465 other_menu->col_flags(0, placeable::kAlignRight);
2466 other_menu->col_flags(1, placeable::kAlignLeft);
2467 std::vector<std::string> menu_shortcuts = {
2468 "N", "Begin new game",
2469 #if (defined(__APPLE__) && defined(__MACH__))
2470 "Cmd-Option-N", "Level select",
2471 #else
2472 "Ctrl+Shift+N", "Level select",
2473 #endif
2474 "O", "Continue saved game",
2475 "G", "Gather network game",
2476 "J", "Join network game",
2477 "R", "Replay saved film",
2478 "P", "Preferences",
2479 "Q", "Quit",
2480 "C", "Scenario credits",
2481 "A", "About Aleph One",
2482 #if (defined(__APPLE__) && defined(__MACH__))
2483 "Cmd-Return", "Toggle fullscreen",
2484 #else
2485 "Alt+Enter", "Toggle fullscreen",
2486 #endif
2487 };
2488 for (auto it = menu_shortcuts.begin(); it != menu_shortcuts.end(); ++it) {
2489 other_menu->dual_add(new w_label(it->c_str()), d);
2490 }
2491 other_table->add(other_menu, true);
2492
2493 table_placer *other_game = new table_placer(2, get_theme_space(ITEM_WIDGET), false);
2494 other_game->col_flags(0, placeable::kAlignRight);
2495 other_game->col_flags(1, placeable::kAlignLeft);
2496 std::vector<std::string> game_shortcuts = {
2497 "F1", "Decrease resolution",
2498 "F2", "Increase resolution",
2499 "F8", "Crosshairs",
2500 "F9", "Screenshot",
2501 "F10", "Debug info",
2502 "F11", "Decrease brightness",
2503 "F12", "Increase brightness",
2504 #if (defined(__APPLE__) && defined(__MACH__))
2505 "Cmd-Return", "Toggle fullscreen",
2506 #else
2507 "Alt+Enter", "Toggle fullscreen",
2508 #endif
2509 "Escape", "Exit game"
2510 };
2511 for (auto it = game_shortcuts.begin(); it != game_shortcuts.end(); ++it) {
2512 other_game->dual_add(new w_label(it->c_str()), d);
2513 }
2514 other_table->add(other_game, true);
2515
2516 other->add(other_table, true);
2517
2518 tabs->add(look, true);
2519 tabs->add(move, true);
2520 tabs->add(actions, true);
2521 tabs->add(iface, true);
2522 tabs->add(other, true);
2523 placer->add(tabs, true);
2524
2525 placer->add(new w_spacer(), true);
2526 placer->dual_add(new w_button("RESET ALL KEYS TO DEFAULTS", load_default_keys, &d), d);
2527 placer->add(new w_spacer(), true);
2528
2529 horizontal_placer *button_placer = new horizontal_placer;
2530 button_placer->dual_add(new w_button("ACCEPT", dialog_ok, &d), d);
2531 button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &d), d);
2532 placer->add(button_placer, true);
2533
2534 d.set_widget_placer(placer);
2535
2536 // Clear screen
2537 clear_screen();
2538
2539 enter_joystick();
2540
2541 // Run dialog
2542 if (d.run() == 0) { // Accepted
2543 bool changed = false;
2544
2545 uint16 flags = input_preferences->modifiers & (_inputmod_use_button_sounds|_inputmod_invert_mouse);
2546 if (always_run_w->get_selection()) flags |= _inputmod_interchange_run_walk;
2547 if (always_swim_w->get_selection()) flags |= _inputmod_interchange_swim_sink;
2548 if (!(weapon_w->get_selection())) flags |= _inputmod_dont_switch_to_new_weapon;
2549 if (!(auto_recenter_w->get_selection())) flags |= _inputmod_dont_auto_recenter;
2550
2551 if (flags != input_preferences->modifiers) {
2552 input_preferences->modifiers = flags;
2553 changed = true;
2554 }
2555
2556 for (int i = 0; i < NUM_KEYS; i++) {
2557 input_preferences->key_bindings[i].clear();
2558 }
2559 for (int i = 0; i < NUMBER_OF_SHELL_KEYS; i++) {
2560 input_preferences->shell_key_bindings[i].clear();
2561 }
2562
2563 for (auto it = key_w.begin(); it != key_w.end(); ++it) {
2564 int i = it->first;
2565 SDL_Scancode key = it->second->get_key();
2566 if (key != SDL_SCANCODE_UNKNOWN) {
2567 unset_scancode(key);
2568 input_preferences->key_bindings[i].insert(key);
2569 changed = true;
2570 }
2571 }
2572
2573 for (auto it = shell_key_w.begin(); it != shell_key_w.end(); ++it) {
2574 int i = it->first;
2575 SDL_Scancode key = it->second->get_key();
2576 if (key != SDL_SCANCODE_UNKNOWN) {
2577 unset_scancode(key);
2578 input_preferences->shell_key_bindings[i].insert(key);
2579 changed = true;
2580 }
2581 }
2582
2583 int16 device = enable_mouse_w->get_selection() ? _mouse_yaw_pitch : _keyboard_or_game_pad;
2584 if (input_preferences->input_device != device) {
2585 input_preferences->input_device = device;
2586 changed = true;
2587 }
2588
2589 bool jaim = (joystick_aiming_w->get_selection() == 1);
2590 if (input_preferences->controller_analog != jaim) {
2591 input_preferences->controller_analog = jaim;
2592 changed = true;
2593 }
2594
2595 if (apply_mouse_feel(mouse_feel_w->get_selection())) {
2596 changed = true;
2597 }
2598
2599 if (changed)
2600 write_preferences();
2601 }
2602
2603 exit_joystick();
2604 }
2605
2606 extern void ResetAllMMLValues();
2607
plugins_dialog(void *)2608 static void plugins_dialog(void *)
2609 {
2610 dialog d;
2611 vertical_placer *placer = new vertical_placer;
2612 w_title *w_header = new w_title("PLUGINS");
2613 placer->dual_add(w_header, d);
2614 placer->add(new w_spacer, true);
2615
2616 std::vector<Plugin> plugins(Plugins::instance()->begin(), Plugins::instance()->end());
2617 w_plugins* plugins_w = new w_plugins(plugins, 400, 7);
2618 placer->dual_add(plugins_w, d);
2619
2620 placer->add(new w_spacer, true);
2621
2622 horizontal_placer* button_placer = new horizontal_placer;
2623 w_button* accept_w = new w_button("ACCEPT", dialog_ok, &d);
2624 button_placer->dual_add(accept_w, d);
2625 w_button* cancel_w = new w_button("CANCEL", dialog_cancel, &d);
2626 button_placer->dual_add(cancel_w, d);
2627
2628 placer->add(button_placer, true);
2629
2630 d.set_widget_placer(placer);
2631 d.activate_widget(plugins_w);
2632
2633 if (d.run() == 0) {
2634 bool changed = false;
2635 Plugins::iterator plugin = Plugins::instance()->begin();
2636 for (Plugins::iterator it = plugins.begin(); it != plugins.end(); ++it, ++plugin) {
2637 changed |= (plugin->enabled != it->enabled);
2638 plugin->enabled = it->enabled;
2639 }
2640
2641 if (changed) {
2642 Plugins::instance()->invalidate();
2643 write_preferences();
2644
2645 ResetAllMMLValues();
2646 LoadBaseMMLScripts();
2647 Plugins::instance()->load_mml();
2648 }
2649 }
2650 }
2651
2652
2653 /*
2654 * Environment dialog
2655 */
2656
2657 static const char* film_profile_labels[] = {
2658 "Aleph One",
2659 "Marathon 2",
2660 "Marathon Infinity",
2661 0
2662 };
2663
environment_dialog(void * arg)2664 static void environment_dialog(void *arg)
2665 {
2666 dialog *parent = (dialog *)arg;
2667
2668 // Create dialog
2669 dialog d;
2670 vertical_placer *placer = new vertical_placer;
2671 w_title *w_header = new w_title("ENVIRONMENT SETTINGS");
2672 placer->dual_add(w_header, d);
2673 placer->add(new w_spacer, true);
2674
2675 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
2676 table->col_flags(0, placeable::kAlignRight);
2677
2678 #ifndef MAC_APP_STORE
2679 w_env_select *map_w = new w_env_select(environment_preferences->map_file, "AVAILABLE MAPS", _typecode_scenario, &d);
2680 table->dual_add(map_w->label("Map"), d);
2681 table->dual_add(map_w, d);
2682
2683 w_env_select *physics_w = new w_env_select(environment_preferences->physics_file, "AVAILABLE PHYSICS MODELS", _typecode_physics, &d);
2684 table->dual_add(physics_w->label("Physics"), d);
2685 table->dual_add(physics_w, d);
2686
2687 w_env_select *shapes_w = new w_env_select(environment_preferences->shapes_file, "AVAILABLE SHAPES", _typecode_shapes, &d);
2688 table->dual_add(shapes_w->label("Shapes"), d);
2689 table->dual_add(shapes_w, d);
2690
2691 w_env_select *sounds_w = new w_env_select(environment_preferences->sounds_file, "AVAILABLE SOUNDS", _typecode_sounds, &d);
2692 table->dual_add(sounds_w->label("Sounds"), d);
2693 table->dual_add(sounds_w, d);
2694
2695 w_env_select* resources_w = new w_env_select(environment_preferences->resources_file, "AVAILABLE FILES", _typecode_unknown, &d);
2696 table->dual_add(resources_w->label("External Resources"), d);
2697 table->dual_add(resources_w, d);
2698 #endif
2699
2700 table->add_row(new w_spacer, true);
2701 table->dual_add_row(new w_button("PLUGINS", plugins_dialog, &d), d);
2702
2703 #ifndef MAC_APP_STORE
2704 table->add_row(new w_spacer, true);
2705 table->dual_add_row(new w_static_text("Solo Script"), d);
2706 w_enabling_toggle* use_solo_lua_w = new w_enabling_toggle(environment_preferences->use_solo_lua);
2707 table->dual_add(use_solo_lua_w->label("Use Solo Script"), d);
2708 table->dual_add(use_solo_lua_w, d);
2709
2710 w_file_chooser *solo_lua_w = new w_file_chooser("Choose Script", _typecode_netscript);
2711 solo_lua_w->set_file(environment_preferences->solo_lua_file);
2712 table->dual_add(solo_lua_w->label("Script File"), d);
2713 table->dual_add(solo_lua_w, d);
2714 use_solo_lua_w->add_dependent_widget(solo_lua_w);
2715 #endif
2716
2717 table->add_row(new w_spacer, true);
2718 table->dual_add_row(new w_static_text("Film Playback"), d);
2719
2720 w_select* film_profile_w = new w_select(environment_preferences->film_profile, film_profile_labels);
2721 table->dual_add(film_profile_w->label("Default Playback Profile"), d);
2722 table->dual_add(film_profile_w, d);
2723
2724 #ifndef MAC_APP_STORE
2725 w_enabling_toggle* use_replay_net_lua_w = new w_enabling_toggle(environment_preferences->use_replay_net_lua);
2726 table->dual_add(use_replay_net_lua_w->label("Use Netscript in Films"), d);
2727 table->dual_add(use_replay_net_lua_w, d);
2728
2729 w_file_chooser *replay_net_lua_w = new w_file_chooser("Choose Script", _typecode_netscript);
2730 replay_net_lua_w->set_file(network_preferences->netscript_file);
2731 table->dual_add(replay_net_lua_w->label("Netscript File"), d);
2732 table->dual_add(replay_net_lua_w, d);
2733 use_replay_net_lua_w->add_dependent_widget(replay_net_lua_w);
2734 #endif
2735
2736 table->add_row(new w_spacer, true);
2737 table->dual_add_row(new w_static_text("Options"), d);
2738
2739 #ifndef MAC_APP_STORE
2740 w_toggle *hide_extensions_w = new w_toggle(environment_preferences->hide_extensions);
2741 table->dual_add(hide_extensions_w->label("Hide File Extensions"), d);
2742 table->dual_add(hide_extensions_w, d);
2743 #endif
2744
2745 w_select *max_saves_w = new w_select(0, max_saves_labels);
2746 for (int i = 0; max_saves_labels[i] != NULL; ++i) {
2747 if (max_saves_values[i] == environment_preferences->maximum_quick_saves)
2748 max_saves_w->set_selection(i);
2749 }
2750 table->dual_add(max_saves_w->label("Unnamed Saves to Keep"), d);
2751 table->dual_add(max_saves_w, d);
2752
2753 placer->add(table, true);
2754
2755 placer->add(new w_spacer, true);
2756
2757 horizontal_placer *button_placer = new horizontal_placer;
2758 w_button *w_accept = new w_button("ACCEPT", dialog_ok, &d);
2759 button_placer->dual_add(w_accept, d);
2760 w_button *w_cancel = new w_button("CANCEL", dialog_cancel, &d);
2761 button_placer->dual_add(w_cancel, d);
2762 placer->add(button_placer, true);
2763
2764 d.set_widget_placer(placer);
2765
2766 // Clear screen
2767 clear_screen();
2768
2769 // Run dialog
2770 bool theme_changed = false;
2771 FileSpecifier old_theme;
2772 const Plugin* theme_plugin = Plugins::instance()->find_theme();
2773 if (theme_plugin)
2774 {
2775 old_theme = theme_plugin->directory + theme_plugin->theme;
2776 }
2777
2778 if (d.run() == 0) { // Accepted
2779 bool changed = false;
2780
2781 #ifndef MAC_APP_STORE
2782 const char *path = map_w->get_path();
2783 if (strcmp(path, environment_preferences->map_file)) {
2784 strncpy(environment_preferences->map_file, path, 256);
2785 environment_preferences->map_checksum = read_wad_file_checksum(map_w->get_file_specifier());
2786 changed = true;
2787 }
2788
2789 path = physics_w->get_path();
2790 if (strcmp(path, environment_preferences->physics_file)) {
2791 strncpy(environment_preferences->physics_file, path, 256);
2792 environment_preferences->physics_checksum = read_wad_file_checksum(physics_w->get_file_specifier());
2793 changed = true;
2794 }
2795
2796 path = shapes_w->get_path();
2797 if (strcmp(path, environment_preferences->shapes_file)) {
2798 strncpy(environment_preferences->shapes_file, path, 256);
2799 environment_preferences->shapes_mod_date = shapes_w->get_file_specifier().GetDate();
2800 changed = true;
2801 }
2802
2803 path = sounds_w->get_path();
2804 if (strcmp(path, environment_preferences->sounds_file)) {
2805 strncpy(environment_preferences->sounds_file, path, 256);
2806 environment_preferences->sounds_mod_date = sounds_w->get_file_specifier().GetDate();
2807 changed = true;
2808 }
2809
2810 path = resources_w->get_path();
2811 if (strcmp(path, environment_preferences->resources_file) != 0)
2812 {
2813 strncpy(environment_preferences->resources_file, path, 256);
2814 changed = true;
2815 }
2816
2817 bool use_solo_lua = use_solo_lua_w->get_selection() != 0;
2818 if (use_solo_lua != environment_preferences->use_solo_lua)
2819 {
2820 environment_preferences->use_solo_lua = use_solo_lua;
2821 changed = true;
2822 }
2823
2824 path = solo_lua_w->get_file().GetPath();
2825 if (strcmp(path, environment_preferences->solo_lua_file)) {
2826 strncpy(environment_preferences->solo_lua_file, path, 256);
2827 changed = true;
2828 }
2829
2830 bool use_replay_net_lua = use_replay_net_lua_w->get_selection() != 0;
2831 if (use_replay_net_lua != environment_preferences->use_replay_net_lua)
2832 {
2833 environment_preferences->use_replay_net_lua = use_replay_net_lua;
2834 changed = true;
2835 }
2836
2837 path = replay_net_lua_w->get_file().GetPath();
2838 if (strcmp(path, network_preferences->netscript_file)) {
2839 strncpy(network_preferences->netscript_file, path, 256);
2840 changed = true;
2841 }
2842 #endif
2843
2844 FileSpecifier new_theme;
2845 theme_plugin = Plugins::instance()->find_theme();
2846 if (theme_plugin)
2847 {
2848 new_theme = theme_plugin->directory + theme_plugin->theme;
2849 }
2850
2851 if (new_theme != old_theme)
2852 {
2853 theme_changed = true;
2854 }
2855
2856 #ifndef MAC_APP_STORE
2857 bool hide_extensions = hide_extensions_w->get_selection() != 0;
2858 if (hide_extensions != environment_preferences->hide_extensions)
2859 {
2860 environment_preferences->hide_extensions = hide_extensions;
2861 changed = true;
2862 }
2863 #endif
2864
2865 if (film_profile_w->get_selection() != environment_preferences->film_profile)
2866 {
2867 environment_preferences->film_profile = static_cast<FilmProfileType>(film_profile_w->get_selection());
2868
2869 changed = true;
2870 }
2871
2872 bool saves_changed = false;
2873 int saves = max_saves_values[max_saves_w->get_selection()];
2874 if (saves != environment_preferences->maximum_quick_saves) {
2875 environment_preferences->maximum_quick_saves = saves;
2876 saves_changed = true;
2877 }
2878
2879 if (changed)
2880 load_environment_from_preferences();
2881
2882 if (theme_changed) {
2883 load_dialog_theme();
2884 }
2885
2886 if (changed || theme_changed || saves_changed)
2887 write_preferences();
2888 }
2889
2890 // Redraw parent dialog
2891 if (theme_changed)
2892 parent->quit(0); // Quit the parent dialog so it won't draw in the old theme
2893 }
2894
2895
2896 extern void hub_set_minimum_send_period(int32);
2897 extern int32& hub_get_minimum_send_period();
2898
2899 struct set_latency_tolerance
2900 {
operator ()set_latency_tolerance2901 void operator() (const std::string& arg) const {
2902 hub_set_minimum_send_period(atoi(arg.c_str()));
2903 screen_printf("latency tolerance is now %i", atoi(arg.c_str()));
2904 write_preferences();
2905 }
2906 };
2907
2908 struct get_latency_tolerance
2909 {
operator ()get_latency_tolerance2910 void operator() (const std::string&) const {
2911 screen_printf("latency tolerance is %i", hub_get_minimum_send_period());
2912 }
2913 };
2914
transition_preferences(const DirectorySpecifier & legacy_preferences_dir)2915 void transition_preferences(const DirectorySpecifier& legacy_preferences_dir)
2916 {
2917 FileSpecifier prefs;
2918 prefs.SetToPreferencesDir();
2919 prefs += getcstr(temporary, strFILENAMES, filenamePREFERENCES);
2920 if (!prefs.Exists())
2921 {
2922 FileSpecifier oldPrefs;
2923 oldPrefs = legacy_preferences_dir;
2924 oldPrefs += getcstr(temporary, strFILENAMES, filenamePREFERENCES);
2925 if (oldPrefs.Exists())
2926 {
2927 oldPrefs.Rename(prefs);
2928 }
2929 }
2930 }
2931
2932 /*
2933 * Initialize preferences (load from file or setup defaults)
2934 */
2935
initialize_preferences(void)2936 void initialize_preferences(
2937 void)
2938 {
2939 logContext("initializing preferences");
2940
2941 // In case this function gets called more than once...
2942 if (!PrefsInited)
2943 {
2944 graphics_preferences= new graphics_preferences_data;
2945 player_preferences= new player_preferences_data;
2946 input_preferences= new input_preferences_data;
2947 sound_preferences = new SoundManager::Parameters;
2948 network_preferences= new network_preferences_data;
2949 environment_preferences= new environment_preferences_data;
2950
2951 for (int i = 0; i < NUM_KEYS; ++i)
2952 input_preferences->key_bindings[i] = std::set<SDL_Scancode>();
2953 for (int i = 0; i < NUMBER_OF_SHELL_KEYS; ++i)
2954 input_preferences->shell_key_bindings[i] = std::set<SDL_Scancode>();
2955
2956 PrefsInited = true;
2957
2958 CommandParser PreferenceSetCommandParser;
2959 PreferenceSetCommandParser.register_command("latency_tolerance", set_latency_tolerance());
2960 CommandParser PreferenceGetCommandParser;
2961 PreferenceGetCommandParser.register_command("latency_tolerance", get_latency_tolerance());
2962
2963 CommandParser PreferenceCommandParser;
2964 PreferenceCommandParser.register_command("set", PreferenceSetCommandParser);
2965 PreferenceCommandParser.register_command("get", PreferenceGetCommandParser);
2966 Console::instance()->register_command("preferences", PreferenceCommandParser);
2967
2968 read_preferences ();
2969 }
2970 }
2971
read_preferences()2972 void read_preferences ()
2973 {
2974 // Set to defaults; will be overridden by reading in the XML stuff
2975 default_graphics_preferences(graphics_preferences);
2976 default_network_preferences(network_preferences);
2977 default_player_preferences(player_preferences);
2978 default_input_preferences(input_preferences);
2979 *sound_preferences = SoundManager::Parameters();
2980 default_environment_preferences(environment_preferences);
2981
2982 // Slurp in the file and parse it
2983
2984 FileSpecifier FileSpec;
2985
2986 FileSpec.SetToPreferencesDir();
2987 FileSpec += getcstr(temporary, strFILENAMES, filenamePREFERENCES);
2988
2989 OpenedFile OFile;
2990 bool defaults = false;
2991 bool opened = FileSpec.Open(OFile);
2992
2993 if (!opened) {
2994 defaults = true;
2995 FileSpec.SetNameWithPath(getcstr(temporary, strFILENAMES, filenamePREFERENCES));
2996 opened = FileSpec.Open(OFile);
2997 }
2998
2999 bool parse_error = false;
3000 if (opened)
3001 {
3002 OFile.Close();
3003 try {
3004 InfoTree prefs = InfoTree::load_xml(FileSpec);
3005 InfoTree root = prefs.get_child("mara_prefs");
3006
3007 std::string version = "";
3008 root.read_attr("version", version);
3009 if (!version.length())
3010 logWarning("Reading older preferences of unknown version. Preferences will be upgraded to version %s when saved. (%s)", A1_DATE_VERSION, FileSpec.GetPath());
3011 else if (version < A1_DATE_VERSION)
3012 logWarning("Reading older preferences of version %s. Preferences will be upgraded to version %s when saved. (%s)", version.c_str(), A1_DATE_VERSION, FileSpec.GetPath());
3013 else if (version > A1_DATE_VERSION)
3014 logWarning("Reading newer preferences of version %s. Preferences will be downgraded to version %s when saved. (%s)", version.c_str(), A1_DATE_VERSION, FileSpec.GetPath());
3015
3016 BOOST_FOREACH(InfoTree child, root.children_named("graphics"))
3017 parse_graphics_preferences(child, version);
3018 BOOST_FOREACH(InfoTree child, root.children_named("player"))
3019 parse_player_preferences(child, version);
3020 BOOST_FOREACH(InfoTree child, root.children_named("input"))
3021 parse_input_preferences(child, version);
3022 BOOST_FOREACH(InfoTree child, root.children_named("sound"))
3023 parse_sound_preferences(child, version);
3024 #if !defined(DISABLE_NETWORKING)
3025 BOOST_FOREACH(InfoTree child, root.children_named("network"))
3026 parse_network_preferences(child, version);
3027 #endif
3028 BOOST_FOREACH(InfoTree child, root.children_named("environment"))
3029 parse_environment_preferences(child, version);
3030
3031 } catch (InfoTree::parse_error ex) {
3032 logError("Error parsing preferences file (%s): %s", FileSpec.GetPath(), ex.what());
3033 parse_error = true;
3034 } catch (InfoTree::path_error ep) {
3035 logError("Could not find mara_prefs in preferences file (%s): %s", FileSpec.GetPath(), ep.what());
3036 parse_error = true;
3037 } catch (InfoTree::data_error ed) {
3038 logError("Unexpected data error in preferences file (%s): %s", FileSpec.GetPath(), ed.what());
3039 parse_error = true;
3040 } catch (InfoTree::unexpected_error ee) {
3041 logError("Unexpected error in preferences file (%s): %s", FileSpec.GetPath(), ee.what());
3042 parse_error = true;
3043 }
3044 }
3045
3046 if (!opened || parse_error)
3047 {
3048 if (defaults)
3049 alert_user(expand_app_variables("There were default preferences-file parsing errors (see $appLogFile$ for details)").c_str(), infoError);
3050 else
3051 alert_user(expand_app_variables("There were preferences-file parsing errors (see $appLogFile$ for details)").c_str(), infoError);
3052 }
3053
3054 // Check on the read-in prefs
3055 validate_graphics_preferences(graphics_preferences);
3056 validate_network_preferences(network_preferences);
3057 validate_player_preferences(player_preferences);
3058 validate_input_preferences(input_preferences);
3059 validate_environment_preferences(environment_preferences);
3060
3061 // jkvw: If we try to load a default file, but can't, we'll have set the game error.
3062 // But that's not useful, because we're just going to try loading the file
3063 // from user preferences. It used to be this code was only called in initialisation,
3064 // and any game error generated here was simply clobbered by an init time
3065 // clear_game_error(). Since I'm using this more generally now, I'm clearing the
3066 // error right here, because it's not like we're bothered when we can't load a
3067 // default file.
3068 // (Problem is SDL specific - socre one for Carbon? :) )
3069 clear_game_error ();
3070 }
3071
3072
3073 /*
3074 * Write preferences to file
3075 */
3076
3077
graphics_preferences_tree()3078 InfoTree graphics_preferences_tree()
3079 {
3080 InfoTree root;
3081
3082 root.put_attr("scmode_width", graphics_preferences->screen_mode.width);
3083 root.put_attr("scmode_height", graphics_preferences->screen_mode.height);
3084 root.put_attr("scmode_auto_resolution", graphics_preferences->screen_mode.auto_resolution);
3085 root.put_attr("scmode_high_dpi", graphics_preferences->screen_mode.high_dpi);
3086 root.put_attr("scmode_hud", graphics_preferences->screen_mode.hud);
3087 root.put_attr("scmode_hud_scale", graphics_preferences->screen_mode.hud_scale_level);
3088 root.put_attr("scmode_term_scale", graphics_preferences->screen_mode.term_scale_level);
3089 root.put_attr("scmode_translucent_map", graphics_preferences->screen_mode.translucent_map);
3090 root.put_attr("scmode_camera_bob", graphics_preferences->screen_mode.camera_bob);
3091 root.put_attr("scmode_accel", graphics_preferences->screen_mode.acceleration);
3092 root.put_attr("scmode_highres", graphics_preferences->screen_mode.high_resolution);
3093 root.put_attr("scmode_fullscreen", graphics_preferences->screen_mode.fullscreen);
3094 root.put_attr("scmode_bitdepth", graphics_preferences->screen_mode.bit_depth);
3095 root.put_attr("scmode_gamma", graphics_preferences->screen_mode.gamma_level);
3096 root.put_attr("scmode_fix_h_not_v", graphics_preferences->screen_mode.fix_h_not_v);
3097 root.put_attr("ogl_flags", graphics_preferences->OGL_Configure.Flags);
3098 root.put_attr("software_alpha_blending", graphics_preferences->software_alpha_blending);
3099 root.put_attr("software_sdl_driver", graphics_preferences->software_sdl_driver);
3100 root.put_attr("anisotropy_level", graphics_preferences->OGL_Configure.AnisotropyLevel);
3101 root.put_attr("multisamples", graphics_preferences->OGL_Configure.Multisamples);
3102 root.put_attr("geforce_fix", graphics_preferences->OGL_Configure.GeForceFix);
3103 root.put_attr("wait_for_vsync", graphics_preferences->OGL_Configure.WaitForVSync);
3104 root.put_attr("gamma_corrected_blending", graphics_preferences->OGL_Configure.Use_sRGB);
3105 root.put_attr("use_npot", graphics_preferences->OGL_Configure.Use_NPOT);
3106 root.put_attr("double_corpse_limit", graphics_preferences->double_corpse_limit);
3107 root.put_attr("hog_the_cpu", graphics_preferences->hog_the_cpu);
3108 root.put_attr("movie_export_video_quality", graphics_preferences->movie_export_video_quality);
3109 root.put_attr("movie_export_audio_quality", graphics_preferences->movie_export_audio_quality);
3110
3111 root.add_color("void.color", graphics_preferences->OGL_Configure.VoidColor);
3112
3113 for (int i = 0; i < 4; ++i)
3114 for (int j = 0; j < 2; ++j)
3115 root.add_color("landscapes.color", graphics_preferences->OGL_Configure.LscpColors[i][j], 2*i+j);
3116
3117 for (int i = 0; i <= OGL_NUMBER_OF_TEXTURE_TYPES; ++i)
3118 {
3119 OGL_Texture_Configure& Config = (i == OGL_NUMBER_OF_TEXTURE_TYPES) ? graphics_preferences->OGL_Configure.ModelConfig : graphics_preferences->OGL_Configure.TxtrConfigList[i];
3120
3121 InfoTree tex;
3122 tex.put_attr("index", i);
3123 tex.put_attr("near_filter", Config.NearFilter);
3124 tex.put_attr("far_filter", Config.FarFilter);
3125 tex.put_attr("resolution", Config.Resolution);
3126 tex.put_attr("color_format", Config.ColorFormat);
3127 tex.put_attr("max_size", Config.MaxSize);
3128 root.add_child("texture", tex);
3129 }
3130 return root;
3131 }
3132
player_preferences_tree()3133 InfoTree player_preferences_tree()
3134 {
3135 InfoTree root;
3136
3137 root.put_attr_cstr("name", player_preferences->name);
3138 root.put_attr("color", player_preferences->color);
3139 root.put_attr("team", player_preferences->team);
3140 root.put_attr("last_time_ran", player_preferences->last_time_ran);
3141 root.put_attr("difficulty", player_preferences->difficulty_level);
3142 root.put_attr("bkgd_music", player_preferences->background_music_on);
3143 root.put_attr("crosshairs_active", player_preferences->crosshairs_active);
3144
3145 ChaseCamData& ChaseCam = player_preferences->ChaseCam;
3146 InfoTree cam;
3147 cam.put_attr("behind", ChaseCam.Behind);
3148 cam.put_attr("upward", ChaseCam.Upward);
3149 cam.put_attr("rightward", ChaseCam.Rightward);
3150 cam.put_attr("flags", ChaseCam.Flags);
3151 cam.put_attr("damping", ChaseCam.Damping);
3152 cam.put_attr("spring", ChaseCam.Spring);
3153 cam.put_attr("opacity", ChaseCam.Opacity);
3154 root.put_child("chase_cam", cam);
3155
3156 CrosshairData& Crosshairs = player_preferences->Crosshairs;
3157 InfoTree cross;
3158 cross.put_attr("thickness", Crosshairs.Thickness);
3159 cross.put_attr("from_center", Crosshairs.FromCenter);
3160 cross.put_attr("length", Crosshairs.Length);
3161 cross.put_attr("shape", Crosshairs.Shape);
3162 cross.put_attr("opacity", Crosshairs.Opacity);
3163 cross.add_color("color", Crosshairs.Color);
3164 root.put_child("crosshairs", cross);
3165
3166 return root;
3167 }
3168
3169 // symbolic names for key and button bindings
3170 static const char *binding_action_name[NUM_KEYS] = {
3171 "forward", "back", "look-left", "look-right", "strafe-left",
3172 "strafe-right", "glance-left", "glance-right", "look-up", "look-down",
3173 "look-ahead", "prev-weapon", "next-weapon", "trigger-1", "trigger-2",
3174 "strafe", "run", "look", "action", "map",
3175 "microphone"
3176 };
3177 static const char *binding_shell_action_name[NUMBER_OF_SHELL_KEYS] = {
3178 "inventory-left", "inventory-right", "switch-player-view", "volume-up", "volume-down",
3179 "map-zoom-in", "map-zoom-out", "fps", "chat", "net-stats"
3180 };
3181 static const char *binding_mouse_button_name[NUM_SDL_MOUSE_BUTTONS] = {
3182 "mouse-left", "mouse-middle", "mouse-right", "mouse-x1", "mouse-x2",
3183 "mouse-scroll-up", "mouse-scroll-down"
3184 };
3185 static const char *binding_joystick_button_name[NUM_SDL_JOYSTICK_BUTTONS] = {
3186 "controller-a", "controller-b", "controller-x", "controller-y",
3187 "controller-back", "controller-guide", "controller-start",
3188 "controller-ls", "controller-rs", "controller-lb", "controller-rb",
3189 "controller-up", "controller-down", "controller-left", "controller-right",
3190 "controller-ls-right", "controller-ls-down", "controller-rs-right",
3191 "controller-rs-down", "controller-lt", "controller-rt",
3192 "controller-ls-left", "controller-ls-up", "controller-rs-left",
3193 "controller-rs-up", "controller-lt-neg", "controller-rt-neg"
3194 };
3195 static const int binding_num_scancodes = 285;
3196 static const char *binding_scancode_name[binding_num_scancodes] = {
3197 "unknown", "unknown-1", "unknown-2", "unknown-3", "a",
3198 "b", "c", "d", "e", "f",
3199 "g", "h", "i", "j", "k",
3200 "l", "m", "n", "o", "p",
3201 "q", "r", "s", "t", "u",
3202 "v", "w", "x", "y", "z",
3203 "1", "2", "3", "4", "5",
3204 "6", "7", "8", "9", "unknown-39",
3205 "return", "escape", "backspace", "tab", "space",
3206 "minus", "equals", "leftbracket", "rightbracket", "backslash",
3207 "nonushash", "semicolon", "apostrophe", "grave", "comma",
3208 "period", "slash", "capslock", "f1", "f2",
3209 "f3", "f4", "f5", "f6", "f7",
3210 "f8", "f9", "f10", "f11", "f12",
3211 "printscreen", "scrolllock", "pause", "insert", "home",
3212 "pageup", "delete", "end", "pagedown", "right",
3213 "left", "down", "up", "numlockclear", "kp-divide",
3214 "kp-multiply", "kp-minus", "kp-plus", "kp-enter", "kp-1",
3215 "kp-2", "kp-3", "kp-4", "kp-5", "kp-6",
3216 "kp-7", "kp-8", "kp-9", "kp-0", "kp-period",
3217 "nonusbackslash", "application", "power", "kp-equals", "f13",
3218 "f14", "f15", "f16", "f17", "f18",
3219 "f19", "f20", "f21", "f22", "f23",
3220 "f24", "execute", "help", "menu", "select",
3221 "stop", "again", "undo", "cut", "copy",
3222 "paste", "find", "mute", "volumeup", "volumedown",
3223 "unknown-130", "unknown-131", "unknown-132", "kp-comma", "kp-equalsas400",
3224 "international1", "international2", "international3", "international4", "international5",
3225 "international6", "international7", "international8", "international9", "lang1",
3226 "lang2", "lang3", "lang4", "lang5", "lang6",
3227 "lang7", "lang8", "lang9", "alterase", "sysreq",
3228 "cancel", "clear", "prior", "return2", "separator",
3229 "out", "oper", "clearagain", "crsel", "exsel",
3230 "unknown-165", "unknown-166", "unknown-167", "unknown-168", "unknown-169",
3231 "unknown-170", "unknown-171", "unknown-172", "unknown-173", "unknown-174",
3232 "unknown-175", "kp-00", "kp-000", "thousandsseparator", "decimalseparator",
3233 "currencyunit", "currencysubunit", "kp-leftparen", "kp-rightparen", "kp-leftbrace",
3234 "kp-rightbrace", "kp-tab", "kp-backspace", "kp-a", "kp-b",
3235 "kp-c", "kp-d", "kp-e", "kp-f", "kp-xor",
3236 "kp-power", "kp-percent", "kp-less", "kp-greater", "kp-ampersand",
3237 "kp-dblampersand", "kp-verticalbar", "kp-dblverticalbar", "kp-colon", "kp-hash",
3238 "kp-space", "kp-at", "kp-exclam", "kp-memstore", "kp-memrecall",
3239 "kp-memclear", "kp-memadd", "kp-memsubtract", "kp-memmultiply", "kp-memdivide",
3240 "kp-plusminus", "kp-clear", "kp-clearentry", "kp-binary", "kp-octal",
3241 "kp-decimal", "kp-hexadecimal", "unknown-222", "unknown-223", "lctrl",
3242 "lshift", "lalt", "lgui", "rctrl", "rshift",
3243 "ralt", "rgui", "unknown-232", "unknown-233", "unknown-234",
3244 "unknown-235", "unknown-236", "unknown-237", "unknown-238", "unknown-239",
3245 "unknown-240", "unknown-241", "unknown-242", "unknown-243", "unknown-244",
3246 "unknown-245", "unknown-246", "unknown-247", "unknown-248", "unknown-249",
3247 "unknown-250", "unknown-251", "unknown-252", "unknown-253", "unknown-254",
3248 "unknown-255", "unknown-256", "mode", "audionext", "audioprev",
3249 "audiostop", "audioplay", "audiomute", "mediaselect", "www",
3250 "mail", "calculator", "computer", "ac-search", "ac-home",
3251 "ac-back", "ac-forward", "ac-stop", "ac-refresh", "ac-bookmarks",
3252 "brightnessdown", "brightnessup", "displayswitch", "kbdillumtoggle", "kbdillumdown",
3253 "kbdillumup", "eject", "sleep", "app1", "app2"
3254 };
3255
binding_name_for_code(SDL_Scancode code)3256 static const char *binding_name_for_code(SDL_Scancode code)
3257 {
3258 int i = static_cast<int>(code);
3259 if (i >= 0 &&
3260 i < binding_num_scancodes)
3261 return binding_scancode_name[i];
3262 else if (i >= AO_SCANCODE_BASE_MOUSE_BUTTON &&
3263 i < (AO_SCANCODE_BASE_MOUSE_BUTTON + NUM_SDL_MOUSE_BUTTONS))
3264 return binding_mouse_button_name[i - AO_SCANCODE_BASE_MOUSE_BUTTON];
3265 else if (i >= AO_SCANCODE_BASE_JOYSTICK_BUTTON &&
3266 i < (AO_SCANCODE_BASE_JOYSTICK_BUTTON + NUM_SDL_JOYSTICK_BUTTONS))
3267 return binding_joystick_button_name[i - AO_SCANCODE_BASE_JOYSTICK_BUTTON];
3268 return "unknown";
3269 }
3270
code_for_binding_name(std::string name)3271 static SDL_Scancode code_for_binding_name(std::string name)
3272 {
3273 for (int i = 0; i < binding_num_scancodes; ++i)
3274 {
3275 if (name == binding_scancode_name[i])
3276 return static_cast<SDL_Scancode>(i);
3277 }
3278 for (int i = 0; i < NUM_SDL_MOUSE_BUTTONS; ++i)
3279 {
3280 if (name == binding_mouse_button_name[i])
3281 return static_cast<SDL_Scancode>(i + AO_SCANCODE_BASE_MOUSE_BUTTON);
3282 }
3283 for (int i = 0; i < NUM_SDL_JOYSTICK_BUTTONS; ++i)
3284 {
3285 if (name == binding_joystick_button_name[i])
3286 return static_cast<SDL_Scancode>(i + AO_SCANCODE_BASE_JOYSTICK_BUTTON);
3287 }
3288 return SDL_SCANCODE_UNKNOWN;
3289 }
3290
index_for_action_name(std::string name,bool & is_shell)3291 static int index_for_action_name(std::string name, bool& is_shell)
3292 {
3293 for (int i = 0; i < NUM_KEYS; ++i)
3294 {
3295 if (name == binding_action_name[i])
3296 {
3297 is_shell = false;
3298 return i;
3299 }
3300 }
3301 for (int i = 0; i < NUMBER_OF_SHELL_KEYS; ++i)
3302 {
3303 if (name == binding_shell_action_name[i])
3304 {
3305 is_shell = true;
3306 return i;
3307 }
3308 }
3309 return -1;
3310 }
3311
input_preferences_tree()3312 InfoTree input_preferences_tree()
3313 {
3314 InfoTree root;
3315
3316 root.put_attr("device", input_preferences->input_device);
3317 root.put_attr("modifiers", input_preferences->modifiers);
3318 root.put_attr("sens_horizontal", input_preferences->sens_horizontal);
3319 root.put_attr("sens_vertical", input_preferences->sens_vertical);
3320 root.put_attr("classic_vertical_aim", input_preferences->classic_vertical_aim);
3321 root.put_attr("classic_aim_speed_limits", input_preferences->classic_aim_speed_limits);
3322 root.put_attr("mouse_accel_type", input_preferences->mouse_accel_type);
3323 root.put_attr("mouse_accel_scale", input_preferences->mouse_accel_scale);
3324 root.put_attr("raw_mouse_input", input_preferences->raw_mouse_input);
3325 root.put_attr("extra_mouse_precision", input_preferences->extra_mouse_precision);
3326
3327 root.put_attr("controller_analog", input_preferences->controller_analog);
3328 root.put_attr("controller_sensitivity", input_preferences->controller_sensitivity);
3329 root.put_attr("controller_deadzone", input_preferences->controller_deadzone);
3330
3331 for (int i = 0; i < (NUMBER_OF_KEYS + NUMBER_OF_SHELL_KEYS); ++i)
3332 {
3333 std::set<SDL_Scancode> codeset;
3334 const char *name;
3335 if (i < NUMBER_OF_KEYS) {
3336 codeset = input_preferences->key_bindings[i];
3337 name = binding_action_name[i];
3338 } else {
3339 codeset = input_preferences->shell_key_bindings[i - NUMBER_OF_KEYS];
3340 name = binding_shell_action_name[i - NUMBER_OF_KEYS];
3341 }
3342
3343 BOOST_FOREACH(const SDL_Scancode &code, codeset)
3344 {
3345 if (code == SDL_SCANCODE_UNKNOWN)
3346 continue;
3347 InfoTree key;
3348 key.put_attr("action", name);
3349 key.put_attr("pressed", binding_name_for_code(code));
3350 root.add_child("binding", key);
3351 }
3352 }
3353
3354 return root;
3355 }
3356
sound_preferences_tree()3357 InfoTree sound_preferences_tree()
3358 {
3359 InfoTree root;
3360
3361 root.put_attr("channels", sound_preferences->channel_count);
3362 root.put_attr("volume", sound_preferences->volume);
3363 root.put_attr("music_volume", sound_preferences->music);
3364 root.put_attr("flags", sound_preferences->flags);
3365 root.put_attr("rate", sound_preferences->rate);
3366 root.put_attr("samples", sound_preferences->samples);
3367 root.put_attr("volume_while_speaking", sound_preferences->volume_while_speaking);
3368 root.put_attr("mute_while_transmitting", sound_preferences->mute_while_transmitting);
3369
3370 return root;
3371 }
3372
network_preferences_tree()3373 InfoTree network_preferences_tree()
3374 {
3375 InfoTree root;
3376
3377 root.put_attr("microphone", network_preferences->allow_microphone);
3378 root.put_attr("untimed", network_preferences->game_is_untimed);
3379 root.put_attr("type", network_preferences->type);
3380 root.put_attr("game_type", network_preferences->game_type);
3381 root.put_attr("difficulty", network_preferences->difficulty_level);
3382 root.put_attr("game_options", network_preferences->game_options);
3383 root.put_attr("time_limit", network_preferences->time_limit);
3384 root.put_attr("kill_limit", network_preferences->kill_limit);
3385 root.put_attr("entry_point", network_preferences->entry_point);
3386 root.put_attr("autogather", network_preferences->autogather);
3387 root.put_attr("join_by_address", network_preferences->join_by_address);
3388 root.put_attr("join_address", network_preferences->join_address);
3389 root.put_attr("local_game_port", network_preferences->game_port);
3390 root.put_attr("game_protocol", sNetworkGameProtocolNames[network_preferences->game_protocol]);
3391 root.put_attr("use_speex_netmic_encoder", network_preferences->use_speex_encoder);
3392 root.put_attr("use_netscript", network_preferences->use_netscript);
3393 root.put_attr_path("netscript_file", network_preferences->netscript_file);
3394 root.put_attr("cheat_flags", network_preferences->cheat_flags);
3395 root.put_attr("advertise_on_metaserver", network_preferences->advertise_on_metaserver);
3396 root.put_attr("attempt_upnp", network_preferences->attempt_upnp);
3397 root.put_attr("check_for_updates", network_preferences->check_for_updates);
3398 root.put_attr("verify_https", network_preferences->verify_https);
3399 root.put_attr("metaserver_login", network_preferences->metaserver_login);
3400
3401 char passwd[33];
3402 for (int i = 0; i < 16; i++)
3403 sprintf(&passwd[2*i], "%.2x", network_preferences->metaserver_password[i] ^ sPasswordMask[i]);
3404 passwd[32] = '\0';
3405 root.put_attr("metaserver_password", passwd);
3406
3407 root.put_attr("use_custom_metaserver_colors", network_preferences->use_custom_metaserver_colors);
3408 root.put_attr("mute_metaserver_guests", network_preferences->mute_metaserver_guests);
3409 root.put_attr("join_metaserver_by_default", network_preferences->join_metaserver_by_default);
3410 root.put_attr("allow_stats", network_preferences->allow_stats);
3411
3412 for (int i = 0; i < 2; i++)
3413 root.add_color("color", network_preferences->metaserver_colors[i], i);
3414
3415 root.put_child("star_protocol", StarPreferencesTree());
3416 root.put_child("ring_protocol", RingPreferencesTree());
3417
3418 return root;
3419 }
3420
environment_preferences_tree()3421 InfoTree environment_preferences_tree()
3422 {
3423 InfoTree root;
3424
3425 root.put_attr_path("map_file", environment_preferences->map_file);
3426 root.put_attr_path("physics_file", environment_preferences->physics_file);
3427 root.put_attr_path("shapes_file", environment_preferences->shapes_file);
3428 root.put_attr_path("sounds_file", environment_preferences->sounds_file);
3429 root.put_attr_path("resources_file", environment_preferences->resources_file);
3430 root.put_attr("map_checksum", environment_preferences->map_checksum);
3431 root.put_attr("physics_checksum", environment_preferences->physics_checksum);
3432 root.put_attr("shapes_mod_date", static_cast<uint32>(environment_preferences->shapes_mod_date));
3433 root.put_attr("sounds_mod_date", static_cast<uint32>(environment_preferences->sounds_mod_date));
3434 root.put_attr("group_by_directory", environment_preferences->group_by_directory);
3435 root.put_attr("reduce_singletons", environment_preferences->reduce_singletons);
3436 root.put_attr("smooth_text", environment_preferences->smooth_text);
3437 root.put_attr_path("solo_lua_file", environment_preferences->solo_lua_file);
3438 root.put_attr("use_solo_lua", environment_preferences->use_solo_lua);
3439 root.put_attr("use_replay_net_lua", environment_preferences->use_replay_net_lua);
3440 root.put_attr("hide_alephone_extensions", environment_preferences->hide_extensions);
3441 root.put_attr("film_profile", static_cast<uint32>(environment_preferences->film_profile));
3442 root.put_attr("maximum_quick_saves", environment_preferences->maximum_quick_saves);
3443
3444 for (Plugins::iterator it = Plugins::instance()->begin(); it != Plugins::instance()->end(); ++it) {
3445 if (it->compatible() && !it->enabled) {
3446 InfoTree disable;
3447 disable.put_attr_path("path", it->directory.GetPath());
3448 root.add_child("disable_plugin", disable);
3449 }
3450 }
3451
3452 return root;
3453 }
3454
write_preferences()3455 void write_preferences()
3456 {
3457 InfoTree root;
3458 root.put_attr("version", A1_DATE_VERSION);
3459
3460 root.put_child("graphics", graphics_preferences_tree());
3461 root.put_child("player", player_preferences_tree());
3462 root.put_child("input", input_preferences_tree());
3463 root.put_child("sound", sound_preferences_tree());
3464 #if !defined(DISABLE_NETWORKING)
3465 root.put_child("network", network_preferences_tree());
3466 #endif
3467 root.put_child("environment", environment_preferences_tree());
3468
3469 InfoTree fileroot;
3470 fileroot.put_child("mara_prefs", root);
3471
3472 FileSpecifier FileSpec;
3473 FileSpec.SetToPreferencesDir();
3474 FileSpec += getcstr(temporary, strFILENAMES, filenamePREFERENCES);
3475
3476 try {
3477 fileroot.save_xml(FileSpec);
3478 } catch (InfoTree::parse_error ex) {
3479 logError("Error saving preferences file (%s): %s", FileSpec.GetPath(), ex.what());
3480 } catch (InfoTree::unexpected_error ex) {
3481 logError("Error saving preferences file (%s): %s", FileSpec.GetPath(), ex.what());
3482 }
3483 }
3484
3485
3486 /*
3487 * Setup default preferences
3488 */
3489
default_graphics_preferences(graphics_preferences_data * preferences)3490 static void default_graphics_preferences(graphics_preferences_data *preferences)
3491 {
3492 memset(&preferences->screen_mode, '\0', sizeof(screen_mode_data));
3493 preferences->screen_mode.gamma_level= DEFAULT_GAMMA_LEVEL;
3494
3495 preferences->screen_mode.width = 640;
3496 preferences->screen_mode.height = 480;
3497 preferences->screen_mode.auto_resolution = true;
3498 preferences->screen_mode.high_dpi = true;
3499 preferences->screen_mode.hud = true;
3500 preferences->screen_mode.hud_scale_level = 0;
3501 preferences->screen_mode.term_scale_level = 2;
3502 preferences->screen_mode.translucent_map = true;
3503 preferences->screen_mode.acceleration = _opengl_acceleration;
3504 preferences->screen_mode.high_resolution = true;
3505 preferences->screen_mode.fullscreen = true;
3506 preferences->screen_mode.fix_h_not_v = true;
3507 preferences->screen_mode.camera_bob = true;
3508 preferences->screen_mode.bit_depth = 32;
3509
3510 preferences->screen_mode.draw_every_other_line= false;
3511
3512 OGL_SetDefaults(preferences->OGL_Configure);
3513
3514 preferences->double_corpse_limit= false;
3515 preferences->hog_the_cpu = false;
3516
3517 preferences->software_alpha_blending = _sw_alpha_off;
3518 preferences->software_sdl_driver = _sw_driver_default;
3519
3520 preferences->movie_export_video_quality = 50;
3521 preferences->movie_export_audio_quality = 50;
3522 }
3523
default_network_preferences(network_preferences_data * preferences)3524 static void default_network_preferences(network_preferences_data *preferences)
3525 {
3526 preferences->type= _ethernet;
3527
3528 preferences->allow_microphone = true;
3529 preferences->game_is_untimed = false;
3530 preferences->difficulty_level = 2;
3531 preferences->game_options = _multiplayer_game | _ammo_replenishes | _weapons_replenish
3532 | _specials_replenish | _burn_items_on_death
3533 | _force_unique_teams | _live_network_stats;
3534 preferences->time_limit = 10 * TICKS_PER_SECOND * 60;
3535 preferences->kill_limit = 10;
3536 preferences->entry_point= 0;
3537 preferences->game_type= _game_of_kill_monsters;
3538 preferences->autogather= false;
3539 preferences->join_by_address= false;
3540 obj_clear(preferences->join_address);
3541 preferences->game_port= DEFAULT_GAME_PORT;
3542 preferences->game_protocol= _network_game_protocol_default;
3543 #if !defined(DISABLE_NETWORKING)
3544 DefaultStarPreferences();
3545 DefaultRingPreferences();
3546 #endif // !defined(DISABLE_NETWORKING)
3547 preferences->use_speex_encoder = true;
3548 preferences->use_netscript = false;
3549 preferences->netscript_file[0] = '\0';
3550 preferences->cheat_flags = _allow_tunnel_vision | _allow_crosshair | _allow_behindview | _allow_overlay_map;
3551 preferences->advertise_on_metaserver = false;
3552 preferences->attempt_upnp = false;
3553 preferences->check_for_updates = true;
3554 preferences->verify_https = false;
3555 strncpy(preferences->metaserver_login, "guest", preferences->kMetaserverLoginLength);
3556 memset(preferences->metaserver_password, 0, preferences->kMetaserverLoginLength);
3557 preferences->mute_metaserver_guests = false;
3558 preferences->use_custom_metaserver_colors = false;
3559 preferences->metaserver_colors[0] = get_interface_color(PLAYER_COLOR_BASE_INDEX);
3560 preferences->metaserver_colors[1] = get_interface_color(PLAYER_COLOR_BASE_INDEX);
3561 preferences->join_metaserver_by_default = false;
3562 preferences->allow_stats = false;
3563 }
3564
default_player_preferences(player_preferences_data * preferences)3565 static void default_player_preferences(player_preferences_data *preferences)
3566 {
3567 obj_clear(*preferences);
3568
3569 preferences->difficulty_level= 2;
3570 strncpy(preferences->name, get_name_from_system().c_str(), PREFERENCES_NAME_LENGTH+1);
3571
3572 // LP additions for new fields:
3573
3574 preferences->ChaseCam.Behind = 1536;
3575 preferences->ChaseCam.Upward = 0;
3576 preferences->ChaseCam.Rightward = 0;
3577 preferences->ChaseCam.Flags = 0;
3578 preferences->ChaseCam.Damping = 0.5;
3579 preferences->ChaseCam.Spring = 0;
3580 preferences->ChaseCam.Opacity = 1;
3581
3582 preferences->Crosshairs.Thickness = 3;
3583 preferences->Crosshairs.FromCenter = 2;
3584 preferences->Crosshairs.Length = 1;
3585 preferences->Crosshairs.Shape = CHShape_RealCrosshairs;
3586 preferences->Crosshairs.Color = rgb_white;
3587 preferences->Crosshairs.Opacity = 0.5;
3588 preferences->Crosshairs.PreCalced = false;
3589 }
3590
default_input_preferences(input_preferences_data * preferences)3591 static void default_input_preferences(input_preferences_data *preferences)
3592 {
3593 preferences->input_device= _mouse_yaw_pitch;
3594 preferences->key_bindings = default_key_bindings;
3595 preferences->shell_key_bindings = default_shell_key_bindings;
3596
3597 // LP addition: set up defaults for modifiers:
3598 // interchange run and walk, but don't interchange swim and sink.
3599 preferences->modifiers = _inputmod_interchange_run_walk;
3600
3601 // LP: split into horizontal and vertical sensitivities
3602 // ZZZ addition: sensitivity factor starts at 1 (no adjustment)
3603 preferences->sens_horizontal = FIXED_ONE;
3604 preferences->sens_vertical = FIXED_ONE;
3605 preferences->mouse_accel_type = _mouse_accel_none;
3606 preferences->mouse_accel_scale = 1.f;
3607 preferences->raw_mouse_input = true;
3608 preferences->extra_mouse_precision = true;
3609 preferences->classic_vertical_aim = false;
3610 preferences->classic_aim_speed_limits = true;
3611
3612 preferences->controller_analog = true;
3613 preferences->controller_sensitivity = FIXED_ONE;
3614 preferences->controller_deadzone = 3276;
3615 }
3616
default_environment_preferences(environment_preferences_data * preferences)3617 static void default_environment_preferences(environment_preferences_data *preferences)
3618 {
3619 obj_set(*preferences, NONE);
3620
3621 FileSpecifier DefaultMapFile;
3622 FileSpecifier DefaultShapesFile;
3623 FileSpecifier DefaultSoundsFile;
3624 FileSpecifier DefaultPhysicsFile;
3625 FileSpecifier DefaultExternalResourcesFile;
3626
3627 get_default_map_spec(DefaultMapFile);
3628 get_default_physics_spec(DefaultPhysicsFile);
3629 get_default_shapes_spec(DefaultShapesFile);
3630 get_default_sounds_spec(DefaultSoundsFile);
3631 get_default_external_resources_spec(DefaultExternalResourcesFile);
3632
3633 preferences->map_checksum= read_wad_file_checksum(DefaultMapFile);
3634 strncpy(preferences->map_file, DefaultMapFile.GetPath(), 256);
3635 preferences->map_file[255] = 0;
3636
3637 preferences->physics_checksum= read_wad_file_checksum(DefaultPhysicsFile);
3638 strncpy(preferences->physics_file, DefaultPhysicsFile.GetPath(), 256);
3639 preferences->physics_file[255] = 0;
3640
3641 preferences->shapes_mod_date = DefaultShapesFile.GetDate();
3642 strncpy(preferences->shapes_file, DefaultShapesFile.GetPath(), 256);
3643 preferences->shapes_file[255] = 0;
3644
3645 preferences->sounds_mod_date = DefaultSoundsFile.GetDate();
3646 strncpy(preferences->sounds_file, DefaultSoundsFile.GetPath(), 256);
3647 preferences->sounds_file[255] = 0;
3648
3649 strncpy(preferences->resources_file, DefaultExternalResourcesFile.GetPath(), 256);
3650 preferences->resources_file[255] = 0;
3651
3652 preferences->group_by_directory = true;
3653 preferences->reduce_singletons = false;
3654 preferences->smooth_text = true;
3655
3656 preferences->solo_lua_file[0] = 0;
3657 preferences->use_solo_lua = false;
3658 preferences->use_replay_net_lua = false;
3659 preferences->hide_extensions = true;
3660 preferences->film_profile = FILM_PROFILE_DEFAULT;
3661 preferences->maximum_quick_saves = 0;
3662 }
3663
3664
3665 /*
3666 * Validate preferences
3667 */
3668
validate_graphics_preferences(graphics_preferences_data * preferences)3669 static bool validate_graphics_preferences(graphics_preferences_data *preferences)
3670 {
3671 bool changed= false;
3672
3673 // Fix bool options
3674 preferences->screen_mode.high_resolution = !!preferences->screen_mode.high_resolution;
3675 preferences->screen_mode.fullscreen = !!preferences->screen_mode.fullscreen;
3676 preferences->screen_mode.draw_every_other_line = !!preferences->screen_mode.draw_every_other_line;
3677 preferences->screen_mode.fix_h_not_v = !!preferences->screen_mode.fix_h_not_v;
3678
3679 if(preferences->screen_mode.gamma_level<0 || preferences->screen_mode.gamma_level>=NUMBER_OF_GAMMA_LEVELS)
3680 {
3681 preferences->screen_mode.gamma_level= DEFAULT_GAMMA_LEVEL;
3682 changed= true;
3683 }
3684
3685 if (preferences->screen_mode.acceleration != _no_acceleration && preferences->screen_mode.acceleration != _opengl_acceleration)
3686 preferences->screen_mode.acceleration = _opengl_acceleration;
3687
3688 // OpenGL requires at least 16 bit color depth
3689 if (preferences->screen_mode.acceleration != _no_acceleration && preferences->screen_mode.bit_depth == 8)
3690 {
3691 preferences->screen_mode.bit_depth= 16;
3692 changed= true;
3693 }
3694
3695 #ifdef TRUE_COLOR_ONLY
3696 if (preferences->screen_mode.bit_depth == 8)
3697 {
3698 preferences->screen_mode.bit_depth = 16;
3699 changed = true;
3700 }
3701 #endif
3702
3703 return changed;
3704 }
3705
validate_network_preferences(network_preferences_data * preferences)3706 static bool validate_network_preferences(network_preferences_data *preferences)
3707 {
3708 bool changed= false;
3709
3710 // Fix bool options
3711 preferences->allow_microphone = !!preferences->allow_microphone;
3712 preferences->game_is_untimed = !!preferences->game_is_untimed;
3713
3714 if(preferences->type<0||preferences->type>_ethernet)
3715 {
3716 if(ethernet_active())
3717 {
3718 preferences->type= _ethernet;
3719 } else {
3720 preferences->type= _localtalk;
3721 }
3722 changed= true;
3723 }
3724
3725 if(preferences->game_is_untimed != true && preferences->game_is_untimed != false)
3726 {
3727 preferences->game_is_untimed= false;
3728 changed= true;
3729 }
3730
3731 if(preferences->allow_microphone != true && preferences->allow_microphone != false)
3732 {
3733 preferences->allow_microphone= true;
3734 changed= true;
3735 }
3736
3737 if(preferences->game_type<0 || preferences->game_type >= NUMBER_OF_GAME_TYPES)
3738 {
3739 preferences->game_type= _game_of_kill_monsters;
3740 changed= true;
3741 }
3742
3743 // ZZZ: is this relevant anymore now with XML prefs? if so, should validate autogather, join_by_address, and join_address.
3744
3745 if(preferences->game_protocol >= NUMBER_OF_NETWORK_GAME_PROTOCOLS)
3746 {
3747 preferences->game_protocol= _network_game_protocol_default;
3748 changed= true;
3749 }
3750
3751 return changed;
3752 }
3753
validate_player_preferences(player_preferences_data * preferences)3754 static bool validate_player_preferences(player_preferences_data *preferences)
3755 {
3756 // Fix bool options
3757 preferences->background_music_on = !!preferences->background_music_on;
3758
3759 return false;
3760 }
3761
validate_input_preferences(input_preferences_data * preferences)3762 static bool validate_input_preferences(input_preferences_data *preferences)
3763 {
3764 (void) (preferences);
3765 return false;
3766 }
3767
validate_environment_preferences(environment_preferences_data * preferences)3768 static bool validate_environment_preferences(environment_preferences_data *preferences)
3769 {
3770 (void) (preferences);
3771 return false;
3772 }
3773
3774
3775 /*
3776 * Load the environment
3777 */
3778
3779 /* Load the environment.. */
load_environment_from_preferences(void)3780 void load_environment_from_preferences(
3781 void)
3782 {
3783 FileSpecifier File;
3784 struct environment_preferences_data *prefs= environment_preferences;
3785
3786 File = prefs->map_file;
3787 if (File.Exists()) {
3788 set_map_file(File);
3789 } else {
3790 /* Try to find the checksum */
3791 if(find_wad_file_that_has_checksum(File,
3792 _typecode_scenario, strPATHS, prefs->map_checksum)) {
3793 set_map_file(File);
3794 } else {
3795 set_to_default_map();
3796 }
3797 }
3798
3799 File = prefs->physics_file;
3800 if (File.Exists()) {
3801 set_physics_file(File);
3802 import_definition_structures();
3803 } else {
3804 if(find_wad_file_that_has_checksum(File,
3805 _typecode_physics, strPATHS, prefs->physics_checksum)) {
3806 set_physics_file(File);
3807 import_definition_structures();
3808 } else {
3809 /* Didn't find it. Don't change them.. */
3810 }
3811 }
3812
3813 File = prefs->shapes_file;
3814 if (File.Exists()) {
3815 open_shapes_file(File);
3816 } else {
3817 if(find_file_with_modification_date(File,
3818 _typecode_shapes, strPATHS, prefs->shapes_mod_date))
3819 {
3820 open_shapes_file(File);
3821 } else {
3822 /* What should I do? */
3823 }
3824 }
3825
3826 File = prefs->sounds_file;
3827 if (File.Exists()) {
3828 SoundManager::instance()->OpenSoundFile(File);
3829 } else {
3830 if(find_file_with_modification_date(File,
3831 _typecode_sounds, strPATHS, prefs->sounds_mod_date)) {
3832 SoundManager::instance()->OpenSoundFile(File);
3833 } else {
3834 /* What should I do? */
3835 }
3836 }
3837
3838 File = prefs->resources_file;
3839 if (File.Exists())
3840 {
3841 set_external_resources_file(File);
3842 }
3843 set_external_resources_images_file(File);
3844 }
3845
3846
3847 // LP addition: get these from the preferences data
GetChaseCamData()3848 ChaseCamData& GetChaseCamData() {return player_preferences->ChaseCam;}
GetCrosshairData()3849 CrosshairData& GetCrosshairData() {return player_preferences->Crosshairs;}
Get_OGL_ConfigureData()3850 OGL_ConfigureData& Get_OGL_ConfigureData() {return graphics_preferences->OGL_Configure;}
3851
3852
3853 // ZZZ: override player-behavior modifiers
3854 static bool sStandardizeModifiers = false;
3855
3856
3857 void
standardize_player_behavior_modifiers()3858 standardize_player_behavior_modifiers() {
3859 sStandardizeModifiers = true;
3860 }
3861
3862
3863 void
restore_custom_player_behavior_modifiers()3864 restore_custom_player_behavior_modifiers() {
3865 sStandardizeModifiers = false;
3866 }
3867
3868
3869 bool
is_player_behavior_standard()3870 is_player_behavior_standard() {
3871 return !dont_switch_to_new_weapon();
3872 }
3873
3874
3875 // LP addition: modification of Josh Elsasser's dont-switch-weapons patch
3876 // so as to access preferences stuff here
dont_switch_to_new_weapon()3877 bool dont_switch_to_new_weapon() {
3878 // ZZZ: let game require standard modifiers for a while
3879 if(!sStandardizeModifiers)
3880 return TEST_FLAG(input_preferences->modifiers,_inputmod_dont_switch_to_new_weapon);
3881 else
3882 return false;
3883 }
3884
3885
3886 bool
dont_auto_recenter()3887 dont_auto_recenter() {
3888 return TEST_FLAG(input_preferences->modifiers, _inputmod_dont_auto_recenter);
3889 }
3890
3891
3892 // LP additions: MML-like prefs stuff
3893 // These parsers are intended to work correctly on both Mac and SDL prefs files;
3894 // including one crossing over to the other platform (uninterpreted fields become defaults)
3895
3896 // To get around both RGBColor and rgb_color being used in the code
CopyColor(CType1 & Dest,CType2 & Src)3897 template<class CType1, class CType2> void CopyColor(CType1& Dest, CType2& Src)
3898 {
3899 Dest.red = Src.red;
3900 Dest.green = Src.green;
3901 Dest.blue = Src.blue;
3902 }
3903
3904
3905
3906 struct ViewSizeData
3907 {
3908 short Width, Height;
3909 bool HUD;
3910 };
3911
3912 const ViewSizeData LegacyViewSizes[32] =
3913 {
3914 { 320, 160, true},
3915 { 480, 240, true},
3916 { 640, 480, true},
3917 { 640, 480, false},
3918 { 800, 600, true},
3919 { 800, 600, false},
3920 { 1024, 768, true},
3921 { 1024, 768, false},
3922 { 1280, 1024, true},
3923 { 1280, 1024, false},
3924 { 1600, 1200, true},
3925 { 1600, 1200, false},
3926 { 1024, 640, true},
3927 { 1024, 640, false},
3928 { 1280, 800, true},
3929 { 1280, 800, false},
3930 { 1280, 854, true},
3931 { 1280, 854, false},
3932 { 1440, 900, true},
3933 { 1440, 900, false},
3934 { 1680, 1050, true},
3935 { 1680, 1050, false},
3936 { 1920, 1200, true},
3937 { 1920, 1200, false},
3938 { 2560, 1600, true},
3939 { 2560, 1600, false},
3940 { 1280, 768, true},
3941 { 1280, 768, false},
3942 { 1280, 960, true},
3943 { 1280, 960, false},
3944 { 1280, 720, true},
3945 { 1280, 720, false}
3946 };
3947
parse_graphics_preferences(InfoTree root,std::string version)3948 void parse_graphics_preferences(InfoTree root, std::string version)
3949 {
3950 int scmode = -1;
3951 root.read_attr("scmode_size", scmode);
3952 if (scmode >= 0 && scmode < 32)
3953 {
3954 graphics_preferences->screen_mode.height = LegacyViewSizes[scmode].Height;
3955 graphics_preferences->screen_mode.width = LegacyViewSizes[scmode].Width;
3956 graphics_preferences->screen_mode.hud = LegacyViewSizes[scmode].HUD;
3957 }
3958
3959 root.read_attr("scmode_height", graphics_preferences->screen_mode.height);
3960 root.read_attr("scmode_width", graphics_preferences->screen_mode.width);
3961 root.read_attr("scmode_auto_resolution", graphics_preferences->screen_mode.auto_resolution);
3962 root.read_attr("scmode_high_dpi", graphics_preferences->screen_mode.high_dpi);
3963 root.read_attr("scmode_hud", graphics_preferences->screen_mode.hud);
3964 root.read_attr("scmode_hud_scale", graphics_preferences->screen_mode.hud_scale_level);
3965 root.read_attr("scmode_term_scale", graphics_preferences->screen_mode.term_scale_level);
3966 root.read_attr("scmode_translucent_map", graphics_preferences->screen_mode.translucent_map);
3967 root.read_attr("scmode_camera_bob", graphics_preferences->screen_mode.camera_bob);
3968 root.read_attr("scmode_accel", graphics_preferences->screen_mode.acceleration);
3969 root.read_attr("scmode_highres", graphics_preferences->screen_mode.high_resolution);
3970 root.read_attr("scmode_fullscreen", graphics_preferences->screen_mode.fullscreen);
3971
3972 root.read_attr("scmode_fix_h_not_v", graphics_preferences->screen_mode.fix_h_not_v);
3973 root.read_attr("scmode_bitdepth", graphics_preferences->screen_mode.bit_depth);
3974 root.read_attr("scmode_gamma", graphics_preferences->screen_mode.gamma_level);
3975 root.read_attr("ogl_flags", graphics_preferences->OGL_Configure.Flags);
3976 root.read_attr("software_alpha_blending", graphics_preferences->software_alpha_blending);
3977 root.read_attr("software_sdl_driver", graphics_preferences->software_sdl_driver);
3978 root.read_attr("anisotropy_level", graphics_preferences->OGL_Configure.AnisotropyLevel);
3979 root.read_attr("multisamples", graphics_preferences->OGL_Configure.Multisamples);
3980 root.read_attr("geforce_fix", graphics_preferences->OGL_Configure.GeForceFix);
3981 root.read_attr("wait_for_vsync", graphics_preferences->OGL_Configure.WaitForVSync);
3982 root.read_attr("gamma_corrected_blending", graphics_preferences->OGL_Configure.Use_sRGB);
3983 root.read_attr("use_npot", graphics_preferences->OGL_Configure.Use_NPOT);
3984 root.read_attr("double_corpse_limit", graphics_preferences->double_corpse_limit);
3985 root.read_attr("hog_the_cpu", graphics_preferences->hog_the_cpu);
3986 root.read_attr_bounded<int16>("movie_export_video_quality", graphics_preferences->movie_export_video_quality, 0, 100);
3987 root.read_attr_bounded<int16>("movie_export_audio_quality", graphics_preferences->movie_export_audio_quality, 0, 100);
3988
3989
3990 BOOST_FOREACH(InfoTree vtree, root.children_named("void"))
3991 {
3992 BOOST_FOREACH(InfoTree color, vtree.children_named("color"))
3993 {
3994 color.read_color(graphics_preferences->OGL_Configure.VoidColor);
3995 }
3996 }
3997
3998 BOOST_FOREACH(InfoTree landscape, root.children_named("landscapes"))
3999 {
4000 BOOST_FOREACH(InfoTree color, root.children_named("color"))
4001 {
4002 int16 index;
4003 if (color.read_indexed("index", index, 8))
4004 color.read_color(graphics_preferences->OGL_Configure.LscpColors[index / 2][index % 2]);
4005 }
4006 }
4007
4008 BOOST_FOREACH(InfoTree tex, root.children_named("texture"))
4009 {
4010 int16 index;
4011 if (tex.read_indexed("index", index, OGL_NUMBER_OF_TEXTURE_TYPES+1))
4012 {
4013 OGL_Texture_Configure& Config = (index == OGL_NUMBER_OF_TEXTURE_TYPES) ? graphics_preferences->OGL_Configure.ModelConfig : graphics_preferences->OGL_Configure.TxtrConfigList[index];
4014 tex.read_attr("near_filter", Config.NearFilter);
4015 tex.read_attr("far_filter", Config.FarFilter);
4016 tex.read_attr("resolution", Config.Resolution);
4017 tex.read_attr("color_format", Config.ColorFormat);
4018 tex.read_attr("max_size", Config.MaxSize);
4019 }
4020 }
4021 }
4022
4023
parse_player_preferences(InfoTree root,std::string version)4024 void parse_player_preferences(InfoTree root, std::string version)
4025 {
4026 root.read_cstr("name", player_preferences->name, PREFERENCES_NAME_LENGTH);
4027 root.read_attr("color", player_preferences->color);
4028 root.read_attr("team", player_preferences->team);
4029 root.read_attr("last_time_ran", player_preferences->last_time_ran);
4030 root.read_attr("difficulty", player_preferences->difficulty_level);
4031 root.read_attr("bkgd_music", player_preferences->background_music_on);
4032 root.read_attr("crosshairs_active", player_preferences->crosshairs_active);
4033
4034 BOOST_FOREACH(InfoTree child, root.children_named("chase_cam"))
4035 {
4036 child.read_attr("behind", player_preferences->ChaseCam.Behind);
4037 child.read_attr("upward", player_preferences->ChaseCam.Upward);
4038 child.read_attr("rightward", player_preferences->ChaseCam.Rightward);
4039 child.read_attr("flags", player_preferences->ChaseCam.Flags);
4040 child.read_attr("damping", player_preferences->ChaseCam.Damping);
4041 child.read_attr("spring", player_preferences->ChaseCam.Spring);
4042 child.read_attr("opacity", player_preferences->ChaseCam.Opacity);
4043 }
4044
4045 BOOST_FOREACH(InfoTree child, root.children_named("crosshairs"))
4046 {
4047 child.read_attr("thickness", player_preferences->Crosshairs.Thickness);
4048 child.read_attr("from_center", player_preferences->Crosshairs.FromCenter);
4049 child.read_attr("length", player_preferences->Crosshairs.Length);
4050 child.read_attr("shape", player_preferences->Crosshairs.Shape);
4051 child.read_attr("opacity", player_preferences->Crosshairs.Opacity);
4052
4053 BOOST_FOREACH(InfoTree color, child.children_named("color"))
4054 color.read_color(player_preferences->Crosshairs.Color);
4055 }
4056 }
4057
translate_old_key(int code)4058 SDL_Scancode translate_old_key(int code)
4059 {
4060 static int num_key_lookups = 323;
4061 static SDL_Keycode key_lookups[] = {
4062 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4063 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_BACKSPACE, SDLK_TAB,
4064 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_CLEAR, SDLK_RETURN, SDLK_UNKNOWN,
4065 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_PAUSE,
4066 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4067 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_ESCAPE, SDLK_UNKNOWN, SDLK_UNKNOWN,
4068 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_SPACE, SDLK_EXCLAIM, SDLK_QUOTEDBL,
4069 SDLK_HASH, SDLK_DOLLAR, SDLK_UNKNOWN, SDLK_AMPERSAND, SDLK_QUOTE,
4070 SDLK_LEFTPAREN, SDLK_RIGHTPAREN, SDLK_ASTERISK, SDLK_PLUS, SDLK_COMMA,
4071 SDLK_MINUS, SDLK_PERIOD, SDLK_SLASH, SDLK_0, SDLK_1,
4072 SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6,
4073 SDLK_7, SDLK_8, SDLK_9, SDLK_COLON, SDLK_SEMICOLON,
4074 SDLK_LESS, SDLK_EQUALS, SDLK_GREATER, SDLK_QUESTION, SDLK_AT,
4075 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4076 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4077 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4078 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4079 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4080 SDLK_UNKNOWN, SDLK_LEFTBRACKET, SDLK_BACKSLASH, SDLK_RIGHTBRACKET, SDLK_CARET,
4081 SDLK_UNDERSCORE, SDLK_BACKQUOTE, SDLK_a, SDLK_b, SDLK_c,
4082 SDLK_d, SDLK_e, SDLK_f, SDLK_g, SDLK_h,
4083 SDLK_i, SDLK_j, SDLK_k, SDLK_l, SDLK_m,
4084 SDLK_n, SDLK_o, SDLK_p, SDLK_q, SDLK_r,
4085 SDLK_s, SDLK_t, SDLK_u, SDLK_v, SDLK_w,
4086 SDLK_x, SDLK_y, SDLK_z, SDLK_UNKNOWN, SDLK_UNKNOWN,
4087 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_DELETE, SDLK_UNKNOWN, SDLK_UNKNOWN,
4088 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4089 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4090 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4091 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4092 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4093 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4094 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4095 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4096 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4097 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4098 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4099 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4100 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4101 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4102 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4103 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4104 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4105 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4106 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4107 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4108 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4109 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4110 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4111 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4112 SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4113 SDLK_UNKNOWN, SDLK_KP_0, SDLK_KP_1, SDLK_KP_2, SDLK_KP_3,
4114 SDLK_KP_4, SDLK_KP_5, SDLK_KP_6, SDLK_KP_7, SDLK_KP_8,
4115 SDLK_KP_9, SDLK_KP_PERIOD, SDLK_KP_DIVIDE, SDLK_KP_MULTIPLY, SDLK_KP_MINUS,
4116 SDLK_KP_PLUS, SDLK_KP_ENTER, SDLK_KP_EQUALS, SDLK_UP, SDLK_DOWN,
4117 SDLK_RIGHT, SDLK_LEFT, SDLK_INSERT, SDLK_HOME, SDLK_END,
4118 SDLK_PAGEUP, SDLK_PAGEDOWN, SDLK_F1, SDLK_F2, SDLK_F3,
4119 SDLK_F4, SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F8,
4120 SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12, SDLK_F13,
4121 SDLK_F14, SDLK_F15, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
4122 SDLK_NUMLOCKCLEAR, SDLK_CAPSLOCK, SDLK_SCROLLLOCK, SDLK_RSHIFT, SDLK_LSHIFT,
4123 SDLK_RCTRL, SDLK_LCTRL, SDLK_RALT, SDLK_LALT, SDLK_RGUI,
4124 SDLK_LGUI, SDLK_LGUI, SDLK_RGUI, SDLK_MODE, SDLK_UNKNOWN,
4125 SDLK_HELP, SDLK_PRINTSCREEN, SDLK_SYSREQ, SDLK_UNKNOWN, SDLK_MENU,
4126 SDLK_POWER, SDLK_CURRENCYUNIT, SDLK_UNDO
4127 };
4128
4129 if (code >= 65 && code < 73)
4130 return static_cast<SDL_Scancode>(AO_SCANCODE_BASE_MOUSE_BUTTON + (code - 65));
4131 else if (code >= 73 && code < 91)
4132 return static_cast<SDL_Scancode>(AO_SCANCODE_BASE_JOYSTICK_BUTTON + (code - 73));
4133 else if (code < num_key_lookups)
4134 return SDL_GetScancodeFromKey(key_lookups[code]);
4135 return SDL_SCANCODE_UNKNOWN;
4136 }
4137
parse_input_preferences(InfoTree root,std::string version)4138 void parse_input_preferences(InfoTree root, std::string version)
4139 {
4140 root.read_attr("device", input_preferences->input_device);
4141 root.read_attr("modifiers", input_preferences->modifiers);
4142
4143 // old prefs may have combined sensitivity
4144 root.read_attr("sensitivity", input_preferences->sens_horizontal);
4145 root.read_attr("sensitivity", input_preferences->sens_vertical);
4146 root.read_attr("sens_horizontal", input_preferences->sens_horizontal);
4147 root.read_attr("sens_vertical", input_preferences->sens_vertical);
4148
4149 if (!version.length() || version < "20181113")
4150 input_preferences->classic_vertical_aim = true;
4151 else if (version < "20190317")
4152 input_preferences->classic_vertical_aim = false;
4153 root.read_attr("classic_vertical_aim", input_preferences->classic_vertical_aim);
4154
4155 if (!root.read_attr("classic_aim_speed_limits", input_preferences->classic_aim_speed_limits))
4156 {
4157 // Assume users with older prefs with "mouse_max_speed" above its default value don't want classic limits
4158 float mouse_max_speed;
4159 if (root.read_attr("mouse_max_speed", mouse_max_speed) && mouse_max_speed > 0.25)
4160 input_preferences->classic_aim_speed_limits = false;
4161 }
4162
4163 // old prefs may have boolean acceleration flag
4164 bool accel = false;
4165 if (root.read_attr("mouse_acceleration", accel))
4166 {
4167 input_preferences->mouse_accel_type = _mouse_accel_classic;
4168 input_preferences->mouse_accel_scale = 1.f;
4169 }
4170 root.read_attr_bounded<int16>("mouse_accel_type",
4171 input_preferences->mouse_accel_type,
4172 0, NUMBER_OF_MOUSE_ACCEL_TYPES - 1);
4173 root.read_attr("mouse_accel_scale", input_preferences->mouse_accel_scale);
4174
4175 // old prefs mixed "classic vertical aim" with acceleration type
4176 if (version >= "20181113" && version < "20190317")
4177 {
4178 if (input_preferences->mouse_accel_type == _mouse_accel_symmetric)
4179 {
4180 input_preferences->classic_vertical_aim = false;
4181 input_preferences->mouse_accel_type = _mouse_accel_classic;
4182 }
4183 else if (input_preferences->mouse_accel_type == _mouse_accel_classic)
4184 {
4185 input_preferences->classic_vertical_aim = true;
4186 input_preferences->sens_vertical *= 4.f;
4187 }
4188 }
4189
4190 if (!version.length() || version < "20170821")
4191 input_preferences->raw_mouse_input = false;
4192 root.read_attr("raw_mouse_input", input_preferences->raw_mouse_input);
4193 if (!version.length() || version < "20181208")
4194 input_preferences->extra_mouse_precision = false;
4195 root.read_attr("extra_mouse_precision", input_preferences->extra_mouse_precision);
4196 root.read_attr("controller_analog", input_preferences->controller_analog);
4197 root.read_attr("controller_sensitivity", input_preferences->controller_sensitivity);
4198 root.read_attr("controller_deadzone", input_preferences->controller_deadzone);
4199
4200 // remove default key bindings the first time we see one from these prefs
4201 bool seen_key[NUMBER_OF_KEYS];
4202 memset(seen_key, 0, sizeof(seen_key));
4203 bool seen_shell_key[NUMBER_OF_SHELL_KEYS];
4204 memset(seen_shell_key, 0, sizeof(seen_shell_key));
4205
4206 // import old key bindings
4207 BOOST_FOREACH(InfoTree key, root.children_named("sdl_key"))
4208 {
4209 int16 index;
4210 if (key.read_indexed("index", index, NUMBER_OF_KEYS))
4211 {
4212 if (!seen_key[index])
4213 {
4214 input_preferences->key_bindings[index].clear();
4215 seen_key[index] = true;
4216 }
4217 int code;
4218 if (key.read_attr("value", code))
4219 {
4220 SDL_Scancode translated = translate_old_key(code);
4221 unset_scancode(translated);
4222 input_preferences->key_bindings[index].insert(translated);
4223 }
4224 }
4225 else if (key.read_indexed("index", index, NUMBER_OF_KEYS + NUMBER_OF_SHELL_KEYS))
4226 {
4227 int shell_index = index - NUMBER_OF_KEYS;
4228 if (!seen_shell_key[shell_index])
4229 {
4230 input_preferences->shell_key_bindings[shell_index].clear();
4231 seen_shell_key[shell_index] = true;
4232 }
4233 int code;
4234 if (key.read_attr("value", code))
4235 {
4236 SDL_Scancode translated = translate_old_key(code);
4237 unset_scancode(translated);
4238 input_preferences->shell_key_bindings[shell_index].insert(translated);
4239 }
4240 }
4241 }
4242
4243 BOOST_FOREACH(InfoTree key, root.children_named("binding"))
4244 {
4245 std::string action_name, pressed_name;
4246 if (key.read_attr("action", action_name) &&
4247 key.read_attr("pressed", pressed_name))
4248 {
4249 bool shell = false;
4250 int index = index_for_action_name(action_name, shell);
4251 if (index < 0)
4252 continue;
4253 SDL_Scancode code = code_for_binding_name(pressed_name);
4254 if (shell)
4255 {
4256 if (!seen_shell_key[index])
4257 {
4258 input_preferences->shell_key_bindings[index].clear();
4259 seen_shell_key[index] = true;
4260 }
4261 unset_scancode(code);
4262 input_preferences->shell_key_bindings[index].insert(code);
4263 }
4264 else
4265 {
4266 if (!seen_key[index])
4267 {
4268 input_preferences->key_bindings[index].clear();
4269 seen_key[index] = true;
4270 }
4271 unset_scancode(code);
4272 input_preferences->key_bindings[index].insert(code);
4273 }
4274 }
4275 }
4276 }
4277
parse_sound_preferences(InfoTree root,std::string version)4278 void parse_sound_preferences(InfoTree root, std::string version)
4279 {
4280 root.read_attr("channels", sound_preferences->channel_count);
4281 root.read_attr("volume", sound_preferences->volume);
4282 root.read_attr("music_volume", sound_preferences->music);
4283 root.read_attr("flags", sound_preferences->flags);
4284 root.read_attr("rate", sound_preferences->rate);
4285 root.read_attr("samples", sound_preferences->samples);
4286 root.read_attr("volume_while_speaking", sound_preferences->volume_while_speaking);
4287 root.read_attr("mute_while_transmitting", sound_preferences->mute_while_transmitting);
4288 }
4289
4290
4291
parse_network_preferences(InfoTree root,std::string version)4292 void parse_network_preferences(InfoTree root, std::string version)
4293 {
4294 root.read_attr("microphone", network_preferences->allow_microphone);
4295 root.read_attr("untimed", network_preferences->game_is_untimed);
4296 root.read_attr("type", network_preferences->type);
4297 root.read_attr("game_type", network_preferences->game_type);
4298 root.read_attr("difficulty", network_preferences->difficulty_level);
4299 root.read_attr("game_options", network_preferences->game_options);
4300 root.read_attr("time_limit", network_preferences->time_limit);
4301 root.read_attr("kill_limit", network_preferences->kill_limit);
4302 root.read_attr("entry_point", network_preferences->entry_point);
4303 root.read_attr("autogather", network_preferences->autogather);
4304 root.read_attr("join_by_address", network_preferences->join_by_address);
4305 root.read_cstr("join_address", network_preferences->join_address, 255);
4306 root.read_attr("local_game_port", network_preferences->game_port);
4307
4308 std::string protocol;
4309 if (root.read_attr("game_protocol", protocol))
4310 {
4311 for (int i = 0; i < NUMBER_OF_NETWORK_GAME_PROTOCOL_NAMES; ++i)
4312 {
4313 if (protocol == sNetworkGameProtocolNames[i])
4314 {
4315 network_preferences->game_protocol = i;
4316 break;
4317 }
4318 }
4319 }
4320
4321 root.read_attr("use_speex_netmic_encoder", network_preferences->use_speex_encoder);
4322 root.read_attr("use_netscript", network_preferences->use_netscript);
4323 root.read_path("netscript_file", network_preferences->netscript_file);
4324 root.read_attr("cheat_flags", network_preferences->cheat_flags);
4325 root.read_attr("advertise_on_metaserver", network_preferences->advertise_on_metaserver);
4326 root.read_attr("attempt_upnp", network_preferences->attempt_upnp);
4327 root.read_attr("check_for_updates", network_preferences->check_for_updates);
4328 root.read_attr("verify_https", network_preferences->verify_https);
4329 root.read_attr("use_custom_metaserver_colors", network_preferences->use_custom_metaserver_colors);
4330 root.read_cstr("metaserver_login", network_preferences->metaserver_login, 15);
4331 root.read_attr("mute_metaserver_guests", network_preferences->mute_metaserver_guests);
4332 root.read_cstr("metaserver_clear_password", network_preferences->metaserver_password, 15);
4333
4334 char obscured_password[33];
4335 if (root.read_cstr("metaserver_password", obscured_password, 32))
4336 {
4337 for (int i = 0; i < 15; i++)
4338 {
4339 unsigned int c;
4340 sscanf(obscured_password + i*2, "%2x", &c);
4341 network_preferences->metaserver_password[i] = (char) c ^ sPasswordMask[i];
4342 }
4343 network_preferences->metaserver_password[15] = '\0';
4344 }
4345
4346 root.read_attr("join_metaserver_by_default", network_preferences->join_metaserver_by_default);
4347 root.read_attr("allow_stats", network_preferences->allow_stats);
4348
4349 BOOST_FOREACH(InfoTree color, root.children_named("color"))
4350 {
4351 int16 index;
4352 if (color.read_indexed("index", index, 2))
4353 color.read_color(network_preferences->metaserver_colors[index]);
4354 }
4355
4356 BOOST_FOREACH(InfoTree child, root.children_named("star_protocol"))
4357 StarGameProtocol::ParsePreferencesTree(child, version);
4358 BOOST_FOREACH(InfoTree child, root.children_named("ring_protocol"))
4359 RingGameProtocol::ParsePreferencesTree(child, version);
4360 }
4361
parse_environment_preferences(InfoTree root,std::string version)4362 void parse_environment_preferences(InfoTree root, std::string version)
4363 {
4364 root.read_path("map_file", environment_preferences->map_file);
4365 root.read_path("physics_file", environment_preferences->physics_file);
4366 root.read_path("shapes_file", environment_preferences->shapes_file);
4367 root.read_path("sounds_file", environment_preferences->sounds_file);
4368 root.read_path("resources_file", environment_preferences->resources_file);
4369 root.read_attr("map_checksum", environment_preferences->map_checksum);
4370 root.read_attr("physics_checksum", environment_preferences->physics_checksum);
4371 root.read_attr("shapes_mod_date", environment_preferences->shapes_mod_date);
4372 root.read_attr("sounds_mod_date", environment_preferences->sounds_mod_date);
4373 root.read_attr("group_by_directory", environment_preferences->group_by_directory);
4374 root.read_attr("reduce_singletons", environment_preferences->reduce_singletons);
4375 root.read_attr("smooth_text", environment_preferences->smooth_text);
4376 root.read_path("solo_lua_file", environment_preferences->solo_lua_file);
4377 root.read_attr("use_solo_lua", environment_preferences->use_solo_lua);
4378 root.read_attr("use_replay_net_lua", environment_preferences->use_replay_net_lua);
4379 root.read_attr("hide_alephone_extensions", environment_preferences->hide_extensions);
4380
4381 uint32 profile = FILM_PROFILE_DEFAULT + 1;
4382 root.read_attr("film_profile", profile);
4383 if (profile <= FILM_PROFILE_DEFAULT)
4384 environment_preferences->film_profile = static_cast<FilmProfileType>(profile);
4385
4386 root.read_attr("maximum_quick_saves", environment_preferences->maximum_quick_saves);
4387
4388 BOOST_FOREACH(InfoTree plugin, root.children_named("disable_plugin"))
4389 {
4390 char tempstr[256];
4391 if (plugin.read_path("path", tempstr))
4392 {
4393 Plugins::instance()->disable(tempstr);
4394 }
4395 }
4396 }
4397