The Battle for Wesnoth  1.17.17+dev
general.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2023
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
244  read(prefs, *stream);
245 
246  config user_prefs;
248  read(user_prefs, *stream);
249 
250  prefs.merge_with(user_prefs);
251 #else
252  prefs.clear();
254  read(prefs, *stream);
255 #endif
256  } catch(const config::error& e) {
257  ERR_CFG << "Error loading preference, message: " << e.what();
258  }
259 }
260 
261 
263  return get("show_ally_orb", game_config::show_ally_orb);
264 }
265 void set_show_ally_orb(bool show_orb) {
266  prefs["show_ally_orb"] = show_orb;
267 }
268 
270  return get("show_status_on_ally_orb", game_config::show_status_on_ally_orb);
271 }
272 void set_show_status_on_ally_orb(bool show_orb) {
273  prefs["show_status_on_ally_orb"] = show_orb;
274 }
275 
277  return get("show_enemy_orb", game_config::show_enemy_orb);
278 }
279 void set_show_enemy_orb(bool show_orb) {
280  prefs["show_enemy_orb"] = show_orb;
281 }
282 
284  return get("show_moved_orb", game_config::show_moved_orb);
285 }
286 void set_show_moved_orb(bool show_orb) {
287  prefs["show_moved_orb"] = show_orb;
288 }
289 
291  return get("show_unmoved_orb", game_config::show_unmoved_orb);
292 }
293 void set_show_unmoved_orb(bool show_orb) {
294  prefs["show_unmoved_orb"] = show_orb;
295 }
296 
298  return get("show_partial_orb", game_config::show_partial_orb);
299 }
300 void set_show_partial_orb(bool show_orb) {
301  prefs["show_partial_orb"] = show_orb;
302 }
303 
305  return get("show_disengaged_orb", game_config::show_disengaged_orb);
306 }
307 void set_show_disengaged_orb(bool show_orb) {
308  prefs["show_disengaged_orb"] = show_orb;
309 }
310 
311 static std::string fix_orb_color_name(const std::string& color) {
312  if (color.substr(0,4) == "orb_") {
313  if(color[4] >= '0' && color[4] <= '9') {
314  return color.substr(5);
315  } else {
316  return color.substr(4);
317  }
318  }
319  return color;
320 }
321 
322 std::string allied_color() {
323  std::string ally_color = get("ally_orb_color");
324  if (ally_color.empty())
326  return fix_orb_color_name(ally_color);
327 }
328 void set_allied_color(const std::string& color_id) {
329  prefs["ally_orb_color"] = color_id;
330 }
331 
332 std::string core_id() {
333  std::string core_id = get("core");
334  if (core_id.empty())
335  return "default";
336  return core_id;
337 }
338 void set_core_id(const std::string& core_id) {
339  prefs["core"] = core_id;
340 }
341 
342 std::string enemy_color() {
343  std::string enemy_color = get("enemy_orb_color");
344  if (enemy_color.empty())
347 }
348 void set_enemy_color(const std::string& color_id) {
349  prefs["enemy_orb_color"] = color_id;
350 }
351 
352 std::string moved_color() {
353  std::string moved_color = get("moved_orb_color");
354  if (moved_color.empty())
357 }
358 void set_moved_color(const std::string& color_id) {
359  prefs["moved_orb_color"] = color_id;
360 }
361 
362 std::string unmoved_color() {
363  std::string unmoved_color = get("unmoved_orb_color");
364  if (unmoved_color.empty())
367 }
368 void set_unmoved_color(const std::string& color_id) {
369  prefs["unmoved_orb_color"] = color_id;
370 }
371 
372 std::string partial_color() {
373  std::string partmoved_color = get("partial_orb_color");
374  if (partmoved_color.empty())
376  return fix_orb_color_name(partmoved_color);
377 }
378 void set_partial_color(const std::string& color_id) {
379  prefs["partial_orb_color"] = color_id;
380 }
381 
383 {
384  return get("scroll_to_action", true);
385 }
386 
387 void set_scroll_to_action(bool ison)
388 {
389  prefs["scroll_to_action"] = ison;
390 }
391 
393 {
394  const unsigned x_res = prefs["xresolution"].to_unsigned();
395  const unsigned y_res = prefs["yresolution"].to_unsigned();
396 
397  // Either resolution was unspecified, return default.
398  if(x_res == 0 || y_res == 0) {
400  }
401 
402  return point(
403  std::max<unsigned>(x_res, min_window_width),
404  std::max<unsigned>(y_res, min_window_height)
405  );
406 }
407 
409 {
410  // For now this has a minimum value of 1 and a maximum of 4.
411  return std::max<int>(std::min<int>(prefs["pixel_scale"].to_int(1), max_pixel_scale), min_pixel_scale);
412 }
413 
414 void set_pixel_scale(const int scale)
415 {
416  prefs["pixel_scale"] = std::clamp(scale, min_pixel_scale, max_pixel_scale);
417 }
418 
420 {
421  return get("auto_pixel_scale", true);
422 }
423 
424 void set_auto_pixel_scale(bool choice)
425 {
426  prefs["auto_pixel_scale"] = choice;
427 }
428 
429 bool maximized()
430 {
431  return get("maximized", !fullscreen());
432 }
433 
435 {
436  return get("fullscreen", true);
437 }
438 
439 bool vsync()
440 {
441  return get("vsync", true);
442 }
443 
444 void _set_resolution(const point& res)
445 {
446  preferences::set("xresolution", std::to_string(res.x));
447  preferences::set("yresolution", std::to_string(res.y));
448 }
449 
450 void _set_maximized(bool ison)
451 {
452  prefs["maximized"] = ison;
453 }
454 
455 void _set_fullscreen(bool ison)
456 {
457  prefs["fullscreen"] = ison;
458 }
459 
460 void set_vsync(bool ison)
461 {
462  prefs["vsync"] = ison;
463 }
464 
465 bool turbo()
466 {
467  if(video::headless()) {
468  return true;
469  }
470 
471  return get("turbo", false);
472 }
473 
474 void set_turbo(bool ison)
475 {
476  prefs["turbo"] = ison;
477 }
478 
479 double turbo_speed()
480 {
481  return prefs["turbo_speed"].to_double(2.0);
482 }
483 
484 void set_turbo_speed(const double speed)
485 {
486  prefs["turbo_speed"] = speed;
487 }
488 
490 {
491  // Clip at 80 because if it's too low it'll cause crashes
492  return std::max<int>(std::min<int>(prefs["font_scale"].to_int(100), max_font_scaling), min_font_scaling);
493 }
494 
496 {
497  prefs["font_scale"] = std::clamp(scale, min_font_scaling, max_font_scaling);
498 }
499 
501 {
502  return (size * font_scaling()) / 100;
503 }
504 
506 {
507  return prefs["keepalive_timeout"].to_int(10);
508 }
509 
510 void keepalive_timeout(int seconds)
511 {
512  prefs["keepalive_timeout"] = std::abs(seconds);
513 }
514 
515 bool idle_anim()
516 {
517  return get("idle_anim", true);
518 }
519 
520 void set_idle_anim(const bool ison)
521 {
522  prefs["idle_anim"] = ison;
523 }
524 
526 {
527  return prefs["idle_anim_rate"].to_double(1.0);
528 }
529 
530 void set_idle_anim_rate(const int rate)
531 {
532  prefs["idle_anim_rate"] = std::pow(2.0, -rate / 10.0);
533 }
534 
535 std::string language()
536 {
537  return prefs["locale"];
538 }
539 
540 void set_language(const std::string& s)
541 {
542  preferences::set("locale", s);
543 }
544 
545 std::string gui_theme()
546 {
547  return prefs["gui2_theme"];
548 }
549 
550 void set_gui_theme(const std::string& s)
551 {
552  preferences::set("gui2_theme", s);
553 }
554 
555 bool ellipses()
556 {
557  return get("show_side_colors", false);
558 }
559 
560 void set_ellipses(bool ison)
561 {
562  preferences::set("show_side_colors", ison);
563 }
564 
565 bool grid()
566 {
567  return get("grid", false);
568 }
569 
570 void set_grid(bool ison)
571 {
572  preferences::set("grid", ison);
573 }
574 
575 std::size_t sound_buffer_size()
576 {
577  // Sounds don't sound good on Windows unless the buffer size is 4k,
578  // but this seems to cause crashes on other systems...
579  #ifdef _WIN32
580  const std::size_t buf_size = 4096;
581  #else
582  const std::size_t buf_size = 1024;
583  #endif
584 
585  return prefs["sound_buffer_size"].to_int(buf_size);
586 }
587 
588 void save_sound_buffer_size(const std::size_t size)
589 {
590  #ifdef _WIN32
591  const char* buf_size = "4096";
592  #else
593  const char* buf_size = "1024";
594  #endif
595 
596  const std::string new_size = lexical_cast_default<std::string>(size, buf_size);
597  if (get("sound_buffer_size") == new_size)
598  return;
599 
600  preferences::set("sound_buffer_size", new_size);
601 
603 }
604 
606 {
607  return prefs["music_volume"].to_int(100);
608 }
609 
610 void set_music_volume(int vol)
611 {
612  if(music_volume() == vol) {
613  return;
614  }
615 
616  prefs["music_volume"] = vol;
618 }
619 
621 {
622  return prefs["sound_volume"].to_int(100);
623 }
624 
625 void set_sound_volume(int vol)
626 {
627  if(sound_volume() == vol) {
628  return;
629  }
630 
631  prefs["sound_volume"] = vol;
633 }
634 
636 {
637  return prefs["bell_volume"].to_int(100);
638 }
639 
640 void set_bell_volume(int vol)
641 {
642  if(bell_volume() == vol) {
643  return;
644  }
645 
646  prefs["bell_volume"] = vol;
648 }
649 
651 {
652  return prefs["UI_volume"].to_int(100);
653 }
654 
655 void set_UI_volume(int vol)
656 {
657  if(UI_volume() == vol) {
658  return;
659  }
660 
661  prefs["UI_volume"] = vol;
663 }
664 
665 unsigned int tile_size()
666 {
667  return prefs["tile_size"].to_unsigned();
668 }
669 
670 void set_tile_size(const unsigned int size)
671 {
672  prefs["tile_size"] = size;
673 }
674 
675 bool turn_bell()
676 {
677  return get("turn_bell", true);
678 }
679 
680 bool set_turn_bell(bool ison)
681 {
682  if(!turn_bell() && ison) {
683  preferences::set("turn_bell", true);
684  if(!music_on() && !sound_on() && !UI_sound_on()) {
685  if(!sound::init_sound()) {
686  preferences::set("turn_bell", false);
687  return false;
688  }
689  }
690  } else if(turn_bell() && !ison) {
691  preferences::set("turn_bell", false);
693  if(!music_on() && !sound_on() && !UI_sound_on())
695  }
696  return true;
697 }
698 
700 {
701  return get("UI_sound", true);
702 }
703 
704 bool set_UI_sound(bool ison)
705 {
706  if(!UI_sound_on() && ison) {
707  preferences::set("UI_sound", true);
708  if(!music_on() && !sound_on() && !turn_bell()) {
709  if(!sound::init_sound()) {
710  preferences::set("UI_sound", false);
711  return false;
712  }
713  }
714  } else if(UI_sound_on() && !ison) {
715  preferences::set("UI_sound", false);
717  if(!music_on() && !sound_on() && !turn_bell())
719  }
720  return true;
721 }
722 
724 {
725  return get("message_bell", true);
726 }
727 
728 bool sound_on()
729 {
730  return get("sound", true);
731 }
732 
733 bool set_sound(bool ison) {
734  if(!sound_on() && ison) {
735  preferences::set("sound", true);
736  if(!music_on() && !turn_bell() && !UI_sound_on()) {
737  if(!sound::init_sound()) {
738  preferences::set("sound", false);
739  return false;
740  }
741  }
742  } else if(sound_on() && !ison) {
743  preferences::set("sound", false);
745  if(!music_on() && !turn_bell() && !UI_sound_on())
747  }
748  return true;
749 }
750 
751 bool music_on()
752 {
753  return get("music", true);
754 }
755 
756 bool set_music(bool ison) {
757  if(!music_on() && ison) {
758  preferences::set("music", true);
759  if(!sound_on() && !turn_bell() && !UI_sound_on()) {
760  if(!sound::init_sound()) {
761  preferences::set("music", false);
762  return false;
763  }
764  }
765  else
767  } else if(music_on() && !ison) {
768  preferences::set("music", false);
769  if(!sound_on() && !turn_bell() && !UI_sound_on())
771  else
773  }
774  return true;
775 }
776 
778 {
779  return get("stop_music_in_background", false);
780 }
781 
783 {
784  preferences::set("stop_music_in_background", ison);
785 }
786 
787 namespace {
788  double scroll = 0.2;
789 }
790 
792 {
793  const int value = std::clamp<int>(lexical_cast_default<int>(get("scroll"), 50), 1, 100);
794  scroll = value/100.0;
795 
796  return value;
797 }
798 
799 void set_scroll_speed(const int new_speed)
800 {
801  prefs["scroll"] = new_speed;
802  scroll = new_speed / 100.0;
803 }
804 
806 {
807  return get("middle_click_scrolls", true);
808 }
809 
811 {
812  return get("mouse_scrolling", true);
813 }
814 
815 void enable_mouse_scroll(bool value)
816 {
817  set("mouse_scrolling", value);
818 }
819 
821 {
822  return prefs["scroll_threshold"].to_int(10);
823 }
824 
826 {
827  return preferences::get("animate_map", true);
828 }
829 
831 {
832  return preferences::get("animate_water", true);
833 }
834 
836 {
837  return preferences::get("minimap_movement_coding", true);
838 }
839 
841 {
842  set("minimap_movement_coding", !minimap_movement_coding());
843 }
844 
846 {
847  return preferences::get("minimap_terrain_coding", true);
848 }
849 
851 {
852  set("minimap_terrain_coding", !minimap_terrain_coding());
853 }
854 
856 {
857  return preferences::get("minimap_draw_units", true);
858 }
859 
861 {
862  set("minimap_draw_units", !minimap_draw_units());
863 }
864 
866 {
867  return preferences::get("minimap_draw_villages", true);
868 }
869 
871 {
872  set("minimap_draw_villages", !minimap_draw_villages());
873 }
874 
876 {
877  return preferences::get("minimap_draw_terrain", true);
878 }
879 
881 {
882  set("minimap_draw_terrain", !minimap_draw_terrain());
883 }
884 
885 void set_animate_map(bool value)
886 {
887  set("animate_map", value);
888 }
889 
890 void set_animate_water(bool value)
891 {
892  set("animate_water", value);
893 }
894 
895 bool show_fps()
896 {
897  return fps;
898 }
899 
900 void set_show_fps(bool value)
901 {
902  fps = value;
903 }
904 
906 {
907  return prefs["draw_delay"].to_int(-1);
908 }
909 
910 void set_draw_delay(int value)
911 {
912  prefs["draw_delay"] = value;
913 }
914 
916 {
917  return get("color_cursors", true);
918 }
919 
920 void _set_color_cursors(bool value)
921 {
922  preferences::set("color_cursors", value);
923 }
924 
926 {
928 }
929 
931 {
933 }
934 
936 {
938  prefs.clear_children("hotkey");
939 }
940 
941 void add_alias(const std::string &alias, const std::string &command)
942 {
943  config &alias_list = prefs.child_or_add("alias");
944  alias_list[alias] = command;
945 }
946 
947 
949 {
950  return get_child("alias");
951 }
952 
953 unsigned int sample_rate()
954 {
955  return prefs["sample_rate"].to_int(44100);
956 }
957 
958 void save_sample_rate(const unsigned int rate)
959 {
960  if (sample_rate() == rate)
961  return;
962 
963  prefs["sample_rate"] = static_cast<int>(rate);
964 
965  // If audio is open, we have to re set sample rate
967 }
968 
970 {
971  return get("confirm_load_save_from_different_version", true);
972 }
973 
975 {
976  return get("use_twelve_hour_clock_format", false);
977 }
978 
980 {
981  return get("disable_auto_moves", false);
982 }
983 
984 void set_disable_auto_moves(bool value)
985 {
986  preferences::set("disable_auto_moves", value);
987 }
988 
990 {
991  return get("damage_prediction_allow_monte_carlo_simulation", true);
992 }
993 
995 {
996  set("damage_prediction_allow_monte_carlo_simulation", value);
997 }
998 
1000 {
1001  return get("addon_manager_saved_order_name");
1002 }
1003 
1004 void set_addon_manager_saved_order_name(const std::string& value)
1005 {
1006  set("addon_manager_saved_order_name", value);
1007 }
1008 
1010 {
1011  return sort_order::get_enum(get("addon_manager_saved_order_direction")).value_or(sort_order::type::none);
1012 }
1013 
1015 {
1016  set("addon_manager_saved_order_direction", sort_order::get_string(value));
1017 }
1018 
1020 {
1021  return get("selected_achievement_group");
1022 }
1023 
1024 void set_selected_achievement_group(const std::string& content_for)
1025 {
1026  set("selected_achievement_group", content_for);
1027 }
1028 
1029 bool achievement(const std::string& content_for, const std::string& id)
1030 {
1031  for(config& ach : prefs.child_range("achievements"))
1032  {
1033  if(ach["content_for"].str() == content_for)
1034  {
1035  std::vector<std::string> ids = utils::split(ach["ids"]);
1036  return std::find(ids.begin(), ids.end(), id) != ids.end();
1037  }
1038  }
1039  return false;
1040 }
1041 
1042 void set_achievement(const std::string& content_for, const std::string& id)
1043 {
1044  for(config& ach : prefs.child_range("achievements"))
1045  {
1046  // if achievements already exist for this content and the achievement has not already been set, add it
1047  if(ach["content_for"].str() == content_for)
1048  {
1049  std::vector<std::string> ids = utils::split(ach["ids"]);
1050 
1051  if(ids.empty())
1052  {
1053  ach["ids"] = id;
1054  }
1055  else if(std::find(ids.begin(), ids.end(), id) == ids.end())
1056  {
1057  ach["ids"] = ach["ids"].str() + "," + id;
1058  }
1059  ach.remove_children("in_progress", [&id](config cfg){return cfg["id"].str() == id;});
1060  return;
1061  }
1062  }
1063 
1064  // else no achievements have been set for this content yet
1065  config ach;
1066  ach["content_for"] = content_for;
1067  ach["ids"] = id;
1068  prefs.add_child("achievements", ach);
1069 }
1070 
1071 int progress_achievement(const std::string& content_for, const std::string& id, int limit, int max_progress, int amount)
1072 {
1073  if(achievement(content_for, id))
1074  {
1075  return -1;
1076  }
1077 
1078  for(config& ach : prefs.child_range("achievements"))
1079  {
1080  // if achievements already exist for this content and the achievement has not already been set, add it
1081  if(ach["content_for"].str() == content_for)
1082  {
1083  // check if this achievement has progressed before - if so then increment it
1084  for(config& in_progress : ach.child_range("in_progress"))
1085  {
1086  if(in_progress["id"].str() == id)
1087  {
1088  // don't let using 'limit' decrease the achievement's current progress
1089  int starting_progress = in_progress["progress_at"].to_int();
1090  if(starting_progress >= limit) {
1091  return starting_progress;
1092  }
1093 
1094  in_progress["progress_at"] = std::clamp(starting_progress + amount, 0, std::min(limit, max_progress));
1095  return in_progress["progress_at"].to_int();
1096  }
1097  }
1098 
1099  // else this is the first time this achievement is progressing
1100  if(amount != 0)
1101  {
1102  config set_progress;
1103  set_progress["id"] = id;
1104  set_progress["progress_at"] = std::clamp(amount, 0, std::min(limit, max_progress));
1105 
1106  config& child = ach.add_child("in_progress", set_progress);
1107  return child["progress_at"].to_int();
1108  }
1109  return 0;
1110  }
1111  }
1112 
1113  // else not only has this achievement not progressed before, this is the first achievement for this achievement group to be added
1114  if(amount != 0)
1115  {
1116  config ach;
1117  config set_progress;
1118 
1119  set_progress["id"] = id;
1120  set_progress["progress_at"] = std::clamp(amount, 0, std::min(limit, max_progress));
1121 
1122  ach["content_for"] = content_for;
1123  ach["ids"] = "";
1124 
1125  config& child = ach.add_child("in_progress", set_progress);
1126  prefs.add_child("achievements", ach);
1127  return child["progress_at"].to_int();
1128  }
1129  return 0;
1130 }
1131 
1132 bool sub_achievement(const std::string& content_for, const std::string& id, const std::string& sub_id)
1133 {
1134  // this achievement is already completed
1135  if(achievement(content_for, id))
1136  {
1137  return true;
1138  }
1139 
1140  for(config& ach : prefs.child_range("achievements"))
1141  {
1142  if(ach["content_for"].str() == content_for)
1143  {
1144  // check if the specific sub-achievement has been completed but the overall achievement is not completed
1145  for(const auto& in_progress : ach.child_range("in_progress"))
1146  {
1147  if(in_progress["id"] == id)
1148  {
1149  std::vector<std::string> sub_ids = utils::split(in_progress["sub_ids"]);
1150  return std::find(sub_ids.begin(), sub_ids.end(), sub_id) != sub_ids.end();
1151  }
1152  }
1153  }
1154  }
1155  return false;
1156 }
1157 
1158 void set_sub_achievement(const std::string& content_for, const std::string& id, const std::string& sub_id)
1159 {
1160  // this achievement is already completed
1161  if(achievement(content_for, id))
1162  {
1163  return;
1164  }
1165 
1166  for(config& ach : prefs.child_range("achievements"))
1167  {
1168  // if achievements already exist for this content and the achievement has not already been set, add it
1169  if(ach["content_for"].str() == content_for)
1170  {
1171  // check if this achievement has had sub-achievements set before
1172  for(config& in_progress : ach.child_range("in_progress"))
1173  {
1174  if(in_progress["id"].str() == id)
1175  {
1176  std::vector<std::string> sub_ids = utils::split(ach["ids"]);
1177 
1178  if(std::find(sub_ids.begin(), sub_ids.end(), sub_id) == sub_ids.end())
1179  {
1180  in_progress["sub_ids"] = in_progress["sub_ids"].str() + "," + sub_id;
1181  }
1182 
1183  in_progress["progress_at"] = sub_ids.size()+1;
1184  return;
1185  }
1186  }
1187 
1188  // else if this is the first sub-achievement being set
1189  config set_progress;
1190  set_progress["id"] = id;
1191  set_progress["sub_ids"] = sub_id;
1192  set_progress["progress_at"] = 1;
1193  ach.add_child("in_progress", set_progress);
1194  return;
1195  }
1196  }
1197 
1198  // 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
1199  config ach;
1200  config set_progress;
1201 
1202  set_progress["id"] = id;
1203  set_progress["sub_ids"] = sub_id;
1204  set_progress["progress_at"] = 1;
1205 
1206  ach["content_for"] = content_for;
1207  ach["ids"] = "";
1208 
1209  ach.add_child("in_progress", set_progress);
1210  prefs.add_child("achievements", ach);
1211 }
1212 
1213 } // 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:161
child_itors child_range(config_key_type key)
Definition: config.cpp:277
config & add_child(config_key_type key)
Definition: config.cpp:445
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:215
New lexcical_cast header.
Standard logging facilities (interface).
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
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:51
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:52
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:1042
void set_scroll_speed(const int new_speed)
Definition: general.cpp:799
void set_show_disengaged_orb(bool show_orb)
Definition: general.cpp:307
bool stop_music_in_background()
Definition: general.cpp:777
const int max_window_height
Definition: general.cpp:73
const int def_window_width
Definition: general.cpp:69
std::size_t sound_buffer_size()
Definition: general.cpp:575
void disable_preferences_save()
Definition: general.cpp:231
void set_turbo(bool ison)
Definition: general.cpp:474
void set_allied_color(const std::string &color_id)
Definition: general.cpp:328
void set_addon_manager_saved_order_direction(sort_order::type value)
Definition: general.cpp:1014
bool have_setting(const std::string &key)
Definition: general.cpp:209
void set_music_volume(int vol)
Definition: general.cpp:610
void set_show_partial_orb(bool show_orb)
Definition: general.cpp:300
void set_idle_anim(const bool ison)
Definition: general.cpp:520
bool minimap_movement_coding()
Definition: general.cpp:835
void clear(const std::string &key)
Definition: general.cpp:190
void set_core_id(const std::string &core_id)
Definition: general.cpp:338
bool show_unmoved_orb()
Definition: general.cpp:290
bool set_turn_bell(bool ison)
Definition: general.cpp:680
int UI_volume()
Definition: general.cpp:650
bool vsync()
Definition: general.cpp:439
void set_show_enemy_orb(bool show_orb)
Definition: general.cpp:279
void set_sound_volume(int vol)
Definition: general.cpp:625
sort_order::type addon_manager_saved_order_direction()
Definition: general.cpp:1009
bool maximized()
Definition: general.cpp:429
void set_gui_theme(const std::string &s)
Definition: general.cpp:550
unsigned int tile_size()
Definition: general.cpp:665
void save_sound_buffer_size(const std::size_t size)
Definition: general.cpp:588
void save_credentials()
const int min_pixel_scale
Definition: general.cpp:78
bool set_sound(bool ison)
Definition: general.cpp:733
bool use_twelve_hour_clock_format()
Definition: general.cpp:974
bool auto_pixel_scale()
Definition: general.cpp:419
bool show_partial_orb()
Definition: general.cpp:297
bool minimap_draw_villages()
Definition: general.cpp:865
void toggle_minimap_draw_villages()
Definition: general.cpp:870
int font_scaled(int size)
Definition: general.cpp:500
std::string moved_color()
Definition: general.cpp:352
void set_bell_volume(int vol)
Definition: general.cpp:640
void set_damage_prediction_allow_monte_carlo_simulation(bool value)
Definition: general.cpp:994
void set_turbo_speed(const double speed)
Definition: general.cpp:484
void set_grid(bool ison)
Definition: general.cpp:570
bool music_on()
Definition: general.cpp:751
void set_draw_delay(int value)
Definition: general.cpp:910
void set(const std::string &key, bool value)
Definition: general.cpp:165
bool minimap_terrain_coding()
Definition: general.cpp:845
const int max_window_width
Definition: general.cpp:72
bool damage_prediction_allow_monte_carlo_simulation()
Definition: general.cpp:989
void load_base_prefs()
Definition: general.cpp:240
bool scroll_to_action()
Definition: general.cpp:382
double idle_anim_rate()
Definition: general.cpp:525
void set_unmoved_color(const std::string &color_id)
Definition: general.cpp:368
void set_show_fps(bool value)
Definition: general.cpp:900
bool turbo()
Definition: general.cpp:465
bool sound_on()
Definition: general.cpp:728
int bell_volume()
Definition: general.cpp:635
int mouse_scroll_threshold()
Gets the threshold for when to scroll.
Definition: general.cpp:820
void set_idle_anim_rate(const int rate)
Definition: general.cpp:530
void set_addon_manager_saved_order_name(const std::string &value)
Definition: general.cpp:1004
void write_preferences()
Definition: general.cpp:141
std::string addon_manager_saved_order_name()
Definition: general.cpp:999
bool idle_anim()
Definition: general.cpp:515
double turbo_speed()
Definition: general.cpp:479
void set_stop_music_in_background(bool ison)
Definition: general.cpp:782
bool minimap_draw_terrain()
Definition: general.cpp:875
optional_const_config get_alias()
Definition: general.cpp:948
std::string selected_achievement_group()
Definition: general.cpp:1019
void set_animate_water(bool value)
Definition: general.cpp:890
const int max_font_scaling
Definition: general.cpp:76
void clear_hotkeys()
Definition: general.cpp:935
void set_vsync(bool ison)
Definition: general.cpp:460
const int min_font_scaling
Definition: general.cpp:75
std::string partial_color()
Definition: general.cpp:372
point resolution()
Definition: general.cpp:392
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:860
bool fullscreen()
Definition: general.cpp:434
void set_font_scaling(int scale)
Definition: general.cpp:495
bool mouse_scroll_enabled()
Definition: general.cpp:810
bool set_music(bool ison)
Definition: general.cpp:756
void enable_mouse_scroll(bool value)
Definition: general.cpp:815
prefs_event_handler event_handler_
Definition: general.cpp:88
bool use_color_cursors()
Definition: general.cpp:915
void set_pixel_scale(const int scale)
Definition: general.cpp:414
bool show_status_on_ally_orb()
Definition: general.cpp:269
void set_show_ally_orb(bool show_orb)
Definition: general.cpp:265
std::string enemy_color()
Definition: general.cpp:342
void _set_fullscreen(bool ison)
Definition: general.cpp:455
void add_alias(const std::string &alias, const std::string &command)
Definition: general.cpp:941
void set_disable_auto_moves(bool value)
Definition: general.cpp:984
config * get_prefs()
Definition: general.cpp:235
bool UI_sound_on()
Definition: general.cpp:699
void load_hotkeys()
Definition: general.cpp:925
bool show_ally_orb()
Definition: general.cpp:262
std::string allied_color()
Definition: general.cpp:322
void set_language(const std::string &s)
Definition: general.cpp:540
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:1158
bool disable_auto_moves()
Definition: general.cpp:979
int music_volume()
Definition: general.cpp:605
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:1071
bool show_enemy_orb()
Definition: general.cpp:276
void toggle_minimap_terrain_coding()
Definition: general.cpp:850
void _set_maximized(bool ison)
Definition: general.cpp:450
void set_UI_volume(int vol)
Definition: general.cpp:655
optional_const_config get_child(const std::string &key)
Definition: general.cpp:200
void save_sample_rate(const unsigned int rate)
Definition: general.cpp:958
bool animate_water()
Definition: general.cpp:830
unsigned int sample_rate()
Definition: general.cpp:953
std::string unmoved_color()
Definition: general.cpp:362
int pixel_scale()
Definition: general.cpp:408
void set_auto_pixel_scale(bool choice)
Definition: general.cpp:424
int keepalive_timeout()
Definition: general.cpp:505
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:930
bool ellipses()
Definition: general.cpp:555
bool message_bell()
Definition: general.cpp:723
std::string gui_theme()
Definition: general.cpp:545
int draw_delay()
Definition: general.cpp:905
bool set_UI_sound(bool ison)
Definition: general.cpp:704
void set_tile_size(const unsigned int size)
Definition: general.cpp:670
static std::string fix_orb_color_name(const std::string &color)
Definition: general.cpp:311
void set_ellipses(bool ison)
Definition: general.cpp:560
bool confirm_load_save_from_different_version()
Definition: general.cpp:969
void set_selected_achievement_group(const std::string &content_for)
Definition: general.cpp:1024
void set_enemy_color(const std::string &color_id)
Definition: general.cpp:348
bool show_moved_orb()
Definition: general.cpp:283
void set_moved_color(const std::string &color_id)
Definition: general.cpp:358
bool minimap_draw_units()
Definition: general.cpp:855
std::string core_id()
Definition: general.cpp:332
const int min_window_width
Definition: general.cpp:66
void set_animate_map(bool value)
Definition: general.cpp:885
void load_credentials()
bool middle_click_scrolls()
Definition: general.cpp:805
void toggle_minimap_draw_terrain()
Definition: general.cpp:880
std::string get(const std::string &key)
Definition: general.cpp:213
int sound_volume()
Definition: general.cpp:620
void set_show_status_on_ally_orb(bool show_orb)
Definition: general.cpp:272
void set_show_moved_orb(bool show_orb)
Definition: general.cpp:286
void erase(const std::string &key)
Definition: general.cpp:205
std::string language()
Definition: general.cpp:535
bool grid()
Definition: general.cpp:565
void _set_color_cursors(bool value)
Definition: general.cpp:920
void set_show_unmoved_orb(bool show_orb)
Definition: general.cpp:293
bool achievement(const std::string &content_for, const std::string &id)
Definition: general.cpp:1029
bool animate_map()
Definition: general.cpp:825
bool show_disengaged_orb()
Definition: general.cpp:304
int font_scaling()
Definition: general.cpp:489
bool show_fps()
Definition: general.cpp:895
void toggle_minimap_movement_coding()
Definition: general.cpp:840
void set_scroll_to_action(bool ison)
Definition: general.cpp:387
int scroll_speed()
Definition: general.cpp:791
void set_partial_color(const std::string &color_id)
Definition: general.cpp:378
bool turn_bell()
Definition: general.cpp:675
void _set_resolution(const point &res)
Definition: general.cpp:444
bool sub_achievement(const std::string &content_for, const std::string &id, const std::string &sub_id)
Definition: general.cpp:1132
void set_bell_volume(int vol)
Definition: sound.cpp:1122
void reset_sound()
Definition: sound.cpp:526
bool init_sound()
Definition: sound.cpp:443
void close_sound()
Definition: sound.cpp:495
void play_music()
Definition: sound.cpp:617
void stop_music()
Definition: sound.cpp:557
void stop_UI_sound()
Definition: sound.cpp:592
void stop_bell()
Definition: sound.cpp:580
void set_music_volume(int vol)
Definition: sound.cpp:1082
void stop_sound()
Definition: sound.cpp:565
void set_UI_volume(int vol)
Definition: sound.cpp:1134
void set_sound_volume(int vol)
Definition: sound.cpp:1102
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
std::vector< std::string > split(const config_attribute_value &val)
bool headless()
The game is running headless.
Definition: video.cpp:142
point window_size()
Returns the size of the window in display units / screen coordinates.
Definition: video.cpp:413
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:1190
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:65
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