The Battle for Wesnoth  1.19.16+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::move_all_areas(int x_offset, int y_offset) {
302  for (auto& area : areas_) {
303  decltype(area.hexes) new_locs;
304  for (auto& loc : area.hexes) {
305  map_location new_loc{ loc.x - x_offset, loc.y - y_offset };
306  new_locs.insert(new_loc);
307  }
308  area.hexes = new_locs;
309  }
310 }
311 
312 void tod_manager::replace_area_locations(int area_index, const std::set<map_location>& locs)
313 {
314  assert(area_index < static_cast<int>(areas_.size()));
315  areas_[area_index].hexes = locs;
316  has_tod_bonus_changed_ = true;
317 }
318 
319 void tod_manager::replace_local_schedule(const std::vector<time_of_day>& schedule, int area_index, int initial_time)
320 {
321  assert(area_index < static_cast<int>(areas_.size()));
322  area_time_of_day& area = areas_[area_index];
323 
324  if(area.times.empty() || schedule.empty()) {
325  // If one of those is empty then their 'previous' time of day might depend on other areas_,
326  // its better to just assume the illumination has changes than to do the explicit computation.
327  has_tod_bonus_changed_ = true;
328  } else if(area.times[area.currentTime].lawful_bonus != schedule.front().lawful_bonus) {
329  // the current illumination on these tiles has changes.
330  has_tod_bonus_changed_ = true;
331  }
332 
333  area.times = schedule;
334  area.currentTime = initial_time;
335 }
336 
337 void tod_manager::set_area_id(int area_index, const std::string& id)
338 {
339  assert(area_index < static_cast<int>(areas_.size()));
340  areas_[area_index].id = id;
341 }
342 
343 const std::string& tod_manager::get_area_id(int area_index) const
344 {
345  assert(area_index < static_cast<int>(areas_.size()));
346  return areas_[area_index].id;
347 }
348 
349 std::vector<std::string> tod_manager::get_area_ids() const
350 {
351  std::vector<std::string> areas;
352  for(const area_time_of_day& area : areas_) {
353  areas.push_back(area.id);
354  }
355 
356  return areas;
357 }
358 
359 const std::set<map_location>& tod_manager::get_area_by_id(const std::string& id) const
360 {
361  for(const area_time_of_day& area : areas_) {
362  if(area.id == id) {
363  return area.hexes;
364  }
365  }
366 
367  static const std::set<map_location> res;
368  return res;
369 }
370 
371 const std::set<map_location>& tod_manager::get_area_by_index(int index) const
372 {
373  return areas_[index].hexes;
374 }
375 
376 std::pair<int, std::string> tod_manager::get_area_on_hex(const map_location& loc) const
377 {
379  for(auto i = areas_.rbegin(), i_end = areas_.rend();
380  i != i_end; ++i) {
381  if(i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
382  return {std::distance(areas_.rbegin(), i), i->id};
383  }
384  }
385 
386  return {-1, ""};
387 }
388 
390 {
391  areas_.emplace_back();
392  area_time_of_day& area = areas_.back();
393  area.id = cfg["id"].str();
394  area.xsrc = cfg["x"].str();
395  area.ysrc = cfg["y"].str();
396  area.currentTime = cfg["current_time"].to_int(0);
397  const std::vector<map_location>& locs(map.parse_location_range(area.xsrc, area.ysrc, true));
398  area.hexes.insert(locs.begin(), locs.end());
400  has_tod_bonus_changed_ = true;
401 }
402 
403 void tod_manager::add_time_area(const std::string& id, const std::set<map_location>& locs, const config& time_cfg)
404 {
405  areas_.emplace_back();
406  area_time_of_day& area = areas_.back();
407  area.id = id;
408  area.hexes = locs;
409  area.currentTime = time_cfg["current_time"].to_int(0);
410  area.times = time_of_day::parse_times(time_cfg);
411  has_tod_bonus_changed_ = true;
412 }
413 
414 void tod_manager::remove_time_area(const std::string& area_id)
415 {
416  if(area_id.empty()) {
417  areas_.clear();
418  } else {
419  // search for all time areas that match the id.
420  auto i = areas_.begin();
421  while(i != areas_.end()) {
422  if((*i).id == area_id) {
423  i = areas_.erase(i);
424  } else {
425  ++i;
426  }
427  }
428  }
429 
430  has_tod_bonus_changed_ = true;
431 }
432 
433 void tod_manager::remove_time_area(int area_index)
434 {
435  assert(area_index < static_cast<int>(areas_.size()));
436  areas_.erase(areas_.begin() + area_index);
437  has_tod_bonus_changed_ = true;
438 }
439 
441  const std::vector<time_of_day>& times, int nturn, const int current_time) const
442 {
443  if(times.empty()) {
444  return dummytime();
445  }
446 
447  const int time = calculate_time_index_at_turn(times.size(), nturn, current_time);
448  return times[time];
449 }
450 
451 void tod_manager::modify_turns(const std::string& mod)
452 {
453  num_turns_ = std::max<int>(utils::apply_modifier(num_turns_, mod, 0), -1);
454 }
455 
457 {
458  num_turns_ = std::max<int>(num, -1);
459 }
460 
462 {
463  if(resources::controller->current_team().is_local()) {
464  // The currently active side informs the mp server about the turn change.
465  // NOTE: The current implementation does not guarantee that the server gets informed
466  // about those changes in 100% of cases. But that is ok because the information is only
467  // used to display the turn limit in the lobby (as opposed to things that cause OOS).
469  "change_turns_wml", config {
470  "current", turn_,
471  "max", num_turns_,
472  },
473  });
474  }
475 }
476 
477 void tod_manager::modify_turns_by_wml(const std::string& mod)
478 {
479  modify_turns(mod);
481 }
482 
484 {
485  set_number_of_turns(num);
487 }
488 
489 void tod_manager::set_turn(const int num, game_data* vars, const bool increase_limit_if_needed)
490 {
491  has_tod_bonus_changed_ = false;
492  const int new_turn = std::max<int>(num, 1);
493  LOG_NG << "changing current turn number from " << turn_ << " to " << new_turn;
494 
495  // Correct ToD
496  set_new_current_times(new_turn);
497 
498  if(increase_limit_if_needed && (new_turn > num_turns_) && num_turns_ != -1) {
499  set_number_of_turns(new_turn);
500  }
501 
502  turn_ = new_turn;
503 
504  if(vars) {
505  vars->get_variable("turn_number") = new_turn;
506  }
507 }
508 
509 void tod_manager::set_turn_by_wml(const int num, game_data* vars, const bool increase_limit_if_needed)
510 {
511  set_turn(num, vars, increase_limit_if_needed);
513 }
514 
515 void tod_manager::set_new_current_times(const int new_current_turn_number)
516 {
517  set_current_time(calculate_time_index_at_turn(times_.size(), new_current_turn_number, currentTime_));
518 
519  for(area_time_of_day& area : areas_) {
520  set_current_time(calculate_time_index_at_turn(area.times.size(), new_current_turn_number, area.currentTime), area);
521  }
522 }
523 
524 int tod_manager::fix_time_index(int number_of_times, int time)
525 {
526  if(number_of_times == 0) {
527  return 0;
528  }
529 
530  return modulo(time, number_of_times);
531 }
532 
533 int tod_manager::calculate_time_index_at_turn(int number_of_times, int for_turn_number, int current_time) const
534 {
535  if(number_of_times == 0) {
536  return 0;
537  }
538 
539  return modulo(current_time + for_turn_number - turn_, number_of_times);
540 }
541 
543 {
544  time = fix_time_index(times_.size(), time);
545  if(!times_.empty() && times_[time].lawful_bonus != times_[currentTime_].lawful_bonus) {
546  has_tod_bonus_changed_ = true;
547  }
548 
549  currentTime_ = time;
550 }
551 
552 void tod_manager::set_current_time(int time, int area_index)
553 {
554  assert(area_index < static_cast<int>(areas_.size()));
555  set_current_time(time, areas_[area_index]);
556 }
557 
558 void tod_manager::set_current_time(int time, const std::string& area_id)
559 {
560  for(area_time_of_day& area : areas_) {
561  if(area.id == area_id) {
562  set_current_time(time, area);
563  }
564  }
565 }
566 
568 {
569  time = fix_time_index(area.times.size(), time);
570  if(area.times[time].lawful_bonus != area.times[area.currentTime].lawful_bonus) {
571  has_tod_bonus_changed_ = true;
572  }
573 
574  area.currentTime = time;
575 }
576 
578 {
579  set_turn(turn_ + 1, vars, false);
580  has_turn_event_fired_ = false;
581  return is_time_left();
582 }
583 
585 {
586  return num_turns_ == -1 || turn_ <= num_turns_;
587 }
588 
589 int tod_manager::calculate_best_liminal_bonus(const std::vector<time_of_day>& schedule) const
590 {
591  int fearless_chaotic = 0;
592  int fearless_lawful = 0;
593 
594  std::set<int> bonuses;
595  for(const auto& tod : schedule) {
596  fearless_chaotic += generic_combat_modifier(tod.lawful_bonus, unit_alignments::type::chaotic, true, 0);
597  fearless_lawful += generic_combat_modifier(tod.lawful_bonus, unit_alignments::type::lawful, true, 0);
598  bonuses.insert(std::abs(tod.lawful_bonus));
599  }
600 
601  int target = std::max(fearless_chaotic, fearless_lawful);
602  int delta = target;
603  int result = 0;
604 
605  for(int bonus : bonuses) {
606  int liminal_effect = 0;
607  for(const auto& tod : schedule) {
608  liminal_effect += generic_combat_modifier(tod.lawful_bonus, unit_alignments::type::liminal, false, bonus);
609  }
610 
611  if(std::abs(target - liminal_effect) < delta) {
612  result = bonus;
613  delta = std::abs(target - liminal_effect);
614  }
615  }
616 
617  return result;
618 }
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:157
config & add_child(std::string_view key)
Definition: config.cpp:435
bool has_attribute(std::string_view key) const
Definition: config.cpp:156
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 move_all_areas(int x_offset, int y_offset)
Shift all hex locations for all time areas by the given x/y offsets.
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:64
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:584
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:46
constexpr T modulo(T num, int mod, T min=0)
Definition: math.hpp:60
play_controller * controller
Definition: resources.cpp:21
@ EFFECT_WITHOUT_CLAMP_MIN_MAX
Definition: abilities.hpp:29
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