The Battle for Wesnoth  1.17.21+dev
game_config.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2023
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "game_config.hpp"
17 
18 #include "color_range.hpp"
19 #include "config.hpp"
20 #include "gettext.hpp"
21 #include "log.hpp"
22 #include "utils/math.hpp"
23 #include "game_version.hpp"
24 #include "wesconfig.h"
26 
27 static lg::log_domain log_engine("engine");
28 #define LOG_NG LOG_STREAM(info, log_engine)
29 #define ERR_NG LOG_STREAM(err, log_engine)
30 
31 namespace game_config
32 {
33 //
34 // Gameplay constants
35 //
36 int base_income = 2;
39 int recall_cost = 20;
42 
43 int poison_amount = 8;
45 
47 
48 //
49 // Terrain-related constants
50 //
51 unsigned int tile_size = 72;
52 
53 std::string default_terrain;
55 
56 std::vector<unsigned int> zoom_levels {36, 72, 144};
57 
58 //
59 // Display scale constants
60 //
61 double hp_bar_scaling = 0.666;
62 double xp_bar_scaling = 0.5;
63 
64 //
65 // Misc
66 //
67 unsigned lobby_network_timer = 100;
68 unsigned lobby_refresh = 4000;
69 
70 const std::size_t max_loop = 65536;
71 
72 std::vector<server_info> server_list;
73 
74 bool allow_insecure = false;
75 
76 //
77 // Gamestate flags
78 //
79 bool
80  debug_impl = false,
81  debug_lua = false,
82  strict_lua = false,
83  editor = false,
85  mp_debug = false,
86  exit_at_end = false,
87  no_delay = false,
89  no_addons = false;
90 
91 const bool& debug = debug_impl;
92 
93 void set_debug(bool new_debug) {
94  if(debug_impl && !new_debug) {
95  // Turning debug mode off; decrease deprecation severity
96  int severity;
97  if(lg::get_log_domain_severity("deprecation", severity)) {
98  lg::set_log_domain_severity("deprecation", severity - 2);
99  }
100  } else if(!debug_impl && new_debug) {
101  // Turning debug mode on; increase deprecation severity
102  int severity;
103  if(lg::get_log_domain_severity("deprecation", severity)) {
104  lg::set_log_domain_severity("deprecation", severity + 2);
105  }
106  }
107  debug_impl = new_debug;
108 }
109 
110 //
111 // Orb display flags
112 //
120 
121 //
122 // Music constants
123 //
125 
126 std::vector<std::string> default_defeat_music;
127 std::vector<std::string> default_victory_music;
128 
129 //
130 // Color info
131 //
132 std::string flag_rgb, unit_rgb;
133 
134 std::vector<color_t> red_green_scale;
135 std::vector<color_t> red_green_scale_text;
136 
137 static std::vector<color_t> blue_white_scale;
138 static std::vector<color_t> blue_white_scale_text;
139 
140 std::map<std::string, color_range> team_rgb_range;
141 // Map [color_range]id to [color_range]name, or "" if no name
142 std::map<std::string, t_string> team_rgb_name;
143 
144 std::map<std::string, std::vector<color_t>> team_rgb_colors;
145 
146 std::vector<std::string> default_colors;
147 
148 namespace colors
149 {
150 std::string ally_orb_color;
151 std::string enemy_orb_color;
152 std::string moved_orb_color;
153 std::string partial_orb_color;
154 std::string unmoved_orb_color;
155 std::string default_color_list;
156 } // namespace colors
157 
158 //
159 // Image constants
160 //
161 std::vector<std::string> foot_speed_prefix;
162 
164 std::string foot_teleport_exit;
165 
166 namespace images {
167 
168 std::string
176  // orbs and hp/xp bar
180  // top bar icons
183  // flags
186  // hex overlay
195  // GUI elements
199  // TODO: de-hardcode this
200  selected_menu = "buttons/radiobox-pressed.png",
201  deselected_menu = "buttons/radiobox.png",
202  checked_menu = "buttons/checkbox-pressed.png",
203  unchecked_menu = "buttons/checkbox.png",
204  wml_menu = "buttons/WML-custom.png",
209  // notifications icon
210  app_icon = "images/icons/icon-game.png";
211 
212 } //images
213 
214 //
215 // Sound constants
216 //
217 namespace sounds {
218 
219 std::string
220  turn_bell = "bell.wav",
221  timer_bell = "timer.wav",
222  public_message = "chat-[1~3].ogg",
223  private_message = "chat-highlight.ogg",
224  friend_message = "chat-friend.ogg",
225  server_message = "receive.wav",
226  player_joins = "arrive.wav",
227  player_leaves = "leave.wav",
228  game_user_arrive = "join.wav",
229  game_user_leave = "leave.wav",
230  ready_for_start = "bell.wav",
231  game_has_begun = "gamestart.ogg",
232  game_created = "join.wav";
233 
234 const std::string
235  button_press = "button.wav",
236  checkbox_release = "checkbox.wav",
237  slider_adjust = "slider.wav",
238  menu_expand = "expand.wav",
239  menu_contract = "contract.wav",
240  menu_select = "select.wav";
241 
242 namespace status {
243 
244 std::string
245  poisoned = "poison.ogg",
246  slowed = "slowed.wav",
247  petrified = "petrified.ogg";
248 
249 } // status
250 
251 } // sounds
252 
253 static void add_color_info(const game_config_view& v, bool build_defaults);
255 {
256  add_color_info(v, false);
257 }
258 
259 void load_config(const config &v)
260 {
261  base_income = v["base_income"].to_int(2);
262  village_income = v["village_income"].to_int(1);
263  village_support = v["village_support"].to_int(1);
264  poison_amount = v["poison_amount"].to_int(8);
265  rest_heal_amount = v["rest_heal_amount"].to_int(2);
266  recall_cost = v["recall_cost"].to_int(20);
267  kill_experience = v["kill_experience"].to_int(8);
268  combat_experience= v["combat_experience"].to_int(1);
269  lobby_refresh = v["lobby_refresh"].to_int(2000);
270  default_terrain = v["default_terrain"].str();
271  tile_size = v["tile_size"].to_int(72);
272 
273  std::vector<std::string> zoom_levels_str = utils::split(v["zoom_levels"]);
274  if(!zoom_levels_str.empty()) {
275  zoom_levels.clear();
276  std::transform(zoom_levels_str.begin(), zoom_levels_str.end(), std::back_inserter(zoom_levels), [](const std::string zoom) {
277  return static_cast<int>(std::stold(zoom) * tile_size);
278  });
279  }
280 
281  title_music = v["title_music"].str();
282  lobby_music = v["lobby_music"].str();
283 
284  default_victory_music = utils::split(v["default_victory_music"].str());
285  default_defeat_music = utils::split(v["default_defeat_music"].str());
286 
287  if(auto i = v.optional_child("colors")){
288  using namespace game_config::colors;
289 
290  moved_orb_color = i["moved_orb_color"].str();
291  unmoved_orb_color = i["unmoved_orb_color"].str();
292  partial_orb_color = i["partial_orb_color"].str();
293  enemy_orb_color = i["enemy_orb_color"].str();
294  ally_orb_color = i["ally_orb_color"].str();
295  } // colors
296 
297  show_ally_orb = v["show_ally_orb"].to_bool(true);
298  show_enemy_orb = v["show_enemy_orb"].to_bool(false);
299  show_moved_orb = v["show_moved_orb"].to_bool(true);
300  show_partial_orb = v["show_partial_orb"].to_bool(true);
301  show_status_on_ally_orb = v["show_status_on_ally_orb"].to_bool(true);
302  show_unmoved_orb = v["show_unmoved_orb"].to_bool(true);
303  show_disengaged_orb = v["show_disengaged_orb"].to_bool(true);
304 
305  if(auto i = v.optional_child("images")){
306  using namespace game_config::images;
307 
308  game_title = i["game_title"].str();
309  game_title_background = i["game_title_background"].str();
310  game_logo = i["game_logo"].str();
311  game_logo_background = i["game_logo_background"].str();
312 
313  victory_laurel = i["victory_laurel"].str();
314  victory_laurel_hardest = i["victory_laurel_hardest"].str();
315  victory_laurel_easy = i["victory_laurel_easy"].str();
316 
317  orb = i["orb"].str();
318  orb_two_color = i["orb_two_color"].str();
319  energy = i["energy"].str();
320 
321  battery_icon = i["battery_icon"].str();
322  time_icon = i["time_icon"].str();
323 
324  flag = i["flag"].str();
325  flag_icon = i["flag_icon"].str();
326 
327  terrain_mask = i["terrain_mask"].str();
328  grid_top = i["grid_top"].str();
329  grid_bottom = i["grid_bottom"].str();
330  mouseover = i["mouseover"].str();
331  selected = i["selected"].str();
332  editor_brush = i["editor_brush"].str();
333  unreachable = i["unreachable"].str();
334  linger = i["linger"].str();
335 
336  observer = i["observer"].str();
337  tod_bright = i["tod_bright"].str();
338  tod_dark = i["tod_dark"].str();
339  level = i["level"].str();
340  ellipsis = i["ellipsis"].str();
341  missing = i["missing"].str();
342  blank = i["blank"].str();
343  } // images
344 
345  hp_bar_scaling = v["hp_bar_scaling"].to_double(0.666);
346  xp_bar_scaling = v["xp_bar_scaling"].to_double(0.5);
347 
348  foot_speed_prefix = utils::split(v["footprint_prefix"]);
349  foot_teleport_enter = v["footprint_teleport_enter"].str();
350  foot_teleport_exit = v["footprint_teleport_exit"].str();
351 
352  shroud_prefix = v["shroud_prefix"].str();
353  fog_prefix = v["fog_prefix"].str();
354 
356 
357  if(const config::attribute_value* a = v.get("flag_rgb")) {
358  flag_rgb = a->str();
359  }
360 
361  if(const config::attribute_value* a = v.get("unit_rgb")) {
362  unit_rgb = a->str();
363  }
364 
365  const auto parse_config_color_list = [&](
366  const std::string& key,
367  const color_t fallback)->std::vector<color_t>
368  {
369  std::vector<color_t> color_vec;
370 
371  for(const auto& s : utils::split(v[key].str())) {
372  try {
373  color_vec.push_back(color_t::from_hex_string(s));
374  } catch(const std::invalid_argument& e) {
375  ERR_NG << "Error parsing color list '" << key << "'.\n" << e.what();
376  color_vec.push_back(fallback);
377  }
378  }
379 
380  return color_vec;
381  };
382 
383  red_green_scale = parse_config_color_list("red_green_scale", {255, 255, 255});
384  red_green_scale_text = parse_config_color_list("red_green_scale_text", {255, 255, 255});
385  blue_white_scale = parse_config_color_list("blue_white_scale", {0 , 0 , 255});
386  blue_white_scale_text = parse_config_color_list("blue_white_scale_text", {0 , 0 , 255});
387 
388  server_list.clear();
389 
390  for(const config& server : v.child_range("server")) {
391  server_info sinf;
392  sinf.name = server["name"].str();
393  sinf.address = server["address"].str();
394  server_list.push_back(sinf);
395  }
396 
397  if(auto s = v.optional_child("sounds")) {
398  using namespace game_config::sounds;
399 
400  const auto load_attribute = [](const config& c, const std::string& key, std::string& member) {
401  if(c.has_attribute(key)) {
402  member = c[key].str();
403  }
404  };
405 
406  load_attribute(*s, "turn_bell", turn_bell);
407  load_attribute(*s, "timer_bell", timer_bell);
408  load_attribute(*s, "public_message", public_message);
409  load_attribute(*s, "private_message", private_message);
410  load_attribute(*s, "friend_message", friend_message);
411  load_attribute(*s, "server_message", server_message);
412  load_attribute(*s, "player_joins", player_joins);
413  load_attribute(*s, "player_leaves", player_leaves);
414  load_attribute(*s, "game_created", game_created);
415  load_attribute(*s, "game_user_arrive", game_user_arrive);
416  load_attribute(*s, "game_user_leave", game_user_leave);
417  load_attribute(*s, "ready_for_start", ready_for_start);
418  load_attribute(*s, "game_has_begun", game_has_begun);
419 
420  if(auto ss = s->optional_child("status")) {
421  using namespace game_config::sounds::status;
422 
423  load_attribute(*ss, "poisoned", poisoned);
424  load_attribute(*ss, "slowed", slowed);
425  load_attribute(*ss, "petrified", petrified);
426  }
427  }
428 }
429 
430 void add_color_info(const game_config_view& v, bool build_defaults)
431 {
432  if(build_defaults) {
433  default_colors.clear();
434  }
435 
436  for(const config& teamC : v.child_range("color_range")) {
437  const config::attribute_value* a1 = teamC.get("id"), *a2 = teamC.get("rgb");
438  if(!a1 || !a2) {
439  continue;
440  }
441 
442  std::string id = *a1;
443  std::vector<color_t> temp;
444 
445  for(const auto& s : utils::split(*a2)) {
446  try {
447  temp.push_back(color_t::from_hex_string(s));
448  } catch(const std::invalid_argument&) {
449  std::stringstream ss;
450  ss << "can't parse color string:\n" << teamC.debug() << "\n";
451  throw config::error(ss.str());
452  }
453  }
454 
455  team_rgb_range.emplace(id, color_range(temp));
456  team_rgb_name.emplace(id, teamC["name"].t_str());
457 
458  LOG_NG << "registered color range '" << id << "': " << team_rgb_range[id].debug();
459 
460  // Ggenerate palette of same name;
461  std::vector<color_t> tp = palette(team_rgb_range[id]);
462  if(!tp.empty()) {
463  team_rgb_colors.emplace(id, tp);
464  }
465 
466  if(build_defaults && teamC["default"].to_bool()) {
467  default_colors.push_back(*a1);
468  }
469  }
470 
471  for(const config &cp : v.child_range("color_palette")) {
472  for(const config::attribute& rgb : cp.attribute_range()) {
473  std::vector<color_t> temp;
474  for(const auto& s : utils::split(rgb.second)) {
475  try {
476  temp.push_back(color_t::from_hex_string(s));
477  } catch(const std::invalid_argument&) {
478  ERR_NG << "Invalid color in palette: " << s;
479  }
480  }
481 
482  team_rgb_colors.emplace(rgb.first, temp);
483  LOG_NG << "registered color palette: " << rgb.first;
484  }
485  }
486 }
487 
489 {
490  default_colors.clear();
491  team_rgb_colors.clear();
492  team_rgb_name.clear();
493  team_rgb_range.clear();
494 }
495 
496 const color_range& color_info(const std::string& name)
497 {
498  auto i = team_rgb_range.find(name);
499  if(i != team_rgb_range.end()) {
500  return i->second;
501  }
502 
503  std::vector<color_t> temp;
504  for(const auto& s : utils::split(name)) {
505  try {
506  temp.push_back(color_t::from_hex_string(s));
507  } catch(const std::invalid_argument&) {
508  throw config::error(_("Invalid color in range: ") + s);
509  }
510  }
511 
512  team_rgb_range.emplace(name, color_range(temp));
513  return color_info(name);
514 }
515 
516 const std::vector<color_t>& tc_info(const std::string& name)
517 {
518  auto i = team_rgb_colors.find(name);
519  if(i != team_rgb_colors.end()) {
520  return i->second;
521  }
522 
523  std::vector<color_t> temp;
524  for(const auto& s : utils::split(name)) {
525  try {
526  temp.push_back(color_t::from_hex_string(s));
527  } catch(const std::invalid_argument&) {
528  static std::vector<color_t> stv;
529  ERR_NG << "Invalid color in palette: " << s;
530  return stv;
531  }
532  }
533 
534  team_rgb_colors.emplace(name, temp);
535  return tc_info(name);
536 }
537 
538 color_t red_to_green(double val, bool for_text)
539 {
540  const std::vector<color_t>& color_scale = for_text ? red_green_scale_text : red_green_scale;
541 
542  const double val_scaled = std::clamp(0.01 * val, 0.0, 1.0);
543  const int lvl = std::nearbyint((color_scale.size() - 1) * val_scaled);
544 
545  return color_scale[lvl];
546 }
547 
548 color_t blue_to_white(double val, bool for_text)
549 {
550  const std::vector<color_t>& color_scale = for_text ? blue_white_scale_text : blue_white_scale;
551 
552  const double val_scaled = std::clamp(0.01 * val, 0.0, 1.0);
553  const int lvl = std::nearbyint((color_scale.size() - 1) * val_scaled);
554 
555  return color_scale[lvl];
556 }
557 
559 {
560  std::string ret = _("The Battle for Wesnoth") + " - " + revision;
561  return ret;
562 }
563 
564 } // game_config
A color range definition is made of four reference RGB colors, used for calculating conversions from ...
Definition: color_range.hpp:50
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
child_itors child_range(config_key_type key)
Definition: config.cpp:277
attribute_map::value_type attribute
Definition: config.hpp:301
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:691
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:389
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
std::vector< color_t > palette(const color_range &cr)
Creates a reference color palette from a color range.
Definition: color_range.cpp:85
std::size_t i
Definition: function.cpp:968
static lg::log_domain log_engine("engine")
#define ERR_NG
Definition: game_config.cpp:29
#define LOG_NG
Definition: game_config.cpp:28
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _(const char *str)
Definition: gettext.hpp:93
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
Standard logging facilities (interface).
General math utility functions.
Manage the empty-palette in the editor.
Definition: action.cpp:31
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 default_color_list
std::string selected_menu
std::string terrain_mask
std::string victory_laurel_hardest
std::string victory_laurel
std::string orb_two_color
std::string tod_bright
std::string time_icon
std::string selected
std::string app_icon
std::string deselected_menu
std::string observer
std::string ellipsis
std::string unchecked_menu
std::string game_title_background
std::string grid_top
std::string grid_bottom
std::string unreachable
std::string game_title
std::string game_logo
std::string game_logo_background
std::string wml_menu
std::string flag_icon
std::string editor_brush
std::string checked_menu
std::string mouseover
std::string battery_icon
std::string victory_laurel_easy
std::string tod_dark
std::string public_message
std::string private_message
const std::string menu_expand
std::string player_leaves
std::string server_message
std::string game_user_arrive
std::string turn_bell
const std::string menu_contract
std::string game_user_leave
const std::string checkbox_release
std::string timer_bell
std::string friend_message
const std::string menu_select
std::string ready_for_start
std::string game_has_begun
const std::string button_press
std::string game_created
std::string player_joins
const std::string slider_adjust
Game configuration data as global variables.
Definition: build_info.cpp:63
int rest_heal_amount
Definition: game_config.cpp:44
std::vector< std::string > default_defeat_music
std::map< std::string, color_range > team_rgb_range
Colors defined by WML [color_range] tags.
std::string flag_rgb
color_t blue_to_white(double val, bool for_text)
const std::size_t max_loop
The maximum number of hexes on a map and items in an array and also used as maximum in wml loops.
Definition: game_config.cpp:70
std::string get_default_title_string()
bool ignore_replay_errors
Definition: game_config.cpp:84
std::string foot_teleport_enter
int village_income
Definition: game_config.cpp:37
bool show_status_on_ally_orb
std::vector< color_t > red_green_scale_text
bool show_moved_orb
std::vector< std::string > foot_speed_prefix
const int gold_carryover_percentage
Default percentage gold carried over to the next scenario.
Definition: game_config.cpp:46
std::string foot_teleport_exit
std::string lobby_music
static std::vector< color_t > blue_white_scale_text
std::string fog_prefix
Definition: game_config.cpp:54
const std::vector< color_t > & tc_info(const std::string &name)
const bool & debug
Definition: game_config.cpp:91
std::vector< std::string > default_colors
std::string shroud_prefix
Definition: game_config.cpp:54
double hp_bar_scaling
Definition: game_config.cpp:61
bool disable_autosave
Definition: game_config.cpp:88
std::vector< server_info > server_list
Definition: game_config.cpp:72
int kill_experience
Definition: game_config.cpp:40
std::string unit_rgb
unsigned int tile_size
Definition: game_config.cpp:51
bool show_ally_orb
bool allow_insecure
Definition: game_config.cpp:74
static void add_color_info(const game_config_view &v, bool build_defaults)
std::map< std::string, t_string > team_rgb_name
bool show_disengaged_orb
std::vector< unsigned int > zoom_levels
Definition: game_config.cpp:56
bool show_partial_orb
const color_range & color_info(const std::string &name)
std::string title_music
std::string default_terrain
Definition: game_config.cpp:53
bool show_enemy_orb
unsigned lobby_network_timer
Definition: game_config.cpp:67
static std::vector< color_t > blue_white_scale
bool show_unmoved_orb
unsigned lobby_refresh
Definition: game_config.cpp:68
std::vector< std::string > default_victory_music
int combat_experience
Definition: game_config.cpp:41
void reset_color_info()
std::map< std::string, std::vector< color_t > > team_rgb_colors
const std::string revision
void set_debug(bool new_debug)
Definition: game_config.cpp:93
std::vector< color_t > red_green_scale
bool exit_at_end
Definition: game_config.cpp:86
void load_config(const config &v)
color_t red_to_green(double val, bool for_text)
Return a color corresponding to the value val red for val=0.0 to green for val=100....
double xp_bar_scaling
Definition: game_config.cpp:62
int village_support
Definition: game_config.cpp:38
severity
Definition: log.hpp:76
bool set_log_domain_severity(const std::string &name, int severity)
Definition: log.cpp:266
bool get_log_domain_severity(const std::string &name, int &severity)
Definition: log.cpp:290
std::vector< std::string > split(const config_attribute_value &val)
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
static color_t from_hex_string(const std::string &c)
Creates a new color_t object from a string variable in hex format.
Definition: color.cpp:62
std::string address
may include ':' followed by port number
Definition: game_config.hpp:72
mock_char c
static map_location::DIRECTION s
Some defines: VERSION, PACKAGE, MIN_SAVEGAME_VERSION.
#define e
#define a