The Battle for Wesnoth  1.15.6+dev
tod_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Eugen Jiresch
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 #include "tod_manager.hpp"
16 
17 #include "display_context.hpp"
19 #include "game_data.hpp"
20 #include "gettext.hpp"
21 #include "log.hpp"
22 #include "map/map.hpp"
23 #include "play_controller.hpp"
24 #include "random.hpp"
25 #include "units/unit.hpp"
26 #include "units/alignment.hpp"
27 #include "units/abilities.hpp"
28 #include "resources.hpp"
29 
30 #include <algorithm>
31 #include <iterator>
32 #include "utils/functional.hpp"
33 #include "actions/attack.hpp"
34 
35 static lg::log_domain log_engine("engine");
36 #define LOG_NG LOG_STREAM(info, log_engine)
37 
38 tod_manager::tod_manager(const config& scenario_cfg):
39  currentTime_(0),
40  times_(),
41  areas_(),
42  liminal_bonus_(25),
43  turn_(scenario_cfg["turn_at"].to_int(1)),
44  num_turns_(scenario_cfg["turns"].to_int(-1)),
45  has_turn_event_fired_(!scenario_cfg["it_is_a_new_turn"].to_bool(true)),
46  has_tod_bonus_changed_ (false),
47  has_cfg_liminal_bonus_ (false)
48 {
49  // ? : operator doesn't work in this case.
50  if (scenario_cfg["current_time"].to_int(-17403) == -17403)
51  random_tod_ = scenario_cfg["random_start_time"];
52  else
53  random_tod_ = false;
54 
55  time_of_day::parse_times(scenario_cfg,times_);
57  if (scenario_cfg.has_attribute("liminal_bonus")) {
58  liminal_bonus_ = scenario_cfg["liminal_bonus"].to_int(liminal_bonus_);
60  }
61  //We need to call parse_times before fix_time_index because otherwise the first parameter will always be 0.
62  currentTime_ = fix_time_index(times_.size(), scenario_cfg["current_time"].to_int(0));
63 
64 }
65 
67 {
68  //process the random_start_time string, which can be boolean yes/no true/false or a
69  //comma-separated string of integers >= 1 referring to the times_ array indices
70  std::vector<std::string> output_strings = utils::split(random_tod_.str());
71  std::vector<int> output;
72 
73  try
74  {
75  std::transform(output_strings.begin(), output_strings.end(), std::back_inserter(output),
76  [](const std::string& str)
77  {
78  return std::stoi(str);
79  });
80  }
81  catch (const std::invalid_argument&)
82  {
83  // This happens if the random_start_time string is a boolean.
84  // Simply ignore the exception.
85  }
86 
87  // Remove non-positive times
88  output.erase(
89  std::remove_if(
90  output.begin(),
91  output.end(),
92  [](int time){ return time <= 0; }),
93  output.end());
94 
95  if(!output.empty())
96  {
97  int chosen = output[r.next_random() % output.size()];
98  currentTime_ = fix_time_index(times_.size(), chosen);
99  r.next_random();
100  }
101  else if (random_tod_.to_bool(false))
102  {
104  }
105  random_tod_ = false;
106 }
108 {
109  config cfg;
110  cfg["turn_at"] = turn_;
111  cfg["turns"] = num_turns_;
112  //this 'if' is for the editor.
113  if(times_.size() != 0) {
114  cfg["current_time"] = currentTime_;
115  }
116  cfg["random_start_time"] = random_tod_;
117  cfg["it_is_a_new_turn"] = !has_turn_event_fired_;
119  cfg["liminal_bonus"] = liminal_bonus_;
120 
121  for(const time_of_day& tod : times_) {
122  tod.write(cfg.add_child("time"));
123  }
124 
125  for(const area_time_of_day& a_tod : areas_) {
126  config& area = cfg.add_child("time_area");
127 
128  // If no ranges, then use hexes to generate ranges
129  if(a_tod.xsrc.empty() && a_tod.ysrc.empty()) {
130  write_location_range(a_tod.hexes, area);
131  } else {
132  area["x"] = a_tod.xsrc;
133  area["y"] = a_tod.ysrc;
134  }
135 
136  for(const time_of_day& tod : a_tod.times) {
137  // Don't write the stub default ToD if it happens to be present.
138  if(tod.id != "nulltod") {
139  tod.write(area.add_child("time"));
140  }
141  }
142 
143  area["current_time"] = a_tod.currentTime;
144 
145  if(!a_tod.id.empty()) {
146  area["id"] = a_tod.id;
147  }
148  }
149 
150  return cfg;
151 }
152 
153 static const time_of_day& dummytime()
154 {
155  static time_of_day* pdummy = new time_of_day();
156  return *pdummy;
157 }
158 
160 {
162 }
163 
165 {
166  assert(index < static_cast<int>(areas_.size()) );
167  return areas_[index].currentTime;
168 }
169 
171 {
172  if ( loc != map_location::null_location() ) {
173  for ( std::vector<area_time_of_day>::const_reverse_iterator
174  i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i )
175  {
176  if (i->hexes.find(loc) != i->hexes.end())
177  return i->currentTime;
178  }
179  }
180 
181  return currentTime_;
182 }
183 
184 const std::vector<time_of_day>& tod_manager::times(const map_location& loc) const
185 {
186  if ( loc != map_location::null_location() ) {
187  for ( std::vector<area_time_of_day>::const_reverse_iterator
188  i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i )
189  {
190  if (i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
191  return i->times;
192  }
193  }
194 
195  return times_;
196 }
197 
198 const time_of_day& tod_manager::get_time_of_day(const map_location& loc, int n_turn) const
199 {
200  if(n_turn == 0)
201  n_turn = turn_;
202 
203  if ( loc != map_location::null_location() )
204  {
205  for ( std::vector<area_time_of_day>::const_reverse_iterator
206  i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i )
207  {
208  if (i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
209  return get_time_of_day_turn(i->times, n_turn, i->currentTime);
210  }
211  }
212 
213  return get_time_of_day_turn(times_, n_turn, currentTime_);
214 }
215 
216 const time_of_day tod_manager::get_illuminated_time_of_day(const unit_map & units, const gamemap & map, const map_location& loc, int for_turn) const
217 {
218  // get ToD ignoring illumination
219  time_of_day tod = get_time_of_day(loc, for_turn);
220 
221  if ( map.on_board_with_border(loc) )
222  {
223  // Now add terrain illumination.
224  const int terrain_light = map.get_terrain_info(loc).light_bonus(tod.lawful_bonus);
225 
226  std::vector<int> mod_list;
227  std::vector<int> max_list;
228  std::vector<int> min_list;
229  int most_add = 0;
230  int most_sub = 0;
231 
232  // Find the "illuminates" effects from units that can affect loc.
233  std::array<map_location, 7> locs;
234  locs[0] = loc;
235  get_adjacent_tiles(loc, locs.data() + 1); // start at [1]
236  for ( std::size_t i = 0; i < locs.size(); ++i ) {
237  const unit_map::const_iterator itor = units.find(locs[i]);
238  if (itor != units.end() && !itor->incapacitated())
239  {
240  unit_ability_list illum = itor->get_abilities("illuminates");
241  if(!illum.empty()) {
242  unit_abilities::effect illum_effect(illum, terrain_light, false);
243  const int unit_mod = illum_effect.get_composite_value();
244 
245  // Record this value.
246  mod_list.push_back(unit_mod);
247  max_list.push_back(illum.highest("max_value").first);
248  min_list.push_back(illum.lowest("min_value").first);
249  if ( unit_mod > most_add )
250  most_add = unit_mod;
251  else if ( unit_mod < most_sub )
252  most_sub = unit_mod;
253  }
254  }
255  }
256  const bool net_darker = most_add < -most_sub;
257 
258  // Apply each unit's effect, tracking the best result.
259  int best_result = terrain_light;
260  const int base_light = terrain_light + (net_darker ? most_add : most_sub);
261  for ( std::size_t i = 0; i != mod_list.size(); ++i ) {
262  int result = bounded_add( base_light, mod_list[i], max_list[i], min_list[i] );
263 
264  if ( net_darker && result < best_result )
265  best_result = result;
266  else if ( !net_darker && result > best_result )
267  best_result = result;
268  }
269 
270  // Update the object we will return.
271  tod.bonus_modified = best_result - tod.lawful_bonus;
272  tod.lawful_bonus = best_result;
273  }
274 
275  return tod;
276 }
277 
278 
280 {
281  return !random_start_time.empty()
282  && utils::string_bool(random_start_time, true);
283 }
284 
286 {
287  std::vector<time_of_day> new_scedule;
288  time_of_day::parse_times(time_cfg, new_scedule);
289  replace_schedule(new_scedule);
290 }
291 
292 void tod_manager::replace_schedule(const std::vector<time_of_day>& schedule)
293 {
294  if(times_.empty() || schedule.empty() || times_[currentTime_].lawful_bonus != schedule.front().lawful_bonus) {
295  has_tod_bonus_changed_ = true;
296  }
297 
298  times_ = schedule;
299  currentTime_ = 0;
300 }
301 
302 void tod_manager::replace_area_locations(int area_index, const std::set<map_location>& locs)
303 {
304  assert(area_index < static_cast<int>(areas_.size()));
305  areas_[area_index].hexes = locs;
306  has_tod_bonus_changed_ = true;
307 }
308 
309 void tod_manager::replace_local_schedule(const std::vector<time_of_day>& schedule, int area_index)
310 {
311  assert(area_index < static_cast<int>(areas_.size()));
312  area_time_of_day& area = areas_[area_index];
313 
314  if(area.times.empty() || schedule.empty())
315  {
316  //If one of those is empty then their 'prievious' time of day might depend on other areas_,
317  //its better to just assume the illimination has changes than to do the explicit computation.
318  has_tod_bonus_changed_ = true;
319  }
320  else if(area.times[area.currentTime].lawful_bonus != schedule.front().lawful_bonus)
321  {
322  // the current illimination on these tiles has changes.
323  has_tod_bonus_changed_ = true;
324  }
325  area.times = schedule;
326  area.currentTime = 0;
327 }
328 
329 void tod_manager::set_area_id(int area_index, const std::string& id)
330 {
331  assert(area_index < static_cast<int>(areas_.size()));
332  areas_[area_index].id = id;
333 }
334 
335 std::vector<std::string> tod_manager::get_area_ids() const
336 {
337  std::vector<std::string> areas;
338  for (const area_time_of_day& area : areas_) {
339  areas.push_back(area.id);
340  }
341  return areas;
342 }
343 
344 const std::set<map_location>& tod_manager::get_area_by_id(const std::string& id) const
345 {
346  for (const area_time_of_day& area : areas_) {
347  if (area.id == id) {
348  return area.hexes;
349  }
350  }
351  static const std::set<map_location> res;
352  return res;
353 }
354 
355 const std::set<map_location>& tod_manager::get_area_by_index(int index) const
356 {
357  return areas_[index].hexes;
358 }
359 
360 void tod_manager::add_time_area(const gamemap & map, const config& cfg)
361 {
362  areas_.emplace_back();
363  area_time_of_day &area = areas_.back();
364  area.id = cfg["id"].str();
365  area.xsrc = cfg["x"].str();
366  area.ysrc = cfg["y"].str();
367  area.currentTime = cfg["current_time"].to_int(0);
368  const std::vector<map_location>& locs (map.parse_location_range(area.xsrc, area.ysrc, true));
369  area.hexes.insert(locs.begin(), locs.end());
370  time_of_day::parse_times(cfg, area.times);
371  has_tod_bonus_changed_ = true;
372 }
373 
374 void tod_manager::add_time_area(const std::string& id, const std::set<map_location>& locs,
375  const config& time_cfg)
376 {
377  areas_.emplace_back();
378  area_time_of_day& area = areas_.back();
379  area.id = id;
380  area.hexes = locs;
381  area.currentTime = time_cfg["current_time"].to_int(0);
382  time_of_day::parse_times(time_cfg, area.times);
383  has_tod_bonus_changed_ = true;
384 }
385 
387 {
388  if(area_id.empty()) {
389  areas_.clear();
390  } else {
391  // search for all time areas that match the id.
393  while(i != areas_.end()) {
394  if((*i).id == area_id) {
395  i = areas_.erase(i);
396  } else {
397  ++i;
398  }
399  }
400  }
401  has_tod_bonus_changed_ = true;
402 }
403 
404 void tod_manager::remove_time_area(int area_index)
405 {
406  assert(area_index < static_cast<int>(areas_.size()));
407  areas_.erase(areas_.begin() + area_index);
408  has_tod_bonus_changed_ = true;
409 }
410 
411 const time_of_day& tod_manager::get_time_of_day_turn(const std::vector<time_of_day>& times, int nturn, const int current_time) const
412 {
413  if(times.empty()) {
414  return dummytime();
415  }
416  const int time = calculate_time_index_at_turn(times.size(), nturn, current_time);
417  return times[time];
418 }
419 
421 {
422  num_turns_ = std::max<int>(utils::apply_modifier(num_turns_,mod,0),-1);
423 }
425 {
426  num_turns_ = std::max<int>(num, -1);
427 }
428 
430 {
431  if(resources::controller->current_team().is_local()) {
432  //the currently active side informs the mp server about the turn change.
433  //NOTE: The current implementation does not guarnateee that the server gets informed
434  // about those changes in 100% of cases. But that is ok because the information is only
435  // used to display the turn limit in the lobby (as opposed to things that cause OOS).
437  "change_turns_wml", config {
438  "current", turn_,
439  "max", num_turns_,
440  },
441  });
442  }
443 }
445 {
446  modify_turns(mod);
448 }
450 {
451  set_number_of_turns(num);
453 }
454 
455 void tod_manager::set_turn(const int num, game_data* vars, const bool increase_limit_if_needed)
456 {
457  has_tod_bonus_changed_ = false;
458  const int new_turn = std::max<int>(num, 1);
459  LOG_NG << "changing current turn number from " << turn_ << " to " << new_turn << '\n';
460  // Correct ToD
461  set_new_current_times(new_turn);
462 
463  if(increase_limit_if_needed && (new_turn > num_turns_) && num_turns_ != -1) {
464  set_number_of_turns(new_turn);
465  }
466  turn_ = new_turn;
467  if (vars) {
468  vars->get_variable("turn_number") = new_turn;
469  }
470 }
471 
472 void tod_manager::set_turn_by_wml(const int num, game_data* vars, const bool increase_limit_if_needed)
473 {
474  set_turn(num, vars, increase_limit_if_needed);
476 }
477 
478 void tod_manager::set_new_current_times(const int new_current_turn_number)
479 {
480  set_current_time(calculate_time_index_at_turn(times_.size(), new_current_turn_number, currentTime_));
481  for (area_time_of_day& area : areas_) {
483  area.times.size(),
484  new_current_turn_number,
485  area.currentTime),
486  area);
487  }
488 }
489 
491  int number_of_times,
492  int time)
493 {
494  if (number_of_times == 0) return 0;
495  return modulo(time, number_of_times);
496 }
497 
499  int number_of_times,
500  int for_turn_number,
501  int current_time) const
502 {
503  if (number_of_times == 0) return 0;
504  return modulo(current_time + for_turn_number - turn_, number_of_times);
505 }
506 
508 {
509  time = fix_time_index(times_.size(), time);
510  if (!times_.empty() && times_[time].lawful_bonus != times_[currentTime_].lawful_bonus) {
511  has_tod_bonus_changed_ = true;
512  }
513  currentTime_ = time;
514 }
515 
516 void tod_manager::set_current_time(int time, int area_index)
517 {
518  assert(area_index < static_cast<int>(areas_.size()));
519  set_current_time(time, areas_[area_index]);
520 }
521 
523 {
524  for (area_time_of_day& area : areas_) {
525  if (area.id == area_id) {
526  set_current_time(time, area);
527  }
528  }
529 }
530 
532 {
533  time = fix_time_index(area.times.size(), time);
534  if (area.times[time].lawful_bonus != area.times[area.currentTime].lawful_bonus) {
535  has_tod_bonus_changed_ = true;
536  }
537  area.currentTime = time;
538 }
539 
541 {
542  set_turn(turn_ + 1, vars, false);
543  has_turn_event_fired_ = false;
544  return is_time_left();
545 }
546 
547 
549 {
550  return num_turns_ == -1 || turn_ <= num_turns_;
551 }
552 
553 int tod_manager::calculate_best_liminal_bonus(const std::vector<time_of_day>& schedule) const
554 {
555  int fearless_chaotic = 0;
556  int fearless_lawful = 0;
557  std::set<int> bonuses;
558  for (const auto& tod : schedule) {
559  fearless_chaotic += generic_combat_modifier(tod.lawful_bonus, UNIT_ALIGNMENT::CHAOTIC, true, 0);
560  fearless_lawful += generic_combat_modifier(tod.lawful_bonus, UNIT_ALIGNMENT::LAWFUL, true, 0);
561  bonuses.insert(std::abs(tod.lawful_bonus));
562  }
563  int target = std::max(fearless_chaotic, fearless_lawful);
564  int delta = target;
565  int result = 0;
566  for (int bonus : bonuses) {
567  int liminal_effect = 0;
568  for (const auto& tod : schedule) {
569  liminal_effect += generic_combat_modifier(tod.lawful_bonus, UNIT_ALIGNMENT::LIMINAL, false, bonus);
570  }
571  if (std::abs(target - liminal_effect) < delta) {
572  result = bonus;
573  delta = std::abs(target - liminal_effect);
574  }
575  }
576  return result;
577 }
play_controller * controller
Definition: resources.cpp:21
void set_new_current_times(const int new_current_turn_number)
For a change of the current turn number, sets the current times of the main time and all time areas...
int calculate_time_index_at_turn(int number_of_times, int for_turn_number, int current_time) const
Computes for the main time or a time area the index of its times where we&#39;re currently at...
void replace_local_schedule(const std::vector< time_of_day > &schedule, int area_index)
bool empty() const
Definition: unit.hpp:101
unit_iterator end()
Definition: map.hpp:429
bool has_turn_event_fired_
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:474
void replace_schedule(const config &time_cfg)
Replace the time of day schedule.
const time_of_day & get_previous_time_of_day() const
Various functions that implement attacks and attack calculations.
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
void set_turn(const int num, game_data *vars=nullptr, const bool increase_limit_if_needed=true)
Dynamically change the current turn number.
std::string id
Definition: time_of_day.hpp:91
int get_current_time(const map_location &loc=map_location::null_location()) const
void set_area_id(int area_index, const std::string &id)
bool has_tod_bonus_changed_
void resolve_random(randomness::rng &r)
handles random_start_time, should be called before the game starts.
Definition: tod_manager.cpp:66
int lawful_bonus
The % bonus lawful units receive.
Definition: time_of_day.hpp:84
void modify_turns_by_wml(const std::string &mod)
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:97
std::set< map_location > hexes
int generic_combat_modifier(int lawful_bonus, unit_type::ALIGNMENT alignment, bool is_fearless, int max_liminal_bonus)
Returns the amount that a unit&#39;s damage should be multiplied by due to a given lawful_bonus.
Definition: attack.cpp:1611
void write(config &cfg) const
Definition: time_of_day.cpp:54
std::string str
Definition: statement.cpp:110
const std::set< map_location > & get_area_by_id(const std::string &id) const
int calculate_best_liminal_bonus(const std::vector< time_of_day > &schedule) const
Computes the maximum absolute value of lawful_bonus in the schedule.
config::attribute_value & get_variable(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
Definition: game_data.cpp:62
void modify_turns(const std::string &mod)
static int fix_time_index(int number_of_times, int time)
Computes for the main time or a time area the index of its times where we&#39;re currently at...
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:57
void set_current_time(int time)
int light_bonus(int base) const
Returns the light (lawful) bonus for this terrain when the time of day gives a base bonus...
Definition: terrain.hpp:132
std::vector< map_location > parse_location_range(const std::string &xvals, const std::string &yvals, bool with_border=false) const
Parses ranges of locations into a vector of locations, using this map&#39;s dimensions as bounds...
Definition: map.cpp:416
static std::ostream & output()
Definition: log.cpp:52
void set_number_of_turns_by_wml(int num)
std::vector< time_of_day > times
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:382
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
Definition: tod_manager.hpp:54
config::attribute_value random_tod_
void remove_time_area(const std::string &id)
Removes a time area from config, making it follow the scenario&#39;s normal time-of-day sequence...
std::vector< time_of_day > times_
Encapsulates the map of the game.
Definition: map.hpp:36
tod_manager(const config &scenario_cfg=config())
Definition: tod_manager.cpp:38
config to_config() const
void update_server_information() const
std::vector< std::string > get_area_ids() const
void set_turn_by_wml(const int num, game_data *vars=nullptr, const bool increase_limit_if_needed=true)
Dynamically change the current turn number.
Encapsulates the map of the game.
Definition: location.hpp:42
std::pair< int, map_location > lowest(const std::string &key, int def=0) const
Definition: unit.hpp:83
unit_iterator find(std::size_t id)
Definition: map.cpp:311
const time_of_day get_illuminated_time_of_day(const unit_map &units, const gamemap &map, const map_location &loc, int for_turn=0) const
Returns time of day object for the passed turn at a location.
std::size_t i
Definition: function.cpp:933
void write_location_range(const std::set< map_location > &locs, config &cfg)
Write a set of locations into a config using ranges, adding keys x=x1,..,xn and y=y1a-y1b,..,yna-ynb.
Definition: location.cpp:398
void set_number_of_turns(int num)
const std::vector< time_of_day > & times(const map_location &loc=map_location::null_location()) const
static void parse_times(const config &cfg, std::vector< time_of_day > &normal_times)
Parse config and add time of day entries into passed vector.
Definition: time_of_day.cpp:70
static const time_of_day & dummytime()
int get_composite_value() const
Definition: abilities.hpp:48
bool string_bool(const std::string &str, bool def)
Convert no, false, off, 0, 0.0 to false, empty to def, and others to true.
bool is_time_left() const
Function to check the end of turns.
bool to_bool(bool def=false) const
#define LOG_NG
Definition: tod_manager.cpp:36
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
bool has_cfg_liminal_bonus_
static lg::log_domain log_engine("engine")
config & add_child(config_key_type key)
Definition: config.cpp:476
static bool is_start_ToD(const std::string &)
void replace_area_locations(int index, const std::set< map_location > &locs)
std::vector< std::string > split(const config_attribute_value &val)
void add_time_area(const gamemap &map, const config &cfg)
Adds a new local time area from config, making it follow its own time-of-day sequence.
int apply_modifier(const int number, const std::string &amount, const int minimum)
Standard logging facilities (interface).
static const map_location & null_location()
Definition: location.hpp:85
Container associating units to locations.
Definition: map.hpp:99
uint32_t next_random()
Provides the next random draw.
Definition: random.cpp:84
const std::set< map_location > & get_area_by_index(int index) const
std::vector< area_time_of_day > areas_
int bounded_add(int base, int increment, int max_sum, int min_sum=0)
Returns base + increment, but will not increase base above max_sum, nor decrease it below min_sum...
Definition: math.hpp:47
int get_current_area_time(int index) const
const time_of_day & get_time_of_day_turn(const std::vector< time_of_day > &times, int nturn, const int current_time) const
Returns time of day object in the turn "nturn".
bool next_turn(game_data *vars)
Function to move to the next turn.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
bool random_start_time()
Definition: game.cpp:542
int bonus_modified
Definition: time_of_day.hpp:85
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
virtual void send_to_wesnothd(const config &, const std::string &="unknown") const
std::pair< int, map_location > highest(const std::string &key, int def=0) const
Definition: unit.hpp:79
T modulo(T num, int mod, T min=0)
Definition: math.hpp:61
std::string str(const std::string &fallback="") const
this class does not give synced random results derived classes might do.
Definition: random.hpp:27