The Battle for Wesnoth  1.19.7+dev
tod_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
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_()
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 
55  time_of_day::parse_times(scenario_cfg, times_);
57 
58  if(scenario_cfg.has_attribute("liminal_bonus")) {
59  liminal_bonus_ = scenario_cfg["liminal_bonus"].to_int(liminal_bonus_);
61  }
62 
63  // We need to call parse_times before fix_time_index because otherwise the first parameter will always be 0.
64  currentTime_ = fix_time_index(times_.size(), scenario_cfg["current_time"].to_int(0));
65 }
66 
68 {
69  // process the random_start_time string, which can be boolean yes/no true/false or a
70  // comma-separated string of integers >= 1 referring to the times_ array indices
71  std::vector<std::string> output_strings = utils::split(random_tod_.str());
72  std::vector<int> output;
73 
74  try {
75  std::transform(output_strings.begin(), output_strings.end(), std::back_inserter(output),
76  [](const std::string& str) { return std::stoi(str); });
77  } catch(const std::invalid_argument&) {
78  // This happens if the random_start_time string is a boolean.
79  // Simply ignore the exception.
80  }
81 
82  // Remove non-positive times
83  utils::erase_if(output, [](int time) { return time <= 0; });
84 
85  if(!output.empty()) {
86  int chosen = output[r.next_random() % output.size()];
87  currentTime_ = fix_time_index(times_.size(), chosen);
88  r.next_random();
89  } else if(random_tod_.to_bool(false)) {
91  }
92 
93  random_tod_ = false;
94 }
95 
96 config tod_manager::to_config(const std::string& textdomain) const
97 {
98  config cfg;
99  cfg["turn_at"] = turn_;
100  cfg["turns"] = num_turns_;
101 
102  // this 'if' is for the editor.
103  if(times_.size() != 0) {
104  cfg["current_time"] = currentTime_;
105  }
106 
107  cfg["random_start_time"] = random_tod_;
108  cfg["it_is_a_new_turn"] = !has_turn_event_fired_;
109 
111  cfg["liminal_bonus"] = liminal_bonus_;
112  }
113 
114  for(const time_of_day& tod : times_) {
115  // Don't write stub ToD
116  if(tod.id != "nulltod") {
117  tod.write(cfg.add_child("time"), textdomain);
118  }
119  }
120 
121  for(const area_time_of_day& a_tod : areas_) {
122  config& area = cfg.add_child("time_area");
123 
124  // If no ranges, then use hexes to generate ranges
125  if(a_tod.xsrc.empty() && a_tod.ysrc.empty()) {
126  write_location_range(a_tod.hexes, area);
127  } else {
128  area["x"] = a_tod.xsrc;
129  area["y"] = a_tod.ysrc;
130  }
131 
132  for(const time_of_day& tod : a_tod.times) {
133  // Don't write the stub default ToD if it happens to be present.
134  if(tod.id != "nulltod") {
135  tod.write(area.add_child("time"), textdomain);
136  }
137  }
138 
139  area["current_time"] = a_tod.currentTime;
140 
141  if(!a_tod.id.empty()) {
142  area["id"] = a_tod.id;
143  }
144  }
145 
146  return cfg;
147 }
148 
149 static const time_of_day& dummytime()
150 {
151  static time_of_day* pdummy = new time_of_day();
152  return *pdummy;
153 }
154 
156 {
158 }
159 
161 {
162  assert(index < static_cast<int>(areas_.size()));
163  return areas_[index].currentTime;
164 }
165 
167 {
169  for(auto i = areas_.rbegin(), i_end = areas_.rend();
170  i != i_end; ++i) {
171  if(i->hexes.find(loc) != i->hexes.end()) {
172  return i->currentTime;
173  }
174  }
175  }
176 
177  return currentTime_;
178 }
179 
180 const std::vector<time_of_day>& tod_manager::times(const map_location& loc) const
181 {
183  for(auto i = areas_.rbegin(), i_end = areas_.rend();
184  i != i_end; ++i) {
185  if(i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
186  return i->times;
187  }
188  }
189 
190  return times_;
191 }
192 
194 {
195  if(n_turn == 0) {
196  n_turn = turn_;
197  }
198 
200  for(auto i = areas_.rbegin(), i_end = areas_.rend();
201  i != i_end; ++i) {
202  if(i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
203  return get_time_of_day_turn(i->times, n_turn, i->currentTime);
204  }
205  }
206 
207  return get_time_of_day_turn(times_, n_turn, currentTime_);
208 }
209 
210 const time_of_day& tod_manager::get_area_time_of_day(int area_i, int n_turn) const
211 {
212  assert(area_i < static_cast<int>(areas_.size()));
213  if(n_turn == 0) {
214  n_turn = turn_;
215  }
216  return get_time_of_day_turn(areas_[area_i].times, n_turn, areas_[area_i].currentTime);
217 }
218 
220  const unit_map& units, const gamemap& map, const map_location& loc, int for_turn) const
221 {
222  // get ToD ignoring illumination
223  time_of_day tod = get_time_of_day(loc, for_turn);
224 
225  if(map.on_board_with_border(loc)) {
226  // Now add terrain illumination.
227  const int terrain_light = map.get_terrain_info(loc).light_bonus(tod.lawful_bonus);
228 
229  std::vector<int> mod_list;
230  std::vector<int> max_list;
231  std::vector<int> min_list;
232  int most_add = 0;
233  int most_sub = 0;
234 
235  // Find the "illuminates" effects from units that can affect loc.
236  std::array<map_location, 7> locs;
237  locs[0] = loc;
238  get_adjacent_tiles(loc, locs.data() + 1); // start at [1]
239 
240  for(std::size_t i = 0; i < locs.size(); ++i) {
241  const auto itor = units.find(locs[i]);
242  if(itor != units.end() && !itor->incapacitated()) {
243  unit_ability_list illum = itor->get_abilities("illuminates");
244  if(!illum.empty()) {
245  unit_abilities::effect illum_effect(illum, terrain_light, nullptr, unit_abilities::EFFECT_WITHOUT_CLAMP_MIN_MAX);
246  const int unit_mod = illum_effect.get_composite_value();
247 
248  // Record this value.
249  mod_list.push_back(unit_mod);
250  max_list.push_back(illum.highest("max_value").first);
251  min_list.push_back(illum.lowest("min_value").first);
252 
253  if(unit_mod > most_add) {
254  most_add = unit_mod;
255  } else if(unit_mod < most_sub) {
256  most_sub = unit_mod;
257  }
258  }
259  }
260  }
261  const bool net_darker = most_add < -most_sub;
262 
263  // Apply each unit's effect, tracking the best result.
264  int best_result = terrain_light;
265  const int base_light = terrain_light + (net_darker ? most_add : most_sub);
266 
267  for(std::size_t i = 0; i != mod_list.size(); ++i) {
268  int result = bounded_add(base_light, mod_list[i], max_list[i], min_list[i]);
269 
270  if(net_darker && result < best_result) {
271  best_result = result;
272  } else if(!net_darker && result > best_result) {
273  best_result = result;
274  }
275  }
276 
277  // Update the object we will return.
278  tod.bonus_modified = best_result - tod.lawful_bonus;
279  tod.lawful_bonus = best_result;
280  }
281 
282  return tod;
283 }
284 
285 bool tod_manager::is_start_ToD(const std::string& random_start_time)
286 {
287  return !random_start_time.empty() && utils::string_bool(random_start_time, true);
288 }
289 
291 {
292  std::vector<time_of_day> new_scedule;
293  time_of_day::parse_times(time_cfg, new_scedule);
294  replace_schedule(new_scedule, time_cfg["current_time"].to_int(0));
295 }
296 
297 void tod_manager::replace_schedule(const std::vector<time_of_day>& schedule, int initial_time)
298 {
299  if(times_.empty() || schedule.empty() || times_[currentTime_].lawful_bonus != schedule.front().lawful_bonus) {
300  has_tod_bonus_changed_ = true;
301  }
302 
303  times_ = schedule;
304  currentTime_ = initial_time;
305 }
306 
307 void tod_manager::replace_area_locations(int area_index, const std::set<map_location>& locs)
308 {
309  assert(area_index < static_cast<int>(areas_.size()));
310  areas_[area_index].hexes = locs;
311  has_tod_bonus_changed_ = true;
312 }
313 
314 void tod_manager::replace_local_schedule(const std::vector<time_of_day>& schedule, int area_index, int initial_time)
315 {
316  assert(area_index < static_cast<int>(areas_.size()));
317  area_time_of_day& area = areas_[area_index];
318 
319  if(area.times.empty() || schedule.empty()) {
320  // If one of those is empty then their 'previous' time of day might depend on other areas_,
321  // its better to just assume the illumination has changes than to do the explicit computation.
322  has_tod_bonus_changed_ = true;
323  } else if(area.times[area.currentTime].lawful_bonus != schedule.front().lawful_bonus) {
324  // the current illumination on these tiles has changes.
325  has_tod_bonus_changed_ = true;
326  }
327 
328  area.times = schedule;
329  area.currentTime = initial_time;
330 }
331 
332 void tod_manager::set_area_id(int area_index, const std::string& id)
333 {
334  assert(area_index < static_cast<int>(areas_.size()));
335  areas_[area_index].id = id;
336 }
337 
338 const std::string& tod_manager::get_area_id(int area_index) const
339 {
340  assert(area_index < static_cast<int>(areas_.size()));
341  return areas_[area_index].id;
342 }
343 
344 std::vector<std::string> tod_manager::get_area_ids() const
345 {
346  std::vector<std::string> areas;
347  for(const area_time_of_day& area : areas_) {
348  areas.push_back(area.id);
349  }
350 
351  return areas;
352 }
353 
354 const std::set<map_location>& tod_manager::get_area_by_id(const std::string& id) const
355 {
356  for(const area_time_of_day& area : areas_) {
357  if(area.id == id) {
358  return area.hexes;
359  }
360  }
361 
362  static const std::set<map_location> res;
363  return res;
364 }
365 
366 const std::set<map_location>& tod_manager::get_area_by_index(int index) const
367 {
368  return areas_[index].hexes;
369 }
370 
371 std::pair<int, std::string> tod_manager::get_area_on_hex(const map_location& loc) const
372 {
374  for(auto i = areas_.rbegin(), i_end = areas_.rend();
375  i != i_end; ++i) {
376  if(i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
377  return {std::distance(areas_.rbegin(), i), i->id};
378  }
379  }
380 
381  return {-1, ""};
382 }
383 
384 void tod_manager::add_time_area(const gamemap& map, const config& cfg)
385 {
386  areas_.emplace_back();
387  area_time_of_day& area = areas_.back();
388  area.id = cfg["id"].str();
389  area.xsrc = cfg["x"].str();
390  area.ysrc = cfg["y"].str();
391  area.currentTime = cfg["current_time"].to_int(0);
392  const std::vector<map_location>& locs(map.parse_location_range(area.xsrc, area.ysrc, true));
393  area.hexes.insert(locs.begin(), locs.end());
394  time_of_day::parse_times(cfg, area.times);
395  has_tod_bonus_changed_ = true;
396 }
397 
398 void tod_manager::add_time_area(const std::string& id, const std::set<map_location>& locs, const config& time_cfg)
399 {
400  areas_.emplace_back();
401  area_time_of_day& area = areas_.back();
402  area.id = id;
403  area.hexes = locs;
404  area.currentTime = time_cfg["current_time"].to_int(0);
405  time_of_day::parse_times(time_cfg, area.times);
406  has_tod_bonus_changed_ = true;
407 }
408 
409 void tod_manager::remove_time_area(const std::string& area_id)
410 {
411  if(area_id.empty()) {
412  areas_.clear();
413  } else {
414  // search for all time areas that match the id.
415  auto i = areas_.begin();
416  while(i != areas_.end()) {
417  if((*i).id == area_id) {
418  i = areas_.erase(i);
419  } else {
420  ++i;
421  }
422  }
423  }
424 
425  has_tod_bonus_changed_ = true;
426 }
427 
428 void tod_manager::remove_time_area(int area_index)
429 {
430  assert(area_index < static_cast<int>(areas_.size()));
431  areas_.erase(areas_.begin() + area_index);
432  has_tod_bonus_changed_ = true;
433 }
434 
436  const std::vector<time_of_day>& times, int nturn, const int current_time) const
437 {
438  if(times.empty()) {
439  return dummytime();
440  }
441 
442  const int time = calculate_time_index_at_turn(times.size(), nturn, current_time);
443  return times[time];
444 }
445 
446 void tod_manager::modify_turns(const std::string& mod)
447 {
448  num_turns_ = std::max<int>(utils::apply_modifier(num_turns_, mod, 0), -1);
449 }
450 
452 {
453  num_turns_ = std::max<int>(num, -1);
454 }
455 
457 {
458  if(resources::controller->current_team().is_local()) {
459  // The currently active side informs the mp server about the turn change.
460  // NOTE: The current implementation does not guarantee that the server gets informed
461  // about those changes in 100% of cases. But that is ok because the information is only
462  // used to display the turn limit in the lobby (as opposed to things that cause OOS).
464  "change_turns_wml", config {
465  "current", turn_,
466  "max", num_turns_,
467  },
468  });
469  }
470 }
471 
472 void tod_manager::modify_turns_by_wml(const std::string& mod)
473 {
474  modify_turns(mod);
476 }
477 
479 {
480  set_number_of_turns(num);
482 }
483 
484 void tod_manager::set_turn(const int num, game_data* vars, const bool increase_limit_if_needed)
485 {
486  has_tod_bonus_changed_ = false;
487  const int new_turn = std::max<int>(num, 1);
488  LOG_NG << "changing current turn number from " << turn_ << " to " << new_turn;
489 
490  // Correct ToD
491  set_new_current_times(new_turn);
492 
493  if(increase_limit_if_needed && (new_turn > num_turns_) && num_turns_ != -1) {
494  set_number_of_turns(new_turn);
495  }
496 
497  turn_ = new_turn;
498 
499  if(vars) {
500  vars->get_variable("turn_number") = new_turn;
501  }
502 }
503 
504 void tod_manager::set_turn_by_wml(const int num, game_data* vars, const bool increase_limit_if_needed)
505 {
506  set_turn(num, vars, increase_limit_if_needed);
508 }
509 
510 void tod_manager::set_new_current_times(const int new_current_turn_number)
511 {
512  set_current_time(calculate_time_index_at_turn(times_.size(), new_current_turn_number, currentTime_));
513 
514  for(area_time_of_day& area : areas_) {
515  set_current_time(calculate_time_index_at_turn(area.times.size(), new_current_turn_number, area.currentTime), area);
516  }
517 }
518 
519 int tod_manager::fix_time_index(int number_of_times, int time)
520 {
521  if(number_of_times == 0) {
522  return 0;
523  }
524 
525  return modulo(time, number_of_times);
526 }
527 
528 int tod_manager::calculate_time_index_at_turn(int number_of_times, int for_turn_number, int current_time) const
529 {
530  if(number_of_times == 0) {
531  return 0;
532  }
533 
534  return modulo(current_time + for_turn_number - turn_, number_of_times);
535 }
536 
538 {
539  time = fix_time_index(times_.size(), time);
540  if(!times_.empty() && times_[time].lawful_bonus != times_[currentTime_].lawful_bonus) {
541  has_tod_bonus_changed_ = true;
542  }
543 
544  currentTime_ = time;
545 }
546 
547 void tod_manager::set_current_time(int time, int area_index)
548 {
549  assert(area_index < static_cast<int>(areas_.size()));
550  set_current_time(time, areas_[area_index]);
551 }
552 
553 void tod_manager::set_current_time(int time, const std::string& area_id)
554 {
555  for(area_time_of_day& area : areas_) {
556  if(area.id == area_id) {
557  set_current_time(time, area);
558  }
559  }
560 }
561 
563 {
564  time = fix_time_index(area.times.size(), time);
565  if(area.times[time].lawful_bonus != area.times[area.currentTime].lawful_bonus) {
566  has_tod_bonus_changed_ = true;
567  }
568 
569  area.currentTime = time;
570 }
571 
573 {
574  set_turn(turn_ + 1, vars, false);
575  has_turn_event_fired_ = false;
576  return is_time_left();
577 }
578 
580 {
581  return num_turns_ == -1 || turn_ <= num_turns_;
582 }
583 
584 int tod_manager::calculate_best_liminal_bonus(const std::vector<time_of_day>& schedule) const
585 {
586  int fearless_chaotic = 0;
587  int fearless_lawful = 0;
588 
589  std::set<int> bonuses;
590  for(const auto& tod : schedule) {
591  fearless_chaotic += generic_combat_modifier(tod.lawful_bonus, unit_alignments::type::chaotic, true, 0);
592  fearless_lawful += generic_combat_modifier(tod.lawful_bonus, unit_alignments::type::lawful, true, 0);
593  bonuses.insert(std::abs(tod.lawful_bonus));
594  }
595 
596  int target = std::max(fearless_chaotic, fearless_lawful);
597  int delta = target;
598  int result = 0;
599 
600  for(int bonus : bonuses) {
601  int liminal_effect = 0;
602  for(const auto& tod : schedule) {
603  liminal_effect += generic_combat_modifier(tod.lawful_bonus, unit_alignments::type::liminal, false, bonus);
604  }
605 
606  if(std::abs(target - liminal_effect) < delta) {
607  result = bonus;
608  delta = std::abs(target - liminal_effect);
609  }
610  }
611 
612  return result;
613 }
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:1620
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:172
bool has_attribute(config_key_type key) const
Definition: config.cpp:157
config & add_child(config_key_type key)
Definition: config.cpp:440
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:424
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:390
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:132
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 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 std::vector< time_of_day > & times(const map_location &loc=map_location::null_location()) const
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)
config to_config(const std::string &textdomain="") const
Definition: tod_manager.cpp:96
int get_current_time(const map_location &loc=map_location::null_location()) 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.
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:56
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.
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:67
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:49
std::pair< int, map_location > lowest(const std::string &key, int def=0) const
Definition: unit.hpp:72
std::pair< int, map_location > highest(const std::string &key, int def=0) const
Definition: unit.hpp:68
bool empty() const
Definition: unit.hpp:90
Container associating units to locations.
Definition: map.hpp:98
unit_iterator end()
Definition: map.hpp:428
unit_iterator find(std::size_t id)
Definition: map.cpp:302
std::size_t i
Definition: function.cpp:1029
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:198
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:479
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:403
static std::ostream & output()
Definition: log.cpp:75
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
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:106
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:45
static const map_location & null_location()
Definition: location.hpp:102
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
std::string id
Definition: time_of_day.hpp:90
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:69
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:53
std::set< map_location > hexes
std::vector< time_of_day > times
static lg::log_domain log_engine("engine")
static const time_of_day & dummytime()
#define LOG_NG
Definition: tod_manager.cpp:35