The Battle for Wesnoth  1.19.1+dev
preferences.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2024 - 2024
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Get and set user-preferences.
18  */
19 
20 #define GETTEXT_DOMAIN "wesnoth-lib"
21 
23 
24 #include "cursor.hpp"
26 #include "game_board.hpp"
27 #include "game_display.hpp"
28 #include "formula/string_utils.hpp"
29 #include "game_config.hpp"
30 #include "game_data.hpp"
31 #include "gettext.hpp"
35 #include "hotkey/hotkey_item.hpp"
36 #include "log.hpp"
37 #include "map_settings.hpp"
38 #include "map/map.hpp"
39 #include "resources.hpp"
40 #include "serialization/parser.hpp"
41 #include "sound.hpp"
42 #include "units/unit.hpp"
43 #include "video.hpp"
44 
45 #include <sys/stat.h> // for setting the permissions of the preferences file
46 #include <boost/algorithm/string.hpp>
47 
48 #ifdef _WIN32
50 #include <boost/range/iterator_range.hpp>
51 #include <windows.h>
52 #endif
53 
54 #ifndef __APPLE__
55 #include <openssl/evp.h>
56 #include <openssl/err.h>
57 #else
58 #include <CommonCrypto/CommonCryptor.h>
59 #endif
60 
61 static lg::log_domain log_config("config");
62 #define ERR_CFG LOG_STREAM(err , log_config)
63 #define DBG_CFG LOG_STREAM(debug , log_config)
64 
65 static lg::log_domain log_filesystem("filesystem");
66 #define ERR_FS LOG_STREAM(err, log_filesystem)
67 
68 static lg::log_domain advanced_preferences("advanced_preferences");
69 #define ERR_ADV LOG_STREAM(err, advanced_preferences)
70 
72 : preferences_()
73 , fps_(false)
74 , completed_campaigns_()
75 , encountered_units_set_()
76 , encountered_terrains_set_()
77 , history_map_()
78 , acquaintances_()
79 , option_values_()
80 , options_initialized_(false)
81 , mp_modifications_()
82 , mp_modifications_initialized_(false)
83 , sp_modifications_()
84 , sp_modifications_initialized_(false)
85 , message_private_on_(false)
86 , credentials_()
87 , advanced_prefs_()
88 {
91 
92  // make sure this has a default set
93  if(!preferences_.has_attribute("scroll_threshold")) {
94  preferences_[prefs_list::scroll_threshold] = 10;
95  }
96 
97  for(const config& acfg : preferences_.child_range("acquaintance")) {
99  acquaintances_[ac.get_nick()] = ac;
100  }
101 }
102 
104 {
105  config campaigns;
106  for(const auto& elem : completed_campaigns_) {
107  config cmp;
108  cmp["name"] = elem.first;
109  cmp["difficulty_levels"] = utils::join(elem.second);
110  campaigns.add_child("campaign", cmp);
111  }
112 
113  set_child(prefs_list::completed_campaigns, campaigns);
114 
115  preferences_[prefs_list::encountered_units] = utils::join(encountered_units_set_);
117  preferences_[prefs_list::encountered_terrain_list] = t_translation::write_list(terrain);
118 
119  /* Structure of the history
120  [history]
121  [history_id]
122  [line]
123  message = foobar
124  [/line]
125  */
126  config history;
127  for(const auto& history_id : history_map_) {
128  config history_id_cfg; // [history_id]
129  for(const std::string& line : history_id.second) {
130  config cfg; // [line]
131 
132  cfg["message"] = line;
133  history_id_cfg.add_child("line", std::move(cfg));
134  }
135 
136  history.add_child(history_id.first, history_id_cfg);
137  }
138  set_child(prefs_list::history, history);
139 
140  preferences_.clear_children("acquaintance");
141 
142  for(auto& a : acquaintances_) {
143  config& item = preferences_.add_child("acquaintance");
144  a.second.save(item);
145  }
146 
147  history_map_.clear();
148  encountered_units_set_.clear();
150 
151  try {
152  if(!no_preferences_save) {
154  }
155  } catch (...) {
156  ERR_FS << "Failed to write preferences due to exception: " << utils::get_unknown_exception_type();
157  }
158 }
159 
161 {
162  for(const config& pref : gc.child_range("advanced_preference")) {
163  try {
164  advanced_prefs_.emplace_back(pref);
165  } catch(const std::invalid_argument& e) {
166  ERR_ADV << e.what();
167  continue;
168  }
169  }
170 
171  // show_deprecation has a different default on the dev branch
172  if(game_config::wesnoth_version.is_dev_version()) {
174  if(op.field == prefs_list::show_deprecation) {
175  op.cfg["default"] = true;
176  }
177  }
178  }
179 
180  std::sort(advanced_prefs_.begin(), advanced_prefs_.end(), [](const auto& lhs, const auto& rhs) { return translation::icompare(lhs.name, rhs.name) < 0; });
181 }
182 
183 void prefs::migrate_preferences(const std::string& migrate_prefs_file)
184 {
185  if(migrate_prefs_file != filesystem::get_synced_prefs_file() && filesystem::file_exists(migrate_prefs_file)) {
186  // if the file doesn't exist, just copy the file over
187  // else need to merge the preferences file
190  } else {
191  config current_cfg;
193  read(current_cfg, *current_stream);
194  config old_cfg;
195  filesystem::scoped_istream old_stream = filesystem::istream_file(migrate_prefs_file, false);
196  read(old_cfg, *old_stream);
197 
198  // when both files have the same attribute, use the one from whichever was most recently modified
199  bool current_prefs_are_older = filesystem::file_modified_time(filesystem::get_synced_prefs_file()) < filesystem::file_modified_time(migrate_prefs_file);
200  for(const config::attribute& val : old_cfg.attribute_range()) {
201  if(current_prefs_are_older || !current_cfg.has_attribute(val.first)) {
202  preferences_[val.first] = val.second;
203  }
204  }
205 
206  // don't touch child tags
207 
209  }
210  }
211 }
213 {
217 }
218 
219 std::set<std::string> prefs::all_attributes()
220 {
221  std::set<std::string> attrs;
222 
223  // attributes that exist in the preferences file
224  for(const auto& attr : preferences_.attribute_range()) {
225  attrs.emplace(attr.first);
226  }
227  // all mainline preference attributes, whether they're set or not
228  for(const auto attr : prefs_list::values) {
229  attrs.emplace(attr);
230  }
231 
232  return attrs;
233 }
234 
236 {
238  try{
239  config default_prefs;
240  config unsynced_prefs;
241  config synced_prefs;
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 files, which takes precedence over any values in the system preferences file
245  {
247  read(default_prefs, *stream);
248  }
249 #endif
250  {
252  read(unsynced_prefs, *stream);
253  }
254 
255  {
257  read(synced_prefs, *stream);
258  }
259 
260  preferences_.merge_with(default_prefs);
261  preferences_.merge_with(unsynced_prefs);
262  preferences_.merge_with(synced_prefs);
263 
264  // check for any unknown preferences
265  for(const auto& attr : synced_prefs.attribute_range()) {
266  if(std::find(synced_attributes_.begin(), synced_attributes_.end(), attr.first) == synced_attributes_.end()) {
267  unknown_synced_attributes_.insert(attr.first);
268  }
269  }
270  for(const auto& attr : unsynced_prefs.attribute_range()) {
271  if(std::find(unsynced_attributes_.begin(), unsynced_attributes_.end(), attr.first) == unsynced_attributes_.end()) {
272  unknown_unsynced_attributes_.insert(attr.first);
273  }
274  }
275 
276  for(const auto& child : synced_prefs.all_children_range()) {
277  if(std::find(synced_children_.begin(), synced_children_.end(), child.key) == synced_children_.end()) {
278  unknown_synced_children_.insert(child.key);
279  }
280  }
281  for(const auto& child : unsynced_prefs.all_children_range()) {
282  if(std::find(unsynced_children_.begin(), unsynced_children_.end(), child.key) == unsynced_children_.end()) {
283  unknown_unsynced_children_.insert(child.key);
284  }
285  }
286  } catch(const config::error& e) {
287  ERR_CFG << "Error loading preference, message: " << e.what();
288  }
289 
292 
293  /*
294  completed_campaigns = "A,B,C"
295  [completed_campaigns]
296  [campaign]
297  name = "A"
298  difficulty_levels = "EASY,MEDIUM"
299  [/campaign]
300  [/completed_campaigns]
301  */
302  // presumably for backwards compatibility?
303  // nothing actually sets the attribute, only the child tags
304  for(const std::string& c : utils::split(preferences_[prefs_list::completed_campaigns])) {
305  completed_campaigns_[c]; // create the elements
306  }
307 
308  if(auto ccc = get_child(prefs_list::completed_campaigns)) {
309  for(const config& cc : ccc->child_range("campaign")) {
310  std::set<std::string>& d = completed_campaigns_[cc["name"]];
311  std::vector<std::string> nd = utils::split(cc["difficulty_levels"]);
312  std::copy(nd.begin(), nd.end(), std::inserter(d, d.begin()));
313  }
314  }
315 
316  encountered_units_set_ = utils::split_set(preferences_[prefs_list::encountered_units].str());
317 
318  const t_translation::ter_list terrain(t_translation::read_list(preferences_[prefs_list::encountered_terrain_list].str()));
319  encountered_terrains_set_.insert(terrain.begin(), terrain.end());
320 
321  if(auto history = get_child(prefs_list::history)) {
322  /* Structure of the history
323  [history]
324  [history_id]
325  [line]
326  message = foobar
327  [/line]
328  */
329  for(const config::any_child h : history->all_children_range()) {
330  for(const config& l : h.cfg.child_range("line")) {
331  history_map_[h.key].push_back(l["message"]);
332  }
333  }
334  }
335 }
336 
338 {
339 #ifndef _WIN32
340  bool synced_prefs_file_existed = filesystem::file_exists(filesystem::get_synced_prefs_file());
341  bool unsynced_prefs_file_existed = filesystem::file_exists(filesystem::get_unsynced_prefs_file());
342 #endif
343 
344  config synced;
345  config unsynced;
346 
347  for(const char* attr : synced_attributes_) {
348  if(preferences_.has_attribute(attr)) {
349  synced[attr] = preferences_[attr];
350  }
351  }
352  for(const char* attr : synced_children_) {
353  for(const auto& child : preferences_.child_range(attr)) {
354  synced.add_child(attr, child);
355  }
356  }
357 
358  for(const char* attr : unsynced_attributes_) {
359  if(preferences_.has_attribute(attr)) {
360  unsynced[attr] = preferences_[attr];
361  }
362  }
363  for(const char* attr : unsynced_children_) {
364  for(const auto& child : preferences_.child_range(attr)) {
365  unsynced.add_child(attr, child);
366  }
367  }
368 
369  // write any unknown preferences back out
370  for(const std::string& attr : unknown_synced_attributes_) {
371  synced[attr] = preferences_[attr];
372  }
373  for(const std::string& attr : unknown_synced_children_) {
374  for(const auto& child : preferences_.child_range(attr)) {
375  synced.add_child(attr, child);
376  }
377  }
378 
379  for(const std::string& attr : unknown_unsynced_attributes_) {
380  unsynced[attr] = preferences_[attr];
381  }
382  for(const std::string& attr : unknown_unsynced_children_) {
383  for(const auto& child : preferences_.child_range(attr)) {
384  unsynced.add_child(attr, child);
385  }
386  }
387 
388  try {
390  write(*synced_prefs_file, synced);
391  } catch(const filesystem::io_exception&) {
392  ERR_FS << "error writing to synced preferences file '" << filesystem::get_synced_prefs_file() << "'";
393  }
394 
395  try {
397  write(*unsynced_prefs_file, unsynced);
398  } catch(const filesystem::io_exception&) {
399  ERR_FS << "error writing to unsynced preferences file '" << filesystem::get_unsynced_prefs_file() << "'";
400  }
401 
403 
404 #ifndef _WIN32
405  if(!synced_prefs_file_existed) {
406  if(chmod(filesystem::get_synced_prefs_file().c_str(), 0600) == -1) {
407  ERR_FS << "error setting permissions of preferences file '" << filesystem::get_synced_prefs_file() << "'";
408  }
409  }
410  if(!unsynced_prefs_file_existed) {
411  if(chmod(filesystem::get_unsynced_prefs_file().c_str(), 0600) == -1) {
412  ERR_FS << "error setting permissions of unsynced preferences file '" << filesystem::get_unsynced_prefs_file() << "'";
413  }
414  }
415 #endif
416 }
417 
419 {
420  // Zero them before clearing.
421  // Probably overly paranoid, but doesn't hurt?
422  for(auto& cred : credentials_) {
423  std::fill(cred.username.begin(), cred.username.end(), '\0');
424  std::fill(cred.server.begin(), cred.server.end(), '\0');
425  }
426  credentials_.clear();
427 }
428 
430 {
431  if(!remember_password()) {
432  return;
433  }
435  std::string cred_file = filesystem::get_credentials_file();
436  if(!filesystem::file_exists(cred_file)) {
437  return;
438  }
439  filesystem::scoped_istream stream = filesystem::istream_file(cred_file, false);
440  // Credentials file is a binary blob, so use streambuf iterator
441  preferences::secure_buffer data((std::istreambuf_iterator<char>(*stream)), (std::istreambuf_iterator<char>()));
443  if(data.empty() || data[0] != pref_constants::CREDENTIAL_SEPARATOR) {
444  ERR_CFG << "Invalid data in credentials file";
445  return;
446  }
447  for(const std::string& elem : utils::split(std::string(data.begin(), data.end()), pref_constants::CREDENTIAL_SEPARATOR, utils::REMOVE_EMPTY)) {
448  std::size_t at = elem.find_last_of('@');
449  std::size_t eq = elem.find_first_of('=', at + 1);
450  if(at != std::string::npos && eq != std::string::npos) {
451  preferences::secure_buffer key(elem.begin() + eq + 1, elem.end());
452  credentials_.emplace_back(elem.substr(0, at), elem.substr(at + 1, eq - at - 1), unescape(key));
453  }
454  }
455 }
456 
458 {
459  if(!remember_password()) {
461  return;
462  }
463 
464 #ifndef _WIN32
465  bool creds_file_existed = filesystem::file_exists(filesystem::get_credentials_file());
466 #endif
467 
468  preferences::secure_buffer credentials_data;
469  for(const auto& cred : credentials_) {
470  credentials_data.push_back(pref_constants::CREDENTIAL_SEPARATOR);
471  credentials_data.insert(credentials_data.end(), cred.username.begin(), cred.username.end());
472  credentials_data.push_back('@');
473  credentials_data.insert(credentials_data.end(), cred.server.begin(), cred.server.end());
474  credentials_data.push_back('=');
475  preferences::secure_buffer key_escaped = escape(cred.key);
476  credentials_data.insert(credentials_data.end(), key_escaped.begin(), key_escaped.end());
477  }
478  try {
480  preferences::secure_buffer encrypted = aes_encrypt(credentials_data, build_key("global", get_system_username()));
481  credentials_file->write(reinterpret_cast<const char*>(encrypted.data()), encrypted.size());
482  } catch(const filesystem::io_exception&) {
483  ERR_CFG << "error writing to credentials file '" << filesystem::get_credentials_file() << "'";
484  }
485 
486 #ifndef _WIN32
487  if(!creds_file_existed) {
488  if(chmod(filesystem::get_credentials_file().c_str(), 0600) == -1) {
489  ERR_FS << "error setting permissions of credentials file '" << filesystem::get_credentials_file() << "'";
490  }
491  }
492 #endif
493 }
494 
495 //
496 // helpers
497 //
498 void prefs::set_child(const std::string& key, const config& val) {
500  preferences_.add_child(key, val);
501 }
502 
504 {
505  return preferences_.optional_child(key);
506 }
507 
508 std::string prefs::get(const std::string& key, const std::string& def) {
509  return preferences_[key].empty() ? def : preferences_[key];
510 }
511 
513 {
514  return preferences_[key];
515 }
516 
517 //
518 // accessors
519 //
522 }
523 void prefs::set_show_ally_orb(bool show_orb) {
525 }
526 
529 }
532 }
533 
536 }
537 void prefs::set_show_enemy_orb(bool show_orb) {
539 }
540 
543 }
544 void prefs::set_show_moved_orb(bool show_orb) {
546 }
547 
550 }
551 void prefs::set_show_unmoved_orb(bool show_orb) {
553 }
554 
557 }
558 void prefs::set_show_partial_orb(bool show_orb) {
560 }
561 
564 }
565 void prefs::set_show_disengaged_orb(bool show_orb) {
567 }
568 
569 static std::string fix_orb_color_name(const std::string& color) {
570  if (color.substr(0,4) == "orb_") {
571  if(color[4] >= '0' && color[4] <= '9') {
572  return color.substr(5);
573  } else {
574  return color.substr(4);
575  }
576  }
577  return color;
578 }
579 
580 std::string prefs::allied_color() {
581  std::string ally_color = preferences_[prefs_list::ally_orb_color].str();
582  if (ally_color.empty())
584  return fix_orb_color_name(ally_color);
585 }
586 void prefs::set_allied_color(const std::string& color_id) {
588 }
589 
590 std::string prefs::enemy_color() {
592  if (enemy_color.empty())
595 }
596 void prefs::set_enemy_color(const std::string& color_id) {
598 }
599 
600 std::string prefs::moved_color() {
602  if (moved_color.empty())
605 }
606 void prefs::set_moved_color(const std::string& color_id) {
608 }
609 
610 std::string prefs::unmoved_color() {
612  if (unmoved_color.empty())
615 }
616 void prefs::set_unmoved_color(const std::string& color_id) {
618 }
619 
620 std::string prefs::partial_color() {
621  std::string partmoved_color = preferences_[prefs_list::partial_orb_color].str();
622  if (partmoved_color.empty())
624  return fix_orb_color_name(partmoved_color);
625 }
626 void prefs::set_partial_color(const std::string& color_id) {
628 }
629 
630 std::string prefs::core_id() {
631  std::string core_id = preferences_[prefs_list::core].str();
632  if (core_id.empty())
633  return "default";
634  return core_id;
635 }
636 void prefs::set_core_id(const std::string& core_id) {
637  preferences_[prefs_list::core] = core_id;
638 }
639 
641 {
642  return preferences_[prefs_list::scroll_to_action].to_bool(true);
643 }
644 
646 {
647  preferences_[prefs_list::scroll_to_action] = ison;
648 }
649 
651 {
652  const unsigned x_res = preferences_[prefs_list::xresolution].to_unsigned();
653  const unsigned y_res = preferences_[prefs_list::yresolution].to_unsigned();
654 
655  // Either resolution was unspecified, return default.
656  if(x_res == 0 || y_res == 0) {
658  }
659 
660  return point(
661  std::max<unsigned>(x_res, pref_constants::min_window_width),
662  std::max<unsigned>(y_res, pref_constants::min_window_height)
663  );
664 }
665 
667 {
668  // For now this has a minimum value of 1 and a maximum of 4.
669  return std::max<int>(std::min<int>(preferences_[prefs_list::pixel_scale].to_int(1), pref_constants::max_pixel_scale), pref_constants::min_pixel_scale);
670 }
671 
673 {
675 }
676 
678 {
679  return preferences_[prefs_list::auto_pixel_scale].to_bool(true);
680 }
681 
683 {
684  preferences_[prefs_list::auto_pixel_scale] = choice;
685 }
686 
688 {
689  return preferences_[prefs_list::maximized].to_bool(!fullscreen());
690 }
691 
693 {
694  return preferences_[prefs_list::fullscreen].to_bool(true);
695 }
696 
698 {
699  return preferences_[prefs_list::vsync].to_bool(true);
700 }
701 
702 void prefs::set_resolution(const point& res)
703 {
704  preferences_[prefs_list::xresolution] = std::to_string(res.x);
705  preferences_[prefs_list::yresolution] = std::to_string(res.y);
706 }
707 
708 void prefs::set_maximized(bool ison)
709 {
710  preferences_[prefs_list::maximized] = ison;
711 }
712 
713 void prefs::set_fullscreen(bool ison)
714 {
715  preferences_[prefs_list::fullscreen] = ison;
716 }
717 
718 void prefs::set_vsync(bool ison)
719 {
720  preferences_[prefs_list::vsync] = ison;
721 }
722 
724 {
725  if(video::headless()) {
726  return true;
727  }
728 
729  return preferences_[prefs_list::turbo].to_bool();
730 }
731 
732 void prefs::set_turbo(bool ison)
733 {
734  preferences_[prefs_list::turbo] = ison;
735 }
736 
738 {
739  return preferences_[prefs_list::turbo_speed].to_double(2.0);
740 }
741 
742 void prefs::set_turbo_speed(const double speed)
743 {
744  preferences_[prefs_list::turbo_speed] = speed;
745 }
746 
748 {
749  // Clip at 80 because if it's too low it'll cause crashes
750  return std::max<int>(std::min<int>(preferences_[prefs_list::font_scale].to_int(100), pref_constants::max_font_scaling), pref_constants::min_font_scaling);
751 }
752 
754 {
756 }
757 
759 {
760  return (size * font_scaling()) / 100;
761 }
762 
764 {
765  return preferences_[prefs_list::keepalive_timeout].to_int(20);
766 }
767 
768 void prefs::keepalive_timeout(int seconds)
769 {
770  preferences_[prefs_list::keepalive_timeout] = std::abs(seconds);
771 }
772 
774 {
775  return preferences_[prefs_list::idle_anim].to_bool(true);
776 }
777 
778 void prefs::set_idle_anim(const bool ison)
779 {
780  preferences_[prefs_list::idle_anim] = ison;
781 }
782 
784 {
785  return preferences_[prefs_list::idle_anim_rate].to_int();
786 }
787 
789 {
790  preferences_[prefs_list::idle_anim_rate] = rate;
791 }
792 
793 std::string prefs::language()
794 {
795  return preferences_[prefs_list::locale].str();
796 }
797 
798 void prefs::set_language(const std::string& s)
799 {
800  preferences_[prefs_list::locale] = s;
801 }
802 
803 std::string prefs::gui_theme()
804 {
805  return preferences_[prefs_list::gui2_theme].str();
806 }
807 
808 void prefs::set_gui_theme(const std::string& s)
809 {
810  preferences_[prefs_list::gui2_theme] = s;
811 }
812 
814 {
815  return preferences_[prefs_list::show_side_colors].to_bool();
816 }
817 
818 void prefs::set_ellipses(bool ison)
819 {
820  preferences_[prefs_list::show_side_colors] = ison;
821 }
822 
824 {
825  return preferences_[prefs_list::grid].to_bool();
826 }
827 
828 void prefs::set_grid(bool ison)
829 {
830  preferences_[prefs_list::grid] = ison;
831 }
832 
834 {
835  // Sounds don't sound good on Windows unless the buffer size is 4k,
836  // but this seems to cause crashes on other systems...
837  #ifdef _WIN32
838  const std::size_t buf_size = 4096;
839  #else
840  const std::size_t buf_size = 1024;
841  #endif
842 
843  return preferences_[prefs_list::sound_buffer_size].to_int(buf_size);
844 }
845 
846 void prefs::save_sound_buffer_size(const std::size_t size)
847 {
848  const std::string new_size = std::to_string(size);
849  if (preferences_[prefs_list::sound_buffer_size] == new_size)
850  return;
851 
852  preferences_[prefs_list::sound_buffer_size] = new_size;
853 
855 }
856 
858 {
859  return preferences_[prefs_list::music_volume].to_int(100);
860 }
861 
863 {
864  if(music_volume() == vol) {
865  return;
866  }
867 
870 }
871 
873 {
874  return preferences_[prefs_list::sound_volume].to_int(100);
875 }
876 
878 {
879  if(sound_volume() == vol) {
880  return;
881  }
882 
885 }
886 
888 {
889  return preferences_[prefs_list::bell_volume].to_int(100);
890 }
891 
893 {
894  if(bell_volume() == vol) {
895  return;
896  }
897 
900 }
901 
903 {
904  return preferences_[prefs_list::ui_volume].to_int(100);
905 }
906 
907 void prefs::set_ui_volume(int vol)
908 {
909  if(ui_volume() == vol) {
910  return;
911  }
912 
915 }
916 
917 unsigned int prefs::tile_size()
918 {
919  return preferences_[prefs_list::tile_size].to_unsigned();
920 }
921 
922 void prefs::set_tile_size(const unsigned int size)
923 {
925 }
926 
928 {
929  return preferences_[prefs_list::turn_bell].to_bool(true);
930 }
931 
932 bool prefs::set_turn_bell(bool ison)
933 {
934  if(!turn_bell() && ison) {
936  if(!music_on() && !sound_on() && !ui_sound_on()) {
937  if(!sound::init_sound()) {
939  return false;
940  }
941  }
942  } else if(turn_bell() && !ison) {
945  if(!music_on() && !sound_on() && !ui_sound_on())
947  }
948  return true;
949 }
950 
952 {
953  return preferences_[prefs_list::ui_sound].to_bool(true);
954 }
955 
956 bool prefs::set_ui_sound(bool ison)
957 {
958  if(!ui_sound_on() && ison) {
959  preferences_[prefs_list::ui_sound] = true;
960  if(!music_on() && !sound_on() && !turn_bell()) {
961  if(!sound::init_sound()) {
962  preferences_[prefs_list::ui_sound] = false;
963  return false;
964  }
965  }
966  } else if(ui_sound_on() && !ison) {
967  preferences_[prefs_list::ui_sound] = false;
969  if(!music_on() && !sound_on() && !turn_bell())
971  }
972  return true;
973 }
974 
976 {
977  return preferences_[prefs_list::message_bell].to_bool(true);
978 }
979 
981 {
982  return preferences_[prefs_list::sound].to_bool(true);
983 }
984 
985 bool prefs::set_sound(bool ison) {
986  if(!sound_on() && ison) {
987  preferences_[prefs_list::sound] = true;
988  if(!music_on() && !turn_bell() && !ui_sound_on()) {
989  if(!sound::init_sound()) {
990  preferences_[prefs_list::sound] = false;
991  return false;
992  }
993  }
994  } else if(sound_on() && !ison) {
995  preferences_[prefs_list::sound] = false;
997  if(!music_on() && !turn_bell() && !ui_sound_on())
999  }
1000  return true;
1001 }
1002 
1004 {
1005  return preferences_[prefs_list::music].to_bool(true);
1006 }
1007 
1008 bool prefs::set_music(bool ison) {
1009  if(!music_on() && ison) {
1010  preferences_[prefs_list::music] = true;
1011  if(!sound_on() && !turn_bell() && !ui_sound_on()) {
1012  if(!sound::init_sound()) {
1013  preferences_[prefs_list::music] = false;
1014  return false;
1015  }
1016  }
1017  else
1019  } else if(music_on() && !ison) {
1020  preferences_[prefs_list::music] = false;
1021  if(!sound_on() && !turn_bell() && !ui_sound_on())
1023  else
1025  }
1026  return true;
1027 }
1028 
1030 {
1031  return preferences_[prefs_list::stop_music_in_background].to_bool();
1032 }
1033 
1035 {
1036  preferences_[prefs_list::stop_music_in_background] = ison;
1037 }
1038 
1040 {
1041  return std::clamp<int>(preferences_[prefs_list::scroll].to_int(50), 1, 100);
1042 }
1043 
1044 void prefs::set_scroll_speed(const int new_speed)
1045 {
1046  preferences_[prefs_list::scroll] = new_speed;
1047 }
1048 
1050 {
1051  return preferences_[prefs_list::middle_click_scrolls].to_bool(true);
1052 }
1053 
1055 {
1056  return preferences_[prefs_list::mouse_scrolling].to_bool(true);
1057 }
1058 
1060 {
1061  preferences_[prefs_list::mouse_scrolling] = value;
1062 }
1063 
1065 {
1066  return preferences_[prefs_list::scroll_threshold].to_int(10);
1067 }
1068 
1070 {
1071  return preferences_[prefs_list::animate_map].to_bool(true);
1072 }
1073 
1075 {
1076  return preferences_[prefs_list::animate_water].to_bool(true);
1077 }
1078 
1080 {
1081  return preferences_[prefs_list::minimap_movement_coding].to_bool(true);
1082 }
1083 
1085 {
1086  preferences_[prefs_list::minimap_movement_coding] = !minimap_movement_coding();
1087 }
1088 
1090 {
1091  return preferences_[prefs_list::minimap_terrain_coding].to_bool(true);
1092 }
1093 
1095 {
1096  preferences_[prefs_list::minimap_terrain_coding] = !minimap_terrain_coding();
1097 }
1098 
1100 {
1101  return preferences_[prefs_list::minimap_draw_units].to_bool(true);
1102 }
1103 
1105 {
1106  preferences_[prefs_list::minimap_draw_units] = !minimap_draw_units();
1107 }
1108 
1110 {
1111  return preferences_[prefs_list::minimap_draw_villages].to_bool(true);
1112 }
1113 
1115 {
1116  preferences_[prefs_list::minimap_draw_villages] = !minimap_draw_villages();
1117 }
1118 
1120 {
1121  return preferences_[prefs_list::minimap_draw_terrain].to_bool(true);
1122 }
1123 
1125 {
1126  preferences_[prefs_list::minimap_draw_terrain] = !minimap_draw_terrain();
1127 }
1128 
1129 void prefs::set_animate_map(bool value)
1130 {
1131  preferences_[prefs_list::animate_map] = value;
1132 }
1133 
1135 {
1136  preferences_[prefs_list::animate_water] = value;
1137 }
1138 
1140 {
1141  return fps_;
1142 }
1143 
1144 void prefs::set_show_fps(bool value)
1145 {
1146  fps_ = value;
1147 }
1148 
1150 {
1151  return preferences_[prefs_list::draw_delay].to_int(-1);
1152 }
1153 
1154 void prefs::set_draw_delay(int value)
1155 {
1156  preferences_[prefs_list::draw_delay] = value;
1157 }
1158 
1160 {
1162 }
1163 
1165 {
1167 }
1168 
1170 {
1172  preferences_.clear_children("hotkey");
1173 }
1174 
1175 void prefs::add_alias(const std::string &alias, const std::string &command)
1176 {
1177  config &alias_list = preferences_.child_or_add("alias");
1178  alias_list[alias] = command;
1179 }
1180 
1181 
1183 {
1184  return get_child(prefs_list::alias);
1185 }
1186 
1187 unsigned int prefs::sample_rate()
1188 {
1189  return preferences_[prefs_list::sample_rate].to_int(44100);
1190 }
1191 
1192 void prefs::save_sample_rate(const unsigned int rate)
1193 {
1194  if (sample_rate() == rate)
1195  return;
1196 
1197  preferences_[prefs_list::sample_rate] = static_cast<int>(rate);
1198 
1199  // If audio is open, we have to re set sample rate
1201 }
1202 
1204 {
1205  return preferences_[prefs_list::confirm_load_save_from_different_version].to_bool(true);
1206 }
1207 
1209 {
1210  return preferences_[prefs_list::use_twelve_hour_clock_format].to_bool();
1211 }
1212 
1214 {
1215  return preferences_[prefs_list::disable_auto_moves].to_bool();
1216 }
1217 
1219 {
1220  preferences_[prefs_list::disable_auto_moves] = value;
1221 }
1222 
1224 {
1225  return preferences_[prefs_list::damage_prediction_allow_monte_carlo_simulation].to_bool(true);
1226 }
1227 
1229 {
1230  preferences_[prefs_list::damage_prediction_allow_monte_carlo_simulation] = value;
1231 }
1232 
1234 {
1235  return preferences_[prefs_list::addon_manager_saved_order_name].str();
1236 }
1237 
1238 void prefs::set_addon_manager_saved_order_name(const std::string& value)
1239 {
1240  preferences_[prefs_list::addon_manager_saved_order_name] = value;
1241 }
1242 
1244 {
1245  return sort_order::get_enum(preferences_[prefs_list::addon_manager_saved_order_direction]).value_or(sort_order::type::none);
1246 }
1247 
1249 {
1250  preferences_[prefs_list::addon_manager_saved_order_direction] = sort_order::get_string(value);
1251 }
1252 
1254 {
1255  return preferences_[prefs_list::selected_achievement_group].str();
1256 }
1257 
1258 void prefs::set_selected_achievement_group(const std::string& content_for)
1259 {
1260  preferences_[prefs_list::selected_achievement_group] = content_for;
1261 }
1262 
1263 bool prefs::achievement(const std::string& content_for, const std::string& id)
1264 {
1265  for(config& ach : preferences_.child_range(prefs_list::achievements))
1266  {
1267  if(ach["content_for"].str() == content_for)
1268  {
1269  std::vector<std::string> ids = utils::split(ach["ids"]);
1270  return std::find(ids.begin(), ids.end(), id) != ids.end();
1271  }
1272  }
1273  return false;
1274 }
1275 
1276 void prefs::set_achievement(const std::string& content_for, const std::string& id)
1277 {
1278  for(config& ach : preferences_.child_range(prefs_list::achievements))
1279  {
1280  // if achievements already exist for this content and the achievement has not already been set, add it
1281  if(ach["content_for"].str() == content_for)
1282  {
1283  std::vector<std::string> ids = utils::split(ach["ids"]);
1284 
1285  if(ids.empty())
1286  {
1287  ach["ids"] = id;
1288  }
1289  else if(std::find(ids.begin(), ids.end(), id) == ids.end())
1290  {
1291  ach["ids"] = ach["ids"].str() + "," + id;
1292  }
1293  ach.remove_children("in_progress", [&id](config cfg){return cfg["id"].str() == id;});
1294  return;
1295  }
1296  }
1297 
1298  // else no achievements have been set for this content yet
1299  config ach;
1300  ach["content_for"] = content_for;
1301  ach["ids"] = id;
1302  preferences_.add_child(prefs_list::achievements, ach);
1303 }
1304 
1305 int prefs::progress_achievement(const std::string& content_for, const std::string& id, int limit, int max_progress, int amount)
1306 {
1307  if(achievement(content_for, id))
1308  {
1309  return -1;
1310  }
1311 
1312  for(config& ach : preferences_.child_range(prefs_list::achievements))
1313  {
1314  // if achievements already exist for this content and the achievement has not already been set, add it
1315  if(ach["content_for"].str() == content_for)
1316  {
1317  // check if this achievement has progressed before - if so then increment it
1318  for(config& in_progress : ach.child_range("in_progress"))
1319  {
1320  if(in_progress["id"].str() == id)
1321  {
1322  // don't let using 'limit' decrease the achievement's current progress
1323  int starting_progress = in_progress["progress_at"].to_int();
1324  if(starting_progress >= limit) {
1325  return starting_progress;
1326  }
1327 
1328  in_progress["progress_at"] = std::clamp(starting_progress + amount, 0, std::min(limit, max_progress));
1329  return in_progress["progress_at"].to_int();
1330  }
1331  }
1332 
1333  // else this is the first time this achievement is progressing
1334  if(amount != 0)
1335  {
1336  config set_progress;
1337  set_progress["id"] = id;
1338  set_progress["progress_at"] = std::clamp(amount, 0, std::min(limit, max_progress));
1339 
1340  config& child = ach.add_child("in_progress", set_progress);
1341  return child["progress_at"].to_int();
1342  }
1343  return 0;
1344  }
1345  }
1346 
1347  // else not only has this achievement not progressed before, this is the first achievement for this achievement group to be added
1348  if(amount != 0)
1349  {
1350  config ach;
1351  config set_progress;
1352 
1353  set_progress["id"] = id;
1354  set_progress["progress_at"] = std::clamp(amount, 0, std::min(limit, max_progress));
1355 
1356  ach["content_for"] = content_for;
1357  ach["ids"] = "";
1358 
1359  config& child = ach.add_child("in_progress", set_progress);
1360  preferences_.add_child(prefs_list::achievements, ach);
1361  return child["progress_at"].to_int();
1362  }
1363  return 0;
1364 }
1365 
1366 bool prefs::sub_achievement(const std::string& content_for, const std::string& id, const std::string& sub_id)
1367 {
1368  // this achievement is already completed
1369  if(achievement(content_for, id))
1370  {
1371  return true;
1372  }
1373 
1374  for(config& ach : preferences_.child_range(prefs_list::achievements))
1375  {
1376  if(ach["content_for"].str() == content_for)
1377  {
1378  // check if the specific sub-achievement has been completed but the overall achievement is not completed
1379  for(const auto& in_progress : ach.child_range("in_progress"))
1380  {
1381  if(in_progress["id"] == id)
1382  {
1383  std::vector<std::string> sub_ids = utils::split(in_progress["sub_ids"]);
1384  return std::find(sub_ids.begin(), sub_ids.end(), sub_id) != sub_ids.end();
1385  }
1386  }
1387  }
1388  }
1389  return false;
1390 }
1391 
1392 void prefs::set_sub_achievement(const std::string& content_for, const std::string& id, const std::string& sub_id)
1393 {
1394  // this achievement is already completed
1395  if(achievement(content_for, id))
1396  {
1397  return;
1398  }
1399 
1400  for(config& ach : preferences_.child_range(prefs_list::achievements))
1401  {
1402  // if achievements already exist for this content and the achievement has not already been set, add it
1403  if(ach["content_for"].str() == content_for)
1404  {
1405  // check if this achievement has had sub-achievements set before
1406  for(config& in_progress : ach.child_range("in_progress"))
1407  {
1408  if(in_progress["id"].str() == id)
1409  {
1410  std::vector<std::string> sub_ids = utils::split(ach["ids"]);
1411 
1412  if(std::find(sub_ids.begin(), sub_ids.end(), sub_id) == sub_ids.end())
1413  {
1414  in_progress["sub_ids"] = in_progress["sub_ids"].str() + "," + sub_id;
1415  }
1416 
1417  in_progress["progress_at"] = sub_ids.size()+1;
1418  return;
1419  }
1420  }
1421 
1422  // else if this is the first sub-achievement being set
1423  config set_progress;
1424  set_progress["id"] = id;
1425  set_progress["sub_ids"] = sub_id;
1426  set_progress["progress_at"] = 1;
1427  ach.add_child("in_progress", set_progress);
1428  return;
1429  }
1430  }
1431 
1432  // 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
1433  config ach;
1434  config set_progress;
1435 
1436  set_progress["id"] = id;
1437  set_progress["sub_ids"] = sub_id;
1438  set_progress["progress_at"] = 1;
1439 
1440  ach["content_for"] = content_for;
1441  ach["ids"] = "";
1442 
1443  ach.add_child("in_progress", set_progress);
1444  preferences_.add_child(prefs_list::achievements, ach);
1445 }
1446 
1447 void prefs::set_editor_chosen_addon(const std::string& addon_id)
1448 {
1449  preferences_[prefs_list::editor_chosen_addon] = addon_id;
1450 }
1451 
1453 {
1454  return preferences_[prefs_list::editor_chosen_addon].str();
1455 }
1456 
1457 void prefs::set_last_cache_cleared_version(const std::string& version)
1458 {
1459  preferences_[prefs_list::_last_cache_cleaned_ver] = version;
1460 }
1462 {
1463  return preferences_[prefs_list::_last_cache_cleaned_ver].str();
1464 }
1465 
1467 {
1468  return preferences_[prefs_list::show_deprecation].to_bool(def);
1469 }
1470 
1472 {
1473  return preferences_[prefs_list::scroll_when_mouse_outside].to_bool(def);
1474 }
1475 
1477 {
1478  set_child(prefs_list::dir_bookmarks, cfg);
1479 }
1481 {
1482  return get_child(prefs_list::dir_bookmarks);
1483 }
1484 
1486 {
1487  return preferences_[prefs_list::lobby_whisper_friends_only].to_bool();
1488 }
1489 
1491 {
1492  preferences_[prefs_list::lobby_whisper_friends_only] = v;
1493 }
1494 
1496 {
1497  return preferences_[prefs_list::lobby_auto_open_whisper_windows].to_bool(true);
1498 }
1499 
1501 {
1502  return preferences_[prefs_list::fi_invert].to_bool();
1503 }
1504 
1505 void prefs::set_fi_invert(bool value)
1506 {
1507  preferences_[prefs_list::fi_invert] = value;
1508 }
1509 
1511 {
1512  return preferences_[prefs_list::fi_vacant_slots].to_bool();
1513 }
1514 
1516 {
1517  preferences_[prefs_list::fi_vacant_slots] = value;
1518 }
1519 
1521 {
1522  return preferences_[prefs_list::fi_friends_in_game].to_bool();
1523 }
1524 
1526 {
1527  preferences_[prefs_list::fi_friends_in_game] = value;
1528 }
1529 
1531 {
1532  return preferences_[prefs_list::fi_blocked_in_game].to_bool();
1533 }
1534 
1536 {
1537  preferences_[prefs_list::fi_blocked_in_game] = value;
1538 }
1539 
1541  return preferences_[prefs_list::editor_auto_update_transitions].to_int(pref_constants::TRANSITION_UPDATE_PARTIAL);
1542 }
1543 
1545  preferences_[prefs_list::editor_auto_update_transitions] = value;
1546 }
1547 
1549  return preferences_[prefs_list::editor_draw_terrain_codes].to_bool();
1550 }
1551 
1553  preferences_[prefs_list::editor_draw_terrain_codes] = value;
1554 }
1555 
1557  return preferences_[prefs_list::editor_draw_hex_coordinates].to_bool();
1558 }
1559 
1561  preferences_[prefs_list::editor_draw_hex_coordinates] = value;
1562 }
1563 
1565  return preferences_[prefs_list::editor_draw_num_of_bitmaps].to_bool();
1566 }
1567 
1569  preferences_[prefs_list::editor_draw_num_of_bitmaps] = value;
1570 }
1571 
1573 {
1574  return std::max(std::size_t(1), preferences_[prefs_list::editor_max_recent_files].to_size_t(10));
1575 }
1576 
1577 //
1578 // NOTE: The MRU read/save functions enforce the entry count limit in
1579 // order to ensure the list on disk doesn't grow forever. Otherwise,
1580 // normally this would be the UI's responsibility instead.
1581 //
1582 
1583 std::vector<std::string> prefs::do_read_editor_mru()
1584 {
1585  auto cfg = get_child(prefs_list::editor_recent_files);
1586 
1587  std::vector<std::string> mru;
1588  if(!cfg) {
1589  return mru;
1590  }
1591 
1592  for(const config& child : cfg->child_range("entry"))
1593  {
1594  const std::string& entry = child["path"].str();
1595  if(!entry.empty()) {
1596  mru.push_back(entry);
1597  }
1598  }
1599 
1600  mru.resize(std::min(editor_mru_limit(), mru.size()));
1601 
1602  return mru;
1603 }
1604 
1605 void prefs::do_commit_editor_mru(const std::vector<std::string>& mru)
1606 {
1607  config cfg;
1608  unsigned n = 0;
1609 
1610  for(const std::string& entry : mru)
1611  {
1612  if(entry.empty()) {
1613  continue;
1614  }
1615 
1616  config& child = cfg.add_child("entry");
1617  child["path"] = entry;
1618 
1619  if(++n >= editor_mru_limit()) {
1620  break;
1621  }
1622  }
1623 
1624  set_child(prefs_list::editor_recent_files, cfg);
1625 }
1626 
1627 std::vector<std::string> prefs::recent_files()
1628 {
1629  return do_read_editor_mru();
1630 }
1631 
1632 void prefs::add_recent_files_entry(const std::string& path)
1633 {
1634  if(path.empty()) {
1635  return;
1636  }
1637 
1638  std::vector<std::string> mru = do_read_editor_mru();
1639 
1640  // Enforce uniqueness. Normally shouldn't do a thing unless somebody
1641  // has been tampering with the preferences file.
1642  mru.erase(std::remove(mru.begin(), mru.end(), path), mru.end());
1643 
1644  mru.insert(mru.begin(), path);
1645  mru.resize(std::min(editor_mru_limit(), mru.size()));
1646 
1647  do_commit_editor_mru(mru);
1648 }
1649 
1651 {
1652  return preferences_[prefs_list::color_cursors].to_bool(true);
1653 }
1654 
1656 {
1657  preferences_[prefs_list::color_cursors] = value;
1658 
1659  cursor::set();
1660 }
1661 
1663 {
1664  return preferences_[prefs_list::unit_standing_animations].to_bool(true);
1665 }
1666 
1668 {
1669  preferences_[prefs_list::unit_standing_animations] = value;
1670 
1671  if(display* d = display::get_singleton()) {
1672  d->reset_standing_animations();
1673  }
1674 }
1675 
1677 {
1678  std::vector<theme_info> themes = theme::get_basic_theme_info();
1679 
1680  if (themes.empty()) {
1682  _("No known themes. Try changing from within an existing game."));
1683 
1684  return false;
1685  }
1686 
1687  gui2::dialogs::theme_list dlg(themes);
1688 
1689  for (std::size_t k = 0; k < themes.size(); ++k) {
1690  if(themes[k].id == theme()) {
1691  dlg.set_selected_index(static_cast<int>(k));
1692  }
1693  }
1694 
1695  dlg.show();
1696  const int action = dlg.selected_index();
1697 
1698  if (action >= 0) {
1699  set_theme(themes[action].id);
1700  if(display::get_singleton() && resources::gamedata && resources::gamedata->get_theme().empty()) {
1701  display::get_singleton()->set_theme(themes[action].id);
1702  }
1703 
1704  return true;
1705  }
1706 
1707  return false;
1708 }
1709 
1711 {
1712  const std::string filename = filesystem::get_wesnothd_name();
1713 
1714  const std::string& old_path = filesystem::directory_name(get_mp_server_program_name());
1715  std::string path =
1716  !old_path.empty() && filesystem::is_directory(old_path)
1717  ? old_path : filesystem::get_exe_dir();
1718 
1719  const std::string msg = VGETTEXT("The <b>$filename</b> server application provides multiplayer server functionality and is required for hosting local network games. It will normally be found in the same folder as the game executable.", {{"filename", filename}});
1720 
1722 
1723  dlg.set_title(_("Find Server Application"))
1724  .set_message(msg)
1725  .set_ok_label(_("Select"))
1726  .set_read_only(true)
1727  .set_filename(filename)
1728  .set_path(path);
1729 
1730  if(dlg.show()) {
1731  path = dlg.path();
1733  }
1734 }
1735 
1736 std::string prefs::theme()
1737 {
1738  if(video::headless()) {
1739  static const std::string null_theme = "null";
1740  return null_theme;
1741  }
1742 
1743  std::string res = preferences_[prefs_list::theme];
1744  if(res.empty()) {
1745  return "Default";
1746  }
1747 
1748  return res;
1749 }
1750 
1751 void prefs::set_theme(const std::string& theme)
1752 {
1753  if(theme != "null") {
1754  preferences_[prefs_list::theme] = theme;
1755  }
1756 }
1757 
1758 void prefs::set_mp_server_program_name(const std::string& path)
1759 {
1760  if(path.empty()) {
1761  preferences_.remove_attribute(prefs_list::mp_server_program_name);
1762  } else {
1763  preferences_[prefs_list::mp_server_program_name] = path;
1764  }
1765 }
1766 
1768 {
1769  return preferences_[prefs_list::mp_server_program_name].str();
1770 }
1771 
1772 const std::map<std::string, preferences::acquaintance>& prefs::get_acquaintances()
1773 {
1774  return acquaintances_;
1775 }
1776 
1777 const std::string prefs::get_ignored_delim()
1778 {
1779  std::vector<std::string> ignored;
1780 
1781  for(const auto& person : acquaintances_) {
1782  if(person.second.get_status() == "ignore") {
1783  ignored.push_back(person.second.get_nick());
1784  }
1785  }
1786 
1787  return utils::join(ignored);
1788 }
1789 
1790 // returns acquaintances in the form nick => notes where the status = filter
1791 std::map<std::string, std::string> prefs::get_acquaintances_nice(const std::string& filter)
1792 {
1793  std::map<std::string, std::string> ac_nice;
1794 
1795  for(const auto& a : acquaintances_) {
1796  if(a.second.get_status() == filter) {
1797  ac_nice[a.second.get_nick()] = a.second.get_notes();
1798  }
1799  }
1800 
1801  return ac_nice;
1802 }
1803 
1804 std::pair<preferences::acquaintance*, bool> prefs::add_acquaintance(const std::string& nick, const std::string& mode, const std::string& notes)
1805 {
1806  if(!utils::isvalid_wildcard(nick)) {
1807  return std::pair(nullptr, false);
1808  }
1809 
1810  preferences::acquaintance new_entry(nick, mode, notes);
1811  auto [iter, added_new] = acquaintances_.insert_or_assign(nick, new_entry);
1812 
1813  return std::pair(&iter->second, added_new);
1814 }
1815 
1816 bool prefs::remove_acquaintance(const std::string& nick)
1817 {
1819 
1820  // nick might include the notes, depending on how we're removing
1821  if(i == acquaintances_.end()) {
1822  std::size_t pos = nick.find_first_of(' ');
1823 
1824  if(pos != std::string::npos) {
1825  i = acquaintances_.find(nick.substr(0, pos));
1826  }
1827  }
1828 
1829  if(i == acquaintances_.end()) {
1830  return false;
1831  }
1832 
1833  acquaintances_.erase(i);
1834 
1835  return true;
1836 }
1837 
1838 bool prefs::is_friend(const std::string& nick)
1839 {
1840  const auto it = acquaintances_.find(nick);
1841 
1842  if(it == acquaintances_.end()) {
1843  return false;
1844  } else {
1845  return it->second.get_status() == "friend";
1846  }
1847 }
1848 
1849 bool prefs::is_ignored(const std::string& nick)
1850 {
1851  const auto it = acquaintances_.find(nick);
1852 
1853  if(it == acquaintances_.end()) {
1854  return false;
1855  } else {
1856  return it->second.get_status() == "ignore";
1857  }
1858 }
1859 
1860 void prefs::add_completed_campaign(const std::string& campaign_id, const std::string& difficulty_level)
1861 {
1862  completed_campaigns_[campaign_id].insert(difficulty_level);
1863 }
1864 
1865 bool prefs::is_campaign_completed(const std::string& campaign_id)
1866 {
1867  return completed_campaigns_.count(campaign_id) != 0;
1868 }
1869 
1870 bool prefs::is_campaign_completed(const std::string& campaign_id, const std::string& difficulty_level)
1871 {
1872  const auto it = completed_campaigns_.find(campaign_id);
1873  return it == completed_campaigns_.end() ? false : it->second.count(difficulty_level) != 0;
1874 }
1875 
1876 bool prefs::parse_should_show_lobby_join(const std::string& sender, const std::string& message)
1877 {
1878  // If it's actually not a lobby join or leave message return true (show it).
1879  if(sender != "server") {
1880  return true;
1881  }
1882 
1883  std::string::size_type pos = message.find(" has logged into the lobby");
1884  if(pos == std::string::npos) {
1885  pos = message.find(" has disconnected");
1886  if(pos == std::string::npos) {
1887  return true;
1888  }
1889  }
1890 
1893  return false;
1894  }
1895 
1897  return true;
1898  }
1899 
1900  return is_friend(message.substr(0, pos));
1901 }
1902 
1904 {
1905  std::string pref = preferences_[prefs_list::lobby_joins];
1906  if(pref == "friends") {
1908  } else if(pref == "all") {
1910  } else if(pref == "none") {
1912  } else {
1914  }
1915 }
1916 
1918 {
1925  }
1926 }
1927 
1928 const std::vector<game_config::server_info>& prefs::builtin_servers_list()
1929 {
1930  static std::vector<game_config::server_info> pref_servers = game_config::server_list;
1931  return pref_servers;
1932 }
1933 
1934 std::vector<game_config::server_info> prefs::user_servers_list()
1935 {
1936  std::vector<game_config::server_info> pref_servers;
1937 
1938  for(const config& server : preferences_.child_range("server")) {
1939  pref_servers.emplace_back();
1940  pref_servers.back().name = server["name"].str();
1941  pref_servers.back().address = server["address"].str();
1942  }
1943 
1944  return pref_servers;
1945 }
1946 
1947 void prefs::set_user_servers_list(const std::vector<game_config::server_info>& value)
1948 {
1949  preferences_.clear_children("server");
1950 
1951  for(const auto& svinfo : value) {
1952  config& sv_cfg = preferences_.add_child("server");
1953  sv_cfg["name"] = svinfo.name;
1954  sv_cfg["address"] = svinfo.address;
1955  }
1956 }
1957 
1958 std::string prefs::network_host()
1959 {
1960  const std::string res = preferences_[prefs_list::host];
1961  if(res.empty()) {
1962  return builtin_servers_list().front().address;
1963  } else {
1964  return res;
1965  }
1966 }
1967 
1968 void prefs::set_network_host(const std::string& host)
1969 {
1970  preferences_[prefs_list::host] = host;
1971 }
1972 
1974 {
1975  if(!preferences_[prefs_list::campaign_server].empty()) {
1976  return preferences_[prefs_list::campaign_server].str();
1977  } else {
1979  }
1980 }
1981 
1982 void prefs::set_campaign_server(const std::string& host)
1983 {
1984  preferences_[prefs_list::campaign_server] = host;
1985 }
1986 
1988 {
1989  return preferences_[prefs_list::turn_dialog].to_bool();
1990 }
1991 
1992 void prefs::set_turn_dialog(bool ison)
1993 {
1994  preferences_[prefs_list::turn_dialog] = ison;
1995 }
1996 
1998 {
1999  return preferences_[prefs_list::enable_planning_mode_on_start].to_bool();
2000 }
2001 
2003 {
2004  preferences_[prefs_list::enable_planning_mode_on_start] = value;
2005 }
2006 
2008 {
2009  return preferences_[prefs_list::hide_whiteboard].to_bool();
2010 }
2011 
2013 {
2014  preferences_[prefs_list::hide_whiteboard] = value;
2015 }
2016 
2018 {
2019  return preferences_[prefs_list::show_combat].to_bool(true);
2020 }
2021 
2023 {
2024  return preferences_[prefs_list::allow_observers].to_bool(true);
2025 }
2026 
2028 {
2029  preferences_[prefs_list::allow_observers] = value;
2030 }
2031 
2033 {
2034  return preferences_[prefs_list::shuffle_sides].to_bool();
2035 }
2036 
2038 {
2039  preferences_[prefs_list::shuffle_sides] = value;
2040 }
2041 
2043 {
2045 }
2046 
2047 void prefs::set_random_faction_mode(const std::string& value)
2048 {
2050 }
2051 
2053 {
2054  return preferences_[prefs_list::mp_use_map_settings].to_bool(true);
2055 }
2056 
2058 {
2059  preferences_[prefs_list::mp_use_map_settings] = value;
2060 }
2061 
2063 {
2064  return preferences_[prefs_list::mp_server_warning_disabled].to_int();
2065 }
2066 
2068 {
2069  preferences_[prefs_list::mp_server_warning_disabled] = value;
2070 }
2071 
2073 {
2074  return preferences_[prefs_list::mp_random_start_time].to_bool(true);
2075 }
2076 
2078 {
2079  preferences_[prefs_list::mp_random_start_time] = value;
2080 }
2081 
2083 {
2084  return preferences_[prefs_list::mp_fog].to_bool(true);
2085 }
2086 
2087 void prefs::set_fog(bool value)
2088 {
2089  preferences_[prefs_list::mp_fog] = value;
2090 }
2091 
2093 {
2094  return preferences_[prefs_list::mp_shroud].to_bool();
2095 }
2096 
2097 void prefs::set_shroud(bool value)
2098 {
2099  preferences_[prefs_list::mp_shroud] = value;
2100 }
2101 
2103 {
2104  return settings::get_turns(preferences_[prefs_list::mp_turns]);
2105 }
2106 
2107 void prefs::set_turns(int value)
2108 {
2109  preferences_[prefs_list::mp_turns] = value;
2110 }
2111 
2113 {
2114  if(options_initialized_) {
2115  return option_values_;
2116  }
2117 
2118  if(!get_child(prefs_list::options)) {
2119  // It may be an invalid config, which would cause problems in
2120  // multiplayer_create, so let's replace it with an empty but valid
2121  // config
2123  } else {
2124  option_values_ = *get_child(prefs_list::options);
2125  }
2126 
2127  options_initialized_ = true;
2128 
2129  return option_values_;
2130 }
2131 
2132 void prefs::set_options(const config& values)
2133 {
2134  set_child(prefs_list::options, values);
2135  options_initialized_ = false;
2136 }
2137 
2139 {
2140  return preferences_[prefs_list::skip_mp_replay].to_bool();
2141 }
2142 
2144 {
2145  preferences_[prefs_list::skip_mp_replay] = value;
2146 }
2147 
2149 {
2150  return preferences_[prefs_list::blindfold_replay].to_bool();
2151 }
2152 
2154 {
2155  preferences_[prefs_list::blindfold_replay] = value;
2156 }
2157 
2159 {
2160  return preferences_[prefs_list::mp_countdown].to_bool();
2161 }
2162 
2163 void prefs::set_countdown(bool value)
2164 {
2165  preferences_[prefs_list::mp_countdown] = value;
2166 }
2167 
2169 {
2170  return std::clamp<int>(preferences_[prefs_list::mp_countdown_init_time].to_int(240), 0, 1500);
2171 }
2172 
2174 {
2175  preferences_[prefs_list::mp_countdown_init_time] = value;
2176 }
2177 
2179 {
2180  preferences_.remove_attribute(prefs_list::mp_countdown_init_time);
2181 }
2182 
2184 {
2185  return std::clamp<int>(preferences_[prefs_list::mp_countdown_reservoir_time].to_int(360), 30, 1500);
2186 }
2187 
2189 {
2190  preferences_[prefs_list::mp_countdown_reservoir_time] = value;
2191 }
2192 
2194 {
2195  preferences_.remove_attribute(prefs_list::mp_countdown_reservoir_time);
2196 }
2197 
2199 {
2200  return std::clamp<int>(preferences_[prefs_list::mp_countdown_turn_bonus].to_int(240), 0, 300);
2201 }
2202 
2204 {
2205  preferences_[prefs_list::mp_countdown_turn_bonus] = value;
2206 }
2207 
2209 {
2210  preferences_.remove_attribute(prefs_list::mp_countdown_turn_bonus);
2211 }
2212 
2214 {
2215  return std::clamp<int>(preferences_[prefs_list::mp_countdown_action_bonus], 0, 30);
2216 }
2217 
2219 {
2220  preferences_[prefs_list::mp_countdown_action_bonus] = value;
2221 }
2222 
2224 {
2225  preferences_.remove_attribute(prefs_list::mp_countdown_action_bonus);
2226 }
2227 
2229 {
2230  return settings::get_village_gold(preferences_[prefs_list::mp_village_gold]);
2231 }
2232 
2234 {
2235  preferences_[prefs_list::mp_village_gold] = value;
2236 }
2237 
2239 {
2240  return settings::get_village_support(preferences_[prefs_list::mp_village_support]);
2241 }
2242 
2244 {
2245  preferences_[prefs_list::mp_village_support] = std::to_string(value);
2246 }
2247 
2249 {
2250  return settings::get_xp_modifier(preferences_[prefs_list::mp_xp_modifier]);
2251 }
2252 
2253 void prefs::set_xp_modifier(int value)
2254 {
2255  preferences_[prefs_list::mp_xp_modifier] = value;
2256 }
2257 
2258 std::string prefs::era()
2259 {
2260  return preferences_[prefs_list::mp_era].str();
2261 }
2262 
2263 void prefs::set_era(const std::string& value)
2264 {
2265  preferences_[prefs_list::mp_era] = value;
2266 }
2267 
2268 std::string prefs::level()
2269 {
2270  return preferences_[prefs_list::mp_level].str();
2271 }
2272 
2273 void prefs::set_level(const std::string& value)
2274 {
2275  preferences_[prefs_list::mp_level] = value;
2276 }
2277 
2279 {
2280  return preferences_[prefs_list::mp_level_type].to_int();
2281 }
2282 
2283 void prefs::set_level_type(int value)
2284 {
2285  preferences_[prefs_list::mp_level_type] = value;
2286 }
2287 
2288 const std::vector<std::string>& prefs::modifications(bool mp)
2289 {
2291  if(mp) {
2292  mp_modifications_ = utils::split(preferences_[prefs_list::mp_modifications].str(), ',');
2294  } else {
2295  sp_modifications_ = utils::split(preferences_[prefs_list::sp_modifications].str(), ',');
2297  }
2298  }
2299 
2301 }
2302 
2303 void prefs::set_modifications(const std::vector<std::string>& value, bool mp)
2304 {
2305  if(mp) {
2306  preferences_[prefs_list::mp_modifications] = utils::join(value, ",");
2308  } else {
2309  preferences_[prefs_list::sp_modifications] = utils::join(value, ",");
2311  }
2312 }
2313 
2315 {
2316  return preferences_[prefs_list::skip_ai_moves].to_bool();
2317 }
2318 
2320 {
2321  preferences_[prefs_list::skip_ai_moves] = value;
2322 }
2323 
2325 {
2326  preferences_[prefs_list::show_side_colors] = value;
2327 }
2328 
2330 {
2331  return preferences_[prefs_list::show_side_colors].to_bool(true);
2332 }
2333 
2334 void prefs::set_save_replays(bool value)
2335 {
2336  preferences_[prefs_list::save_replays] = value;
2337 }
2338 
2340 {
2341  return preferences_[prefs_list::save_replays].to_bool(true);
2342 }
2343 
2344 void prefs::set_delete_saves(bool value)
2345 {
2346  preferences_[prefs_list::delete_saves] = value;
2347 }
2348 
2350 {
2351  return preferences_[prefs_list::delete_saves].to_bool();
2352 }
2353 
2355 {
2356  preferences_[prefs_list::ask_delete] = value;
2357 }
2358 
2360 {
2361  return preferences_[prefs_list::ask_delete].to_bool(true);
2362 }
2363 
2365 {
2366  preferences_[prefs_list::ally_sighted_interrupts] = value;
2367 }
2368 
2370 {
2371  return preferences_[prefs_list::ally_sighted_interrupts].to_bool(true);
2372 }
2373 
2375 {
2376  return preferences_[prefs_list::auto_save_max].to_int(10);
2377 }
2378 
2379 void prefs::set_autosavemax(int value)
2380 {
2381  preferences_[prefs_list::auto_save_max] = value;
2382 }
2383 
2385 {
2386  return preferences_[prefs_list::floating_labels].to_bool(true);
2387 }
2388 
2390 {
2391  preferences_[prefs_list::floating_labels] = value;
2392 }
2393 
2395 {
2396  return message_private_on_;
2397 }
2398 
2400 {
2401  message_private_on_ = value;
2402 }
2403 
2405 {
2406  const std::string& choice = preferences_[prefs_list::compress_saves];
2407 
2408  // "yes" was used in 1.11.7 and earlier; the compress_saves
2409  // option used to be a toggle for gzip in those versions.
2410  if(choice.empty() || choice == "gzip" || choice == "yes") {
2412  } else if(choice == "bzip2") {
2414  } else if(choice == "none" || choice == "no") { // see above
2416  } /*else*/
2417 
2418  // In case the preferences file was created by a later version
2419  // supporting some algorithm we don't; although why would anyone
2420  // playing a game need more algorithms, really...
2422 }
2423 
2424 std::string prefs::get_chat_timestamp(const std::time_t& t)
2425 {
2426  if(chat_timestamping()) {
2427  if(use_twelve_hour_clock_format() == false) {
2428  return lg::get_timestamp(t, _("[%H:%M]")) + " ";
2429  } else {
2430  return lg::get_timestamp(t, _("[%I:%M %p]")) + " ";
2431  }
2432  }
2433 
2434  return "";
2435 }
2436 
2438 {
2439  return preferences_[prefs_list::chat_timestamp].to_bool();
2440 }
2441 
2443 {
2444  preferences_[prefs_list::chat_timestamp] = value;
2445 }
2446 
2448 {
2449  return preferences_[prefs_list::chat_lines].to_int(6);
2450 }
2451 
2452 void prefs::set_chat_lines(int lines)
2453 {
2454  preferences_[prefs_list::chat_lines] = lines;
2455 }
2456 
2457 void prefs::set_chat_message_aging(const int aging)
2458 {
2459  preferences_[prefs_list::chat_message_aging] = aging;
2460 }
2461 
2463 {
2464  return preferences_[prefs_list::chat_message_aging].to_int(20);
2465 }
2466 
2468 {
2469  return preferences_[prefs_list::show_all_units_in_help].to_bool();
2470 }
2471 
2473 {
2474  preferences_[prefs_list::show_all_units_in_help] = value;
2475 }
2476 
2477 std::set<std::string>& prefs::encountered_units()
2478 {
2479  return encountered_units_set_;
2480 }
2481 
2482 std::set<t_translation::terrain_code>& prefs::encountered_terrains()
2483 {
2485 }
2486 
2488 {
2489  return preferences_[prefs_list::custom_command].str();
2490 }
2491 
2492 void prefs::set_custom_command(const std::string& command)
2493 {
2494  preferences_[prefs_list::custom_command] = command;
2495 }
2496 
2497 /**
2498  * Returns a pointer to the history vector associated with given id
2499  * making a new one if it doesn't exist.
2500  *
2501  * @todo FIXME only used for gui2. Could be used for the above histories.
2502  */
2503 std::vector<std::string>* prefs::get_history(const std::string& id)
2504 {
2505  return &history_map_[id];
2506 }
2507 
2509 {
2510  const std::string confirmation = preferences_[prefs_list::confirm_end_turn];
2511  return confirmation == "green" || confirmation == "yes";
2512 }
2513 
2515 {
2516  return preferences_[prefs_list::confirm_end_turn] == "yellow";
2517 }
2518 
2520 {
2521  // This is very non-intrusive so it is on by default
2522  const std::string confirmation = preferences_[prefs_list::confirm_end_turn];
2523  return confirmation == "no_moves" || confirmation.empty();
2524 }
2525 
2526 void prefs::encounter_recruitable_units(const std::vector<team>& teams)
2527 {
2528  for(const team& help_team : teams) {
2529  help_team.log_recruitable();
2530  encountered_units_set_.insert(help_team.recruits().begin(), help_team.recruits().end());
2531  }
2532 }
2533 
2535 {
2536  for(const auto& help_unit : units) {
2537  encountered_units_set_.insert(help_unit.type_id());
2538  }
2539 }
2540 
2541 void prefs::encounter_recallable_units(const std::vector<team>& teams)
2542 {
2543  for(const team& t : teams) {
2544  for(const unit_const_ptr u : t.recall_list()) {
2545  encountered_units_set_.insert(u->type_id());
2546  }
2547  }
2548 }
2549 
2551 {
2552  map.for_each_loc([&](const map_location& loc) {
2553  const t_translation::terrain_code terrain = map.get_terrain(loc);
2554  encountered_terrains().insert(terrain);
2556  encountered_terrains().insert(t);
2557  }
2558  });
2559 }
2560 
2562 {
2563  encounter_recruitable_units(gameboard_.teams());
2564  encounter_start_units(gameboard_.units());
2565  encounter_recallable_units(gameboard_.teams());
2566  encounter_map_terrain(gameboard_.map());
2567 }
2568 
2570 {
2571  return preferences_[prefs_list::player_joins_sound].to_bool(true);
2572 }
2574 {
2575  preferences_[prefs_list::player_joins_sound] = val;
2576 }
2578 {
2579  return preferences_[prefs_list::player_joins_notif].to_bool(false);
2580 }
2582 {
2583  preferences_[prefs_list::player_joins_notif] = val;
2584 }
2586 {
2587  return preferences_[prefs_list::player_joins_lobby].to_bool(false);
2588 }
2590 {
2591  preferences_[prefs_list::player_joins_lobby] = val;
2592 }
2593 
2595 {
2596  return preferences_[prefs_list::player_leaves_sound].to_bool(true);
2597 }
2599 {
2600  preferences_[prefs_list::player_leaves_sound] = val;
2601 }
2603 {
2604  return preferences_[prefs_list::player_leaves_notif].to_bool(false);
2605 }
2607 {
2608  preferences_[prefs_list::player_leaves_notif] = val;
2609 }
2611 {
2612  return preferences_[prefs_list::player_leaves_lobby].to_bool(false);
2613 }
2615 {
2616  preferences_[prefs_list::player_leaves_lobby] = val;
2617 }
2618 
2620 {
2621  return preferences_[prefs_list::private_message_sound].to_bool(true);
2622 }
2624 {
2625  preferences_[prefs_list::private_message_sound] = val;
2626 }
2628 {
2629  return preferences_[prefs_list::private_message_notif].to_bool(desktop::notifications::available());
2630 }
2632 {
2633  preferences_[prefs_list::private_message_notif] = val;
2634 }
2636 {
2637  return preferences_[prefs_list::private_message_lobby].to_bool(true);
2638 }
2640 {
2641  preferences_[prefs_list::private_message_lobby] = val;
2642 }
2643 
2645 {
2646  return preferences_[prefs_list::friend_message_sound].to_bool(false);
2647 }
2649 {
2650  preferences_[prefs_list::friend_message_sound] = val;
2651 }
2653 {
2654  return preferences_[prefs_list::friend_message_notif].to_bool(false);
2655 }
2657 {
2658  preferences_[prefs_list::friend_message_notif] = val;
2659 }
2661 {
2662  return preferences_[prefs_list::friend_message_lobby].to_bool(false);
2663 }
2665 {
2666  preferences_[prefs_list::friend_message_lobby] = val;
2667 }
2668 
2670 {
2671  return preferences_[prefs_list::public_message_sound].to_bool(false);
2672 }
2674 {
2675  preferences_[prefs_list::public_message_sound] = val;
2676 }
2678 {
2679  return preferences_[prefs_list::public_message_notif].to_bool(false);
2680 }
2682 {
2683  preferences_[prefs_list::public_message_notif] = val;
2684 }
2686 {
2687  return preferences_[prefs_list::public_message_lobby].to_bool(false);
2688 }
2690 {
2691  preferences_[prefs_list::public_message_lobby] = val;
2692 }
2693 
2695 {
2696  return preferences_[prefs_list::server_message_sound].to_bool(true);
2697 }
2699 {
2700  preferences_[prefs_list::server_message_sound] = val;
2701 }
2703 {
2704  return preferences_[prefs_list::server_message_notif].to_bool(false);
2705 }
2707 {
2708  preferences_[prefs_list::server_message_notif] = val;
2709 }
2711 {
2712  return preferences_[prefs_list::server_message_lobby].to_bool(true);
2713 }
2715 {
2716  preferences_[prefs_list::server_message_lobby] = val;
2717 }
2718 
2720 {
2721  return preferences_[prefs_list::ready_for_start_sound].to_bool(true);
2722 }
2724 {
2725  preferences_[prefs_list::ready_for_start_sound] = val;
2726 }
2728 {
2729  return preferences_[prefs_list::ready_for_start_notif].to_bool(desktop::notifications::available());
2730 }
2732 {
2733  preferences_[prefs_list::ready_for_start_notif] = val;
2734 }
2736 {
2737  return preferences_[prefs_list::ready_for_start_lobby].to_bool(false);
2738 }
2740 {
2741  preferences_[prefs_list::ready_for_start_lobby] = val;
2742 }
2743 
2745 {
2746  return preferences_[prefs_list::game_has_begun_sound].to_bool(true);
2747 }
2749 {
2750  preferences_[prefs_list::game_has_begun_sound] = val;
2751 }
2753 {
2754  return preferences_[prefs_list::game_has_begun_notif].to_bool(desktop::notifications::available());
2755 }
2757 {
2758  preferences_[prefs_list::game_has_begun_notif] = val;
2759 }
2761 {
2762  return preferences_[prefs_list::game_has_begun_lobby].to_bool(false);
2763 }
2765 {
2766  preferences_[prefs_list::game_has_begun_lobby] = val;
2767 }
2768 
2770 {
2771  return preferences_[prefs_list::turn_changed_sound].to_bool(true);
2772 }
2774 {
2775  preferences_[prefs_list::turn_changed_sound] = val;
2776 }
2778 {
2779  return preferences_[prefs_list::turn_changed_notif].to_bool(desktop::notifications::available());
2780 }
2782 {
2783  preferences_[prefs_list::turn_changed_notif] = val;
2784 }
2786 {
2787  return preferences_[prefs_list::turn_changed_lobby].to_bool(false);
2788 }
2790 {
2791  preferences_[prefs_list::turn_changed_lobby] = val;
2792 }
2793 
2795 {
2796  return preferences_[prefs_list::game_created_sound].to_bool(true);
2797 }
2799 {
2800  preferences_[prefs_list::game_created_sound] = val;
2801 }
2803 {
2804  return preferences_[prefs_list::game_created_notif].to_bool(desktop::notifications::available());
2805 }
2807 {
2808  preferences_[prefs_list::game_created_notif] = val;
2809 }
2811 {
2812  return preferences_[prefs_list::game_created_lobby].to_bool(true);
2813 }
2815 {
2816  preferences_[prefs_list::game_created_lobby] = val;
2817 }
2818 
2820 {
2821  preferences_.remove_attribute(prefs_list::player_joins_sound);
2822  preferences_.remove_attribute(prefs_list::player_joins_notif);
2823  preferences_.remove_attribute(prefs_list::player_joins_lobby);
2824  preferences_.remove_attribute(prefs_list::player_leaves_sound);
2825  preferences_.remove_attribute(prefs_list::player_leaves_notif);
2826  preferences_.remove_attribute(prefs_list::player_leaves_lobby);
2827  preferences_.remove_attribute(prefs_list::private_message_sound);
2828  preferences_.remove_attribute(prefs_list::private_message_notif);
2829  preferences_.remove_attribute(prefs_list::private_message_lobby);
2830  preferences_.remove_attribute(prefs_list::friend_message_sound);
2831  preferences_.remove_attribute(prefs_list::friend_message_notif);
2832  preferences_.remove_attribute(prefs_list::friend_message_lobby);
2833  preferences_.remove_attribute(prefs_list::public_message_sound);
2834  preferences_.remove_attribute(prefs_list::public_message_notif);
2835  preferences_.remove_attribute(prefs_list::public_message_lobby);
2836  preferences_.remove_attribute(prefs_list::server_message_sound);
2837  preferences_.remove_attribute(prefs_list::server_message_notif);
2838  preferences_.remove_attribute(prefs_list::server_message_lobby);
2839  preferences_.remove_attribute(prefs_list::ready_for_start_sound);
2840  preferences_.remove_attribute(prefs_list::ready_for_start_notif);
2841  preferences_.remove_attribute(prefs_list::ready_for_start_lobby);
2842  preferences_.remove_attribute(prefs_list::game_has_begun_sound);
2843  preferences_.remove_attribute(prefs_list::game_has_begun_notif);
2844  preferences_.remove_attribute(prefs_list::game_has_begun_lobby);
2845  preferences_.remove_attribute(prefs_list::turn_changed_sound);
2846  preferences_.remove_attribute(prefs_list::turn_changed_notif);
2847  preferences_.remove_attribute(prefs_list::turn_changed_lobby);
2848  preferences_.remove_attribute(prefs_list::game_created_sound);
2849  preferences_.remove_attribute(prefs_list::game_created_notif);
2850  preferences_.remove_attribute(prefs_list::game_created_lobby);
2851 }
2852 
2854 {
2855  std::string res;
2856 #ifdef _WIN32
2857  wchar_t buffer[300];
2858  DWORD size = 300;
2859  if(GetUserNameW(buffer, &size)) {
2860  //size includes a terminating null character.
2861  assert(size > 0);
2862  res = unicode_cast<std::string>(boost::iterator_range<wchar_t*>(buffer, buffer + size - 1));
2863  }
2864 #else
2865  if(char* const login = getenv("USER")) {
2866  res = login;
2867  }
2868 #endif
2869  return res;
2870 }
2871 
2872 preferences::secure_buffer prefs::build_key(const std::string& server, const std::string& login)
2873 {
2874  std::string sysname = get_system_username();
2875  preferences::secure_buffer result(std::max<std::size_t>(server.size() + login.size() + sysname.size(), 32));
2876  unsigned char i = 0;
2877  std::generate(result.begin(), result.end(), [&i]() {return 'x' ^ i++;});
2878  std::copy(login.begin(), login.end(), result.begin());
2879  std::copy(sysname.begin(), sysname.end(), result.begin() + login.size());
2880  std::copy(server.begin(), server.end(), result.begin() + login.size() + sysname.size());
2881  return result;
2882 }
2883 
2885 {
2886 #ifndef __APPLE__
2887  int update_length;
2888  int extra_length;
2889  int total_length;
2890  // AES IV is generally 128 bits
2891  const unsigned char iv[] = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};
2892  unsigned char encrypted_buffer[1024];
2893 
2894  if(plaintext.size() > 1008)
2895  {
2896  ERR_CFG << "Cannot encrypt data larger than 1008 bytes.";
2897  return preferences::secure_buffer();
2898  }
2899  DBG_CFG << "Encrypting data with length: " << plaintext.size();
2900 
2901  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
2902  if(!ctx)
2903  {
2904  ERR_CFG << "AES EVP_CIPHER_CTX_new failed with error:";
2905  ERR_CFG << ERR_error_string(ERR_get_error(), NULL);
2906  return preferences::secure_buffer();
2907  }
2908 
2909  // TODO: use EVP_EncryptInit_ex2 once openssl 3.0 is more widespread
2910  if(EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key.data(), iv) != 1)
2911  {
2912  ERR_CFG << "AES EVP_EncryptInit_ex failed with error:";
2913  ERR_CFG << ERR_error_string(ERR_get_error(), NULL);
2914  EVP_CIPHER_CTX_free(ctx);
2915  return preferences::secure_buffer();
2916  }
2917 
2918  if(EVP_EncryptUpdate(ctx, encrypted_buffer, &update_length, plaintext.data(), plaintext.size()) != 1)
2919  {
2920  ERR_CFG << "AES EVP_EncryptUpdate failed with error:";
2921  ERR_CFG << ERR_error_string(ERR_get_error(), NULL);
2922  EVP_CIPHER_CTX_free(ctx);
2923  return preferences::secure_buffer();
2924  }
2925  DBG_CFG << "Update length: " << update_length;
2926 
2927  if(EVP_EncryptFinal_ex(ctx, encrypted_buffer + update_length, &extra_length) != 1)
2928  {
2929  ERR_CFG << "AES EVP_EncryptFinal failed with error:";
2930  ERR_CFG << ERR_error_string(ERR_get_error(), NULL);
2931  EVP_CIPHER_CTX_free(ctx);
2932  return preferences::secure_buffer();
2933  }
2934  DBG_CFG << "Extra length: " << extra_length;
2935 
2936  EVP_CIPHER_CTX_free(ctx);
2937 
2938  total_length = update_length+extra_length;
2940  for(int i = 0; i < total_length; i++)
2941  {
2942  result.push_back(encrypted_buffer[i]);
2943  }
2944 
2945  DBG_CFG << "Successfully encrypted plaintext value of '" << utils::join(plaintext, "") << "' having length " << plaintext.size();
2946  DBG_CFG << "For a total encrypted length of: " << total_length;
2947 
2948  return result;
2949 #else
2950  size_t outWritten = 0;
2951  preferences::secure_buffer result(plaintext.size(), '\0');
2952 
2953  CCCryptorStatus ccStatus = CCCrypt(kCCDecrypt,
2954  kCCAlgorithmRC4,
2955  kCCOptionPKCS7Padding,
2956  key.data(),
2957  key.size(),
2958  nullptr,
2959  plaintext.data(),
2960  plaintext.size(),
2961  result.data(),
2962  result.size(),
2963  &outWritten);
2964 
2965  assert(ccStatus == kCCSuccess);
2966  assert(outWritten == plaintext.size());
2967 
2968  return result;
2969 #endif
2970 }
2971 
2973 {
2974 #ifndef __APPLE__
2975  int update_length;
2976  int extra_length;
2977  int total_length;
2978  // AES IV is generally 128 bits
2979  const unsigned char iv[] = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};
2980  unsigned char plaintext_buffer[1024];
2981 
2982  if(encrypted.size() > 1024)
2983  {
2984  ERR_CFG << "Cannot decrypt data larger than 1024 bytes.";
2985  return preferences::secure_buffer();
2986  }
2987  DBG_CFG << "Decrypting data with length: " << encrypted.size();
2988 
2989  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
2990  if(!ctx)
2991  {
2992  ERR_CFG << "AES EVP_CIPHER_CTX_new failed with error:";
2993  ERR_CFG << ERR_error_string(ERR_get_error(), NULL);
2994  return preferences::secure_buffer();
2995  }
2996 
2997  // TODO: use EVP_DecryptInit_ex2 once openssl 3.0 is more widespread
2998  if(EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key.data(), iv) != 1)
2999  {
3000  ERR_CFG << "AES EVP_DecryptInit_ex failed with error:";
3001  ERR_CFG << ERR_error_string(ERR_get_error(), NULL);
3002  EVP_CIPHER_CTX_free(ctx);
3003  return preferences::secure_buffer();
3004  }
3005 
3006  if(EVP_DecryptUpdate(ctx, plaintext_buffer, &update_length, encrypted.data(), encrypted.size()) != 1)
3007  {
3008  ERR_CFG << "AES EVP_DecryptUpdate failed with error:";
3009  ERR_CFG << ERR_error_string(ERR_get_error(), NULL);
3010  EVP_CIPHER_CTX_free(ctx);
3011  return preferences::secure_buffer();
3012  }
3013  DBG_CFG << "Update length: " << update_length;
3014 
3015  if(EVP_DecryptFinal_ex(ctx, plaintext_buffer + update_length, &extra_length) != 1)
3016  {
3017  ERR_CFG << "AES EVP_DecryptFinal failed with error:";
3018  ERR_CFG << ERR_error_string(ERR_get_error(), NULL);
3019  EVP_CIPHER_CTX_free(ctx);
3020  return preferences::secure_buffer();
3021  }
3022  DBG_CFG << "Extra length: " << extra_length;
3023 
3024  EVP_CIPHER_CTX_free(ctx);
3025 
3026  total_length = update_length+extra_length;
3028  for(int i = 0; i < total_length; i++)
3029  {
3030  result.push_back(plaintext_buffer[i]);
3031  }
3032 
3033  DBG_CFG << "Successfully decrypted data to the value: " << utils::join(result, "");
3034  DBG_CFG << "For a total decrypted length of: " << total_length;
3035 
3036  return result;
3037 #else
3038  size_t outWritten = 0;
3039  preferences::secure_buffer result(encrypted.size(), '\0');
3040 
3041  CCCryptorStatus ccStatus = CCCrypt(kCCDecrypt,
3042  kCCAlgorithmRC4,
3043  kCCOptionPKCS7Padding,
3044  key.data(),
3045  key.size(),
3046  nullptr,
3047  encrypted.data(),
3048  encrypted.size(),
3049  result.data(),
3050  result.size(),
3051  &outWritten);
3052 
3053  assert(ccStatus == kCCSuccess);
3054  assert(outWritten == encrypted.size());
3055 
3056  // the decrypted result is likely shorter than the encrypted data, so the extra padding needs to be removed.
3057  while(!result.empty() && result.back() == 0) {
3058  result.pop_back();
3059  }
3060 
3061  return result;
3062 #endif
3063 }
3064 
3066 {
3067  preferences::secure_buffer unescaped;
3068  unescaped.reserve(text.size());
3069  bool escaping = false;
3070  for(char c : text) {
3071  if(escaping) {
3072  if(c == '\xa') {
3073  unescaped.push_back('\xc');
3074  } else if(c == '.') {
3075  unescaped.push_back('@');
3076  } else {
3077  unescaped.push_back(c);
3078  }
3079  escaping = false;
3080  } else if(c == '\x1') {
3081  escaping = true;
3082  } else {
3083  unescaped.push_back(c);
3084  }
3085  }
3086  assert(!escaping);
3087  return unescaped;
3088 }
3089 
3091 {
3093  escaped.reserve(text.size());
3094  for(char c : text) {
3095  if(c == '\x1') {
3096  escaped.push_back('\x1');
3097  escaped.push_back('\x1');
3098  } else if(c == '\xc') {
3099  escaped.push_back('\x1');
3100  escaped.push_back('\xa');
3101  } else if(c == '@') {
3102  escaped.push_back('\x1');
3103  escaped.push_back('.');
3104  } else {
3105  escaped.push_back(c);
3106  }
3107  }
3108  return escaped;
3109 }
3110 
3112 {
3113  return preferences_[prefs_list::remember_password].to_bool();
3114 }
3115 
3116 void prefs::set_remember_password(bool remember)
3117 {
3118  preferences_[prefs_list::remember_password] = remember;
3119 
3120  if(remember) {
3121  load_credentials();
3122  } else {
3124  }
3125 }
3126 
3127 std::string prefs::login()
3128 {
3129  std::string name = get("login", pref_constants::EMPTY_LOGIN);
3130  if(name == pref_constants::EMPTY_LOGIN) {
3131  name = get_system_username();
3132  } else if(name.size() > 2 && name.front() == '@' && name.back() == '@') {
3133  name = name.substr(1, name.size() - 2);
3134  } else {
3135  ERR_CFG << "malformed user credentials (did you manually edit the preferences file?)";
3136  }
3137  if(name.empty()) {
3138  return "player";
3139  }
3140  return name;
3141 }
3142 
3143 void prefs::set_login(const std::string& login)
3144 {
3145  auto login_clean = login;
3146  boost::trim(login_clean);
3147 
3148  preferences_[prefs_list::login] = '@' + login_clean + '@';
3149 }
3150 
3151 std::string prefs::password(const std::string& server, const std::string& login)
3152 {
3153  DBG_CFG << "Retrieving password for server: '" << server << "', login: '" << login << "'";
3154  auto login_clean = login;
3155  boost::trim(login_clean);
3156 
3157  if(!remember_password()) {
3158  if(!credentials_.empty() && credentials_[0].username == login_clean && credentials_[0].server == server) {
3159  auto temp = aes_decrypt(credentials_[0].key, build_key(server, login_clean));
3160  return std::string(temp.begin(), temp.end());
3161  } else {
3162  return "";
3163  }
3164  }
3165  auto cred = std::find_if(credentials_.begin(), credentials_.end(), [&](const preferences::login_info& cred) {
3166  return cred.server == server && cred.username == login_clean;
3167  });
3168  if(cred == credentials_.end()) {
3169  return "";
3170  }
3171  auto temp = aes_decrypt(cred->key, build_key(server, login_clean));
3172  return std::string(temp.begin(), temp.end());
3173 }
3174 
3175 void prefs::set_password(const std::string& server, const std::string& login, const std::string& key)
3176 {
3177  DBG_CFG << "Setting password for server: '" << server << "', login: '" << login << "'";
3178  auto login_clean = login;
3179  boost::trim(login_clean);
3180 
3181  preferences::secure_buffer temp(key.begin(), key.end());
3182  if(!remember_password()) {
3184  credentials_.emplace_back(login_clean, server, aes_encrypt(temp, build_key(server, login_clean)));
3185  return;
3186  }
3187  auto cred = std::find_if(credentials_.begin(), credentials_.end(), [&](const preferences::login_info& cred) {
3188  return cred.server == server && cred.username == login_clean;
3189  });
3190  if(cred == credentials_.end()) {
3191  // This is equivalent to emplace_back, but also returns the iterator to the new element
3192  cred = credentials_.emplace(credentials_.end(), login_clean, server);
3193  }
3194  cred->key = aes_encrypt(temp, build_key(server, login_clean));
3195 }
double t
Definition: astarsearch.cpp:63
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
const_attr_itors attribute_range() const
Definition: config.cpp:763
void clear_children(T... keys)
Definition: config.hpp:642
bool has_attribute(config_key_type key) const
Definition: config.cpp:155
void merge_with(const config &c)
Merge config 'c' into this config, overwriting this config's values.
Definition: config.cpp:1126
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:887
child_itors child_range(config_key_type key)
Definition: config.cpp:273
config & child_or_add(config_key_type key)
Returns a reference to the first child with the given key.
Definition: config.cpp:406
void remove_attribute(config_key_type key)
Definition: config.cpp:160
attribute_map::value_type attribute
Definition: config.hpp:299
bool empty() const
Definition: config.cpp:852
void clear()
Definition: config.cpp:831
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Euivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition: config.cpp:385
config & add_child(config_key_type key)
Definition: config.cpp:441
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:88
void set_theme(const std::string &new_theme)
Definition: display.cpp:248
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:102
Game board class.
Definition: game_board.hpp:46
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:79
virtual const unit_map & units() const override
Definition: game_board.hpp:106
virtual const gamemap & map() const override
Definition: game_board.hpp:96
A class grating read only view to a vector of config objects, viewed as one config with all children ...
static game_config_view wrap(const config &cfg)
config_array_view child_range(config_key_type key) const
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:301
void for_each_loc(const F &f) const
Definition: map.hpp:136
Encapsulates the map of the game.
Definition: map.hpp:172
const t_translation::ter_list & underlying_union_terrain(const map_location &loc) const
Definition: map.cpp:58
file_dialog & set_ok_label(const std::string &value)
Sets the OK button label.
file_dialog & set_path(const std::string &value)
Sets the initial file selection.
file_dialog & set_title(const std::string &value)
Sets the current dialog title text.
Definition: file_dialog.hpp:59
file_dialog & set_read_only(bool value)
Whether to provide user interface elements for manipulating existing objects.
file_dialog & set_filename(const std::string &value)
Sets the initial file name input but not the path.
file_dialog & set_message(const std::string &value)
Sets the current dialog instructions/message text.
Definition: file_dialog.hpp:78
bool show(const unsigned auto_close_time=0)
Shows the window.
int selected_index() const
Returns the selected item index after displaying.
Definition: theme_list.hpp:35
void set_selected_index(int index)
Sets the initially selected item index (-1 by default).
Definition: theme_list.hpp:41
const std::string & get_nick() const
Definition: preferences.hpp:90
bool player_joins_notif()
void set_lobby_joins(pref_constants::lobby_joins show)
bool player_joins_lobby()
std::string enemy_color()
bool allow_observers()
bool server_message_notif()
bool ready_for_start_sound()
config::attribute_value get_as_attribute(const std::string &key)
void set_show_ally_orb(bool show_orb)
void set_network_host(const std::string &host)
void set_friend_message_notif(bool val)
std::set< t_translation::terrain_code > & encountered_terrains()
const config & options()
void set_player_leaves_notif(bool val)
bool set_music(bool ison)
void set_friend_message_lobby(bool val)
void set_sound_volume(int vol)
int turns()
void set_remember_password(bool remember)
std::string language()
bool chat_timestamping()
bool show_ally_orb()
const std::map< std::string, preferences::acquaintance > & get_acquaintances()
optional_const_config get_alias()
bool friend_message_notif()
bool skip_ai_moves()
bool show_theme_dialog()
void set_turbo(bool ison)
void set_animate_water(bool value)
void set_show_disengaged_orb(bool show_orb)
bool game_has_begun_sound()
bool turn_changed_notif()
void set_player_joins_lobby(bool val)
void set_core_id(const std::string &root)
std::string get_system_username()
bool show_side_colors()
int mp_server_warning_disabled()
void set_fi_blocked_in_game(bool value)
bool show_status_on_ally_orb()
bool mp_modifications_initialized_
std::map< std::string, std::vector< std::string > > history_map_
void save_hotkeys()
std::string gui_theme()
int village_support()
void set_addon_manager_saved_order_direction(sort_order::type value)
void set_language(const std::string &s)
bool public_message_sound()
bool maximized()
void set_autosavemax(int value)
bool middle_click_scrolls()
void toggle_minimap_draw_units()
bool turn_bell()
void set_editor_draw_hex_coordinates(bool value)
void set_show_side_colors(bool value)
int countdown_init_time()
std::string addon_manager_saved_order_name()
std::set< std::string > & encountered_units()
bool editor_draw_hex_coordinates()
void add_alias(const std::string &alias, const std::string &command)
bool minimap_draw_villages()
void set_idle_anim(const bool ison)
void set_countdown_reservoir_time(int value)
double turbo_speed()
void set_turns(int value)
void write_preferences()
void clear_preferences()
int autosavemax()
std::vector< std::string > sp_modifications_
void clear_mp_alert_prefs()
void set_editor_draw_num_of_bitmaps(bool value)
unsigned int tile_size()
void set_village_gold(int value)
void set_chat_message_aging(const int aging)
bool enable_whiteboard_mode_on_start()
void toggle_minimap_draw_villages()
void set_ready_for_start_notif(bool val)
bool confirm_load_save_from_different_version()
std::string network_host()
void clear_countdown_init_time()
std::set< std::string > unknown_unsynced_attributes_
void set_draw_delay(int value)
void set_show_floating_labels(bool value)
bool set_ui_sound(bool ison)
bool damage_prediction_allow_monte_carlo_simulation()
bool idle_anim()
void set_mp_server_warning_disabled(int value)
bool show_unmoved_orb()
void set_login(const std::string &login)
static prefs & get()
bool skip_mp_replay()
const std::string get_ignored_delim()
bool ready_for_start_lobby()
std::map< std::string, preferences::acquaintance > acquaintances_
bool editor_draw_num_of_bitmaps()
bool interrupt_when_ally_sighted()
static constexpr std::array unsynced_children_
bool game_created_notif()
bool game_has_begun_lobby()
bool show_floating_labels()
bool player_leaves_notif()
void set_turbo_speed(const double speed)
void enable_mouse_scroll(bool value)
bool ask_delete_saves()
bool fps_
bool game_created_lobby()
void set_countdown_action_bonus(int value)
void set_player_leaves_lobby(bool val)
int scroll_speed()
void set_whisper_friends_only(bool v)
bool message_private()
void encounter_recallable_units(const std::vector< team > &teams)
std::map< std::string, std::set< std::string > > completed_campaigns_
bool show_combat()
std::string selected_achievement_group()
bool blindfold_replay()
std::string theme()
void set_level_type(int value)
optional_const_config dir_bookmarks()
bool friend_message_sound()
void set_theme(const std::string &theme)
void set_ready_for_start_lobby(bool val)
int chat_message_aging()
void set_xp_modifier(int value)
void set_server_message_sound(bool val)
void set_user_servers_list(const std::vector< game_config::server_info > &value)
void toggle_minimap_draw_terrain()
preferences::secure_buffer build_key(const std::string &server, const std::string &login)
Fills a secure_buffer with 32 bytes of deterministically generated bytes, then overwrites it with the...
void set_auto_pixel_scale(bool choice)
void set_delete_saves(bool value)
bool player_leaves_sound()
int countdown_action_bonus()
int level_type()
void set_chat_lines(int lines)
void set_stop_music_in_background(bool ison)
bool is_campaign_completed(const std::string &campaign_id)
void set_allied_color(const std::string &color_id)
bool get_scroll_when_mouse_outside(bool def)
void show_wesnothd_server_search()
bool green_confirm()
int bell_volume()
int mouse_scroll_threshold()
Gets the threshold for when to scroll.
bool show_moved_orb()
void set_editor_auto_update_transitions(int value)
bool is_ignored(const std::string &nick)
void set_turn_changed_sound(bool val)
bool save_replays()
std::vector< std::string > mp_modifications_
bool hide_whiteboard()
bool achievement(const std::string &content_for, const std::string &id)
bool minimap_draw_units()
std::set< std::string > unknown_synced_attributes_
void set_enemy_color(const std::string &color_id)
void set_ask_delete_saves(bool value)
void set_player_joins_notif(bool val)
void save_credentials()
void set_password(const std::string &server, const std::string &login, const std::string &key)
void set_gui_theme(const std::string &s)
bool sub_achievement(const std::string &content_for, const std::string &id, const std::string &sub_id)
void clear_credentials()
bool delete_saves()
std::vector< preferences::login_info > credentials_
std::vector< std::string > do_read_editor_mru()
bool fog()
void set_game_has_begun_lobby(bool val)
void set_friend_message_sound(bool val)
bool scroll_to_action()
bool ellipses()
void encounter_recruitable_units(const std::vector< team > &teams)
std::string era()
bool parse_should_show_lobby_join(const std::string &sender, const std::string &message)
bool friend_message_lobby()
int progress_achievement(const std::string &content_for, const std::string &id, int limit=999999, int max_progress=999999, int amount=0)
Increments the achievement's current progress by amount if it hasn't already been completed.
sort_order::type addon_manager_saved_order_direction()
bool set_turn_bell(bool ison)
static constexpr std::array synced_attributes_
unsigned int sample_rate()
void set_show_status_on_ally_orb(bool show_orb)
static constexpr std::array synced_children_
void set_public_message_notif(bool val)
void set_private_message_notif(bool val)
void set_last_cache_cleared_version(const std::string &version)
void set_chat_timestamping(bool value)
void set_player_leaves_sound(bool val)
void set_game_has_begun_sound(bool val)
void set_options(const config &values)
void set_message_private(bool value)
bool mouse_scroll_enabled()
std::vector< game_config::server_info > user_servers_list()
optional_const_config get_child(const std::string &key)
void load_credentials()
std::string unmoved_color()
void set_music_volume(int vol)
void set_save_replays(bool value)
void set_countdown(bool value)
void load_advanced_prefs(const game_config_view &gc)
std::string editor_chosen_addon()
std::string allied_color()
bool minimap_draw_terrain()
bool public_message_lobby()
bool vsync()
void set_show_standing_animations(bool value)
void set_show_fps(bool value)
std::string custom_command()
void set_pixel_scale(const int scale)
std::size_t editor_mru_limit()
bool show_partial_orb()
void set_color_cursors(bool value)
void set_selected_achievement_group(const std::string &content_for)
int editor_auto_update_transitions()
void set_show_all_units_in_help(bool value)
int draw_delay()
std::vector< preferences::option > advanced_prefs_
void encounter_start_units(const unit_map &units)
void set_countdown_turn_bonus(int value)
pref_constants::lobby_joins get_lobby_joins()
bool auto_pixel_scale()
bool ready_for_start_notif()
bool minimap_terrain_coding()
void set_editor_draw_terrain_codes(bool value)
void set_player_joins_sound(bool val)
void set_fi_friends_in_game(bool value)
bool show_fps()
void load_hotkeys()
std::string random_faction_mode()
void encounter_map_terrain(const gamemap &map)
int font_scaling()
void set_disable_auto_moves(bool value)
void set_blindfold_replay(bool value)
void set_public_message_lobby(bool val)
bool fi_blocked_in_game()
void set_village_support(int value)
preferences::secure_buffer escape(const preferences::secure_buffer &text)
std::string moved_color()
bool confirm_no_moves()
bool minimap_movement_coding()
void set_font_scaling(int scale)
std::size_t sound_buffer_size()
bool use_color_cursors()
void set_game_created_notif(bool val)
void set_addon_manager_saved_order_name(const std::string &value)
bool yellow_confirm()
bool server_message_lobby()
config option_values_
void set_use_map_settings(bool value)
void set_show_partial_orb(bool show_orb)
void migrate_preferences(const std::string &prefs_dir)
bool grid()
bool show_disengaged_orb()
bool whisper_friends_only()
bool message_bell()
void set_server_message_notif(bool val)
void set_interrupt_when_ally_sighted(bool value)
void set_dir_bookmarks(const config &cfg)
bool message_private_on_
std::set< t_translation::terrain_code > encountered_terrains_set_
bool set_sound(bool ison)
void set_fi_invert(bool value)
bool is_friend(const std::string &nick)
void set_achievement(const std::string &content_for, const std::string &id)
Marks the specified achievement as completed.
preferences::secure_buffer aes_decrypt(const preferences::secure_buffer &text, const preferences::secure_buffer &key)
Same as aes_encrypt(), except of course it takes encrypted data as an argument and returns decrypted ...
bool animate_map()
bool public_message_notif()
int village_gold()
config preferences_
bool private_message_lobby()
void toggle_minimap_movement_coding()
void clear_countdown_turn_bonus()
std::string login()
bool music_on()
void set_random_faction_mode(const std::string &value)
void set_turn_changed_notif(bool val)
void set_show_unmoved_orb(bool show_orb)
void set_idle_anim_rate(int rate)
bool server_message_sound()
bool show_all_units_in_help()
int font_scaled(int size)
void set_scroll_speed(const int scroll)
bool turn_dialog()
std::pair< preferences::acquaintance *, bool > add_acquaintance(const std::string &nick, const std::string &mode, const std::string &notes)
void set_random_start_time(bool value)
bool ui_sound_on()
bool random_start_time()
bool options_initialized_
bool private_message_notif()
void set_allow_observers(bool value)
int music_volume()
bool disable_auto_moves()
void set_shroud(bool value)
bool game_created_sound()
int pixel_scale()
std::string partial_color()
int idle_anim_rate()
preferences::secure_buffer unescape(const preferences::secure_buffer &text)
void set_scroll_to_action(bool ison)
void set_resolution(const point &res)
void set_fullscreen(bool ison)
void set_campaign_server(const std::string &host)
void set_countdown_init_time(int value)
void set_unmoved_color(const std::string &color_id)
bool remove_acquaintance(const std::string &nick)
void clear_countdown_reservoir_time()
bool show_enemy_orb()
void set_ui_volume(int vol)
bool turbo()
void toggle_minimap_terrain_coding()
const std::vector< std::string > & modifications(bool mp=true)
void do_commit_editor_mru(const std::vector< std::string > &mru)
void set_game_has_begun_notif(bool val)
bool fi_invert()
compression::format save_compression_format()
std::vector< std::string > recent_files()
Retrieves the list of recently opened files.
void set_hide_whiteboard(bool value)
bool game_has_begun_notif()
std::set< std::string > encountered_units_set_
void set_bell_volume(int vol)
std::string get_mp_server_program_name()
void set_ready_for_start_sound(bool val)
void set_public_message_sound(bool val)
void set_era(const std::string &value)
bool private_message_sound()
void set_enable_whiteboard_mode_on_start(bool value)
bool countdown()
void set_custom_command(const std::string &command)
std::string level()
void set_partial_color(const std::string &color_id)
bool fi_friends_in_game()
bool shroud()
void set_child(const std::string &key, const config &val)
static constexpr std::array unsynced_attributes_
void set_animate_map(bool value)
std::set< std::string > all_attributes()
void set_game_created_sound(bool val)
void set_skip_ai_moves(bool value)
int keepalive_timeout()
void set_mp_server_program_name(const std::string &)
bool animate_water()
void set_fi_vacant_slots(bool value)
bool remember_password()
int ui_volume()
int chat_lines()
void add_recent_files_entry(const std::string &path)
Adds an entry to the recent files list.
void set_moved_color(const std::string &color_id)
std::string get_chat_timestamp(const std::time_t &t)
void set_show_enemy_orb(bool show_orb)
void set_private_message_lobby(bool val)
point resolution()
void save_sample_rate(const unsigned int rate)
bool use_twelve_hour_clock_format()
void set_editor_chosen_addon(const std::string &addon_id)
static bool no_preferences_save
std::string last_cache_cleared_version()
bool editor_draw_terrain_codes()
void set_tile_size(const unsigned int size)
void set_grid(bool ison)
int sound_volume()
void set_modifications(const std::vector< std::string > &value, bool mp=true)
void set_turn_changed_lobby(bool val)
void set_game_created_lobby(bool val)
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.
void set_shuffle_sides(bool value)
int countdown_reservoir_time()
std::set< std::string > unknown_unsynced_children_
bool player_joins_sound()
const std::vector< game_config::server_info > & builtin_servers_list()
bool player_leaves_lobby()
void set_ellipses(bool ison)
bool turn_changed_lobby()
void reload_preferences()
std::string campaign_server()
std::set< std::string > unknown_synced_children_
bool fullscreen()
void set_skip_mp_replay(bool value)
bool sound_on()
void set_turn_dialog(bool ison)
std::string core_id()
void set_show_moved_orb(bool show_orb)
int countdown_turn_bonus()
void set_server_message_lobby(bool val)
void set_damage_prediction_allow_monte_carlo_simulation(bool value)
bool shuffle_sides()
void add_completed_campaign(const std::string &campaign_id, const std::string &difficulty_level)
void set_level(const std::string &value)
void set_fog(bool value)
void clear_hotkeys()
void set_maximized(bool ison)
void save_sound_buffer_size(const std::size_t size)
int xp_modifier()
bool use_map_settings()
void encounter_all_content(const game_board &gb)
std::string password(const std::string &server, const std::string &login)
bool sp_modifications_initialized_
void set_vsync(bool ison)
std::vector< std::string > * get_history(const std::string &id)
Returns a pointer to the history vector associated with given id making a new one if it doesn't exist...
preferences::secure_buffer aes_encrypt(const preferences::secure_buffer &text, const preferences::secure_buffer &key)
Encrypts the value of text using key and a hard coded IV using AES.
void set_private_message_sound(bool val)
bool auto_open_whisper_windows()
void load_preferences()
std::map< std::string, std::string > get_acquaintances_nice(const std::string &filter)
bool get_show_deprecation(bool def)
bool show_standing_animations()
void clear_countdown_action_bonus()
bool fi_vacant_slots()
bool turn_changed_sound()
bool stop_music_in_background()
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:74
Definition: theme.hpp:44
static std::vector< theme_info > get_basic_theme_info(bool include_hidden=false)
Returns minimal info about saved themes, optionally including hidden ones.
Definition: theme.cpp:987
Container associating units to locations.
Definition: map.hpp:98
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:968
static std::string _(const char *str)
Definition: gettext.hpp:93
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:205
Standard logging facilities (interface).
General settings and defaults for scenarios.
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:176
bool available()
Returns whether we were compiled with support for desktop notifications.
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:50
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:202
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:180
std::time_t file_modified_time(const std::string &fname)
Get the modification time of a file.
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
void copy_file(const std::string &src, const std::string &dest)
Read a file and then writes it back out.
bool delete_file(const std::string &filename)
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:324
std::string get_exe_dir()
Definition: filesystem.cpp:969
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::string get_synced_prefs_file()
location of preferences file containing preferences that are synced between computers note that wesno...
std::string get_unsynced_prefs_file()
location of preferences file containing preferences that aren't synced between computers
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:52
std::string get_credentials_file()
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:53
std::string get_wesnothd_name()
Definition: filesystem.cpp:975
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
std::string turn_bell
std::string path
Definition: filesystem.cpp:89
bool show_status_on_ally_orb
bool show_moved_orb
const version_info wesnoth_version(VERSION)
std::vector< server_info > server_list
Definition: game_config.cpp:73
unsigned int tile_size
Definition: game_config.cpp:52
bool show_ally_orb
bool show_disengaged_orb
bool show_partial_orb
bool show_enemy_orb
bool show_unmoved_orb
void show(const std::string &window_id, const t_string &message, const point &mouse, const SDL_Rect &source_rect)
Shows a tip.
Definition: tooltip.cpp:65
void remove()
Removes a tip.
Definition: tooltip.cpp:95
static int bell_volume()
static int music_volume()
static int ui_volume()
static int sound_volume()
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:410
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.
std::string get_timestamp(const std::time_t &t, const std::string &format)
Definition: log.cpp:401
Main entry points of multiplayer mode.
Definition: lobby_data.cpp:49
const int min_window_height
Definition: preferences.hpp:36
const int max_pixel_scale
Definition: preferences.hpp:48
const std::string EMPTY_LOGIN
Definition: preferences.hpp:56
const int min_pixel_scale
Definition: preferences.hpp:47
const std::string default_addons_server
Definition: preferences.hpp:60
const int def_window_width
Definition: preferences.hpp:38
const int min_font_scaling
Definition: preferences.hpp:44
const int min_window_width
Definition: preferences.hpp:35
const int max_font_scaling
Definition: preferences.hpp:45
const int def_window_height
Definition: preferences.hpp:39
const unsigned char CREDENTIAL_SEPARATOR
Definition: preferences.hpp:55
const int TRANSITION_UPDATE_PARTIAL
Definition: preferences.hpp:52
game_data * gamedata
Definition: resources.cpp:22
static std::string at(const std::string &file, int line)
int get_village_support(const std::string &value)
Gets the village unit level support.
int get_turns(const std::string &value)
Gets the number of turns.
int get_xp_modifier(const std::string &value)
Gets the xp modifier.
int get_village_gold(const std::string &value, const game_classification *classification)
Gets the village gold.
void set_bell_volume(int vol)
Definition: sound.cpp:1122
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:1082
void stop_sound()
Definition: sound.cpp:563
void set_UI_volume(int vol)
Definition: sound.cpp:1134
void set_sound_volume(int vol)
Definition: sound.cpp:1102
std::vector< terrain_code > ter_list
Definition: translation.hpp:77
ter_list read_list(std::string_view str, const ter_layer filler)
Reads a list of terrains from a string, when reading the.
std::string write_list(const ter_list &list)
Writes a list of terrains to a string, only writes the new format.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
@ REMOVE_EMPTY
void trim(std::string_view &s)
bool isvalid_wildcard(const std::string &username)
Check if the username pattern contains only valid characters.
std::set< std::string > split_set(std::string_view s, char sep, const int flags)
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
Definition: general.cpp:23
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< std::string > split(const config_attribute_value &val)
bool headless()
The game is running headless.
Definition: video.cpp:141
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
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
std::string_view data
Definition: picture.cpp:194
static lg::log_domain log_filesystem("filesystem")
#define ERR_CFG
Definition: preferences.cpp:62
#define DBG_CFG
Definition: preferences.cpp:63
#define ERR_ADV
Definition: preferences.cpp:69
static lg::log_domain advanced_preferences("advanced_preferences")
static std::string fix_orb_color_name(const std::string &color)
#define ERR_FS
Definition: preferences.cpp:66
static lg::log_domain log_config("config")
std::shared_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:27
string_enums::enum_base< random_faction_mode_defines > random_faction_mode
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:624
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:761
An exception object used when an IO error occurs.
Definition: filesystem.hpp:66
Encapsulates the map of the game.
Definition: location.hpp:38
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
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
mock_char c
static map_location::DIRECTION n
static map_location::DIRECTION s
#define d
#define e
#define h
#define a