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