The Battle for Wesnoth  1.19.5+dev
label.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "map/label.hpp"
17 #include "color.hpp"
18 #include "display.hpp"
19 #include "floating_label.hpp"
20 #include "formula/string_utils.hpp"
21 #include "game_board.hpp"
22 #include "game_data.hpp"
23 #include "resources.hpp"
24 #include "tooltips.hpp"
25 
26 /**
27  * Our definition of map labels being obscured is if the tile is obscured,
28  * or the tile below is obscured. This is because in the case where the tile
29  * itself is visible, but the tile below is obscured, the bottom half of the
30  * tile will still be shrouded, and the label being drawn looks weird.
31  */
32 inline bool is_shrouded(const display* disp, const map_location& loc)
33 {
34  return disp->shrouded(loc) || disp->shrouded(loc.get_direction(map_location::direction::south));
35 }
36 
37 /**
38  * Rather simple test for a hex being fogged.
39  * This only exists because is_shrouded() does. (The code looks nicer if
40  * the test for being fogged looks similar to the test for being shrouded.)
41  */
42 inline bool is_fogged(const display* disp, const map_location& loc)
43 {
44  return disp->fogged(loc);
45 }
46 
48  : team_(team)
49  , labels_()
50  , enabled_(true)
51  , categories_dirty(true)
52 {
53 }
54 
56  : team_(other.team_)
57  , labels_()
58  , enabled_(true)
59 {
60  config cfg;
61  other.write(cfg);
62  read(cfg);
63 }
64 
66 {
67  clear_all();
68 }
69 
71 {
72  if(this != &other) {
73  this->~map_labels();
74  new(this) map_labels(other);
75  }
76 
77  return *this;
78 }
79 
80 void map_labels::write(config& res) const
81 {
82  for(const auto& group : labels_) {
83  for(const auto& label : group.second) {
84  config item;
85  label.second.write(item);
86 
87  res.add_child("label", std::move(item));
88  }
89  }
90 }
91 
92 void map_labels::read(const config& cfg)
93 {
94  clear_all();
95 
96  for(const config& i : cfg.child_range("label")) {
97  add_label(*this, i);
98  }
99 
101 }
102 
103 terrain_label* map_labels::get_label_private(const map_location& loc, const std::string& team_name)
104 {
105  auto label_map = labels_.find(team_name);
106  if(label_map != labels_.end()) {
107  auto itor = label_map->second.find(loc);
108  if(itor != label_map->second.end()) {
109  return &itor->second;
110  }
111  }
112 
113  return nullptr;
114 }
115 
117 {
118  const terrain_label* res = get_label(loc, team_name());
119 
120  // No such team label. Try to find global label, except if that's what we just did.
121  // NOTE: This also avoid infinite recursion
122  if(res == nullptr && !team_name().empty()) {
123  return get_label(loc, "");
124  }
125 
126  return res;
127 }
128 
129 const std::string& map_labels::team_name() const
130 {
131  if(team_) {
132  return team_->team_name();
133  }
134 
135  static const std::string empty;
136  return empty;
137 }
138 
140 {
141  if(team_ != team) {
142  team_ = team;
143  categories_dirty = true;
144  }
145 }
146 
148  const t_string& text,
149  const int creator,
150  const std::string& team_name,
151  const color_t color,
152  const bool visible_in_fog,
153  const bool visible_in_shroud,
154  const bool immutable,
155  const std::string& category,
156  const t_string& tooltip)
157 {
158  terrain_label* res = nullptr;
159 
160  // See if there is already a label in this location for this team.
161  // (We do not use get_label_private() here because we might need
162  // the label_map as well as the terrain_label.)
163  team_label_map::iterator current_label_map = labels_.find(team_name);
164  label_map::iterator current_label;
165 
166  if(current_label_map != labels_.end() &&
167  (current_label = current_label_map->second.find(loc)) != current_label_map->second.end())
168  {
169  // Found old checking if need to erase it
170  if(text.str().empty()) {
171  // Erase the old label.
172  current_label_map->second.erase(current_label);
173 
174  // Restore the global label in the same spot, if any.
175  if(terrain_label* global_label = get_label_private(loc, "")) {
176  global_label->recalculate();
177  }
178  } else {
179  current_label->second.update_info(
180  text, creator, tooltip, team_name, color, visible_in_fog, visible_in_shroud, immutable, category);
181 
182  res = &current_label->second;
183  }
184  } else if(!text.str().empty()) {
185  // See if we will be replacing a global label.
186  terrain_label* global_label = get_label_private(loc, "");
187 
188  // Add the new label.
189  res = add_label(
190  *this, text, creator, team_name, loc, color, visible_in_fog, visible_in_shroud, immutable, category, tooltip);
191 
192  // Hide the old label.
193  if(global_label != nullptr) {
194  global_label->recalculate();
195  }
196  }
197 
198  categories_dirty = true;
199  return res;
200 }
201 
202 template<typename... T>
204 {
205  categories_dirty = true;
206 
207  terrain_label t(std::forward<T>(args)...);
208  return &(*labels_[t.team_name()].emplace(t.location(), std::move(t)).first).second;
209 }
210 
211 void map_labels::clear(const std::string& team_name, bool force)
212 {
214  if(i != labels_.end()) {
215  clear_map(i->second, force);
216  }
217 
218  i = labels_.find("");
219  if(i != labels_.end()) {
220  clear_map(i->second, force);
221  }
222 
223  categories_dirty = true;
224 }
225 
226 void map_labels::clear_map(label_map& m, bool force)
227 {
228  label_map::iterator i = m.begin();
229  while(i != m.end()) {
230  if(!i->second.immutable() || force) {
231  m.erase(i++);
232  } else {
233  ++i;
234  }
235  }
236 
237  categories_dirty = true;
238 }
239 
241 {
242  labels_.clear();
243 }
244 
246 {
247  for(auto& m : labels_) {
248  for(auto& l : m.second) {
249  l.second.recalculate();
250  }
251  }
252 }
253 
254 void map_labels::enable(bool is_enabled)
255 {
256  if(is_enabled != enabled_) {
257  enabled_ = is_enabled;
259  }
260 }
261 
262 /**
263  * Returns whether or not a global (non-team) label can be shown at a
264  * specified location.
265  * (Global labels are suppressed in favor of team labels.)
266  */
268 {
269  if(team_ == nullptr) {
270  // We're in the editor. All global labels can be shown.
271  return true;
272  }
273 
274  const team_label_map::const_iterator glabels = labels_.find(team_name());
275  return glabels == labels_.end() || glabels->second.find(loc) == glabels->second.end();
276 }
277 
279 {
280  for(auto& m : labels_) {
281  for(auto& l : m.second) {
282  l.second.calculate_shroud();
283  }
284  }
285 }
286 
287 const std::vector<std::string>& map_labels::all_categories() const
288 {
289  if(categories_dirty) {
290  categories_dirty = false;
291  categories.clear();
292  categories.push_back("team");
293 
294  for(const team& t : resources::gameboard->teams()) {
295  categories.push_back("side:" + std::to_string(t.side()));
296  }
297 
298  std::set<std::string> unique_cats;
299  for(const auto& m : labels_) {
300  for(const auto& l : m.second) {
301  if(l.second.category().empty()) {
302  continue;
303  }
304 
305  unique_cats.insert("cat:" + l.second.category());
306  }
307  }
308 
309  std::copy(unique_cats.begin(), unique_cats.end(), std::back_inserter(categories));
310  }
311 
312  return categories;
313 }
314 
315 /** Create a new label. */
317  const t_string& text,
318  const int creator,
319  const std::string& team_name,
320  const map_location& loc,
321  const color_t color,
322  const bool visible_in_fog,
323  const bool visible_in_shroud,
324  const bool immutable,
325  const std::string& category,
326  const t_string& tooltip)
327  : handle_(0)
328  , text_(text)
329  , tooltip_(tooltip)
330  , category_(category)
331  , team_name_(team_name)
332  , visible_in_fog_(visible_in_fog)
333  , visible_in_shroud_(visible_in_shroud)
334  , immutable_(immutable)
335  , creator_(creator)
336  , color_(color)
337  , parent_(&parent)
338  , loc_(loc)
339 {
340  recalculate();
341 }
342 
343 /** Load label from config. */
345  : handle_(0)
346  , tooltip_handle_(0)
347  , text_()
348  , tooltip_()
349  , team_name_()
350  , visible_in_fog_(true)
351  , visible_in_shroud_(false)
352  , immutable_(true)
353  , creator_(-1)
354  , color_()
355  , parent_(&parent)
356  , loc_()
357 {
358  read(cfg);
359 }
360 
362  : handle_(l.handle_)
363  , tooltip_handle_(l.tooltip_handle_)
364  , text_(l.text_)
365  , tooltip_(l.tooltip_)
366  , category_(l.category_)
367  , team_name_(l.team_name_)
368  , visible_in_fog_(l.visible_in_fog_)
369  , visible_in_shroud_(l.visible_in_shroud_)
370  , immutable_(l.immutable_)
371  , creator_(l.creator_)
372  , color_(l.color_)
373  , parent_(l.parent_)
374  , loc_(l.loc_)
375 {
376  l.handle_ = 0;
377  l.tooltip_handle_ = 0;
378 }
379 
381 {
382  clear();
383 }
384 
385 void terrain_label::read(const config& cfg)
386 {
387  const variable_set& vs = *resources::gamedata;
388 
389  loc_ = map_location(cfg, &vs);
391 
392  std::string tmp_color = cfg["color"];
393 
394  text_ = cfg["text"];
395  tooltip_ = cfg["tooltip"];
396  team_name_ = cfg["team_name"].str();
397  visible_in_fog_ = cfg["visible_in_fog"].to_bool(true);
398  visible_in_shroud_ = cfg["visible_in_shroud"].to_bool();
399  immutable_ = cfg["immutable"].to_bool(true);
400  category_ = cfg["category"].str();
401 
402  int side = cfg["side"].to_int(-1);
403  if(side >= 0) {
404  creator_ = side - 1;
405  } else if(cfg["side"].str() == "current") {
406  config::attribute_value current_side = vs.get_variable_const("side_number");
407  if(!current_side.empty()) {
408  creator_ = current_side.to_int();
409  }
410  }
411 
412  // Not moved to rendering, as that would depend on variables at render-time
414 
416  tmp_color = utils::interpolate_variables_into_string(tmp_color, vs);
417 
418  if(!tmp_color.empty()) {
419  try {
420  color = color_t::from_rgb_string(tmp_color);
421  } catch(const std::invalid_argument&) {
422  // Prior to the color_t conversion, labels were written to savefiles with an alpha key, despite alpha not
423  // being accepted in color=. Because of this, this enables the loading of older saves without an exception
424  // throwing.
425  color = color_t::from_rgba_string(tmp_color);
426  }
427  }
428 
429  color_ = color;
430 }
431 
432 void terrain_label::write(config& cfg) const
433 {
434  loc_.write(cfg);
435 
436  cfg["text"] = text();
437  cfg["tooltip"] = tooltip();
438  cfg["team_name"] = (this->team_name());
439  cfg["color"] = color_.to_rgb_string();
440  cfg["visible_in_fog"] = visible_in_fog_;
441  cfg["visible_in_shroud"] = visible_in_shroud_;
442  cfg["immutable"] = immutable_;
443  cfg["category"] = category_;
444  cfg["side"] = creator_ + 1;
445 }
446 
448  const int creator,
449  const t_string& tooltip,
450  const std::string& team_name,
451  const color_t color)
452 {
453  color_ = color;
454  text_ = text;
455  tooltip_ = tooltip;
457  creator_ = creator;
458 
459  recalculate();
460 }
461 
463  const int creator,
464  const t_string& tooltip,
465  const std::string& team_name,
466  const color_t color,
467  const bool visible_in_fog,
468  const bool visible_in_shroud,
469  const bool immutable,
470  const std::string& category)
471 {
476 
478 }
479 
481 {
482  if(handle_) {
484  }
485 
486  if(tooltip_.empty() || hidden()) {
488  tooltip_handle_ = 0;
489  return;
490  }
491 
492  // tooltips::update_tooltip(tooltip_handle, get_rect(), tooltip_.str(), "", true);
493 
494  if(tooltip_handle_) {
496  } else {
498  }
499 }
500 
501 SDL_Rect terrain_label::get_rect() const
502 {
504  if(!disp) {
505  return sdl::empty_rect;
506  }
507 
508  SDL_Rect res = disp->get_location_rect(loc_);
509  res.x += disp->hex_size() / 4;
510  res.w -= disp->hex_size() / 2;
511 
512  return res;
513 }
514 
515 static int scale_to_map_zoom(int val)
516 {
517  return val * std::max(1.0, display::get_zoom_factor());
518 }
519 
521 {
523  if(!disp) {
524  return;
525  }
526 
527  if(text_.empty() && tooltip_.empty()) {
528  return;
529  }
530 
531  clear();
532 
533  if(!viewable(*disp)) {
534  return;
535  }
536 
537  // Note: the y part of loc_nextx is not used at all.
540  const int xloc = (disp->get_location(loc_).x + disp->get_location(loc_nextx).x * 2) / 3;
541  const int yloc = disp->get_location(loc_nexty).y - scale_to_map_zoom(font::SIZE_NORMAL);
542 
543  // If a color is specified don't allow to override it with markup. (prevents faking map labels for example)
544  // FIXME: @todo Better detect if it's team label and not provided by the scenario.
545  bool use_markup = color_ == font::LABEL_COLOR;
546 
547  font::floating_label flabel(text_.str());
549  flabel.set_color(color_);
550  flabel.set_position(xloc, yloc);
551  flabel.set_clip_rect(disp->map_outside_area());
555  flabel.use_markup(use_markup);
556 
558 
560 }
561 
562 /**
563  * This is a lightweight test used to see if labels are revealed as a result
564  * of unit actions (i.e. fog/shroud clearing). It should not contain any tests
565  * that are invariant during unit movement (disregarding potential WML events);
566  * those belong in visible().
567  */
569 {
571  if(!disp) {
572  return false;
573  }
574 
575  // Respect user's label preferences
576  std::string category = "cat:" + category_;
577  std::string creator = "side:" + std::to_string(creator_ + 1);
578  const std::vector<std::string>& hidden_categories = disp->context().hidden_label_categories();
579 
580  if(std::find(hidden_categories.begin(), hidden_categories.end(), category) != hidden_categories.end()) {
581  return true;
582  }
583 
584  if(creator_ >= 0 &&
585  std::find(hidden_categories.begin(), hidden_categories.end(), creator) != hidden_categories.end())
586  {
587  return true;
588  }
589 
590  if(!team_name().empty() &&
591  std::find(hidden_categories.begin(), hidden_categories.end(), "team") != hidden_categories.end())
592  {
593  return true;
594  }
595 
596  // Fog can hide some labels.
597  if(!visible_in_fog_ && is_fogged(disp, loc_)) {
598  return true;
599  }
600 
601  // Shroud can hide some labels.
602  if(!visible_in_shroud_ && is_shrouded(disp, loc_)) {
603  return true;
604  }
605 
606  return false;
607 }
608 
609 /**
610  * This is a test used to see if we should bother with the overhead of actually
611  * creating a label. Conditions that can change during unit movement (disregarding
612  * potential WML events) should not be listed here; they belong in hidden().
613  */
614 bool terrain_label::viewable(const display& disp) const
615 {
616  if(!parent_->enabled()) {
617  return false;
618  }
619 
620  // In the editor, all labels are viewable.
621  if(disp.in_editor()) {
622  return true;
623  }
624 
625  // Observers are not privvy to team labels.
626  const bool can_see_team_labels = !disp.context().is_observer();
627 
628  // Global labels are shown unless covered by a team label.
629  if(team_name_.empty()) {
630  return !can_see_team_labels || parent_->visible_global_label(loc_);
631  }
632 
633  // Team labels are only shown to members of the team.
634  return can_see_team_labels && parent_->team_name() == team_name_;
635 }
636 
638 {
639  if(handle_) {
641  handle_ = 0;
642  }
643 
644  if(tooltip_handle_) {
646  tooltip_handle_ = 0;
647  }
648 }
double t
Definition: astarsearch.cpp:63
Variant for storing WML attributes.
bool empty() const
Tests for an attribute that either was never set or was set to "".
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
child_itors child_range(config_key_type key)
Definition: config.cpp:272
config & add_child(config_key_type key)
Definition: config.cpp:440
bool is_observer() const
Check if we are an observer in this game.
virtual const std::vector< std::string > & hidden_label_categories() const =0
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:97
point get_location(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:679
static int hex_size()
Function which returns the size of a hex in pixels (from top tip to bottom tip or left edge to right ...
Definition: display.hpp:267
static double get_zoom_factor()
Returns the current zoom factor.
Definition: display.hpp:270
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:674
rect map_outside_area() const
Returns the available area for a map, this may differ from the above.
Definition: display.cpp:521
virtual bool in_editor() const
Definition: display.hpp:219
const display_context & context() const
Definition: display.hpp:193
rect get_location_rect(const map_location &loc) const
Returns the on-screen rect corresponding to a loc.
Definition: display.cpp:687
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:111
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:669
void set_position(double xpos, double ypos)
void set_color(const color_t &color)
void set_clip_rect(const SDL_Rect &r)
void set_scroll_mode(LABEL_SCROLL_MODE scroll)
void set_font_size(int font_size)
void write(config &res) const
Definition: label.cpp:80
void clear_map(label_map &, bool)
Definition: label.cpp:226
const std::vector< std::string > & all_categories() const
Definition: label.cpp:287
const team * team_
Definition: label.hpp:97
bool enabled() const
Definition: label.hpp:67
const std::string & team_name() const
Definition: label.cpp:129
bool visible_global_label(const map_location &) const
Returns whether or not a global (non-team) label can be shown at a specified location.
Definition: label.cpp:267
terrain_label * add_label(T &&... args)
Definition: label.cpp:203
const terrain_label * set_label(const map_location &loc, const t_string &text, const int creator=-1, const std::string &team="", const color_t color=font::NORMAL_COLOR, const bool visible_in_fog=true, const bool visible_in_shroud=false, const bool immutable=false, const std::string &category="", const t_string &tooltip="")
Definition: label.cpp:147
const terrain_label * get_label(const map_location &loc, const std::string &team_name) const
Definition: label.hpp:48
void recalculate_shroud()
Definition: label.cpp:278
terrain_label * get_label_private(const map_location &loc, const std::string &team_name)
Definition: label.cpp:103
void clear_all()
Definition: label.cpp:240
map_labels & operator=(const map_labels &)
Definition: label.cpp:70
void enable(bool is_enabled)
Definition: label.cpp:254
void set_team(const team *)
Definition: label.cpp:139
void clear(const std::string &, bool force)
Definition: label.cpp:211
bool enabled_
Definition: label.hpp:100
team_label_map labels_
Definition: label.hpp:99
std::vector< std::string > categories
Definition: label.hpp:102
bool categories_dirty
Definition: label.hpp:103
map_labels(const map_labels &)
Definition: label.cpp:55
void recalculate_labels()
Definition: label.cpp:245
~map_labels()
Definition: label.cpp:65
std::map< map_location, terrain_label > label_map
Definition: label.hpp:35
void read(const config &cfg)
Definition: label.cpp:92
bool empty() const
Definition: tstring.hpp:194
const std::string & str() const
Definition: tstring.hpp:198
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:75
const std::string & team_name() const
Definition: team.hpp:282
To store label data Class implements logic for rendering.
Definition: label.hpp:111
~terrain_label()
Definition: label.cpp:380
terrain_label(const terrain_label &)=delete
Delete copy ctor and assignment ops.
bool visible_in_shroud() const
Definition: label.hpp:169
bool visible_in_fog_
Definition: label.hpp:223
t_string tooltip_
Definition: label.hpp:218
bool immutable() const
Definition: label.hpp:174
int creator() const
Definition: label.hpp:149
std::string category_
Definition: label.hpp:220
color_t color_
Definition: label.hpp:228
void update_info(const t_string &, const int creator, const t_string &, const std::string &, const color_t)
Definition: label.cpp:447
bool visible_in_fog() const
Definition: label.hpp:164
const t_string & tooltip() const
Definition: label.hpp:144
std::string team_name_
Definition: label.hpp:221
int tooltip_handle_
Definition: label.hpp:215
void write(config &res) const
Definition: label.cpp:432
map_location loc_
Definition: label.hpp:231
int creator_
Definition: label.hpp:226
const map_labels * parent_
Definition: label.hpp:230
SDL_Rect get_rect() const
Definition: label.cpp:501
bool immutable_
Definition: label.hpp:225
bool hidden() const
This is a lightweight test used to see if labels are revealed as a result of unit actions (i....
Definition: label.cpp:568
void clear()
Definition: label.cpp:637
const color_t & color() const
Definition: label.hpp:184
void recalculate()
Definition: label.cpp:520
bool viewable(const display &disp) const
This is a test used to see if we should bother with the overhead of actually creating a label.
Definition: label.cpp:614
const std::string & category() const
Definition: label.hpp:159
bool visible_in_shroud_
Definition: label.hpp:224
const t_string & text() const
Definition: label.hpp:139
void calculate_shroud()
Definition: label.cpp:480
void read(const config &cfg)
Definition: label.cpp:385
const std::string & team_name() const
Definition: label.hpp:154
t_string text_
Definition: label.hpp:217
virtual config::attribute_value get_variable_const(const std::string &id) const =0
map_display and display: classes which take care of displaying the map and game-data on the screen.
std::size_t i
Definition: function.cpp:1028
map_location loc_
std::string label
What to show in the filter's drop-down list.
Definition: manager.cpp:200
std::string tooltip
Shown when hovering over an entry in the filter's drop-down list.
Definition: manager.cpp:202
bool is_shrouded(const display *disp, const map_location &loc)
Our definition of map labels being obscured is if the tile is obscured, or the tile below is obscured...
Definition: label.cpp:32
static int scale_to_map_zoom(int val)
Definition: label.cpp:515
bool is_fogged(const display *disp, const map_location &loc)
Rather simple test for a hex being fogged.
Definition: label.cpp:42
const color_t LABEL_COLOR
int add_floating_label(const floating_label &flabel)
add a label floating on the screen above everything else.
void show_floating_label(int handle, bool value)
hides or shows a floating label
void remove_floating_label(int handle, const std::chrono::milliseconds &fadeout)
removes the floating label given by 'handle' from the screen
const int SIZE_NORMAL
Definition: constants.cpp:20
@ ANCHOR_LABEL_MAP
game_board * gameboard
Definition: resources.cpp:20
game_data * gamedata
Definition: resources.cpp:22
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:30
int add_tooltip(const SDL_Rect &origin, const std::string &message, const std::string &action)
Definition: tooltips.cpp:299
void remove_tooltip(int id)
Definition: tooltips.cpp:289
bool update_tooltip(int id, const SDL_Rect &origin, const std::string &message)
Definition: tooltips.cpp:267
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with '$' in the string 'str' with the equivalent ...
t_string interpolate_variables_into_tstring(const t_string &tstr, const variable_set &variables)
Function that does the same as the above, for t_stringS.
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
static color_t from_rgb_string(std::string_view c)
Creates a new opaque color_t object from a string variable in "R,G,B" format.
Definition: color.cpp:44
std::string to_rgb_string() const
Returns the stored color as an "R,G,B" string.
Definition: color.cpp:117
static color_t from_rgba_string(std::string_view c)
Creates a new color_t object from a string variable in "R,G,B,A" format.
Definition: color.cpp:23
Encapsulates the map of the game.
Definition: location.hpp:45
map_location get_direction(direction dir, unsigned int n=1u) const
Definition: location.cpp:364
void write(config &cfg) const
Definition: location.cpp:225