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
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(20);
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 
788 {
789  return std::clamp<int>(lexical_cast_default<int>(get("scroll"), 50), 1, 100);
790 }
791 
792 void set_scroll_speed(const int new_speed)
793 {
794  prefs["scroll"] = new_speed;
795 }
796 
798 {
799  return get("middle_click_scrolls", true);
800 }
801 
803 {
804  return get("mouse_scrolling", true);
805 }
806 
807 void enable_mouse_scroll(bool value)
808 {
809  set("mouse_scrolling", value);
810 }
811 
813 {
814  return prefs["scroll_threshold"].to_int(10);
815 }
816 
818 {
819  return preferences::get("animate_map", true);
820 }
821 
823 {
824  return preferences::get("animate_water", true);
825 }
826 
828 {
829  return preferences::get("minimap_movement_coding", true);
830 }
831 
833 {
834  set("minimap_movement_coding", !minimap_movement_coding());
835 }
836 
838 {
839  return preferences::get("minimap_terrain_coding", true);
840 }
841 
843 {
844  set("minimap_terrain_coding", !minimap_terrain_coding());
845 }
846 
848 {
849  return preferences::get("minimap_draw_units", true);
850 }
851 
853 {
854  set("minimap_draw_units", !minimap_draw_units());
855 }
856 
858 {
859  return preferences::get("minimap_draw_villages", true);
860 }
861 
863 {
864  set("minimap_draw_villages", !minimap_draw_villages());
865 }
866 
868 {
869  return preferences::get("minimap_draw_terrain", true);
870 }
871 
873 {
874  set("minimap_draw_terrain", !minimap_draw_terrain());
875 }
876 
877 void set_animate_map(bool value)
878 {
879  set("animate_map", value);
880 }
881 
882 void set_animate_water(bool value)
883 {
884  set("animate_water", value);
885 }
886 
887 bool show_fps()
888 {
889  return fps;
890 }
891 
892 void set_show_fps(bool value)
893 {
894  fps = value;
895 }
896 
898 {
899  return prefs["draw_delay"].to_int(-1);
900 }
901 
902 void set_draw_delay(int value)
903 {
904  prefs["draw_delay"] = value;
905 }
906 
908 {
909  return get("color_cursors", true);
910 }
911 
912 void _set_color_cursors(bool value)
913 {
914  preferences::set("color_cursors", value);
915 }
916 
918 {
920 }
921 
923 {
925 }
926 
928 {
930  prefs.clear_children("hotkey");
931 }
932 
933 void add_alias(const std::string &alias, const std::string &command)
934 {
935  config &alias_list = prefs.child_or_add("alias");
936  alias_list[alias] = command;
937 }
938 
939 
941 {
942  return get_child("alias");
943 }
944 
945 unsigned int sample_rate()
946 {
947  return prefs["sample_rate"].to_int(44100);
948 }
949 
950 void save_sample_rate(const unsigned int rate)
951 {
952  if (sample_rate() == rate)
953  return;
954 
955  prefs["sample_rate"] = static_cast<int>(rate);
956 
957  // If audio is open, we have to re set sample rate
959 }
960 
962 {
963  return get("confirm_load_save_from_different_version", true);
964 }
965 
967 {
968  return get("use_twelve_hour_clock_format", false);
969 }
970 
972 {
973  return get("disable_auto_moves", false);
974 }
975 
976 void set_disable_auto_moves(bool value)
977 {
978  preferences::set("disable_auto_moves", value);
979 }
980 
982 {
983  return get("damage_prediction_allow_monte_carlo_simulation", true);
984 }
985 
987 {
988  set("damage_prediction_allow_monte_carlo_simulation", value);
989 }
990 
992 {
993  return get("addon_manager_saved_order_name");
994 }
995 
996 void set_addon_manager_saved_order_name(const std::string& value)
997 {
998  set("addon_manager_saved_order_name", value);
999 }
1000 
1002 {
1003  return sort_order::get_enum(get("addon_manager_saved_order_direction")).value_or(sort_order::type::none);
1004 }
1005 
1007 {
1008  set("addon_manager_saved_order_direction", sort_order::get_string(value));
1009 }
1010 
1012 {
1013  return get("selected_achievement_group");
1014 }
1015 
1016 void set_selected_achievement_group(const std::string& content_for)
1017 {
1018  set("selected_achievement_group", content_for);
1019 }
1020 
1021 bool achievement(const std::string& content_for, const std::string& id)
1022 {
1023  for(config& ach : prefs.child_range("achievements"))
1024  {
1025  if(ach["content_for"].str() == content_for)
1026  {
1027  std::vector<std::string> ids = utils::split(ach["ids"]);
1028  return std::find(ids.begin(), ids.end(), id) != ids.end();
1029  }
1030  }
1031  return false;
1032 }
1033 
1034 void set_achievement(const std::string& content_for, const std::string& id)
1035 {
1036  for(config& ach : prefs.child_range("achievements"))
1037  {
1038  // if achievements already exist for this content and the achievement has not already been set, add it
1039  if(ach["content_for"].str() == content_for)
1040  {
1041  std::vector<std::string> ids = utils::split(ach["ids"]);
1042 
1043  if(ids.empty())
1044  {
1045  ach["ids"] = id;
1046  }
1047  else if(std::find(ids.begin(), ids.end(), id) == ids.end())
1048  {
1049  ach["ids"] = ach["ids"].str() + "," + id;
1050  }
1051  ach.remove_children("in_progress", [&id](config cfg){return cfg["id"].str() == id;});
1052  return;
1053  }
1054  }
1055 
1056  // else no achievements have been set for this content yet
1057  config ach;
1058  ach["content_for"] = content_for;
1059  ach["ids"] = id;
1060  prefs.add_child("achievements", ach);
1061 }
1062 
1063 int progress_achievement(const std::string& content_for, const std::string& id, int limit, int max_progress, int amount)
1064 {
1065  if(achievement(content_for, id))
1066  {
1067  return -1;
1068  }
1069 
1070  for(config& ach : prefs.child_range("achievements"))
1071  {
1072  // if achievements already exist for this content and the achievement has not already been set, add it
1073  if(ach["content_for"].str() == content_for)
1074  {
1075  // check if this achievement has progressed before - if so then increment it
1076  for(config& in_progress : ach.child_range("in_progress"))
1077  {
1078  if(in_progress["id"].str() == id)
1079  {
1080  // don't let using 'limit' decrease the achievement's current progress
1081  int starting_progress = in_progress["progress_at"].to_int();
1082  if(starting_progress >= limit) {
1083  return starting_progress;
1084  }
1085 
1086  in_progress["progress_at"] = std::clamp(starting_progress + amount, 0, std::min(limit, max_progress));
1087  return in_progress["progress_at"].to_int();
1088  }
1089  }
1090 
1091  // else this is the first time this achievement is progressing
1092  if(amount != 0)
1093  {
1094  config set_progress;
1095  set_progress["id"] = id;
1096  set_progress["progress_at"] = std::clamp(amount, 0, std::min(limit, max_progress));
1097 
1098  config& child = ach.add_child("in_progress", set_progress);
1099  return child["progress_at"].to_int();
1100  }
1101  return 0;
1102  }
1103  }
1104 
1105  // else not only has this achievement not progressed before, this is the first achievement for this achievement group to be added
1106  if(amount != 0)
1107  {
1108  config ach;
1109  config set_progress;
1110 
1111  set_progress["id"] = id;
1112  set_progress["progress_at"] = std::clamp(amount, 0, std::min(limit, max_progress));
1113 
1114  ach["content_for"] = content_for;
1115  ach["ids"] = "";
1116 
1117  config& child = ach.add_child("in_progress", set_progress);
1118  prefs.add_child("achievements", ach);
1119  return child["progress_at"].to_int();
1120  }
1121  return 0;
1122 }
1123 
1124 bool sub_achievement(const std::string& content_for, const std::string& id, const std::string& sub_id)
1125 {
1126  // this achievement is already completed
1127  if(achievement(content_for, id))
1128  {
1129  return true;
1130  }
1131 
1132  for(config& ach : prefs.child_range("achievements"))
1133  {
1134  if(ach["content_for"].str() == content_for)
1135  {
1136  // check if the specific sub-achievement has been completed but the overall achievement is not completed
1137  for(const auto& in_progress : ach.child_range("in_progress"))
1138  {
1139  if(in_progress["id"] == id)
1140  {
1141  std::vector<std::string> sub_ids = utils::split(in_progress["sub_ids"]);
1142  return std::find(sub_ids.begin(), sub_ids.end(), sub_id) != sub_ids.end();
1143  }
1144  }
1145  }
1146  }
1147  return false;
1148 }
1149 
1150 void set_sub_achievement(const std::string& content_for, const std::string& id, const std::string& sub_id)
1151 {
1152  // this achievement is already completed
1153  if(achievement(content_for, id))
1154  {
1155  return;
1156  }
1157 
1158  for(config& ach : prefs.child_range("achievements"))
1159  {
1160  // if achievements already exist for this content and the achievement has not already been set, add it
1161  if(ach["content_for"].str() == content_for)
1162  {
1163  // check if this achievement has had sub-achievements set before
1164  for(config& in_progress : ach.child_range("in_progress"))
1165  {
1166  if(in_progress["id"].str() == id)
1167  {
1168  std::vector<std::string> sub_ids = utils::split(ach["ids"]);
1169 
1170  if(std::find(sub_ids.begin(), sub_ids.end(), sub_id) == sub_ids.end())
1171  {
1172  in_progress["sub_ids"] = in_progress["sub_ids"].str() + "," + sub_id;
1173  }
1174 
1175  in_progress["progress_at"] = sub_ids.size()+1;
1176  return;
1177  }
1178  }
1179 
1180  // else if this is the first sub-achievement being set
1181  config set_progress;
1182  set_progress["id"] = id;
1183  set_progress["sub_ids"] = sub_id;
1184  set_progress["progress_at"] = 1;
1185  ach.add_child("in_progress", set_progress);
1186  return;
1187  }
1188  }
1189 
1190  // 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
1191  config ach;
1192  config set_progress;
1193 
1194  set_progress["id"] = id;
1195  set_progress["sub_ids"] = sub_id;
1196  set_progress["progress_at"] = 1;
1197 
1198  ach["content_for"] = content_for;
1199  ach["ids"] = "";
1200 
1201  ach.add_child("in_progress", set_progress);
1202  prefs.add_child("achievements", ach);
1203 }
1204 
1205 void set_editor_chosen_addon(const std::string& addon_id)
1206 {
1207  prefs["editor_chosen_addon"] = addon_id;
1208 }
1209 
1210 std::string editor_chosen_addon()
1211 {
1212  return prefs["editor_chosen_addon"];
1213 }
1214 
1215 } // 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:1034
void set_scroll_speed(const int new_speed)
Definition: general.cpp:792
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:1006
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:827
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:1001
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:966
bool auto_pixel_scale()
Definition: general.cpp:419
bool show_partial_orb()
Definition: general.cpp:297
bool minimap_draw_villages()
Definition: general.cpp:857
void toggle_minimap_draw_villages()
Definition: general.cpp:862
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:986
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:902
void set(const std::string &key, bool value)
Definition: general.cpp:165
bool minimap_terrain_coding()
Definition: general.cpp:837
const int max_window_width
Definition: general.cpp:72
bool damage_prediction_allow_monte_carlo_simulation()
Definition: general.cpp:981
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:892
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:812
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:996
void write_preferences()
Definition: general.cpp:141
std::string addon_manager_saved_order_name()
Definition: general.cpp:991
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:867
optional_const_config get_alias()
Definition: general.cpp:940
std::string editor_chosen_addon()
Definition: general.cpp:1210
std::string selected_achievement_group()
Definition: general.cpp:1011
void set_animate_water(bool value)
Definition: general.cpp:882
const int max_font_scaling
Definition: general.cpp:76
void clear_hotkeys()
Definition: general.cpp:927
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:852
bool fullscreen()
Definition: general.cpp:434
void set_font_scaling(int scale)
Definition: general.cpp:495
bool mouse_scroll_enabled()
Definition: general.cpp:802
bool set_music(bool ison)
Definition: general.cpp:756
void enable_mouse_scroll(bool value)
Definition: general.cpp:807
prefs_event_handler event_handler_
Definition: general.cpp:88
bool use_color_cursors()
Definition: general.cpp:907
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:933
void set_disable_auto_moves(bool value)
Definition: general.cpp:976
config * get_prefs()
Definition: general.cpp:235
bool UI_sound_on()
Definition: general.cpp:699
void load_hotkeys()
Definition: general.cpp:917
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:1150
bool disable_auto_moves()
Definition: general.cpp:971
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:1063
bool show_enemy_orb()
Definition: general.cpp:276
void toggle_minimap_terrain_coding()
Definition: general.cpp:842
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:950
bool animate_water()
Definition: general.cpp:822
unsigned int sample_rate()
Definition: general.cpp:945
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:922
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:897
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
void set_editor_chosen_addon(const std::string &addon_id)
Definition: general.cpp:1205
bool confirm_load_save_from_different_version()
Definition: general.cpp:961
void set_selected_achievement_group(const std::string &content_for)
Definition: general.cpp:1016
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:847
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:877
void load_credentials()
bool middle_click_scrolls()
Definition: general.cpp:797
void toggle_minimap_draw_terrain()
Definition: general.cpp:872
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:912
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:1021
bool animate_map()
Definition: general.cpp:817
bool show_disengaged_orb()
Definition: general.cpp:304
int font_scaling()
Definition: general.cpp:489
bool show_fps()
Definition: general.cpp:887
void toggle_minimap_movement_coding()
Definition: general.cpp:832
void set_scroll_to_action(bool ison)
Definition: general.cpp:387
int scroll_speed()
Definition: general.cpp:787
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:1124
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