The Battle for Wesnoth  1.15.3+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  cfg["current_time"] = currentTime_;
113  cfg["random_start_time"] = random_tod_;
114  cfg["it_is_a_new_turn"] = !has_turn_event_fired_;
116  cfg["liminal_bonus"] = liminal_bonus_;
117 
118  for(const time_of_day& tod : times_) {
119  tod.write(cfg.add_child("time"));
120  }
121 
122  for(const area_time_of_day& a_tod : areas_) {
123  config& area = cfg.add_child("time_area");
124 
125  // If no ranges, then use hexes to generate ranges
126  if(a_tod.xsrc.empty() && a_tod.ysrc.empty()) {
127  write_location_range(a_tod.hexes, area);
128  } else {
129  area["x"] = a_tod.xsrc;
130  area["y"] = a_tod.ysrc;
131  }
132 
133  for(const time_of_day& tod : a_tod.times) {
134  // Don't write the stub default ToD if it happens to be present.
135  if(tod.id != "nulltod") {
136  tod.write(area.add_child("time"));
137  }
138  }
139 
140  area["current_time"] = a_tod.currentTime;
141 
142  if(!a_tod.id.empty()) {
143  area["id"] = a_tod.id;
144  }
145  }
146 
147  return cfg;
148 }
149 
150 static const time_of_day& dummytime()
151 {
152  static time_of_day* pdummy = new time_of_day();
153  return *pdummy;
154 }
155 
157 {
159 }
160 
162 {
163  assert(index < static_cast<int>(areas_.size()) );
164  return areas_[index].currentTime;
165 }
166 
168 {
169  if ( loc != map_location::null_location() ) {
170  for ( std::vector<area_time_of_day>::const_reverse_iterator
171  i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i )
172  {
173  if (i->hexes.find(loc) != i->hexes.end())
174  return i->currentTime;
175  }
176  }
177 
178  return currentTime_;
179 }
180 
181 const std::vector<time_of_day>& tod_manager::times(const map_location& loc) const
182 {
183  if ( loc != map_location::null_location() ) {
184  for ( std::vector<area_time_of_day>::const_reverse_iterator
185  i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i )
186  {
187  if (i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
188  return i->times;
189  }
190  }
191 
192  return times_;
193 }
194 
195 const time_of_day& tod_manager::get_time_of_day(const map_location& loc, int n_turn) const
196 {
197  if(n_turn == 0)
198  n_turn = turn_;
199 
200  if ( loc != map_location::null_location() )
201  {
202  for ( std::vector<area_time_of_day>::const_reverse_iterator
203  i = areas_.rbegin(), i_end = areas_.rend(); i != i_end; ++i )
204  {
205  if (i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
206  return get_time_of_day_turn(i->times, n_turn, i->currentTime);
207  }
208  }
209 
210  return get_time_of_day_turn(times_, n_turn, currentTime_);
211 }
212 
213 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
214 {
215  // get ToD ignoring illumination
216  time_of_day tod = get_time_of_day(loc, for_turn);
217 
218  if ( map.on_board_with_border(loc) )
219  {
220  // Now add terrain illumination.
221  const int terrain_light = map.get_terrain_info(loc).light_bonus(tod.lawful_bonus);
222 
223  std::vector<int> mod_list;
224  std::vector<int> max_list;
225  std::vector<int> min_list;
226  int most_add = 0;
227  int most_sub = 0;
228 
229  // Find the "illuminates" effects from units that can affect loc.
230  std::array<map_location, 7> locs;
231  locs[0] = loc;
232  get_adjacent_tiles(loc, locs.data() + 1); // start at [1]
233  for ( std::size_t i = 0; i < locs.size(); ++i ) {
234  const unit_map::const_iterator itor = units.find(locs[i]);
235  if (itor != units.end() && !itor->incapacitated())
236  {
237  unit_ability_list illum = itor->get_abilities("illuminates");
238  if(!illum.empty()) {
239  unit_abilities::effect illum_effect(illum, terrain_light, false);
240  const int unit_mod = illum_effect.get_composite_value();
241 
242  // Record this value.
243  mod_list.push_back(unit_mod);
244  max_list.push_back(illum.highest("max_value").first);
245  min_list.push_back(illum.lowest("min_value").first);
246  if ( unit_mod > most_add )
247  most_add = unit_mod;
248  else if ( unit_mod < most_sub )
249  most_sub = unit_mod;
250  }
251  }
252  }
253  const bool net_darker = most_add < -most_sub;
254 
255  // Apply each unit's effect, tracking the best result.
256  int best_result = terrain_light;
257  const int base_light = terrain_light + (net_darker ? most_add : most_sub);
258  for ( std::size_t i = 0; i != mod_list.size(); ++i ) {
259  int result = bounded_add( base_light, mod_list[i], max_list[i], min_list[i] );
260 
261  if ( net_darker && result < best_result )
262  best_result = result;
263  else if ( !net_darker && result > best_result )
264  best_result = result;
265  }
266 
267  // Update the object we will return.
268  tod.bonus_modified = best_result - tod.lawful_bonus;
269  tod.lawful_bonus = best_result;
270  }
271 
272  return tod;
273 }
274 
275 
277 {
278  return !random_start_time.empty()
279  && utils::string_bool(random_start_time, true);
280 }
281 
283 {
284  std::vector<time_of_day> new_scedule;
285  time_of_day::parse_times(time_cfg, new_scedule);
286  replace_schedule(new_scedule);
287 }
288 
289 void tod_manager::replace_schedule(const std::vector<time_of_day>& schedule)
290 {
291  if(times_.empty() || schedule.empty() || times_[currentTime_].lawful_bonus != schedule.front().lawful_bonus) {
292  has_tod_bonus_changed_ = true;
293  }
294 
295  times_ = schedule;
296  currentTime_ = 0;
297 }
298 
299 void tod_manager::replace_area_locations(int area_index, const std::set<map_location>& locs)
300 {
301  assert(area_index < static_cast<int>(areas_.size()));
302  areas_[area_index].hexes = locs;
303  has_tod_bonus_changed_ = true;
304 }
305 
306 void tod_manager::replace_local_schedule(const std::vector<time_of_day>& schedule, int area_index)
307 {
308  assert(area_index < static_cast<int>(areas_.size()));
309  area_time_of_day& area = areas_[area_index];
310 
311  if(area.times.empty() || schedule.empty())
312  {
313  //If one of those is empty then their 'prievious' time of day might depend on other areas_,
314  //its better to just assume the illimination has changes than to do the explicit computation.
315  has_tod_bonus_changed_ = true;
316  }
317  else if(area.times[area.currentTime].lawful_bonus != schedule.front().lawful_bonus)
318  {
319  // the current illimination on these tiles has changes.
320  has_tod_bonus_changed_ = true;
321  }
322  area.times = schedule;
323  area.currentTime = 0;
324 }
325 
326 void tod_manager::set_area_id(int area_index, const std::string& id)
327 {
328  assert(area_index < static_cast<int>(areas_.size()));
329  areas_[area_index].id = id;
330 }
331 
332 std::vector<std::string> tod_manager::get_area_ids() const
333 {
334  std::vector<std::string> areas;
335  for (const area_time_of_day& area : areas_) {
336  areas.push_back(area.id);
337  }
338  return areas;
339 }
340 
341 const std::set<map_location>& tod_manager::get_area_by_id(const std::string& id) const
342 {
343  for (const area_time_of_day& area : areas_) {
344  if (area.id == id) {
345  return area.hexes;
346  }
347  }
348  static const std::set<map_location> res;
349  return res;
350 }
351 
352 const std::set<map_location>& tod_manager::get_area_by_index(int index) const
353 {
354  return areas_[index].hexes;
355 }
356 
357 void tod_manager::add_time_area(const gamemap & map, const config& cfg)
358 {
359  areas_.emplace_back();
360  area_time_of_day &area = areas_.back();
361  area.id = cfg["id"].str();
362  area.xsrc = cfg["x"].str();
363  area.ysrc = cfg["y"].str();
364  area.currentTime = cfg["current_time"].to_int(0);
365  const std::vector<map_location>& locs (map.parse_location_range(area.xsrc, area.ysrc, true));
366  area.hexes.insert(locs.begin(), locs.end());
367  time_of_day::parse_times(cfg, area.times);
368  has_tod_bonus_changed_ = true;
369 }
370 
371 void tod_manager::add_time_area(const std::string& id, const std::set<map_location>& locs,
372  const config& time_cfg)
373 {
374  areas_.emplace_back();
375  area_time_of_day& area = areas_.back();
376  area.id = id;
377  area.hexes = locs;
378  area.currentTime = time_cfg["current_time"].to_int(0);
379  time_of_day::parse_times(time_cfg, area.times);
380  has_tod_bonus_changed_ = true;
381 }
382 
384 {
385  if(area_id.empty()) {
386  areas_.clear();
387  } else {
388  // search for all time areas that match the id.
390  while(i != areas_.end()) {
391  if((*i).id == area_id) {
392  i = areas_.erase(i);
393  } else {
394  ++i;
395  }
396  }
397  }
398  has_tod_bonus_changed_ = true;
399 }
400 
401 void tod_manager::remove_time_area(int area_index)
402 {
403  assert(area_index < static_cast<int>(areas_.size()));
404  areas_.erase(areas_.begin() + area_index);
405  has_tod_bonus_changed_ = true;
406 }
407 
408 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
409 {
410  if(times.empty()) {
411  return dummytime();
412  }
413  const int time = calculate_time_index_at_turn(times.size(), nturn, current_time);
414  return times[time];
415 }
416 
418 {
419  num_turns_ = std::max<int>(utils::apply_modifier(num_turns_,mod,0),-1);
420 }
422 {
423  num_turns_ = std::max<int>(num, -1);
424 }
425 
427 {
428  if(resources::controller->current_team().is_local()) {
429  //the currently active side informs the mp server about the turn change.
430  //NOTE: The current implementation does not guarnateee that the server gets informed
431  // about those changes in 100% of cases. But that is ok because the information is only
432  // used to display the turn limit in the lobby (as opposed to things that cause OOS).
434  "change_turns_wml", config {
435  "current", turn_,
436  "max", num_turns_,
437  },
438  });
439  }
440 }
442 {
443  modify_turns(mod);
445 }
447 {
448  set_number_of_turns(num);
450 }
451 
452 void tod_manager::set_turn(const int num, game_data* vars, const bool increase_limit_if_needed)
453 {
454  has_tod_bonus_changed_ = false;
455  const int new_turn = std::max<int>(num, 1);
456  LOG_NG << "changing current turn number from " << turn_ << " to " << new_turn << '\n';
457  // Correct ToD
458  set_new_current_times(new_turn);
459 
460  if(increase_limit_if_needed && (new_turn > num_turns_) && num_turns_ != -1) {
461  set_number_of_turns(new_turn);
462  }
463  turn_ = new_turn;
464  if (vars) {
465  vars->get_variable("turn_number") = new_turn;
466  }
467 }
468 
469 void tod_manager::set_turn_by_wml(const int num, game_data* vars, const bool increase_limit_if_needed)
470 {
471  set_turn(num, vars, increase_limit_if_needed);
473 }
474 
475 void tod_manager::set_new_current_times(const int new_current_turn_number)
476 {
477  set_current_time(calculate_time_index_at_turn(times_.size(), new_current_turn_number, currentTime_));
478  for (area_time_of_day& area : areas_) {
480  area.times.size(),
481  new_current_turn_number,
482  area.currentTime),
483  area);
484  }
485 }
486 
488  int number_of_times,
489  int time)
490 {
491  if (number_of_times == 0) return 0;
492  return modulo(time, number_of_times);
493 }
494 
496  int number_of_times,
497  int for_turn_number,
498  int current_time) const
499 {
500  if (number_of_times == 0) return 0;
501  return modulo(current_time + for_turn_number - turn_, number_of_times);
502 }
503 
505 {
506  time = fix_time_index(times_.size(), time);
507  if (!times_.empty() && times_[time].lawful_bonus != times_[currentTime_].lawful_bonus) {
508  has_tod_bonus_changed_ = true;
509  }
510  currentTime_ = time;
511 }
512 
513 void tod_manager::set_current_time(int time, int area_index)
514 {
515  assert(area_index < static_cast<int>(areas_.size()));
516  set_current_time(time, areas_[area_index]);
517 }
518 
520 {
521  for (area_time_of_day& area : areas_) {
522  if (area.id == area_id) {
523  set_current_time(time, area);
524  }
525  }
526 }
527 
529 {
530  time = fix_time_index(area.times.size(), time);
531  if (area.times[time].lawful_bonus != area.times[area.currentTime].lawful_bonus) {
532  has_tod_bonus_changed_ = true;
533  }
534  area.currentTime = time;
535 }
536 
538 {
539  set_turn(turn_ + 1, vars, false);
540  has_turn_event_fired_ = false;
541  return is_time_left();
542 }
543 
544 
546 {
547  return num_turns_ == -1 || turn_ <= num_turns_;
548 }
549 
550 int tod_manager::calculate_best_liminal_bonus(const std::vector<time_of_day>& schedule) const
551 {
552  int fearless_chaotic = 0;
553  int fearless_lawful = 0;
554  std::set<int> bonuses;
555  for (const auto& tod : schedule) {
556  fearless_chaotic += generic_combat_modifier(tod.lawful_bonus, UNIT_ALIGNMENT::CHAOTIC, true, 0);
557  fearless_lawful += generic_combat_modifier(tod.lawful_bonus, UNIT_ALIGNMENT::LAWFUL, true, 0);
558  bonuses.insert(std::abs(tod.lawful_bonus));
559  }
560  int target = std::max(fearless_chaotic, fearless_lawful);
561  int delta = target;
562  int result = 0;
563  for (int bonus : bonuses) {
564  int liminal_effect = 0;
565  for (const auto& tod : schedule) {
566  liminal_effect += generic_combat_modifier(tod.lawful_bonus, UNIT_ALIGNMENT::LIMINAL, false, bonus);
567  }
568  if (std::abs(target - liminal_effect) < delta) {
569  result = bonus;
570  delta = std::abs(target - liminal_effect);
571  }
572  }
573  return result;
574 }
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:1592
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:51
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:552
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