The Battle for Wesnoth  1.19.0-dev
general.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
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 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Get and set user-preferences.
19  */
20 
21 #define GETTEXT_DOMAIN "wesnoth-lib"
22 
23 #include "preferences/general.hpp"
24 
25 #include "config.hpp"
26 #include "credentials.hpp"
27 #include "filesystem.hpp"
28 #include "game_config.hpp"
29 #include "hotkey/hotkey_item.hpp"
30 #include "lexical_cast.hpp"
31 #include "log.hpp"
32 #include "sdl/point.hpp"
33 #include "serialization/parser.hpp"
34 #include "sound.hpp"
35 #include "video.hpp"
36 #include "game_config_view.hpp"
37 
38 #include <sys/stat.h> // for setting the permissions of the preferences file
39 #ifndef _WIN32
40 #include <unistd.h>
41 #endif
42 
43 static lg::log_domain log_config("config");
44 #define ERR_CFG LOG_STREAM(err , log_config)
45 
46 static lg::log_domain log_filesystem("filesystem");
47 #define ERR_FS LOG_STREAM(err, log_filesystem)
48 
49 namespace {
50 
51 bool no_preferences_save = false;
52 
53 bool fps = false;
54 
56 }
57 
58 namespace preferences {
59 
60 /*
61  * Stores all the static, default values for certain game preferences. The values
62  * are kept here for easy modification without a lengthy rebuild.
63  *
64  * Add any variables of similar type here.
65  */
66 const int min_window_width = 800;
67 const int min_window_height = 540;
68 
69 const int def_window_width = 1280;
70 const int def_window_height = 720;
71 
72 const int max_window_width = 1920;
73 const int max_window_height = 1080;
74 
75 const int min_font_scaling = 80;
76 const int max_font_scaling = 150;
77 
78 const int min_pixel_scale = 1;
79 const int max_pixel_scale = 4;
80 
82 public:
83  virtual void handle_event(const SDL_Event &) {}
84  virtual void handle_window_event(const SDL_Event &event);
86 };
87 
89 
91 {
93 
96 }
97 
99 {
101 
102  try {
103  if (no_preferences_save) return;
104 
105  // Set the 'hidden' preferences.
106  prefs["scroll_threshold"] = mouse_scroll_threshold();
107 
109  } catch (...) {}
110 }
111 
112 /*
113  * Hook for setting window state variables on window resize and maximize
114  * events. Since there is no fullscreen window event, that setter is called
115  * from the video function instead.
116  */
117 void prefs_event_handler::handle_window_event(const SDL_Event& event)
118 {
119 
120  // Safety check to make sure this is a window event
121  if (event.type != SDL_WINDOWEVENT) return;
122 
123  switch(event.window.event) {
124  case SDL_WINDOWEVENT_RESIZED:
126 
127  break;
128 
129  case SDL_WINDOWEVENT_MAXIMIZED:
130  set_maximized(true);
131 
132  break;
133 
134  case SDL_WINDOWEVENT_RESTORED:
135  set_maximized(fullscreen() || false);
136 
137  break;
138  }
139 }
140 
142 {
143 #ifndef _WIN32
144  bool prefs_file_existed = access(filesystem::get_prefs_file().c_str(), F_OK) == 0;
145 #endif
146 
147  try {
149  write(*prefs_file, prefs);
150  } catch(const filesystem::io_exception&) {
151  ERR_FS << "error writing to preferences file '" << filesystem::get_prefs_file() << "'";
152  }
153 
155 
156 #ifndef _WIN32
157  if(!prefs_file_existed) {
158  if(chmod(filesystem::get_prefs_file().c_str(), 0600) == -1) {
159  ERR_FS << "error setting permissions of preferences file '" << filesystem::get_prefs_file() << "'";
160  }
161  }
162 #endif
163 }
164 
165 void set(const std::string &key, bool value)
166 {
167  prefs[key] = value;
168 }
169 
170 void set(const std::string &key, int value)
171 {
172  prefs[key] = value;
173 }
174 
175 void set(const std::string &key, char const *value)
176 {
177  prefs[key] = value;
178 }
179 
180 void set(const std::string &key, const std::string &value)
181 {
182  prefs[key] = value;
183 }
184 
185 void set(const std::string &key, const config::attribute_value &value)
186 {
187  prefs[key] = value;
188 }
189 
190 void clear(const std::string& key)
191 {
192  prefs.recursive_clear_value(key);
193 }
194 
195 void set_child(const std::string& key, const config& val) {
196  prefs.clear_children(key);
197  prefs.add_child(key, val);
198 }
199 
200 optional_const_config get_child(const std::string& key)
201 {
202  return prefs.optional_child(key);
203 }
204 
205 void erase(const std::string& key) {
206  prefs.remove_attribute(key);
207 }
208 
209 bool have_setting(const std::string& key) {
210  return prefs.has_attribute(key);
211 }
212 
213 std::string get(const std::string& key) {
214  return prefs[key];
215 }
216 
217 std::string get(const std::string& key, const std::string& def) {
218  return prefs[key].empty() ? def : prefs[key];
219 }
220 
221 bool get(const std::string &key, bool def)
222 {
223  return prefs[key].to_bool(def);
224 }
225 
227 {
228  return prefs[key];
229 }
230 
232  no_preferences_save = true;
233 }
234 
236  config* pointer = &prefs;
237  return pointer;
238 }
239 
241  try{
242 #ifdef DEFAULT_PREFS_PATH
243  // NOTE: the system preferences file is only ever relevant for the first time wesnoth starts
244  // any default values will subsequently be written to the normal preferences file, which takes precedence over any values in the system preferences file
246  read(prefs, *stream);
247 
248  config user_prefs;
250  read(user_prefs, *stream);
251 
252  prefs.merge_with(user_prefs);
253 #else
254  prefs.clear();
256  read(prefs, *stream);
257 #endif
258  } catch(const config::error& e) {
259  ERR_CFG << "Error loading preference, message: " << e.what();
260  }
261 }
262 
263 
265  return get("show_ally_orb", game_config::show_ally_orb);
266 }
267 void set_show_ally_orb(bool show_orb) {
268  prefs["show_ally_orb"] = show_orb;
269 }
270 
272  return get("show_status_on_ally_orb", game_config::show_status_on_ally_orb);
273 }
274 void set_show_status_on_ally_orb(bool show_orb) {
275  prefs["show_status_on_ally_orb"] = show_orb;
276 }
277 
279  return get("show_enemy_orb", game_config::show_enemy_orb);
280 }
281 void set_show_enemy_orb(bool show_orb) {
282  prefs["show_enemy_orb"] = show_orb;
283 }
284 
286  return get("show_moved_orb", game_config::show_moved_orb);
287 }
288 void set_show_moved_orb(bool show_orb) {
289  prefs["show_moved_orb"] = show_orb;
290 }
291 
293  return get("show_unmoved_orb", game_config::show_unmoved_orb);
294 }
295 void set_show_unmoved_orb(bool show_orb) {
296  prefs["show_unmoved_orb"] = show_orb;
297 }
298 
300  return get("show_partial_orb", game_config::show_partial_orb);
301 }
302 void set_show_partial_orb(bool show_orb) {
303  prefs["show_partial_orb"] = show_orb;
304 }
305 
307  return get("show_disengaged_orb", game_config::show_disengaged_orb);
308 }
309 void set_show_disengaged_orb(bool show_orb) {
310  prefs["show_disengaged_orb"] = show_orb;
311 }
312 
313 static std::string fix_orb_color_name(const std::string& color) {
314  if (color.substr(0,4) == "orb_") {
315  if(color[4] >= '0' && color[4] <= '9') {
316  return color.substr(5);
317  } else {
318  return color.substr(4);
319  }
320  }
321  return color;
322 }
323 
324 std::string allied_color() {
325  std::string ally_color = get("ally_orb_color");
326  if (ally_color.empty())
328  return fix_orb_color_name(ally_color);
329 }
330 void set_allied_color(const std::string& color_id) {
331  prefs["ally_orb_color"] = color_id;
332 }
333 
334 std::string core_id() {
335  std::string core_id = get("core");
336  if (core_id.empty())
337  return "default";
338  return core_id;
339 }
340 void set_core_id(const std::string& core_id) {
341  prefs["core"] = core_id;
342 }
343 
344 std::string enemy_color() {
345  std::string enemy_color = get("enemy_orb_color");
346  if (enemy_color.empty())
349 }
350 void set_enemy_color(const std::string& color_id) {
351  prefs["enemy_orb_color"] = color_id;
352 }
353 
354 std::string moved_color() {
355  std::string moved_color = get("moved_orb_color");
356  if (moved_color.empty())
359 }
360 void set_moved_color(const std::string& color_id) {
361  prefs["moved_orb_color"] = color_id;
362 }
363 
364 std::string unmoved_color() {
365  std::string unmoved_color = get("unmoved_orb_color");
366  if (unmoved_color.empty())
369 }
370 void set_unmoved_color(const std::string& color_id) {
371  prefs["unmoved_orb_color"] = color_id;
372 }
373 
374 std::string partial_color() {
375  std::string partmoved_color = get("partial_orb_color");
376  if (partmoved_color.empty())
378  return fix_orb_color_name(partmoved_color);
379 }
380 void set_partial_color(const std::string& color_id) {
381  prefs["partial_orb_color"] = color_id;
382 }
383 
385 {
386  return get("scroll_to_action", true);
387 }
388 
389 void set_scroll_to_action(bool ison)
390 {
391  prefs["scroll_to_action"] = ison;
392 }
393 
395 {
396  const unsigned x_res = prefs["xresolution"].to_unsigned();
397  const unsigned y_res = prefs["yresolution"].to_unsigned();
398 
399  // Either resolution was unspecified, return default.
400  if(x_res == 0 || y_res == 0) {
402  }
403 
404  return point(
405  std::max<unsigned>(x_res, min_window_width),
406  std::max<unsigned>(y_res, min_window_height)
407  );
408 }
409 
411 {
412  // For now this has a minimum value of 1 and a maximum of 4.
413  return std::max<int>(std::min<int>(prefs["pixel_scale"].to_int(1), max_pixel_scale), min_pixel_scale);
414 }
415 
416 void set_pixel_scale(const int scale)
417 {
418  prefs["pixel_scale"] = std::clamp(scale, min_pixel_scale, max_pixel_scale);
419 }
420 
422 {
423  return get("auto_pixel_scale", true);
424 }
425 
426 void set_auto_pixel_scale(bool choice)
427 {
428  prefs["auto_pixel_scale"] = choice;
429 }
430 
431 bool maximized()
432 {
433  return get("maximized", !fullscreen());
434 }
435 
437 {
438  return get("fullscreen", true);
439 }
440 
441 bool vsync()
442 {
443  return get("vsync", true);
444 }
445 
446 void set_resolution(const point& res)
447 {
448  prefs["xresolution"] = std::to_string(res.x);
449  prefs["yresolution"] = std::to_string(res.y);
450 }
451 
452 void set_maximized(bool ison)
453 {
454  prefs["maximized"] = ison;
455 }
456 
457 void set_fullscreen(bool ison)
458 {
459  prefs["fullscreen"] = ison;
460 }
461 
462 void set_vsync(bool ison)
463 {
464  prefs["vsync"] = ison;
465 }
466 
467 bool turbo()
468 {
469  if(video::headless()) {
470  return true;
471  }
472 
473  return get("turbo", false);
474 }
475 
476 void set_turbo(bool ison)
477 {
478  prefs["turbo"] = ison;
479 }
480 
481 double turbo_speed()
482 {
483  return prefs["turbo_speed"].to_double(2.0);
484 }
485 
486 void set_turbo_speed(const double speed)
487 {
488  prefs["turbo_speed"] = speed;
489 }
490 
492 {
493  // Clip at 80 because if it's too low it'll cause crashes
494  return std::max<int>(std::min<int>(prefs["font_scale"].to_int(100), max_font_scaling), min_font_scaling);
495 }
496 
498 {
499  prefs["font_scale"] = std::clamp(scale, min_font_scaling, max_font_scaling);
500 }
501 
503 {
504  return (size * font_scaling()) / 100;
505 }
506 
508 {
509  return prefs["keepalive_timeout"].to_int(20);
510 }
511 
512 void keepalive_timeout(int seconds)
513 {
514  prefs["keepalive_timeout"] = std::abs(seconds);
515 }
516 
517 bool idle_anim()
518 {
519  return get("idle_anim", true);
520 }
521 
522 void set_idle_anim(const bool ison)
523 {
524  prefs["idle_anim"] = ison;
525 }
526 
528 {
529  return prefs["idle_anim_rate"];
530 }
531 
532 void set_idle_anim_rate(int rate)
533 {
534  prefs["idle_anim_rate"] = rate;
535 }
536 
537 std::string language()
538 {
539  return prefs["locale"];
540 }
541 
542 void set_language(const std::string& s)
543 {
544  prefs["locale"] = s;
545 }
546 
547 std::string gui_theme()
548 {
549  return prefs["gui2_theme"];
550 }
551 
552 void set_gui_theme(const std::string& s)
553 {
554  prefs["gui2_theme"] = s;
555 }
556 
557 bool ellipses()
558 {
559  return get("show_side_colors", false);
560 }
561 
562 void set_ellipses(bool ison)
563 {
564  prefs["show_side_colors"] = ison;
565 }
566 
567 bool grid()
568 {
569  return get("grid", false);
570 }
571 
572 void set_grid(bool ison)
573 {
574  prefs["grid"] = ison;
575 }
576 
577 std::size_t sound_buffer_size()
578 {
579  // Sounds don't sound good on Windows unless the buffer size is 4k,
580  // but this seems to cause crashes on other systems...
581  #ifdef _WIN32
582  const std::size_t buf_size = 4096;
583  #else
584  const std::size_t buf_size = 1024;
585  #endif
586 
587  return prefs["sound_buffer_size"].to_int(buf_size);
588 }
589 
590 void save_sound_buffer_size(const std::size_t size)
591 {
592  #ifdef _WIN32
593  const char* buf_size = "4096";
594  #else
595  const char* buf_size = "1024";
596  #endif
597 
598  const std::string new_size = lexical_cast_default<std::string>(size, buf_size);
599  if (get("sound_buffer_size") == new_size)
600  return;
601 
602  prefs["sound_buffer_size"] = new_size;
603 
605 }
606 
608 {
609  return prefs["music_volume"].to_int(100);
610 }
611 
612 void set_music_volume(int vol)
613 {
614  if(music_volume() == vol) {
615  return;
616  }
617 
618  prefs["music_volume"] = vol;
620 }
621 
623 {
624  return prefs["sound_volume"].to_int(100);
625 }
626 
627 void set_sound_volume(int vol)
628 {
629  if(sound_volume() == vol) {
630  return;
631  }
632 
633  prefs["sound_volume"] = vol;
635 }
636 
638 {
639  return prefs["bell_volume"].to_int(100);
640 }
641 
642 void set_bell_volume(int vol)
643 {
644  if(bell_volume() == vol) {
645  return;
646  }
647 
648  prefs["bell_volume"] = vol;
650 }
651 
653 {
654  return prefs["UI_volume"].to_int(100);
655 }
656 
657 void set_UI_volume(int vol)
658 {
659  if(UI_volume() == vol) {
660  return;
661  }
662 
663  prefs["UI_volume"] = vol;
665 }
666 
667 unsigned int tile_size()
668 {
669  return prefs["tile_size"].to_unsigned();
670 }
671 
672 void set_tile_size(const unsigned int size)
673 {
674  prefs["tile_size"] = size;
675 }
676 
677 bool turn_bell()
678 {
679  return get("turn_bell", true);
680 }
681 
682 bool set_turn_bell(bool ison)
683 {
684  if(!turn_bell() && ison) {
685  prefs["turn_bell"] = true;
686  if(!music_on() && !sound_on() && !UI_sound_on()) {
687  if(!sound::init_sound()) {
688  prefs["turn_bell"] = false;
689  return false;
690  }
691  }
692  } else if(turn_bell() && !ison) {
693  prefs["turn_bell"] = false;
695  if(!music_on() && !sound_on() && !UI_sound_on())
697  }
698  return true;
699 }
700 
702 {
703  return get("UI_sound", true);
704 }
705 
706 bool set_UI_sound(bool ison)
707 {
708  if(!UI_sound_on() && ison) {
709  prefs["UI_sound"] = true;
710  if(!music_on() && !sound_on() && !turn_bell()) {
711  if(!sound::init_sound()) {
712  prefs["UI_sound"] = false;
713  return false;
714  }
715  }
716  } else if(UI_sound_on() && !ison) {
717  prefs["UI_sound"] = false;
719  if(!music_on() && !sound_on() && !turn_bell())
721  }
722  return true;
723 }
724 
726 {
727  return get("message_bell", true);
728 }
729 
730 bool sound_on()
731 {
732  return get("sound", true);
733 }
734 
735 bool set_sound(bool ison) {
736  if(!sound_on() && ison) {
737  prefs["sound"] = true;
738  if(!music_on() && !turn_bell() && !UI_sound_on()) {
739  if(!sound::init_sound()) {
740  prefs["sound"] = false;
741  return false;
742  }
743  }
744  } else if(sound_on() && !ison) {
745  prefs["sound"] = false;
747  if(!music_on() && !turn_bell() && !UI_sound_on())
749  }
750  return true;
751 }
752 
753 bool music_on()
754 {
755  return get("music", true);
756 }
757 
758 bool set_music(bool ison) {
759  if(!music_on() && ison) {
760  prefs["music"] = true;
761  if(!sound_on() && !turn_bell() && !UI_sound_on()) {
762  if(!sound::init_sound()) {
763  prefs["music"] = false;
764  return false;
765  }
766  }
767  else
769  } else if(music_on() && !ison) {
770  prefs["music"] = false;
771  if(!sound_on() && !turn_bell() && !UI_sound_on())
773  else
775  }
776  return true;
777 }
778 
780 {
781  return get("stop_music_in_background", false);
782 }
783 
785 {
786  prefs["stop_music_in_background"] = ison;
787 }
788 
790 {
791  return std::clamp<int>(lexical_cast_default<int>(get("scroll"), 50), 1, 100);
792 }
793 
794 void set_scroll_speed(const int new_speed)
795 {
796  prefs["scroll"] = new_speed;
797 }
798 
800 {
801  return get("middle_click_scrolls", true);
802 }
803 
805 {
806  return get("mouse_scrolling", true);
807 }
808 
809 void enable_mouse_scroll(bool value)
810 {
811  set("mouse_scrolling", value);
812 }
813 
815 {
816  return prefs["scroll_threshold"].to_int(10);
817 }
818 
820 {
821  return get("animate_map", true);
822 }
823 
825 {
826  return get("animate_water", true);
827 }
828 
830 {
831  return get("minimap_movement_coding", true);
832 }
833 
835 {
836  set("minimap_movement_coding", !minimap_movement_coding());
837 }
838 
840 {
841  return get("minimap_terrain_coding", true);
842 }
843 
845 {
846  set("minimap_terrain_coding", !minimap_terrain_coding());
847 }
848 
850 {
851  return get("minimap_draw_units", true);
852 }
853 
855 {
856  set("minimap_draw_units", !minimap_draw_units());
857 }
858 
860 {
861  return get("minimap_draw_villages", true);
862 }
863 
865 {
866  set("minimap_draw_villages", !minimap_draw_villages());
867 }
868 
870 {
871  return get("minimap_draw_terrain", true);
872 }
873 
875 {
876  set("minimap_draw_terrain", !minimap_draw_terrain());
877 }
878 
879 void set_animate_map(bool value)
880 {
881  set("animate_map", value);
882 }
883 
884 void set_animate_water(bool value)
885 {
886  set("animate_water", value);
887 }
888 
889 bool show_fps()
890 {
891  return fps;
892 }
893 
894 void set_show_fps(bool value)
895 {
896  fps = value;
897 }
898 
900 {
901  return prefs["draw_delay"].to_int(-1);
902 }
903 
904 void set_draw_delay(int value)
905 {
906  prefs["draw_delay"] = value;
907 }
908 
910 {
912 }
913 
915 {
917 }
918 
920 {
922  prefs.clear_children("hotkey");
923 }
924 
925 void add_alias(const std::string &alias, const std::string &command)
926 {
927  config &alias_list = prefs.child_or_add("alias");
928  alias_list[alias] = command;
929 }
930 
931 
933 {
934  return get_child("alias");
935 }
936 
937 unsigned int sample_rate()
938 {
939  return prefs["sample_rate"].to_int(44100);
940 }
941 
942 void save_sample_rate(const unsigned int rate)
943 {
944  if (sample_rate() == rate)
945  return;
946 
947  prefs["sample_rate"] = static_cast<int>(rate);
948 
949  // If audio is open, we have to re set sample rate
951 }
952 
954 {
955  return get("confirm_load_save_from_different_version", true);
956 }
957 
959 {
960  return get("use_twelve_hour_clock_format", false);
961 }
962 
964 {
965  return get("disable_auto_moves", false);
966 }
967 
968 void set_disable_auto_moves(bool value)
969 {
970  prefs["disable_auto_moves"] = value;
971 }
972 
974 {
975  return get("damage_prediction_allow_monte_carlo_simulation", true);
976 }
977 
979 {
980  set("damage_prediction_allow_monte_carlo_simulation", value);
981 }
982 
984 {
985  return get("addon_manager_saved_order_name");
986 }
987 
988 void set_addon_manager_saved_order_name(const std::string& value)
989 {
990  set("addon_manager_saved_order_name", value);
991 }
992 
994 {
995  return sort_order::get_enum(get("addon_manager_saved_order_direction")).value_or(sort_order::type::none);
996 }
997 
999 {
1000  set("addon_manager_saved_order_direction", sort_order::get_string(value));
1001 }
1002 
1004 {
1005  return get("selected_achievement_group");
1006 }
1007 
1008 void set_selected_achievement_group(const std::string& content_for)
1009 {
1010  set("selected_achievement_group", content_for);
1011 }
1012 
1013 bool achievement(const std::string& content_for, const std::string& id)
1014 {
1015  for(config& ach : prefs.child_range("achievements"))
1016  {
1017  if(ach["content_for"].str() == content_for)
1018  {
1019  std::vector<std::string> ids = utils::split(ach["ids"]);
1020  return std::find(ids.begin(), ids.end(), id) != ids.end();
1021  }
1022  }
1023  return false;
1024 }
1025 
1026 void set_achievement(const std::string& content_for, const std::string& id)
1027 {
1028  for(config& ach : prefs.child_range("achievements"))
1029  {
1030  // if achievements already exist for this content and the achievement has not already been set, add it
1031  if(ach["content_for"].str() == content_for)
1032  {
1033  std::vector<std::string> ids = utils::split(ach["ids"]);
1034 
1035  if(ids.empty())
1036  {
1037  ach["ids"] = id;
1038  }
1039  else if(std::find(ids.begin(), ids.end(), id) == ids.end())
1040  {
1041  ach["ids"] = ach["ids"].str() + "," + id;
1042  }
1043  ach.remove_children("in_progress", [&id](config cfg){return cfg["id"].str() == id;});
1044  return;
1045  }
1046  }
1047 
1048  // else no achievements have been set for this content yet
1049  config ach;
1050  ach["content_for"] = content_for;
1051  ach["ids"] = id;
1052  prefs.add_child("achievements", ach);
1053 }
1054 
1055 int progress_achievement(const std::string& content_for, const std::string& id, int limit, int max_progress, int amount)
1056 {
1057  if(achievement(content_for, id))
1058  {
1059  return -1;
1060  }
1061 
1062  for(config& ach : prefs.child_range("achievements"))
1063  {
1064  // if achievements already exist for this content and the achievement has not already been set, add it
1065  if(ach["content_for"].str() == content_for)
1066  {
1067  // check if this achievement has progressed before - if so then increment it
1068  for(config& in_progress : ach.child_range("in_progress"))
1069  {
1070  if(in_progress["id"].str() == id)
1071  {
1072  // don't let using 'limit' decrease the achievement's current progress
1073  int starting_progress = in_progress["progress_at"].to_int();
1074  if(starting_progress >= limit) {
1075  return starting_progress;
1076  }
1077 
1078  in_progress["progress_at"] = std::clamp(starting_progress + amount, 0, std::min(limit, max_progress));
1079  return in_progress["progress_at"].to_int();
1080  }
1081  }
1082 
1083  // else this is the first time this achievement is progressing
1084  if(amount != 0)
1085  {
1086  config set_progress;
1087  set_progress["id"] = id;
1088  set_progress["progress_at"] = std::clamp(amount, 0, std::min(limit, max_progress));
1089 
1090  config& child = ach.add_child("in_progress", set_progress);
1091  return child["progress_at"].to_int();
1092  }
1093  return 0;
1094  }
1095  }
1096 
1097  // else not only has this achievement not progressed before, this is the first achievement for this achievement group to be added
1098  if(amount != 0)
1099  {
1100  config ach;
1101  config set_progress;
1102 
1103  set_progress["id"] = id;
1104  set_progress["progress_at"] = std::clamp(amount, 0, std::min(limit, max_progress));
1105 
1106  ach["content_for"] = content_for;
1107  ach["ids"] = "";
1108 
1109  config& child = ach.add_child("in_progress", set_progress);
1110  prefs.add_child("achievements", ach);
1111  return child["progress_at"].to_int();
1112  }
1113  return 0;
1114 }
1115 
1116 bool sub_achievement(const std::string& content_for, const std::string& id, const std::string& sub_id)
1117 {
1118  // this achievement is already completed
1119  if(achievement(content_for, id))
1120  {
1121  return true;
1122  }
1123 
1124  for(config& ach : prefs.child_range("achievements"))
1125  {
1126  if(ach["content_for"].str() == content_for)
1127  {
1128  // check if the specific sub-achievement has been completed but the overall achievement is not completed
1129  for(const auto& in_progress : ach.child_range("in_progress"))
1130  {
1131  if(in_progress["id"] == id)
1132  {
1133  std::vector<std::string> sub_ids = utils::split(in_progress["sub_ids"]);
1134  return std::find(sub_ids.begin(), sub_ids.end(), sub_id) != sub_ids.end();
1135  }
1136  }
1137  }
1138  }
1139  return false;
1140 }
1141 
1142 void set_sub_achievement(const std::string& content_for, const std::string& id, const std::string& sub_id)
1143 {
1144  // this achievement is already completed
1145  if(achievement(content_for, id))
1146  {
1147  return;
1148  }
1149 
1150  for(config& ach : prefs.child_range("achievements"))
1151  {
1152  // if achievements already exist for this content and the achievement has not already been set, add it
1153  if(ach["content_for"].str() == content_for)
1154  {
1155  // check if this achievement has had sub-achievements set before
1156  for(config& in_progress : ach.child_range("in_progress"))
1157  {
1158  if(in_progress["id"].str() == id)
1159  {
1160  std::vector<std::string> sub_ids = utils::split(ach["ids"]);
1161 
1162  if(std::find(sub_ids.begin(), sub_ids.end(), sub_id) == sub_ids.end())
1163  {
1164  in_progress["sub_ids"] = in_progress["sub_ids"].str() + "," + sub_id;
1165  }
1166 
1167  in_progress["progress_at"] = sub_ids.size()+1;
1168  return;
1169  }
1170  }
1171 
1172  // else if this is the first sub-achievement being set
1173  config set_progress;
1174  set_progress["id"] = id;
1175  set_progress["sub_ids"] = sub_id;
1176  set_progress["progress_at"] = 1;
1177  ach.add_child("in_progress", set_progress);
1178  return;
1179  }
1180  }
1181 
1182  // else not only has this achievement not had a sub-achievement completed before, this is the first achievement for this achievement group to be added
1183  config ach;
1184  config set_progress;
1185 
1186  set_progress["id"] = id;
1187  set_progress["sub_ids"] = sub_id;
1188  set_progress["progress_at"] = 1;
1189 
1190  ach["content_for"] = content_for;
1191  ach["ids"] = "";
1192 
1193  ach.add_child("in_progress", set_progress);
1194  prefs.add_child("achievements", ach);
1195 }
1196 
1197 void set_editor_chosen_addon(const std::string& addon_id)
1198 {
1199  prefs["editor_chosen_addon"] = addon_id;
1200 }
1201 
1202 std::string editor_chosen_addon()
1203 {
1204  return prefs["editor_chosen_addon"];
1205 }
1206 
1207 void set_mp_alert_option(const std::string& id, const std::string& type, bool value)
1208 {
1209  prefs[id+"_"+type] = value;
1210 }
1211 bool mp_alert_option(const std::string& id, const std::string& type, bool def)
1212 {
1213  return prefs[id+"_"+type].to_bool(def);
1214 }
1215 bool has_mp_alert_option(const std::string& id, const std::string& type)
1216 {
1217  return have_setting(id+"_"+type);
1218 }
1219 
1220 void set_last_cache_cleared_version(const std::string& version)
1221 {
1222  prefs["_last_cache_cleaned_ver"] = version;
1223 }
1225 {
1226  return prefs["_last_cache_cleaned_ver"];
1227 }
1228 
1229 bool get_show_deprecation(bool def)
1230 {
1231  return get("show_deprecation", def);
1232 }
1233 
1235 {
1236  return get("scroll_when_mouse_outside", def);
1237 }
1238 
1239 void set_dir_bookmarks(const config& cfg)
1240 {
1241  set_child("dir_bookmarks", cfg);
1242 }
1244 {
1245  return get_child("dir_bookmarks");
1246 }
1247 
1248 } // end namespace preferences
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
child_itors child_range(config_key_type key)
Definition: config.cpp:273
config & add_child(config_key_type key)
Definition: config.cpp:441
virtual void join_global()
Definition: events.cpp:373
virtual void leave_global()
Definition: events.cpp:393
sdl_handler(sdl_handler &&)=delete
static game_config_view wrap(const config &cfg)
virtual void handle_window_event(const SDL_Event &event)
Definition: general.cpp:117
virtual void handle_event(const SDL_Event &)
Definition: general.cpp:83
Declarations for File-IO.
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:207
New lexcical_cast header.
Standard logging facilities (interface).
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:202
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
std::string get_prefs_file()
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:50
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:51
std::string get_default_prefs_file()
std::string partial_orb_color
std::string moved_orb_color
std::string unmoved_orb_color
std::string ally_orb_color
std::string enemy_orb_color
bool show_status_on_ally_orb
bool show_moved_orb
bool show_ally_orb
bool show_disengaged_orb
bool show_partial_orb
bool show_enemy_orb
bool show_unmoved_orb
void save_hotkeys(config &cfg)
Save the non-default hotkeys to the config.
void reset_default_hotkeys()
Reset all hotkeys to the defaults.
void load_custom_hotkeys(const game_config_view &cfg)
Registers all hotkeys present in this config, overwriting any matching default hotkeys.
Modify, read and display user preferences.
void set_achievement(const std::string &content_for, const std::string &id)
Marks the specified achievement as completed.
Definition: general.cpp:1026
bool has_mp_alert_option(const std::string &id, const std::string &type)
Definition: general.cpp:1215
void set_scroll_speed(const int new_speed)
Definition: general.cpp:794
void set_show_disengaged_orb(bool show_orb)
Definition: general.cpp:309
bool stop_music_in_background()
Definition: general.cpp:779
const int max_window_height
Definition: general.cpp:73
int idle_anim_rate()
Definition: general.cpp:527
const int def_window_width
Definition: general.cpp:69
std::size_t sound_buffer_size()
Definition: general.cpp:577
void set_resolution(const point &res)
Definition: general.cpp:446
void disable_preferences_save()
Definition: general.cpp:231
void set_turbo(bool ison)
Definition: general.cpp:476
bool get_show_deprecation(bool def)
Definition: general.cpp:1229
void set_allied_color(const std::string &color_id)
Definition: general.cpp:330
void set_addon_manager_saved_order_direction(sort_order::type value)
Definition: general.cpp:998
bool have_setting(const std::string &key)
Definition: general.cpp:209
void set_music_volume(int vol)
Definition: general.cpp:612
void set_show_partial_orb(bool show_orb)
Definition: general.cpp:302
void set_idle_anim(const bool ison)
Definition: general.cpp:522
bool minimap_movement_coding()
Definition: general.cpp:829
void set_maximized(bool ison)
Definition: general.cpp:452
void clear(const std::string &key)
Definition: general.cpp:190
void set_core_id(const std::string &core_id)
Definition: general.cpp:340
bool show_unmoved_orb()
Definition: general.cpp:292
bool set_turn_bell(bool ison)
Definition: general.cpp:682
int UI_volume()
Definition: general.cpp:652
bool vsync()
Definition: general.cpp:441
void set_mp_alert_option(const std::string &id, const std::string &type, bool value)
Definition: general.cpp:1207
void set_show_enemy_orb(bool show_orb)
Definition: general.cpp:281
void set_sound_volume(int vol)
Definition: general.cpp:627
sort_order::type addon_manager_saved_order_direction()
Definition: general.cpp:993
void set_dir_bookmarks(const config &cfg)
Definition: general.cpp:1239
bool maximized()
Definition: general.cpp:431
void set_gui_theme(const std::string &s)
Definition: general.cpp:552
unsigned int tile_size()
Definition: general.cpp:667
void save_sound_buffer_size(const std::size_t size)
Definition: general.cpp:590
void save_credentials()
const int min_pixel_scale
Definition: general.cpp:78
bool set_sound(bool ison)
Definition: general.cpp:735
bool use_twelve_hour_clock_format()
Definition: general.cpp:958
bool auto_pixel_scale()
Definition: general.cpp:421
bool show_partial_orb()
Definition: general.cpp:299
bool minimap_draw_villages()
Definition: general.cpp:859
void toggle_minimap_draw_villages()
Definition: general.cpp:864
int font_scaled(int size)
Definition: general.cpp:502
std::string moved_color()
Definition: general.cpp:354
void set_bell_volume(int vol)
Definition: general.cpp:642
void set_damage_prediction_allow_monte_carlo_simulation(bool value)
Definition: general.cpp:978
void set_turbo_speed(const double speed)
Definition: general.cpp:486
void set_grid(bool ison)
Definition: general.cpp:572
bool music_on()
Definition: general.cpp:753
void set_draw_delay(int value)
Definition: general.cpp:904
void set(const std::string &key, bool value)
Definition: general.cpp:165
bool minimap_terrain_coding()
Definition: general.cpp:839
std::string last_cache_cleared_version()
Definition: general.cpp:1224
const int max_window_width
Definition: general.cpp:72
bool damage_prediction_allow_monte_carlo_simulation()
Definition: general.cpp:973
void load_base_prefs()
Definition: general.cpp:240
bool scroll_to_action()
Definition: general.cpp:384
void set_unmoved_color(const std::string &color_id)
Definition: general.cpp:370
void set_fullscreen(bool ison)
Definition: general.cpp:457
void set_show_fps(bool value)
Definition: general.cpp:894
bool turbo()
Definition: general.cpp:467
bool sound_on()
Definition: general.cpp:730
int bell_volume()
Definition: general.cpp:637
int mouse_scroll_threshold()
Gets the threshold for when to scroll.
Definition: general.cpp:814
void set_addon_manager_saved_order_name(const std::string &value)
Definition: general.cpp:988
void write_preferences()
Definition: general.cpp:141
std::string addon_manager_saved_order_name()
Definition: general.cpp:983
bool idle_anim()
Definition: general.cpp:517
double turbo_speed()
Definition: general.cpp:481
void set_stop_music_in_background(bool ison)
Definition: general.cpp:784
bool minimap_draw_terrain()
Definition: general.cpp:869
optional_const_config get_alias()
Definition: general.cpp:932
std::string editor_chosen_addon()
Definition: general.cpp:1202
std::string selected_achievement_group()
Definition: general.cpp:1003
void set_animate_water(bool value)
Definition: general.cpp:884
const int max_font_scaling
Definition: general.cpp:76
void clear_hotkeys()
Definition: general.cpp:919
void set_vsync(bool ison)
Definition: general.cpp:462
const int min_font_scaling
Definition: general.cpp:75
std::string partial_color()
Definition: general.cpp:374
point resolution()
Definition: general.cpp:394
const int def_window_height
Definition: general.cpp:70
config::attribute_value get_as_attribute(const std::string &key)
Definition: general.cpp:226
void toggle_minimap_draw_units()
Definition: general.cpp:854
bool fullscreen()
Definition: general.cpp:436
void set_font_scaling(int scale)
Definition: general.cpp:497
bool mouse_scroll_enabled()
Definition: general.cpp:804
bool set_music(bool ison)
Definition: general.cpp:758
void enable_mouse_scroll(bool value)
Definition: general.cpp:809
prefs_event_handler event_handler_
Definition: general.cpp:88
void set_pixel_scale(const int scale)
Definition: general.cpp:416
bool show_status_on_ally_orb()
Definition: general.cpp:271
void set_show_ally_orb(bool show_orb)
Definition: general.cpp:267
std::string enemy_color()
Definition: general.cpp:344
void add_alias(const std::string &alias, const std::string &command)
Definition: general.cpp:925
void set_disable_auto_moves(bool value)
Definition: general.cpp:968
config * get_prefs()
Definition: general.cpp:235
bool UI_sound_on()
Definition: general.cpp:701
void load_hotkeys()
Definition: general.cpp:909
bool show_ally_orb()
Definition: general.cpp:264
std::string allied_color()
Definition: general.cpp:324
void set_language(const std::string &s)
Definition: general.cpp:542
void set_sub_achievement(const std::string &content_for, const std::string &id, const std::string &sub_id)
Marks the specified sub-achievement as completed.
Definition: general.cpp:1142
bool disable_auto_moves()
Definition: general.cpp:963
int music_volume()
Definition: general.cpp:607
int progress_achievement(const std::string &content_for, const std::string &id, int limit, int max_progress, int amount)
Increments the achievement's current progress by amount if it hasn't already been completed.
Definition: general.cpp:1055
bool show_enemy_orb()
Definition: general.cpp:278
void toggle_minimap_terrain_coding()
Definition: general.cpp:844
bool mp_alert_option(const std::string &id, const std::string &type, bool def)
Definition: general.cpp:1211
void set_UI_volume(int vol)
Definition: general.cpp:657
optional_const_config get_child(const std::string &key)
Definition: general.cpp:200
void save_sample_rate(const unsigned int rate)
Definition: general.cpp:942
bool animate_water()
Definition: general.cpp:824
unsigned int sample_rate()
Definition: general.cpp:937
std::string unmoved_color()
Definition: general.cpp:364
int pixel_scale()
Definition: general.cpp:410
void set_auto_pixel_scale(bool choice)
Definition: general.cpp:426
int keepalive_timeout()
Definition: general.cpp:507
const int max_pixel_scale
Definition: general.cpp:79
const int min_window_height
Definition: general.cpp:67
void set_child(const std::string &key, const config &val)
Definition: general.cpp:195
void save_hotkeys()
Definition: general.cpp:914
bool ellipses()
Definition: general.cpp:557
bool message_bell()
Definition: general.cpp:725
std::string gui_theme()
Definition: general.cpp:547
int draw_delay()
Definition: general.cpp:899
bool set_UI_sound(bool ison)
Definition: general.cpp:706
void set_last_cache_cleared_version(const std::string &version)
Definition: general.cpp:1220
void set_tile_size(const unsigned int size)
Definition: general.cpp:672
static std::string fix_orb_color_name(const std::string &color)
Definition: general.cpp:313
void set_ellipses(bool ison)
Definition: general.cpp:562
void set_editor_chosen_addon(const std::string &addon_id)
Definition: general.cpp:1197
bool confirm_load_save_from_different_version()
Definition: general.cpp:953
void set_selected_achievement_group(const std::string &content_for)
Definition: general.cpp:1008
void set_enemy_color(const std::string &color_id)
Definition: general.cpp:350
bool show_moved_orb()
Definition: general.cpp:285
void set_moved_color(const std::string &color_id)
Definition: general.cpp:360
bool minimap_draw_units()
Definition: general.cpp:849
std::string core_id()
Definition: general.cpp:334
const int min_window_width
Definition: general.cpp:66
void set_animate_map(bool value)
Definition: general.cpp:879
void load_credentials()
bool middle_click_scrolls()
Definition: general.cpp:799
void toggle_minimap_draw_terrain()
Definition: general.cpp:874
std::string get(const std::string &key)
Definition: general.cpp:213
int sound_volume()
Definition: general.cpp:622
void set_show_status_on_ally_orb(bool show_orb)
Definition: general.cpp:274
void set_idle_anim_rate(int rate)
Definition: general.cpp:532
void set_show_moved_orb(bool show_orb)
Definition: general.cpp:288
void erase(const std::string &key)
Definition: general.cpp:205
std::string language()
Definition: general.cpp:537
bool grid()
Definition: general.cpp:567
void set_show_unmoved_orb(bool show_orb)
Definition: general.cpp:295
bool achievement(const std::string &content_for, const std::string &id)
Definition: general.cpp:1013
bool animate_map()
Definition: general.cpp:819
optional_const_config dir_bookmarks()
Definition: general.cpp:1243
bool show_disengaged_orb()
Definition: general.cpp:306
int font_scaling()
Definition: general.cpp:491
bool show_fps()
Definition: general.cpp:889
void toggle_minimap_movement_coding()
Definition: general.cpp:834
void set_scroll_to_action(bool ison)
Definition: general.cpp:389
bool get_scroll_when_mouse_outside(bool def)
Definition: general.cpp:1234
int scroll_speed()
Definition: general.cpp:789
void set_partial_color(const std::string &color_id)
Definition: general.cpp:380
bool turn_bell()
Definition: general.cpp:677
bool sub_achievement(const std::string &content_for, const std::string &id, const std::string &sub_id)
Definition: general.cpp:1116
void set_bell_volume(int vol)
Definition: sound.cpp:1120
void reset_sound()
Definition: sound.cpp:524
bool init_sound()
Definition: sound.cpp:441
void close_sound()
Definition: sound.cpp:493
void play_music()
Definition: sound.cpp:615
void stop_music()
Definition: sound.cpp:555
void stop_UI_sound()
Definition: sound.cpp:590
void stop_bell()
Definition: sound.cpp:578
void set_music_volume(int vol)
Definition: sound.cpp:1080
void stop_sound()
Definition: sound.cpp:563
void set_UI_volume(int vol)
Definition: sound.cpp:1132
void set_sound_volume(int vol)
Definition: sound.cpp:1100
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
std::vector< std::string > split(const config_attribute_value &val)
bool headless()
The game is running headless.
Definition: video.cpp:141
point window_size()
Returns the size of the window in display units / screen coordinates.
Definition: video.cpp:421
void scale(size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, const ScalerCfg &cfg=ScalerCfg(), int yFirst=0, int yLast=std::numeric_limits< int >::max())
Definition: xbrz.cpp:1189
static lg::log_domain log_filesystem("filesystem")
#define ERR_CFG
Definition: general.cpp:44
#define ERR_FS
Definition: general.cpp:47
static lg::log_domain log_config("config")
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:627
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:764
An exception object used when an IO error occurs.
Definition: filesystem.hpp:64
Holds a 2D point.
Definition: point.hpp:25
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46
static constexpr std::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
Definition: enum_base.hpp:57
static map_location::DIRECTION s
#define e