The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
reports.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://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 "actions/attack.hpp"
16 #include "attack_prediction.hpp"
17 #include "font/pango/escape.hpp"
18 #include "font/text_formatting.hpp"
19 #include "formatter.hpp"
20 #include "preferences/game.hpp"
21 #include "gettext.hpp"
22 #include "language.hpp"
23 #include "map/map.hpp"
24 #include "font/marked-up_text.hpp"
25 #include "mouse_events.hpp"
26 #include "reports.hpp"
27 #include "color.hpp"
28 #include "team.hpp"
29 #include "tod_manager.hpp"
30 #include "units/unit.hpp"
31 #include "units/helper.hpp"
32 #include "whiteboard/manager.hpp"
33 
34 #include <cassert>
35 #include <ctime>
36 #include <iomanip>
37 #include <boost/dynamic_bitset.hpp>
38 
39 #include "utils/io.hpp"
40 
41 static void add_text(config &report, const std::string &text,
42  const std::string &tooltip, const std::string &help = "")
43 {
44  config &element = report.add_child("element");
45  element["text"] = text;
46  if (!tooltip.empty()) element["tooltip"] = tooltip;
47  if (!help.empty()) element["help"] = help;
48 }
49 
50 static void add_image(config &report, const std::string &image,
51  const std::string &tooltip, const std::string &help = "")
52 {
53  config &element = report.add_child("element");
54  element["image"] = image;
55  if (!tooltip.empty()) element["tooltip"] = tooltip;
56  if (!help.empty()) element["help"] = help;
57 }
58 
59 static config text_report(const std::string &text,
60  const std::string &tooltip = "", const std::string &help = "")
61 {
62  config r;
63  add_text(r, text, tooltip, help);
64  return r;
65 }
66 
68  const std::string &tooltip = "", const std::string &help = "")
69 {
70  config r;
71  add_image(r, image, tooltip, help);
72  return r;
73 }
74 
75 using font::span_color;
76 
77 static void add_status(config &r,
78  char const *path, char const *desc1, char const *desc2)
79 {
80  std::ostringstream s;
81  s << translation::gettext(desc1) << translation::gettext(desc2);
82  add_image(r, path, s.str());
83 }
84 
85 static std::string flush(std::ostringstream &s)
86 {
87  std::string r(s.str());
88  s.str(std::string());
89  return r;
90 }
91 
92 typedef std::map<std::string, reports::generator_function> static_report_generators;
94 
96 {
98  {
99  static_generators.insert(static_report_generators::value_type(name, g));
100  }
101 };
102 
103 #define REPORT_GENERATOR(n, cn) \
104  static config report_##n(reports::context & cn); \
105  static report_generator_helper reg_gen_##n(#n, &report_##n); \
106  static config report_##n(reports::context & cn)
107 
108 static char const *naps = "</span>";
109 
111 {
112  return rc.dc().get_visible_unit(rc.screen().displayed_unit_hex(),
113  rc.teams()[rc.screen().viewing_team()],
114  rc.screen().show_everything());
115 }
116 
118 {
119  return rc.dc().get_visible_unit(rc.screen().selected_hex(),
120  rc.teams()[rc.screen().viewing_team()],
121  rc.screen().show_everything());
122 }
123 
124 static config gray_inactive(reports::context & rc, const std::string &str, const std::string& tooltip = "")
125 {
126  if ( rc.screen().viewing_side() == rc.screen().playing_side() )
127  return text_report(str, tooltip);
128 
129  return text_report(span_color(font::GRAY_COLOR) + str + naps, tooltip);
130 }
131 
132 static config unit_name(const unit *u)
133 {
134  if (!u) {
135  return config();
136  }
137 
138  /*
139  * The name needs to be escaped, it might be set by the user and using
140  * markup. Also names often contain a forbidden single quote.
141  */
142  const std::string& name = font::escape_text(u->name());
143  std::ostringstream str, tooltip;
144  str << "<b>" << name << "</b>";
145  tooltip << _("Name: ") << "<b>" << name << "</b>";
146  return text_report(str.str(), tooltip.str());
147 }
148 
150 {
151  const unit *u = get_visible_unit(rc);
152  return unit_name(u);
153 }
154 REPORT_GENERATOR(selected_unit_name, rc)
155 {
156  const unit *u = get_selected_unit(rc);
157  return unit_name(u);
158 }
159 
160 static config unit_type(const unit* u)
161 {
162  if (!u) return config();
163  std::string has_variations_prefix = (u->type().show_variations_in_help() ? ".." : "");
164  std::ostringstream str, tooltip;
165  str << u->type_name();
166  tooltip << _("Type: ") << "<b>" << u->type_name() << "</b>\n"
167  << u->unit_description();
168  return text_report(str.str(), tooltip.str(), has_variations_prefix + "unit_" + u->type_id());
169 }
171 {
172  const unit *u = get_visible_unit(rc);
173  return unit_type(u);
174 }
175 REPORT_GENERATOR(selected_unit_type, rc)
176 {
177  const unit *u = get_selected_unit(rc);
178  return unit_type(u);
179 }
180 
181 static config unit_race(const unit* u)
182 {
183  if (!u) return config();
184  std::ostringstream str, tooltip;
185  str << u->race()->name(u->gender());
186  tooltip << _("Race: ") << "<b>" << u->race()->name(u->gender()) << "</b>";
187  return text_report(str.str(), tooltip.str(), "..race_" + u->race()->id());
188 }
190 {
191  const unit *u = get_visible_unit(rc);
192  return unit_race(u);
193 }
194 REPORT_GENERATOR(selected_unit_race, rc)
195 {
196  const unit *u = get_selected_unit(rc);
197  return unit_race(u);
198 }
199 
200 static config unit_side(reports::context & rc, const unit* u)
201 {
202  if (!u) return config();
203 
204  config report;
205  const team &u_team = rc.dc().get_team(u->side());
206  std::string flag_icon = u_team.flag_icon();
208  std::string new_rgb = u_team.color();
209  std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
210  if (flag_icon.empty())
211  flag_icon = game_config::images::flag_icon;
212 
213  std::stringstream text;
214  text << " " << u->side();
215 
216  add_image(report, flag_icon + mods, u_team.side_name(), "");
217  add_text(report, text.str(), "", "");
218  return report;
219 }
221 {
222  const unit *u = get_visible_unit(rc);
223  return unit_side(rc,u);
224 }
225 REPORT_GENERATOR(selected_unit_side, rc)
226 {
227  const unit *u = get_selected_unit(rc);
228  return unit_side(rc, u);
229 }
230 
231 static config unit_level(const unit* u)
232 {
233  if (!u) return config();
234  std::ostringstream str, tooltip;
235  str << u->level();
236  tooltip << _("Level: ") << "<b>" << u->level() << "</b>\n";
237  const std::vector<std::string> &adv_to = u->advances_to_translated();
238  if (adv_to.empty())
239  tooltip << _("No advancement");
240  else
241  tooltip << _("Advances to:") << "\n<b>\t"
242  << utils::join(adv_to, "\n\t") << "</b>";
243  return text_report(str.str(), tooltip.str());
244 }
246 {
247  const unit *u = get_visible_unit(rc);
248  return unit_level(u);
249 }
250 REPORT_GENERATOR(selected_unit_level, rc)
251 {
252  const unit *u = get_selected_unit(rc);
253  return unit_level(u);
254 }
255 
256 REPORT_GENERATOR(unit_amla, rc)
257 {
258  const unit *u = get_visible_unit(rc);
259  if (!u) return config();
260  config res;
261  typedef std::pair<std::string, std::string> pair_string;
262  for (const pair_string &ps : u->amla_icons()) {
263  add_image(res, ps.first, ps.second);
264  }
265  return res;
266 }
267 
268 static config unit_traits(const unit* u)
269 {
270  if (!u) return config();
271  config res;
272  const std::vector<t_string> &traits = u->trait_names();
273  const std::vector<t_string> &descriptions = u->trait_descriptions();
274  const std::vector<std::string> &trait_ids = u->get_traits_list();
275  unsigned nb = traits.size();
276  for (unsigned i = 0; i < nb; ++i)
277  {
278  std::ostringstream str, tooltip;
279  str << traits[i];
280  if (i != nb - 1 ) str << ", ";
281  tooltip << _("Trait: ") << "<b>" << traits[i] << "</b>\n"
282  << descriptions[i];
283  add_text(res, str.str(), tooltip.str(), "traits_" + trait_ids[i]);
284  }
285  return res;
286 }
288 {
289  const unit *u = get_visible_unit(rc);
290  return unit_traits(u);
291 }
292 REPORT_GENERATOR(selected_unit_traits, rc)
293 {
294  const unit *u = get_selected_unit(rc);
295  return unit_traits(u);
296 }
297 
298 static config unit_status(reports::context & rc, const unit* u)
299 {
300  if (!u) return config();
301  config res;
302  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
303  if (rc.map().on_board(displayed_unit_hex) && u->invisible(displayed_unit_hex, rc.dc())) {
304  add_status(res, "misc/invisible.png", N_("invisible: "),
305  N_("This unit is invisible. It cannot be seen or attacked by enemy units."));
306  }
307  if (u->get_state(unit::STATE_SLOWED)) {
308  add_status(res, "misc/slowed.png", N_("slowed: "),
309  N_("This unit has been slowed. It will only deal half its normal damage when attacking and its movement cost is doubled."));
310  }
312  add_status(res, "misc/poisoned.png", N_("poisoned: "),
313  N_("This unit is poisoned. It will lose 8 HP every turn until it can seek a cure to the poison in a village or from a friendly unit with the ‘cures’ ability.\n\nUnits cannot be killed by poison alone. The poison will not reduce it below 1 HP."));
314  }
316  add_status(res, "misc/petrified.png", N_("petrified: "),
317  N_("This unit has been petrified. It may not move or attack."));
318  }
319  return res;
320 }
322 {
323  const unit *u = get_visible_unit(rc);
324  return unit_status(rc,u);
325 }
326 REPORT_GENERATOR(selected_unit_status, rc)
327 {
328  const unit *u = get_selected_unit(rc);
329  return unit_status(rc, u);
330 }
331 
333 {
334  if (!u) return config();
335  std::ostringstream str, tooltip;
337  const std::string align_id = u->alignment().to_string();
338  int cm = combat_modifier(rc.units(), rc.map(), rc.screen().displayed_unit_hex(), u->alignment(),
339  u->is_fearless());
340 
341  color_t color = font::weapon_color;
342  if (cm != 0)
343  color = (cm > 0) ? font::good_dmg_color : font::bad_dmg_color;
344 
345  str << align << " (" << span_color(color) << utils::signed_percent(cm)
346  << naps << ")";
347 
348  tooltip << _("Alignment: ") << "<b>" << align << "</b>\n"
349  << string_table[align_id + "_description"];
350 
351  return text_report(str.str(), tooltip.str(), "time_of_day");
352 }
354 {
355  const unit *u = get_visible_unit(rc);
356  return unit_alignment(rc, u);
357 }
358 REPORT_GENERATOR(selected_unit_alignment, rc)
359 {
360  const unit *u = get_selected_unit(rc);
361  return unit_alignment(rc, u);
362 }
363 
364 
365 static config unit_abilities(const unit* u)
366 {
367  if (!u) return config();
368  config res;
369 
370  boost::dynamic_bitset<> active;
371  const std::vector<std::tuple<std::string, t_string,t_string,t_string>> &abilities = u->ability_tooltips(&active);
372  const size_t abilities_size = abilities.size();
373  for ( size_t i = 0; i != abilities_size; ++i )
374  {
375  // Aliases for readability:
376  const std::string& id = std::get<0>(abilities[i]);
377  const std::string& base_name = std::get<1>(abilities[i]).base_str();
378  const t_string& display_name = std::get<2>(abilities[i]);
379  const t_string& description = std::get<3>(abilities[i]);
380 
381  std::ostringstream str, tooltip;
382 
383  if ( active[i] )
384  str << display_name;
385  else
386  str << span_color(font::inactive_ability_color) << display_name << naps;
387  if ( i + 1 != abilities_size )
388  str << ", ";
389 
390  tooltip << _("Ability: ") << "<b>" << display_name << "</b>";
391  if ( !active[i] )
392  tooltip << "<i>" << _(" (inactive)") << "</i>";
393  tooltip << '\n' << description;
394 
395  add_text(res, str.str(), tooltip.str(), "ability_" + id + base_name);
396  }
397  return res;
398 }
400 {
401  const unit *u = get_visible_unit(rc);
402  return unit_abilities(u);
403 }
404 REPORT_GENERATOR(selected_unit_abilities, rc)
405 {
406  const unit *u = get_selected_unit(rc);
407  return unit_abilities(u);
408 }
409 
410 
411 static config unit_hp(reports::context& rc, const unit* u)
412 {
413  if (!u) return config();
414  std::ostringstream str, tooltip;
415  str << span_color(u->hp_color()) << u->hitpoints()
416  << '/' << u->max_hitpoints() << naps;
417 
418  std::set<std::string> resistances_table;
419 
420  bool att_def_diff = false;
421  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
422  for (const utils::string_map::value_type &resist : u->get_base_resistances())
423  {
424  std::ostringstream line;
425  line << translation::gettext(resist.first.c_str()) << ": ";
426  // Some units have different resistances when attacking or defending.
427  int res_att = 100 - u->resistance_against(resist.first, true, displayed_unit_hex);
428  int res_def = 100 - u->resistance_against(resist.first, false, displayed_unit_hex);
429  const std::string def_color = unit_helper::resistance_color(res_def);
430  if (res_att == res_def) {
431  line << "<span foreground=\"" << def_color << "\">" << utils::signed_percent(res_def)
432  << naps << '\n';
433  } else {
434  const std::string att_color = unit_helper::resistance_color(res_att);
435  line << "<span foreground=\"" << att_color << "\">" << utils::signed_percent(res_att)
436  << naps << "/"
437  << "<span foreground=\"" << def_color << "\">" << utils::signed_percent(res_def)
438  << naps << '\n';
439  att_def_diff = true;
440  }
441  resistances_table.insert(line.str());
442  }
443 
444  tooltip << _("Resistances: ");
445  if (att_def_diff)
446  tooltip << _("(Att / Def)");
447  tooltip << '\n';
448  for (const std::string &line : resistances_table) {
449  tooltip << line;
450  }
451  return text_report(str.str(), tooltip.str());
452 }
454 {
455  const unit *u = get_visible_unit(rc);
456  return unit_hp(rc, u);
457 }
458 REPORT_GENERATOR(selected_unit_hp, rc)
459 {
460  const unit *u = get_selected_unit(rc);
461  return unit_hp(rc, u);
462 }
463 
464 static config unit_xp(const unit* u)
465 {
466  if (!u) return config();
467  std::ostringstream str, tooltip;
468  str << span_color(u->xp_color()) << u->experience()
469  << '/' << u->max_experience() << naps;
470 
472  tooltip << _("Experience Modifier: ") << exp_mod << '%';
473  return text_report(str.str(), tooltip.str());
474 }
476 {
477  const unit *u = get_visible_unit(rc);
478  return unit_xp(u);
479 }
480 REPORT_GENERATOR(selected_unit_xp, rc)
481 {
482  const unit *u = get_selected_unit(rc);
483  return unit_xp(u);
484 }
485 
487 {
488  if (!u) return config();
489  config res;
490  typedef std::pair<std::string, std::string> pair_string;
491  for (const pair_string &ps : u->advancement_icons()) {
492  add_image(res, ps.first, ps.second);
493  }
494  return res;
495 }
497 {
498  const unit *u = get_visible_unit(rc);
499  return unit_advancement_options(u);
500 }
501 REPORT_GENERATOR(selected_unit_advancement_options, rc)
502 {
503  const unit *u = get_selected_unit(rc);
504  return unit_advancement_options(u);
505 }
506 
507 static config unit_defense(reports::context & rc, const unit* u, const map_location& displayed_unit_hex)
508 {
509  if(!u) {
510  return config();
511  }
512 
513  std::ostringstream str, tooltip;
514  const gamemap &map = rc.map();
515  if(!rc.map().on_board(displayed_unit_hex)) {
516  return config();
517  }
518 
519  const t_translation::terrain_code &terrain = map[displayed_unit_hex];
520  int def = 100 - u->defense_modifier(terrain);
521  color_t color = game_config::red_to_green(def);
522  str << span_color(color) << def << '%' << naps;
523  tooltip << _("Terrain: ") << "<b>" << map.get_terrain_info(terrain).description() << "</b>\n";
524 
525  const t_translation::ter_list &underlyings = map.underlying_def_terrain(terrain);
526  if (underlyings.size() != 1 || underlyings.front() != terrain)
527  {
528  bool revert = false;
529  for (const t_translation::terrain_code &t : underlyings)
530  {
531  if (t == t_translation::MINUS) {
532  revert = true;
533  } else if (t == t_translation::PLUS) {
534  revert = false;
535  } else {
536  int t_def = 100 - u->defense_modifier(t);
537  color_t t_color = game_config::red_to_green(t_def);
538  tooltip << '\t' << map.get_terrain_info(t).description() << ": "
539  << span_color(t_color) << t_def << '%' << naps
540  << (revert ? _("maximum^max.") : _("minimum^min.")) << '\n';
541  }
542  }
543  }
544 
545  tooltip << "<b>" << _("Defense: ") << span_color(color) << def << '%' << naps << "</b>";
546  return text_report(str.str(), tooltip.str());
547 }
549 {
550  const unit *u = get_visible_unit(rc);
551  const map_location& displayed_unit_hex = rc.screen().displayed_unit_hex();
552  return unit_defense(rc, u, displayed_unit_hex);
553 }
554 REPORT_GENERATOR(selected_unit_defense, rc)
555 {
556  const unit *u = get_selected_unit(rc);
557  const map_location& selected_hex = rc.screen().selected_hex();
558  return unit_defense(rc, u, selected_hex);
559 }
560 
561 static config unit_vision(const unit* u)
562 {
563  if (!u) return config();
564 
565  // TODO
566  std::ostringstream str;
567  if (u->vision() != u->total_movement()) {
568  str << _("vision: ") << u->vision(); }
569  return text_report(str.str());
570 }
572 {
573  const unit* u = get_visible_unit(rc);
574  return unit_vision(u);
575 }
576 REPORT_GENERATOR(selected_unit_vision, rc)
577 {
578  const unit* u = get_selected_unit(rc);
579  return unit_vision(u);
580 }
581 
582 static config unit_moves(reports::context & rc, const unit* u)
583 {
584  if (!u) return config();
585  std::ostringstream str, tooltip;
586  double movement_frac = 1.0;
587  if (u->side() == rc.screen().playing_side()) {
588  movement_frac = double(u->movement_left()) / std::max<int>(1, u->total_movement());
589  if (movement_frac > 1.0)
590  movement_frac = 1.0;
591  }
592 
593  std::set<t_translation::terrain_code>::const_iterator terrain_it =
595 
596  tooltip << _("Movement Costs:") << "\n";
597  for (; terrain_it != preferences::encountered_terrains().end();
598  ++terrain_it) {
599  const t_translation::terrain_code terrain = *terrain_it;
601  continue;
602 
603  const terrain_type& info = rc.map().get_terrain_info(terrain);
604 
605  if (info.union_type().size() == 1 && info.union_type()[0] == info.number() && info.is_nonnull()) {
606 
607  const std::string& name = info.name();
608  const int moves = u->movement_cost(terrain);
609 
610  tooltip << name << ": ";
611 
612  std::string color;
613  //movement - range: 1 .. 5, movetype::UNREACHABLE=impassable
614  const bool cannot_move = moves > u->total_movement();
615  if (cannot_move) // cannot move in this terrain
616  color = "red";
617  else if (moves > 1)
618  color = "yellow";
619  else
620  color = "white";
621  tooltip << "<span foreground=\"" << color << "\">";
622  // A 5 MP margin; if the movement costs go above
623  // the unit's max moves + 5, we replace it with dashes.
624  if(cannot_move && (moves > u->total_movement() + 5)) {
625  tooltip << font::unicode_figure_dash;
626  } else {
627  tooltip << moves;
628  }
629  tooltip << naps << '\n';
630  }
631  }
632 
633  int grey = 128 + int((255 - 128) * movement_frac);
634  color_t c = color_t(grey, grey, grey);
635  str << span_color(c) << u->movement_left() << '/' << u->total_movement() << naps;
636  return text_report(str.str(), tooltip.str());
637 }
639 {
640  const unit *u = get_visible_unit(rc);
641  return unit_moves(rc, u);
642 }
643 REPORT_GENERATOR(selected_unit_moves, rc)
644 {
645  const unit *u = get_selected_unit(rc);
646  return unit_moves(rc, u);
647 }
648 
650 {
651  // Compare unit_helper::resistance_color()
652  if (resistance < 0) return font::BAD_COLOR;
653  if (resistance > 0) return font::GOOD_COLOR;
654  return font::YELLOW_COLOR;
655 }
656 
657 static int attack_info(reports::context & rc, const attack_type &at, config &res, const unit &u, const map_location &displayed_unit_hex)
658 {
659  std::ostringstream str, tooltip;
660 
661  at.set_specials_context(displayed_unit_hex, u.side() == rc.screen().playing_side());
662  int base_damage = at.damage();
663  int specials_damage = at.modified_damage(false);
664  int damage_multiplier = 100;
665  int tod_bonus = combat_modifier(rc.units(), rc.map(), displayed_unit_hex, u.alignment(), u.is_fearless());
666  damage_multiplier += tod_bonus;
667  int leader_bonus = under_leadership(rc.units(), displayed_unit_hex).first;
668  if (leader_bonus != 0)
669  damage_multiplier += leader_bonus;
670 
672  int damage_divisor = slowed ? 20000 : 10000;
673  // Assume no specific resistance (i.e. multiply by 100).
674  int damage = round_damage(specials_damage, damage_multiplier * 100, damage_divisor);
675 
676  // Hit points are used to calculate swarm, so they need to be bounded.
677  unsigned max_hp = u.max_hitpoints();
678  unsigned cur_hp = std::min<unsigned>(std::max(0, u.hitpoints()), max_hp);
679 
680  unsigned base_attacks = at.num_attacks();
681  unsigned min_attacks, max_attacks;
682  at.modified_attacks(false, min_attacks, max_attacks);
683  unsigned num_attacks = swarm_blows(min_attacks, max_attacks, cur_hp, max_hp);
684 
685  color_t dmg_color = font::weapon_color;
686  if ( damage > specials_damage )
687  dmg_color = font::good_dmg_color;
688  else if ( damage < specials_damage )
689  dmg_color = font::bad_dmg_color;
690 
691  str << span_color(dmg_color) << " " << damage << naps << span_color(font::weapon_color)
692  << font::weapon_numbers_sep << num_attacks << ' ' << at.name()
693  << "</span>\n";
694  tooltip << _("Weapon: ") << "<b>" << at.name() << "</b>\n"
695  << _("Damage: ") << "<b>" << damage << "</b>\n";
696 
697  if ( tod_bonus || leader_bonus || slowed || specials_damage != base_damage )
698  {
699  tooltip << '\t' << _("Base damage: ") << base_damage << '\n';
700  if ( specials_damage != base_damage ) {
701  tooltip << '\t' << _("With specials: ") << specials_damage << '\n';
702  }
703  if (tod_bonus) {
704  tooltip << '\t' << _("Time of day: ")
705  << utils::signed_percent(tod_bonus) << '\n';
706  }
707  if (leader_bonus) {
708  tooltip << '\t' << _("Leadership: ")
709  << utils::signed_percent(leader_bonus) << '\n';
710  }
711  if (slowed) {
712  tooltip << '\t' << _("Slowed: ") << "/ 2" << '\n';
713  }
714  }
715 
716  tooltip << _("Attacks: ") << "<b>" << num_attacks << "</b>\n";
717  if ( max_attacks != min_attacks && cur_hp != max_hp ) {
718  if ( max_attacks < min_attacks ) {
719  // "Reverse swarm"
720  tooltip << '\t' << _("Max swarm bonus: ") << (min_attacks-max_attacks) << '\n';
721  tooltip << '\t' << _("Swarm: ") << "* "<< (100 - cur_hp*100/max_hp) << "%\n";
722  tooltip << '\t' << _("Base attacks: ") << '+' << base_attacks << '\n';
723  // The specials line will not necessarily match up with how the
724  // specials are calculated, but for an unusual case, simple brevity
725  // trumps complexities.
726  if ( max_attacks != base_attacks ) {
727  int attack_diff = int(max_attacks) - int(base_attacks);
728  tooltip << '\t' << _("Specials: ") << utils::signed_value(attack_diff) << '\n';
729  }
730  }
731  else {
732  // Regular swarm
733  tooltip << '\t' << _("Base attacks: ") << base_attacks << '\n';
734  if ( max_attacks != base_attacks ) {
735  tooltip << '\t' << _("With specials: ") << max_attacks << '\n';
736  }
737  if ( min_attacks != 0 ) {
738  tooltip << '\t' << _("Subject to swarm: ") << (max_attacks-min_attacks) << '\n';
739  }
740  tooltip << '\t' << _("Swarm: ") << "* "<< (cur_hp*100/max_hp) << "%\n";
741  }
742  }
743  else if ( num_attacks != base_attacks ) {
744  tooltip << '\t' << _("Base attacks: ") << base_attacks << '\n';
745  tooltip << '\t' << _("With specials: ") << num_attacks << '\n';
746  }
747 
748  add_text(res, flush(str), flush(tooltip));
749 
750  std::string range = string_table["range_" + at.range()];
751  std::string lang_type = string_table["type_" + at.type()];
752 
753  str << span_color(font::weapon_details_color) << " " << " "
754  << range << font::weapon_details_sep
755  << lang_type << "</span>\n";
756 
757  tooltip << _("Weapon range: ") << "<b>" << range << "</b>\n"
758  << _("Damage type: ") << "<b>" << lang_type << "</b>\n"
759  << _("Damage versus: ") << '\n';
760 
761  // Show this weapon damage and resistance against all the different units.
762  // We want weak resistances (= good damage) first.
763  std::map<int, std::set<std::string>, std::greater<int>> resistances;
764  std::set<std::string> seen_types;
765  const team &unit_team = rc.dc().get_team(u.side());
766  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
767  for (const unit &enemy : rc.units())
768  {
769  if (enemy.incapacitated()) //we can't attack statues so don't display them in this tooltip
770  continue;
771  if (!unit_team.is_enemy(enemy.side()))
772  continue;
773  const map_location &loc = enemy.get_location();
774  if (viewing_team.fogged(loc) ||
775  (viewing_team.is_enemy(enemy.side()) && enemy.invisible(loc, rc.dc())))
776  continue;
777  bool new_type = seen_types.insert(enemy.type_id()).second;
778  if (new_type) {
779  int resistance = enemy.resistance_against(at, false, loc);
780  resistances[resistance].insert(enemy.type_name());
781  }
782  }
783 
784  typedef std::pair<int, std::set<std::string>> resist_units;
785  for (const resist_units &resist : resistances) {
786  int damage_with_resistance = round_damage(specials_damage, damage_multiplier * resist.first, damage_divisor);
787  tooltip << "<b>" << damage_with_resistance << "</b> "
788  << "<span color='" << attack_info_percent_color(resist.first-100).to_hex_string() << "'>"
789  << "<i>(" << utils::signed_percent(resist.first-100) << ")</i>"
790  << naps
791  << " : \t" // spaces to align the tab to a multiple of 8
792  << utils::join(resist.second, " " + font::unicode_bullet + " ") << '\n';
793  }
794  add_text(res, flush(str), flush(tooltip));
795 
796  const std::string &accuracy_parry = at.accuracy_parry_description();
797  if (!accuracy_parry.empty())
798  {
800  << " " << accuracy_parry << "</span>\n";
801  int accuracy = at.accuracy();
802  if (accuracy) {
803  tooltip << _("Accuracy:") << "<b>"
804  << utils::signed_percent(accuracy) << "</b>\n";
805  }
806  int parry = at.parry();
807  if (parry) {
808  tooltip << _("Parry:") << "<b>"
809  << utils::signed_percent(parry) << "</b>\n";
810  }
811  add_text(res, flush(str), flush(tooltip));
812  }
813 
815  boost::dynamic_bitset<> active;
816  const std::vector<std::pair<t_string, t_string>> &specials = at.special_tooltips(&active);
817  const size_t specials_size = specials.size();
818  for ( size_t i = 0; i != specials_size; ++i )
819  {
820  // Aliases for readability:
821  const t_string &name = specials[i].first;
822  const t_string &description = specials[i].second;
823  const color_t &details_color = active[i] ? font::weapon_details_color :
825 
826  str << span_color(details_color) << " " << " " << name << naps << '\n';
827  std::string help_page = "weaponspecial_" + name.base_str();
828  tooltip << _("Weapon special: ") << "<b>" << name << "</b>";
829  if ( !active[i] )
830  tooltip << "<i>" << _(" (inactive)") << "</i>";
831  tooltip << '\n' << description;
832 
833  add_text(res, flush(str), flush(tooltip), help_page);
834  }
835  return damage;
836 }
837 
838 // Conversion routine for both unscathed and damage change percentage.
839 static std::string format_prob(double prob)
840 {
841  if(prob > 0.9995) {
842  return "100%";
843  }
844  std::ostringstream res;
845  res << std::setprecision(1) << std::setw(4) << 100.0 * prob << "%";
846  return res.str();
847 }
848 
849 static std::string format_hp(unsigned hp)
850 {
851  std::ostringstream res;
852  res << ' ' << std::setw(3) << hp;
853  return res.str();
854 }
855 
856 static config unit_weapons(reports::context & rc, const unit *attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
857 {
858  if (!attacker || !defender) return config();
859 
860  const unit* u = show_attacker ? attacker : defender;
861  const map_location unit_loc = show_attacker ? attacker_pos : defender->get_location();
862 
863  std::ostringstream str, tooltip;
864  config res;
865 
866  std::vector<battle_context> weapons;
867  for (unsigned int i = 0; i < attacker->attacks().size(); i++) {
868  // skip weapons with attack_weight=0
869  if (attacker->attacks()[i].attack_weight() > 0) {
870  battle_context weapon(rc.units(), attacker_pos, defender->get_location(), i, -1, 0.0, nullptr, attacker);
871  weapons.push_back(weapon);
872  }
873  }
874 
875  for (const battle_context& weapon : weapons) {
876 
877  // Predict the battle outcome.
878  combatant attacker_combatant(weapon.get_attacker_stats());
879  combatant defender_combatant(weapon.get_defender_stats());
880  attacker_combatant.fight(defender_combatant);
881 
882  const battle_context_unit_stats& context_unit_stats =
883  show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
884 
885  int total_damage = 0;
886  int base_damage = 0;
887  int num_blows = 0;
888  int chance_to_hit = 0;
889  t_string weapon_name = _("None");
890 
891  color_t dmg_color = font::weapon_color;
892  if (context_unit_stats.weapon) {
893  base_damage = attack_info(rc, *context_unit_stats.weapon, res, *u, unit_loc);
894  total_damage = context_unit_stats.damage;
895  num_blows = context_unit_stats.num_blows;
896  chance_to_hit = context_unit_stats.chance_to_hit;
897  weapon_name = context_unit_stats.weapon->name();
898 
899  if ( total_damage > base_damage )
900  dmg_color = font::good_dmg_color;
901  else if ( total_damage < base_damage )
902  dmg_color = font::bad_dmg_color;
903  } else {
904  str << span_color(font::weapon_color) << weapon_name << naps << "\n";
905  tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
906  << _("Damage: ") << "<b>" << "0" << "</b>\n";
907  }
908 
909  color_t chance_color = game_config::red_to_green(chance_to_hit);
910 
911  // Total damage.
912  str << " " << span_color(dmg_color) << total_damage << naps << span_color(font::weapon_color)
913  << font::unicode_en_dash << num_blows
914  << " (" << span_color(chance_color) << chance_to_hit << "%" << naps << ")"
915  << naps << "\n";
916 
917  tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
918  << _("Total damage") << "<b>" << total_damage << "</b>\n";
919 
920  // Create the hitpoints distribution.
921  std::vector<std::pair<int, double>> hp_prob_vector;
922 
923  // First, we sort the probabilities in ascending order.
924  std::vector<std::pair<double, int>> prob_hp_vector;
925  int i;
926 
927  combatant* c = show_attacker ? &attacker_combatant : &defender_combatant;
928 
929  for(i = 0; i < static_cast<int>(c->hp_dist.size()); i++) {
930  double prob = c->hp_dist[i];
931 
932  // We keep only values above 0.1%.
933  if(prob > 0.001)
934  prob_hp_vector.emplace_back(prob, i);
935  }
936 
937  std::sort(prob_hp_vector.begin(), prob_hp_vector.end());
938 
939  //TODO fendrin -- make that dynamically
940  int max_hp_distrib_rows_ = 10;
941 
942  // We store a few of the highest probability hitpoint values.
943  int nb_elem = std::min<int>(max_hp_distrib_rows_, prob_hp_vector.size());
944 
945  for(i = prob_hp_vector.size() - nb_elem;
946  i < static_cast<int>(prob_hp_vector.size()); i++) {
947 
948  hp_prob_vector.emplace_back(prob_hp_vector[i].second, prob_hp_vector[i].first);
949  }
950 
951  // Then, we sort the hitpoint values in ascending order.
952  std::sort(hp_prob_vector.begin(), hp_prob_vector.end());
953  // And reverse the order. Might be doable in a better manor.
954  std::reverse(hp_prob_vector.begin(), hp_prob_vector.end());
955 
956  for(i = 0; i < static_cast<int>(hp_prob_vector.size()); i++) {
957 
958  int hp = hp_prob_vector[i].first;
959  double prob = hp_prob_vector[i].second;
960  color_t prob_color = game_config::blue_to_white(prob * 100.0, true);
961 
962  str << span_color(font::weapon_details_color) << " " << " "
963  << span_color(u->hp_color(hp)) << format_hp(hp) << naps
964  << " " << font::weapon_numbers_sep << " "
965  << span_color(prob_color) << format_prob(prob) << naps
966  << naps << "\n";
967  }
968 
969  add_text(res, flush(str), flush(tooltip));
970  }
971  return res;
972 }
973 
974 static config unit_weapons(reports::context & rc, const unit *u)
975 {
976  config res = config();
977  if ((u != nullptr) && (!u->attacks().empty())) {
978  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
979 
980  const std::string attack_headline = _n("Attack", "Attacks", u->attacks().size());
981 
983  + attack_headline + "</span>" + '\n', "");
984 
985  for (const attack_type &at : u->attacks())
986  {
987  attack_info(rc, at, res, *u, displayed_unit_hex);
988  }
989  }
990  return res;
991 }
993 {
994  const unit *u = get_visible_unit(rc);
995  if (!u) return config();
996 
997  return unit_weapons(rc, u);
998 }
999 REPORT_GENERATOR(highlighted_unit_weapons, rc)
1000 {
1001  const unit *u = get_selected_unit(rc);
1002  const unit *sec_u = get_visible_unit(rc);
1003 
1004  if (!u) return config();
1005  if (!sec_u || u == sec_u) return unit_weapons(rc, sec_u);
1006 
1007  map_location highlighted_hex = rc.screen().displayed_unit_hex();
1008  map_location attack_loc;
1009  if (rc.mhb())
1010  attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1011 
1012  if (!attack_loc.valid())
1013  return unit_weapons(rc, sec_u);
1014 
1015  return unit_weapons(rc, u, attack_loc, sec_u, false);
1016 }
1017 REPORT_GENERATOR(selected_unit_weapons, rc)
1018 {
1019  const unit *u = get_selected_unit(rc);
1020  const unit *sec_u = get_visible_unit(rc);
1021 
1022  if (!u) return config();
1023  if (!sec_u || u == sec_u) return unit_weapons(rc, u);
1024 
1025  map_location highlighted_hex = rc.screen().displayed_unit_hex();
1026  map_location attack_loc;
1027  if (rc.mhb())
1028  attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1029 
1030  if (!attack_loc.valid())
1031  return unit_weapons(rc, u);
1032 
1033  return unit_weapons(rc, u, attack_loc, sec_u, true);
1034 }
1035 
1036 REPORT_GENERATOR(unit_image,rc)
1037 {
1038  const unit *u = get_visible_unit(rc);
1039  if (!u) return config();
1040  return image_report(u->absolute_image() + u->image_mods());
1041 }
1042 REPORT_GENERATOR(selected_unit_image, rc)
1043 {
1044  const unit *u = get_selected_unit(rc);
1045  if (!u) return config();
1046  return image_report(u->absolute_image() + u->image_mods());
1047 }
1048 
1049 REPORT_GENERATOR(selected_unit_profile, rc)
1050 {
1051  const unit *u = get_selected_unit(rc);
1052  if (!u) return config();
1053  return image_report(u->small_profile());
1054 }
1055 REPORT_GENERATOR(unit_profile, rc)
1056 {
1057  const unit *u = get_visible_unit(rc);
1058  if (!u) return config();
1059  return image_report(u->small_profile());
1060 }
1061 
1062 REPORT_GENERATOR(tod_stats, rc)
1063 {
1064  std::ostringstream tooltip;
1065  std::ostringstream text;
1066 
1067  const map_location& selected_hex = rc.screen().selected_hex();
1068  const map_location& mouseover_hex = rc.screen().mouseover_hex();
1069 
1070  const map_location& hex = mouseover_hex.valid() ? mouseover_hex : selected_hex;
1071 
1072  const std::vector<time_of_day>& schedule = rc.tod().times(hex);
1073 
1074  int current = rc.tod().get_current_time(hex);
1075  int i = 0;
1076  for (const time_of_day& tod : schedule) {
1077  if (i == current) tooltip << "<big><b>";
1078  tooltip << tod.name << "\n";
1079  if (i == current) tooltip << "</b></big>";
1080  i++;
1081  }
1082 
1083  int times = schedule.size();
1084  text << current + 1 << "/" << times;
1085 
1086  return text_report(text.str(), tooltip.str(), "..schedule");
1087 }
1088 
1089 static config time_of_day_at(reports::context & rc, const map_location& mouseover_hex)
1090 {
1091  std::ostringstream tooltip;
1092  time_of_day tod;
1093  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1094  if (viewing_team.shrouded(mouseover_hex)) {
1095  // Don't show time on shrouded tiles.
1096  tod = rc.tod().get_time_of_day();
1097  } else if (viewing_team.fogged(mouseover_hex)) {
1098  // Don't show illuminated time on fogged tiles.
1099  tod = rc.tod().get_time_of_day(mouseover_hex);
1100  } else {
1101  tod = rc.tod().get_illuminated_time_of_day(rc.units(), rc.map(), mouseover_hex);
1102  }
1103 
1104  int b = tod.lawful_bonus;
1105 
1106  std::string lawful_color("white");
1107  std::string chaotic_color("white");
1108  std::string liminal_color("white");
1109 
1110  if (b != 0) {
1111  lawful_color = (b > 0) ? "green" : "red";
1112  chaotic_color = (b < 0) ? "green" : "red";
1113  liminal_color = "red";
1114  }
1115  tooltip << tod.name << '\n'
1116  << _("Lawful units: ") << "<span foreground=\"" << lawful_color << "\">"
1117  << utils::signed_percent(b) << "</span>\n"
1118  << _("Neutral units: ") << utils::signed_percent(0) << '\n'
1119  << _("Chaotic units: ") << "<span foreground=\"" << chaotic_color << "\">"
1120  << utils::signed_percent(-b) << "</span>\n"
1121  << _("Liminal units: ") << "<span foreground=\"" << liminal_color << "\">"
1122  << utils::signed_percent(-(std::abs(b))) << "</span>\n";
1123 
1124  std::string tod_image = tod.image;
1125  if(tod.bonus_modified > 0) {
1126  tod_image += (formatter() << "~BLIT(" << game_config::images::tod_bright << ")").str();
1127  } else if(tod.bonus_modified < 0) {
1128  tod_image += (formatter() << "~BLIT(" << game_config::images::tod_dark << ")").str();
1129  }
1130 
1131  return image_report(tod_image, tooltip.str(), "time_of_day_" + tod.id);
1132 }
1134 {
1135  map_location mouseover_hex = rc.screen().mouseover_hex();
1136  if (mouseover_hex.valid()) return time_of_day_at(rc, mouseover_hex);
1137  return time_of_day_at(rc, rc.screen().selected_hex());
1138 }
1139 
1140 static config unit_box_at(reports::context & rc, const map_location& mouseover_hex)
1141 {
1142  std::ostringstream tooltip;
1143  time_of_day local_tod;
1144  time_of_day global_tod = rc.tod().get_time_of_day();
1145  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1146  if (viewing_team.shrouded(mouseover_hex)) {
1147  // Don't show time on shrouded tiles.
1148  local_tod = global_tod;
1149  } else if (viewing_team.fogged(mouseover_hex)) {
1150  // Don't show illuminated time on fogged tiles.
1151  local_tod = rc.tod().get_time_of_day(mouseover_hex);
1152  } else {
1153  local_tod = rc.tod().get_illuminated_time_of_day(rc.units(), rc.map(),mouseover_hex);
1154  }
1155 
1156  int bonus = local_tod.lawful_bonus;
1157 
1158  std::string lawful_color("white");
1159  std::string chaotic_color("white");
1160  std::string liminal_color("white");
1161 
1162  if (bonus != 0) {
1163  lawful_color = (bonus > 0) ? "green" : "red";
1164  chaotic_color = (bonus < 0) ? "green" : "red";
1165  liminal_color = "red";
1166  }
1167  tooltip << local_tod.name << '\n'
1168  << _("Lawful units: ") << "<span foreground=\"" << lawful_color << "\">"
1169  << utils::signed_percent(bonus) << "</span>\n"
1170  << _("Neutral units: ") << utils::signed_percent(0) << '\n'
1171  << _("Chaotic units: ") << "<span foreground=\"" << chaotic_color << "\">"
1172  << utils::signed_percent(-bonus) << "</span>\n"
1173  << _("Liminal units: ") << "<span foreground=\"" << liminal_color << "\">"
1174  << utils::signed_percent(-(std::abs(bonus))) << "</span>\n";
1175 
1176  std::string local_tod_image = "themes/classic/" + local_tod.image;
1177  std::string global_tod_image = "themes/classic/" + global_tod.image;
1178  if(local_tod.bonus_modified != 0) {
1179  local_tod_image += "~BLIT(";
1180  if (local_tod.bonus_modified > 0) local_tod_image += game_config::images::tod_bright;
1181  else if (local_tod.bonus_modified < 0) local_tod_image += game_config::images::tod_dark;
1182  local_tod_image += ")";
1183  }
1184 
1185  const gamemap &map = rc.map();
1186  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1187 
1188  //if (t_translation::terrain_matches(terrain, t_translation::ALL_OFF_MAP))
1189  // return config();
1190 
1191  //if (map.is_keep(mouseover_hex)) {
1192  // add_image(cfg, "icons/terrain/terrain_type_keep.png", "");
1193  //}
1194 
1195  const t_translation::ter_list& underlying_terrains = map.underlying_union_terrain(terrain);
1196 
1197  std::string bg_terrain_image;
1198 
1199  for (const t_translation::terrain_code& underlying_terrain : underlying_terrains) {
1200  const std::string& terrain_id = map.get_terrain_info(underlying_terrain).id();
1201  bg_terrain_image = "~BLIT(unit_env/terrain/terrain-" + terrain_id + ".png)" + bg_terrain_image;
1202  }
1203 
1204  std::stringstream color;
1205  color << local_tod.color;
1206 
1207  bg_terrain_image = bg_terrain_image + "~CS(" + color.str() + ")";
1208 
1209  const unit *u = get_visible_unit(rc);
1210  std::string unit_image;
1211  if (u)
1212  unit_image = "~BLIT(" + u->absolute_image() + u->image_mods() + ",35,22)";
1213 
1214  std::string tod_image = global_tod_image + "~BLIT(" + local_tod_image + ")";
1215 
1216  return image_report(tod_image + bg_terrain_image + unit_image, tooltip.str(), "time_of_day");
1217 }
1218 REPORT_GENERATOR(unit_box, rc)
1219 {
1220  map_location mouseover_hex = rc.screen().mouseover_hex();
1221  return unit_box_at(rc, mouseover_hex);
1222 }
1223 
1224 
1226 {
1227  std::ostringstream str, tooltip;
1228  str << rc.tod().turn();
1229  int nb = rc.tod().number_of_turns();
1230  if (nb != -1) str << '/' << nb;
1231 
1232  tooltip << _("Turn Number");
1233  if(nb != -1) {
1234  tooltip << "\n\n" << _("When the game reaches the number of turns indicated by the second number, it will end.");
1235  }
1236  return text_report(str.str(), tooltip.str());
1237 }
1238 
1240 {
1241  std::ostringstream str;
1242  int viewing_side = rc.screen().viewing_side();
1243  // Suppose the full unit map is applied.
1244  int fake_gold = rc.dc().get_team(viewing_side).gold();
1245 
1246  if (rc.wb())
1247  fake_gold -= rc.wb()->get_spent_gold_for(viewing_side);
1248  char const *end = naps;
1249  if (viewing_side != rc.screen().playing_side()) {
1250  str << span_color(font::GRAY_COLOR);
1251  }
1252  else if (fake_gold < 0) {
1253  str << span_color(font::BAD_COLOR);
1254  }
1255  else {
1256  end = "";
1257  }
1258  str << utils::half_signed_value(fake_gold) << end;
1259  return text_report(str.str(), _("Gold") + "\n\n" + _("The amount of gold currently available to recruit and maintain your army."));
1260 }
1261 
1262 REPORT_GENERATOR(villages, rc)
1263 {
1264  std::ostringstream str;
1265  int viewing_side = rc.screen().viewing_side();
1266  const team &viewing_team = rc.dc().get_team(viewing_side);
1267  str << viewing_team.villages().size() << '/';
1268  if (viewing_team.uses_shroud()) {
1269  int unshrouded_villages = 0;
1270  for (const map_location &loc : rc.map().villages()) {
1271  if (!viewing_team.shrouded(loc))
1272  ++unshrouded_villages;
1273  }
1274  str << unshrouded_villages;
1275  } else {
1276  str << rc.map().villages().size();
1277  }
1278  return gray_inactive(rc,str.str(), _("Villages") + "\n\n" + _("The fraction of known villages that your side has captured."));
1279 }
1280 
1281 REPORT_GENERATOR(num_units, rc)
1282 {
1283  return gray_inactive(rc, std::to_string(rc.dc().side_units(rc.screen().viewing_side())), _("Units") + "\n\n" + _("The total number of units on your side."));
1284 }
1285 
1286 REPORT_GENERATOR(upkeep, rc)
1287 {
1288  std::ostringstream str;
1289  int viewing_side = rc.screen().viewing_side();
1290  const team &viewing_team = rc.dc().get_team(viewing_side);
1291  team_data td = rc.dc().calculate_team_data(viewing_team);
1292  str << td.expenses << " (" << td.upkeep << ")";
1293  return gray_inactive(rc,str.str(), _("Upkeep") + "\n\n" + _("The expenses incurred at the end of every turn to maintain your army. The first number is the amount of gold that will be deducted. The second is the total cost of upkeep, including that covered by villages — in other words, the amount of gold that would be deducted if you lost all villages."));
1294 }
1295 
1296 REPORT_GENERATOR(expenses, rc)
1297 {
1298  int viewing_side = rc.screen().viewing_side();
1299  const team &viewing_team = rc.dc().get_team(viewing_side);
1300  team_data td = rc.dc().calculate_team_data(viewing_team);
1301  return gray_inactive(rc,std::to_string(td.expenses));
1302 }
1303 
1304 REPORT_GENERATOR(income, rc)
1305 {
1306  std::ostringstream str;
1307  int viewing_side = rc.screen().viewing_side();
1308  const team &viewing_team = rc.dc().get_team(viewing_side);
1309  team_data td = rc.dc().calculate_team_data(viewing_team);
1310  char const *end = naps;
1311  if (viewing_side != rc.screen().playing_side()) {
1312  if (td.net_income < 0) {
1313  td.net_income = - td.net_income;
1314  str << span_color(font::GRAY_COLOR);
1315  str << font::unicode_minus;
1316  }
1317  else {
1318  str << span_color(font::GRAY_COLOR);
1319  }
1320  }
1321  else if (td.net_income < 0) {
1322  td.net_income = - td.net_income;
1323  str << span_color(font::BAD_COLOR);
1324  str << font::unicode_minus;
1325  }
1326  else {
1327  end = "";
1328  }
1329  str << td.net_income << end;
1330  return text_report(str.str(), _("Income") + "\n\n" + _("The amount of gold you gain each turn from your controlled villages, or the amount of gold you will lose each turn for unit upkeep."));
1331 }
1332 
1333 namespace {
1334 void blit_tced_icon(config &cfg, const std::string &terrain_id, const std::string &icon_image, bool high_res,
1335  const std::string &terrain_name) {
1336  const std::string tc_base = high_res ? "images/buttons/icon-base-32.png" : "images/buttons/icon-base-16.png";
1337  const std::string terrain_image = "terrain/" + icon_image + (high_res ? "_30.png" : ".png");
1338  add_image(cfg, tc_base + "~RC(magenta>" + terrain_id + ")~BLIT(" + terrain_image + ")", terrain_name);
1339 }
1340 }
1341 
1342 REPORT_GENERATOR(terrain_info, rc)
1343 {
1344  const gamemap &map = rc.map();
1345  map_location mouseover_hex = rc.screen().mouseover_hex();
1346 
1347  if (!map.on_board(mouseover_hex))
1348  mouseover_hex = rc.screen().selected_hex();
1349 
1350  if (!map.on_board(mouseover_hex))
1351  return config();
1352 
1353  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1355  return config();
1356 
1357  config cfg;
1358 
1359  bool high_res = false;
1360 
1361  if (display::get_singleton()->shrouded(mouseover_hex)) {
1362  return cfg;
1363  }
1364  //TODO
1365 // if (display::get_singleton()->fogged(mouseover_hex)) {
1366 // blit_tced_icon(cfg, "fog", high_res);
1367 // }
1368 //
1369 // if (map.is_keep(mouseover_hex)) {
1370 // blit_tced_icon(cfg, "keep", high_res);
1371 // }
1372 
1373  const t_translation::ter_list& underlying_terrains = map.underlying_union_terrain(terrain);
1374  for (const t_translation::terrain_code& underlying_terrain : underlying_terrains) {
1375 
1377  continue;
1378  const std::string& terrain_id = map.get_terrain_info(underlying_terrain).id();
1379  const std::string& terrain_name = map.get_terrain_string(underlying_terrain);
1380  const std::string& terrain_icon = map.get_terrain_info(underlying_terrain).icon_image();
1381  if (terrain_icon.empty())
1382  continue;
1383  blit_tced_icon(cfg, terrain_id, terrain_icon, high_res, terrain_name);
1384  }
1385  return cfg;
1386 }
1387 
1389 {
1390  const gamemap &map = rc.map();
1391  int viewing_side = rc.screen().viewing_side();
1392  const team &viewing_team = rc.dc().get_team(viewing_side);
1393  map_location mouseover_hex = rc.screen().mouseover_hex();
1394  if (!map.on_board(mouseover_hex) || viewing_team.shrouded(mouseover_hex))
1395  return config();
1396 
1397  t_translation::terrain_code terrain = map.get_terrain(mouseover_hex);
1399  return config();
1400 
1401  std::ostringstream str;
1402  if (map.is_village(mouseover_hex))
1403  {
1404  int owner = rc.dc().village_owner(mouseover_hex) + 1;
1405  if (owner == 0 || viewing_team.fogged(mouseover_hex)) {
1406  str << map.get_terrain_info(terrain).income_description();
1407  } else if (owner == viewing_side) {
1408  str << map.get_terrain_info(terrain).income_description_own();
1409  } else if (viewing_team.is_enemy(owner)) {
1410  str << map.get_terrain_info(terrain).income_description_enemy();
1411  } else {
1412  str << map.get_terrain_info(terrain).income_description_ally();
1413  }
1414 
1415  const std::string& underlying_desc = map.get_underlying_terrain_string(terrain);
1416  if(!underlying_desc.empty()) {
1417  str << underlying_desc;
1418  }
1419  } else {
1420  str << map.get_terrain_string(terrain);
1421  }
1422 
1423  return text_report(str.str());
1424 }
1425 
1426 REPORT_GENERATOR(zoom_level, rc)
1427 {
1428  std::ostringstream text;
1429  std::ostringstream tooltip;
1430  std::ostringstream help;
1431 
1432  text << static_cast<int>(rc.screen().get_zoom_factor() * 100) << "%";
1433 
1434  return text_report(text.str(), tooltip.str(), help.str());
1435 }
1436 
1437 REPORT_GENERATOR(position, rc)
1438 {
1439  const gamemap &map = rc.map();
1440  map_location mouseover_hex = rc.screen().mouseover_hex(),
1441  displayed_unit_hex = rc.screen().displayed_unit_hex(),
1442  selected_hex = rc.screen().selected_hex();
1443 
1444  if (!map.on_board(mouseover_hex)) {
1445  if (!map.on_board(selected_hex))
1446  return config();
1447  else {
1448  mouseover_hex = selected_hex;
1449  }
1450  }
1451 
1452  t_translation::terrain_code terrain = map[mouseover_hex];
1454  return config();
1455 
1456  std::ostringstream str;
1457  str << mouseover_hex;
1458 
1459  const unit *u = get_visible_unit(rc);
1460  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1461  if (!u ||
1462  (displayed_unit_hex != mouseover_hex &&
1463  displayed_unit_hex != rc.screen().selected_hex()) ||
1464  viewing_team.shrouded(mouseover_hex))
1465  return text_report(str.str());
1466 
1467  int move_cost = u->movement_cost(terrain);
1468  int defense = 100 - u->defense_modifier(terrain);
1469  if (move_cost < movetype::UNREACHABLE) {
1470  str << " " << defense << "%," << move_cost;
1471  } else if (mouseover_hex == displayed_unit_hex) {
1472  str << " " << defense << "%,‒";
1473  } else {
1474  str << " ‒";
1475  }
1476  return text_report(str.str());
1477 }
1478 
1479 REPORT_GENERATOR(side_playing, rc)
1480 {
1481  const team &active_team = rc.teams()[rc.screen().playing_team()];
1482  std::string flag_icon = active_team.flag_icon();
1484  std::string new_rgb = team::get_side_color_id(rc.screen().playing_side());
1485  std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
1486  if (flag_icon.empty())
1487  flag_icon = game_config::images::flag_icon;
1488  return image_report(flag_icon + mods, active_team.side_name());
1489 }
1490 
1491 REPORT_GENERATOR(observers, rc)
1492 {
1493  const std::set<std::string> &observers = rc.screen().observers();
1494  if (observers.empty())
1495  return config();
1496 
1497  std::ostringstream str;
1498  str << _("Observers:") << '\n';
1499  for (const std::string &obs : observers) {
1500  str << obs << '\n';
1501  }
1502  return image_report(game_config::images::observer, str.str());
1503 }
1504 
1505 /* TODO unused
1506 REPORT_GENERATOR(selected_terrain)
1507 {
1508  const std::string selected_terrain = editor::get_selected_terrain();
1509  if (selected_terrain.empty())
1510  return config();
1511  else
1512  return text_report(selected_terrain);
1513 }
1514 */
1515 
1516 /* TODO this is unused
1517 REPORT_GENERATOR(edit_left_button_function)
1518 {
1519  const std::string left_button_function = editor::get_left_button_function();
1520  if (left_button_function.empty())
1521  return config();
1522  else
1523  return text_report(left_button_function);
1524 }
1525 */
1526 
1527 REPORT_GENERATOR(report_clock, /*rc*/)
1528 {
1529  std::ostringstream ss;
1530 
1532  ? "%I:%M %p"
1533  : "%H:%M";
1534 
1535  time_t t = std::time(nullptr);
1536  ss << utils::put_time(std::localtime(&t), format);
1537 
1538  return text_report(ss.str(), _("Clock"));
1539 }
1540 
1541 REPORT_GENERATOR(report_countdown, rc)
1542 {
1543  int viewing_side = rc.screen().viewing_side();
1544  const team &viewing_team = rc.dc().get_team(viewing_side);
1545  int min, sec;
1546  if (viewing_team.countdown_time() == 0)
1547  return report_report_clock(rc);
1548  std::ostringstream str;
1549  sec = viewing_team.countdown_time() / 1000;
1550  char const *end = naps;
1551  if (viewing_side != rc.screen().playing_side())
1552  str << span_color(font::GRAY_COLOR);
1553  else if (sec < 60)
1554  str << "<span foreground=\"#c80000\">";
1555  else if (sec < 120)
1556  str << "<span foreground=\"#c8c800\">";
1557  else
1558  end = "";
1559  min = sec / 60;
1560  str << min << ':';
1561  sec = sec % 60;
1562  if (sec < 10) str << '0';
1563  str << sec << end;
1564  return text_report(str.str(), _("Turn Countdown") + "\n\n" + _("Countdown until your turn automatically ends."));
1565 }
1566 
1568 {
1569  dynamic_generators_[name].reset(g);
1570 }
1571 
1573 {
1574  if (!only_static) {
1575  dynamic_report_generators::const_iterator i = dynamic_generators_.find(name);
1576  if (i != dynamic_generators_.end())
1577  return i->second->generate(rc);
1578  }
1579  static_report_generators::const_iterator j = static_generators.find(name);
1580  if (j != static_generators.end())
1581  return j->second(rc);
1582  return config();
1583 }
1584 
1585 const std::set<std::string> &reports::report_list()
1586 {
1587  if (!all_reports_.empty()) return all_reports_;
1588  for (const static_report_generators::value_type &v : static_generators) {
1589  all_reports_.insert(v.first);
1590  }
1591  for (const dynamic_report_generators::value_type &v : dynamic_generators_) {
1592  all_reports_.insert(v.first);
1593  }
1594  return all_reports_;
1595 }
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
Definition: attack.hpp:49
const t_string & name() const
Definition: attack_type.hpp:39
static config unit_level(const unit *u)
Definition: reports.cpp:231
bool uses_shroud() const
Definition: team.hpp:314
const std::vector< t_string > & trait_descriptions() const
Gets the descriptions of the currently registered traits.
Definition: unit.hpp:928
void set_specials_context(const map_location &unit_loc, const map_location &other_loc, bool attacking, const_attack_ptr other_attack) const
Sets the context under which specials will be checked for being active.
Definition: abilities.cpp:703
static config unit_xp(const unit *u)
Definition: reports.cpp:464
std::string tod_dark
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1057
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
std::vector< char_t > string
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:87
static int get_acceleration()
Definition: types.cpp:524
const t_translation::ter_list & union_type() const
Definition: terrain.hpp:50
const std::string & color() const
Definition: team.hpp:254
const std::string weapon_details_sep
Definition: constants.cpp:45
This class represents a single unit of a specific type.
Definition: unit.hpp:100
const color_t inactive_details_color
static config time_of_day_at(reports::context &rc, const map_location &mouseover_hex)
Definition: reports.cpp:1089
const t_string & income_description_enemy() const
Definition: terrain.hpp:73
tod_color color
The color modifications that should be made to the game board to reflect the time of day...
t_string unit_description() const
A detailed description of this unit.
Definition: unit.hpp:354
const t_string & name(GENDER gender=MALE) const
Definition: race.hpp:34
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< std::pair< std::string, std::string > > amla_icons() const
Gets the image and description data for modification advancements.
Definition: unit.cpp:1690
const color_t GRAY_COLOR
bool shrouded(const map_location &loc) const
Definition: team.cpp:633
static config unit_advancement_options(const unit *u)
Definition: reports.cpp:486
std::map< std::string, std::string > advancement_icons() const
Gets and image path and and associated description for each advancement option.
Definition: unit.cpp:1650
int modified_damage(bool is_backstab) const
Returns the damage per attack of this weapon, considering specials.
Definition: abilities.cpp:769
std::vector< std::pair< t_string, t_string > > special_tooltips(boost::dynamic_bitset<> *active_list=nullptr) const
Returns a vector of names and descriptions for the specials of *this.
Definition: abilities.cpp:639
Various functions that implement attacks and attack calculations.
utils::string_map get_base_resistances() const
Gets resistances without any abilities applied.
Definition: unit.hpp:884
static char const * naps
Definition: reports.cpp:108
const color_t GOOD_COLOR
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
const t_translation::ter_list & underlying_union_terrain(const map_location &loc) const
Definition: map.cpp:59
color_t blue_to_white(int val, bool for_text)
logger & info()
Definition: log.cpp:91
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition: movetype.hpp:83
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
const tod_manager & tod() const
Definition: reports.hpp:56
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1067
bool is_village(const map_location &loc) const
Definition: map.cpp:66
bool is_enemy(int n) const
Definition: team.hpp:241
static void add_status(config &r, char const *path, char const *desc1, char const *desc2)
Definition: reports.cpp:77
std::string id
Definition: time_of_day.hpp:91
color_t xp_color() const
Color for this unit's XP.
Definition: unit.cpp:1125
void set_specials_context_for_listing() const
Definition: abilities.cpp:730
static config image_report(const std::string &image, const std::string &tooltip="", const std::string &help="")
Definition: reports.cpp:67
int level() const
The current level of this unit.
Definition: unit.hpp:441
const std::set< std::string > & report_list()
Definition: reports.cpp:1585
static std::string format_hp(unsigned hp)
Definition: reports.cpp:849
const std::string & id() const
Definition: race.hpp:32
int lawful_bonus
The % bonus lawful units receive.
Definition: time_of_day.hpp:84
const color_t good_dmg_color
The unit is poisoned - it loses health each turn.
Definition: unit.hpp:721
const t_string & name() const
Definition: terrain.hpp:33
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
static config text_report(const std::string &text, const std::string &tooltip="", const std::string &help="")
Definition: reports.cpp:59
std::string image
The image to be displayed in the game status.
Definition: time_of_day.hpp:88
static std::string format_prob(double prob)
Definition: reports.cpp:839
const std::vector< std::string > advances_to_translated() const
Gets the names of the possible types this unit can advance to on level-up.
Definition: unit.cpp:1177
const std::string & id() const
Definition: terrain.hpp:37
The unit is petrified - it cannot move or be attacked.
Definition: unit.hpp:722
color_t hp_color() const
Color for this unit's current hitpoints.
Definition: unit.cpp:1115
virtual int playing_side() const
Definition: display.hpp:205
static config unit_side(reports::context &rc, const unit *u)
Definition: reports.cpp:200
static config unit_name(const unit *u)
Definition: reports.cpp:132
static config unit_traits(const unit *u)
Definition: reports.cpp:268
const std::string & type_id() const
The id of this unit's type.
Definition: unit.hpp:267
report_generator_helper(const char *name, reports::generator_function g)
Definition: reports.cpp:97
static config unit_type(const unit *u)
Definition: reports.cpp:160
static const color_t attack_info_percent_color(int resistance)
Definition: reports.cpp:649
const std::set< std::string > movetype::effects resistance
Definition: movetype.cpp:782
-file sdl_utils.hpp
int parry() const
Definition: attack_type.hpp:48
int accuracy() const
Definition: attack_type.hpp:47
display & screen()
Definition: reports.hpp:55
std::string get_terrain_string(const map_location &loc) const
Definition: map.cpp:61
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
Definition: attack.hpp:72
A single unit type that the player may recruit.
Definition: types.hpp:42
int num_attacks() const
Definition: attack_type.hpp:50
const t_string & income_description_own() const
Definition: terrain.hpp:74
static config gray_inactive(reports::context &rc, const std::string &str, const std::string &tooltip="")
Definition: reports.cpp:124
const unit_race * race() const
Gets this unit's race.
Definition: unit.hpp:387
const terrain_code VOID_TERRAIN
static config unit_alignment(reports::context &rc, const unit *u)
Definition: reports.cpp:332
std::string flag_icon
const color_t weapon_color
bool invisible(const map_location &loc, const display_context &dc, bool see_all=true) const
Definition: unit.cpp:2359
#define b
t_translation::terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:301
static static_report_generators static_generators
Definition: reports.cpp:93
t_string name
Definition: time_of_day.hpp:89
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:57
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:417
const t_translation::ter_list & underlying_def_terrain(const map_location &loc) const
Definition: map.cpp:57
static config unit_race(const unit *u)
Definition: reports.cpp:181
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:44
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
static std::string at(const std::string &file, int line)
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
const color_t bad_dmg_color
int resistance_against(const std::string &damage_name, bool attacker, const map_location &loc) const
The unit's resistance against a given damage type.
Definition: unit.cpp:1625
virtual const map_location & displayed_unit_hex() const
Virtual functions shadowed in game_display.
Definition: display.hpp:204
int damage
Effective damage of the weapon (all factors accounted for).
Definition: attack.hpp:73
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition: unit.cpp:2501
const std::string unicode_minus
Definition: constants.cpp:37
const std::string & flag_icon() const
Definition: team.hpp:299
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
Definition: color.cpp:97
bool valid() const
Definition: location.hpp:74
The unit is slowed - it moves slower and does less damage.
Definition: unit.hpp:720
const terrain_code FOGGED
#define REPORT_GENERATOR(n, cn)
Definition: reports.cpp:103
void register_generator(const std::string &name, generator *)
Definition: reports.cpp:1567
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1141
std::ostringstream wrapper.
Definition: formatter.hpp:38
std::string get_underlying_terrain_string(const t_translation::terrain_code &terrain) const
Definition: map.cpp:87
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:393
std::set< std::string > all_reports_
Definition: reports.hpp:86
config generate_report(const std::string &name, context &ct, bool only_static=false)
Definition: reports.cpp:1572
const t_string & name() const
Gets this unit's translatable display name.
Definition: unit.hpp:307
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:360
Encapsulates the map of the game.
Definition: map.hpp:34
static UNUSEDNOWARN std::string _n(const char *str1, const char *str2, int n)
Definition: gettext.hpp:93
const terrain_code MINUS
bool show_variations_in_help() const
Whether the unit type has at least one help-visible variation.
Definition: types.cpp:787
t_translation::terrain_code number() const
Definition: terrain.hpp:44
Computes the statistics of a battle between an attacker and a defender unit.
Definition: attack.hpp:170
const terrain_code PLUS
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:399
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
Definition: unit.cpp:1582
std::set< t_translation::terrain_code > & encountered_terrains()
Definition: game.cpp:946
void fight(combatant &opponent, bool levelup_considered=true)
Simulate a fight! Can be called multiple times for cumulative calculations.
std::string path
Definition: game_config.cpp:56
static config unit_hp(reports::context &rc, const unit *u)
Definition: reports.cpp:411
Structure describing the statistics of a unit involved in the battle.
Definition: attack.hpp:47
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:98
const color_t YELLOW_COLOR
static UNUSEDNOWARN std::string gettext(const char *str)
Definition: gettext.hpp:64
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:411
const std::set< map_location > & villages() const
Definition: team.hpp:183
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:130
const std::string unicode_figure_dash
Definition: constants.cpp:40
int viewing_side() const
Definition: display.hpp:102
bool is_nonnull() const
Definition: terrain.hpp:52
dynamic_report_generators dynamic_generators_
Definition: reports.hpp:88
const std::string & type() const
Definition: attack_type.hpp:41
std::vector< std::tuple< std::string, t_string, t_string, t_string > > ability_tooltips(boost::dynamic_bitset<> *active_list=nullptr) const
Gets the names and descriptions of this unit's abilities.
Definition: abilities.cpp:262
std::function< config(reports::context &)> generator_function
Definition: reports.hpp:80
std::string flag_rgb
static std::string get_side_color_id(unsigned side)
Definition: team.cpp:941
static config unit_status(reports::context &rc, const unit *u)
Definition: reports.cpp:298
std::string base_str() const
Definition: tstring.hpp:190
Encapsulates the map of the game.
Definition: location.hpp:42
static const unit * get_visible_unit(reports::context &rc)
Definition: reports.cpp:110
int round_damage(int base_damage, int bonus, int divisor)
round (base_damage * bonus / divisor) to the closest integer, but up or down towards base_damage ...
Definition: math.hpp:60
const std::vector< team > & teams() const
Definition: reports.hpp:50
unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp, unsigned max_hp)
Calculates the number of blows resulting from swarm.
Definition: attack.hpp:37
static config unit_box_at(reports::context &rc, const map_location &mouseover_hex)
Definition: reports.cpp:1140
All combat-related info.
const color_t weapon_details_color
std::string escape_text(const std::string &text)
Escapes the pango markup characters in a text.
Definition: escape.hpp:30
const t_string & type_name() const
Gets the translatable name of this unit's type.
Definition: unit.hpp:273
std::string small_profile() const
An optional profile image to display in Help.
Definition: unit.cpp:1054
static config unit_moves(reports::context &rc, const unit *u)
Definition: reports.cpp:582
const std::string unicode_en_dash
Definition: constants.cpp:38
const unit_type & type() const
This unit's type, accounting for gender and variation.
Definition: unit.hpp:256
std::string resistance_color(const int resistance)
Definition: helper.cpp:35
const std::set< std::string > movetype::effects defense
Definition: movetype.cpp:782
static const unit * get_selected_unit(reports::context &rc)
Definition: reports.cpp:117
static void add_image(config &report, const std::string &image, const std::string &tooltip, const std::string &help="")
Definition: reports.cpp:50
static map_location::DIRECTION s
int vision() const
Gets the unit's vision points.
Definition: unit.hpp:1184
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1331
const t_string & income_description_ally() const
Definition: terrain.hpp:72
double g
Definition: astarsearch.cpp:64
std::string absolute_image() const
The name of the file to game_display (used in menus).
Definition: unit.cpp:2327
const display_context & dc() const
Definition: reports.hpp:54
std::string signed_percent(int val)
Convert into a percentage (using the Unicode "−" and +0% convention.
const std::string & range() const
Definition: attack_type.hpp:43
attack_itors attacks()
Gets an iterator over this unit's attacks.
Definition: unit.hpp:785
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
Definition: unit.hpp:1224
size_t i
Definition: function.cpp:933
void modified_attacks(bool is_backstab, unsigned &min_attacks, unsigned &max_attacks) const
Calculates the number of attacks this weapon has, considering specials.
Definition: abilities.cpp:743
static std::string flush(std::ostringstream &s)
Definition: reports.cpp:85
bool fogged(const map_location &loc) const
Definition: team.cpp:642
const unit_map & units() const
Definition: reports.hpp:51
#define N_(String)
Definition: gettext.hpp:97
const std::string unicode_bullet
Definition: constants.cpp:42
static int sort(lua_State *L)
Definition: ltablib.cpp:411
std::string observer
static config unit_defense(reports::context &rc, const unit *u, const map_location &displayed_unit_hex)
Definition: reports.cpp:507
config & add_child(config_key_type key)
Definition: config.cpp:475
std::string base_name(const std::string &file, const bool remove_extension=false)
Returns the base filename of a file, with directory name stripped.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:369
int damage() const
Definition: attack_type.hpp:49
std::string accuracy_parry_description() const
Definition: attack_type.cpp:76
std::map< std::string, reports::generator_function > static_report_generators
Definition: reports.cpp:92
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.
static int attack_info(reports::context &rc, const attack_type &at, config &res, const unit &u, const map_location &displayed_unit_hex)
Definition: reports.cpp:657
const ter_match ALL_OFF_MAP
int countdown_time() const
Definition: team.hpp:209
const std::string weapon_numbers_sep
Definition: constants.cpp:44
const std::vector< t_string > & trait_names() const
Gets the names of the currently registered traits.
Definition: unit.hpp:918
double t
Definition: astarsearch.cpp:64
const std::string & side_name() const
Definition: team.hpp:304
color_t red_to_green(int val, bool for_text)
Return a color corresponding to the value val red for val=0 to green for val=100, passing by yellow...
const team & get_team(int side) const
symbol_table string_table
Definition: language.cpp:62
const gamemap & map() const
Definition: reports.hpp:52
static void add_text(config &report, const std::string &text, const std::string &tooltip, const std::string &help="")
Definition: reports.cpp:41
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
Definition: unit.hpp:1038
bool show_everything() const
Definition: display.hpp:89
this module manages the cache of images.
Definition: image.cpp:103
std::string put_time(struct tm *time, const char *fmt)
Definition: io.hpp:27
std::string tod_bright
std::vector< terrain_code > ter_list
Definition: translation.hpp:77
unit_type::ALIGNMENT alignment() const
The alignment of this unit.
Definition: unit.hpp:370
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
unsigned int num_blows
Effective number of blows, takes swarm into account.
Definition: attack.hpp:77
std::pair< int, map_location > under_leadership(const unit_map &units, const map_location &loc)
Tests if the unit at loc is currently affected by leadership.
Definition: attack.cpp:1576
static config unit_weapons(reports::context &rc, const unit *attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
Definition: reports.cpp:856
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:193
Definition: help.cpp:56
size_t viewing_team() const
The viewing team is the team currently viewing the game.
Definition: display.hpp:101
std::string signed_value(int val)
Convert into a signed value (using the Unicode "−" and +0 convention.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
static std::string alignment_description(ALIGNMENT align, unit_race::GENDER gender=unit_race::MALE)
mock_char c
static config unit_abilities(const unit *u)
Definition: reports.cpp:365
const t_string & description() const
Definition: terrain.hpp:35
const unit * get_visible_unit(const map_location &loc, const team &current_team, bool see_all=false) const
static config unit_vision(const unit *u)
Definition: reports.cpp:561
int bonus_modified
Definition: time_of_day.hpp:85
const t_string & income_description() const
Definition: terrain.hpp:71
bool use_twelve_hour_clock_format()
Definition: general.cpp:1044
int side() const
The side this unit belongs to.
Definition: unit.hpp:244
const std::string & icon_image() const
Definition: terrain.hpp:29
const map_location & selected_hex() const
Definition: display.hpp:280
const color_t BAD_COLOR
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has.
Definition: unit.cpp:904
int combat_modifier(const unit_map &units, const gamemap &map, const map_location &loc, unit_type::ALIGNMENT alignment, bool is_fearless)
Returns the amount that a unit's damage should be multiplied by due to the current time of day...
Definition: attack.cpp:1587
const color_t inactive_ability_color