The Battle for Wesnoth  1.13.4+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 - 2016 by David White <[email protected]>
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 "global.hpp"
16 
17 #include "actions/attack.hpp"
18 #include "attack_prediction.hpp"
19 //#include "editor/editor_controller.hpp"
20 //#include "editor/palette/terrain_palettes.hpp"
21 #include "font.hpp"
22 #include "game_preferences.hpp"
23 #include "gettext.hpp"
24 #include "language.hpp"
25 #include "map/map.hpp"
26 #include "marked-up_text.hpp"
27 #include "mouse_events.hpp"
28 #include "reports.hpp"
29 #include "strftime.hpp"
30 #include "team.hpp"
31 #include "text.hpp"
32 #include "tod_manager.hpp"
33 #include "units/unit.hpp"
34 #include "units/helper.hpp"
35 #include "whiteboard/manager.hpp"
36 
37 #include <boost/shared_ptr.hpp>
38 
39 #include <cassert>
40 #include <ctime>
41 
42 static void add_text(config &report, const std::string &text,
43  const std::string &tooltip, const std::string &help = "")
44 {
45  config &element = report.add_child("element");
46  element["text"] = text;
47  if (!tooltip.empty()) element["tooltip"] = tooltip;
48  if (!help.empty()) element["help"] = help;
49 }
50 
51 static void add_image(config &report, const std::string &image,
52  const std::string &tooltip, const std::string &help = "")
53 {
54  config &element = report.add_child("element");
55  element["image"] = image;
56  if (!tooltip.empty()) element["tooltip"] = tooltip;
57  if (!help.empty()) element["help"] = help;
58 }
59 
60 static config text_report(const std::string &text,
61  const std::string &tooltip = "", const std::string &help = "")
62 {
63  config r;
64  add_text(r, text, tooltip, help);
65  return r;
66 }
67 
69  const std::string &tooltip = "", const std::string &help = "")
70 {
71  config r;
72  add_image(r, image, tooltip, help);
73  return r;
74 }
75 
76 using font::span_color;
77 
78 static void add_status(config &r,
79  char const *path, char const *desc1, char const *desc2)
80 {
81  std::ostringstream s;
82  s << translation::gettext(desc1) << translation::gettext(desc2);
83  add_image(r, path, s.str());
84 }
85 
86 static std::string flush(std::ostringstream &s)
87 {
88  std::string r(s.str());
89  s.str(std::string());
90  return r;
91 }
92 
93 typedef std::map<std::string, reports::generator_function> static_report_generators;
95 
97 {
99  {
100  static_generators.insert(static_report_generators::value_type(name, g));
101  }
102 };
103 
104 #define REPORT_GENERATOR(n, cn) \
105  static config report_##n(reports::context & cn); \
106  static report_generator_helper reg_gen_##n(#n, &report_##n); \
107  static config report_##n(reports::context & cn)
108 
109 static char const *naps = "</span>";
110 
112 {
113  return rc.dc().get_visible_unit(rc.screen().displayed_unit_hex(),
114  rc.teams()[rc.screen().viewing_team()],
115  rc.screen().show_everything());
116 }
117 
119 {
120  return rc.dc().get_visible_unit(rc.screen().selected_hex(),
121  rc.teams()[rc.screen().viewing_team()],
122  rc.screen().show_everything());
123 }
124 
126 {
127  if ( rc.screen().viewing_side() == rc.screen().playing_side() )
128  return text_report(str);
129 
130  return text_report(span_color(font::GRAY_COLOR) + str + naps);
131 }
132 
133 static config unit_name(const unit *u)
134 {
135  if (!u) {
136  return config();
137  }
138 
139  /*
140  * The name needs to be escaped, it might be set by the user and using
141  * markup. Also names often contain a forbidden single quote.
142  */
143  const std::string& name = font::escape_text(u->name());
144  std::ostringstream str, tooltip;
145  str << "<b>" << name << "</b>";
146  tooltip << _("Name: ") << "<b>" << name << "</b>";
147  return text_report(str.str(), tooltip.str());
148 }
149 
151 {
152  const unit *u = get_visible_unit(rc);
153  return unit_name(u);
154 }
155 REPORT_GENERATOR(selected_unit_name, rc)
156 {
157  const unit *u = get_selected_unit(rc);
158  return unit_name(u);
159 }
160 
161 static config unit_type(const unit* u)
162 {
163  if (!u) return config();
164  std::string has_variations_prefix = (u->type().show_variations_in_help() ? ".." : "");
165  std::ostringstream str, tooltip;
166  str << u->type_name();
167  tooltip << _("Type: ") << "<b>" << u->type_name() << "</b>\n"
168  << u->unit_description();
169  return text_report(str.str(), tooltip.str(), has_variations_prefix + "unit_" + u->type_id());
170 }
172 {
173  const unit *u = get_visible_unit(rc);
174  return unit_type(u);
175 }
176 REPORT_GENERATOR(selected_unit_type, rc)
177 {
178  const unit *u = get_selected_unit(rc);
179  return unit_type(u);
180 }
181 
182 static config unit_race(const unit* u)
183 {
184  if (!u) return config();
185  std::ostringstream str, tooltip;
186  str << u->race()->name(u->gender());
187  tooltip << _("Race: ") << "<b>" << u->race()->name(u->gender()) << "</b>";
188  return text_report(str.str(), tooltip.str(), "..race_" + u->race()->id());
189 }
191 {
192  const unit *u = get_visible_unit(rc);
193  return unit_race(u);
194 }
195 REPORT_GENERATOR(selected_unit_race, rc)
196 {
197  const unit *u = get_selected_unit(rc);
198  return unit_race(u);
199 }
200 
201 static config unit_side(reports::context & rc, const unit* u)
202 {
203  if (!u) return config();
204 
205  config report;
206  const team &u_team = rc.teams()[u->side() - 1];
207  std::string flag_icon = u_team.flag_icon();
210  std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
211  if (flag_icon.empty())
212  flag_icon = game_config::images::flag_icon;
213 
214  std::stringstream text;
215  text << " " << u->side();
216 
217  add_image(report, flag_icon + mods, u_team.side_name(), "");
218  add_text(report, text.str(), "", "");
219  return report;
220 }
222 {
223  const unit *u = get_visible_unit(rc);
224  return unit_side(rc,u);
225 }
226 REPORT_GENERATOR(selected_unit_side, rc)
227 {
228  const unit *u = get_selected_unit(rc);
229  return unit_side(rc, u);
230 }
231 
232 static config unit_level(const unit* u)
233 {
234  if (!u) return config();
235  std::ostringstream str, tooltip;
236  str << u->level();
237  tooltip << _("Level: ") << "<b>" << u->level() << "</b>\n";
238  const std::vector<std::string> &adv_to = u->advances_to_translated();
239  if (adv_to.empty())
240  tooltip << _("No advancement");
241  else
242  tooltip << _("Advances to:") << "\n<b>\t"
243  << utils::join(adv_to, "\n\t") << "</b>";
244  return text_report(str.str(), tooltip.str());
245 }
247 {
248  const unit *u = get_visible_unit(rc);
249  return unit_level(u);
250 }
251 REPORT_GENERATOR(selected_unit_level, rc)
252 {
253  const unit *u = get_selected_unit(rc);
254  return unit_level(u);
255 }
256 
257 REPORT_GENERATOR(unit_amla, rc)
258 {
259  const unit *u = get_visible_unit(rc);
260  if (!u) return config();
261  config res;
262  typedef std::pair<std::string, std::string> pair_string;
263  for (const pair_string &ps : u->amla_icons()) {
264  add_image(res, ps.first, ps.second);
265  }
266  return res;
267 }
268 
269 static config unit_traits(const unit* u)
270 {
271  if (!u) return config();
272  config res;
273  const std::vector<t_string> &traits = u->trait_names();
274  const std::vector<t_string> &descriptions = u->trait_descriptions();
275  const std::vector<std::string> &trait_ids = u->get_traits_list();
276  unsigned nb = traits.size();
277  for (unsigned i = 0; i < nb; ++i)
278  {
279  std::ostringstream str, tooltip;
280  str << traits[i];
281  if (i != nb - 1 ) str << ", ";
282  tooltip << _("Trait: ") << "<b>" << traits[i] << "</b>\n"
283  << descriptions[i];
284  add_text(res, str.str(), tooltip.str(), "traits_" + trait_ids[i]);
285  }
286  return res;
287 }
289 {
290  const unit *u = get_visible_unit(rc);
291  return unit_traits(u);
292 }
293 REPORT_GENERATOR(selected_unit_traits, rc)
294 {
295  const unit *u = get_selected_unit(rc);
296  return unit_traits(u);
297 }
298 
299 static config unit_status(reports::context & rc, const unit* u)
300 {
301  if (!u) return config();
302  config res;
303  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
304  if (rc.map().on_board(displayed_unit_hex) && u->invisible(displayed_unit_hex)) {
305  add_status(res, "misc/invisible.png", N_("invisible: "),
306  N_("This unit is invisible. It cannot be seen or attacked by enemy units."));
307  }
308  if (u->get_state(unit::STATE_SLOWED)) {
309  add_status(res, "misc/slowed.png", N_("slowed: "),
310  N_("This unit has been slowed. It will only deal half its normal damage when attacking and its movement cost is doubled."));
311  }
313  add_status(res, "misc/poisoned.png", N_("poisoned: "),
314  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."));
315  }
317  add_status(res, "misc/petrified.png", N_("petrified: "),
318  N_("This unit has been petrified. It may not move or attack."));
319  }
320  return res;
321 }
323 {
324  const unit *u = get_visible_unit(rc);
325  return unit_status(rc,u);
326 }
327 REPORT_GENERATOR(selected_unit_status, rc)
328 {
329  const unit *u = get_selected_unit(rc);
330  return unit_status(rc, u);
331 }
332 
334 {
335  if (!u) return config();
336  std::ostringstream str, tooltip;
338  const std::string align_id = u->alignment().to_string();
339  int cm = combat_modifier(rc.units(), rc.map(), rc.screen().displayed_unit_hex(), u->alignment(),
340  u->is_fearless());
341 
342  SDL_Color color = font::weapon_color;
343  if (cm != 0)
344  color = (cm > 0) ? font::good_dmg_color : font::bad_dmg_color;
345 
346  str << align << " (" << span_color(color) << utils::signed_percent(cm)
347  << naps << ")";
348 
349  tooltip << _("Alignment: ") << "<b>" << align << "</b>\n"
350  << string_table[align_id + "_description"];
351 
352  return text_report(str.str(), tooltip.str(), "time_of_day");
353 }
355 {
356  const unit *u = get_visible_unit(rc);
357  return unit_alignment(rc, u);
358 }
359 REPORT_GENERATOR(selected_unit_alignment, rc)
360 {
361  const unit *u = get_selected_unit(rc);
362  return unit_alignment(rc, u);
363 }
364 
365 
366 static config unit_abilities(const unit* u)
367 {
368  if (!u) return config();
369  config res;
370 
371  std::vector<bool> active;
372  const std::vector<boost::tuple<t_string,t_string,t_string> > &abilities = u->ability_tooltips(&active);
373  const size_t abilities_size = abilities.size();
374  for ( size_t i = 0; i != abilities_size; ++i )
375  {
376  // Aliases for readability:
377  const std::string &base_name = abilities[i].get<0>().base_str();
378  const t_string &display_name = abilities[i].get<1>();
379  const t_string &description = abilities[i].get<2>();
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_" + 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::t_terrain &terrain = map[displayed_unit_hex];
520  int def = 100 - u->defense_modifier(terrain);
521  SDL_Color color = int_to_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::t_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::t_terrain &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  SDL_Color color = int_to_color(game_config::red_to_green(t_def));
538  tooltip << '\t' << map.get_terrain_info(t).description() << ": "
539  << span_color(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::t_terrain>::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::t_terrain terrain = *terrain_it;
600  if (terrain == t_translation::FOGGED || terrain == t_translation::VOID_TERRAIN || terrain == t_translation::OFF_MAP_USER)
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 
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 << utils::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  SDL_Color c = create_color(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 
649 static int attack_info(reports::context & rc, const attack_type &at, config &res, const unit &u, const map_location &displayed_unit_hex)
650 {
651  std::ostringstream str, tooltip;
652 
653  at.set_specials_context(displayed_unit_hex, u.side() == rc.screen().playing_side());
654  int base_damage = at.damage();
655  int specials_damage = at.modified_damage(false);
656  int damage_multiplier = 100;
657  int tod_bonus = combat_modifier(rc.units(), rc.map(), displayed_unit_hex, u.alignment(), u.is_fearless());
658  damage_multiplier += tod_bonus;
659  int leader_bonus = 0;
660  if (under_leadership(rc.units(), displayed_unit_hex, &leader_bonus).valid())
661  damage_multiplier += leader_bonus;
662 
664  int damage_divisor = slowed ? 20000 : 10000;
665  // Assume no specific resistance (i.e. multiply by 100).
666  int damage = round_damage(specials_damage, damage_multiplier * 100, damage_divisor);
667 
668  // Hit points are used to calculate swarm, so they need to be bounded.
669  unsigned max_hp = u.max_hitpoints();
670  unsigned cur_hp = std::min<unsigned>(std::max(0, u.hitpoints()), max_hp);
671 
672  unsigned base_attacks = at.num_attacks();
673  unsigned min_attacks, max_attacks;
674  at.modified_attacks(false, min_attacks, max_attacks);
675  unsigned num_attacks = swarm_blows(min_attacks, max_attacks, cur_hp, max_hp);
676 
677  SDL_Color dmg_color = font::weapon_color;
678  if ( damage > specials_damage )
679  dmg_color = font::good_dmg_color;
680  else if ( damage < specials_damage )
681  dmg_color = font::bad_dmg_color;
682 
683  str << span_color(dmg_color) << " " << damage << naps << span_color(font::weapon_color)
684  << font::weapon_numbers_sep << num_attacks << ' ' << at.name()
685  << "</span>\n";
686  tooltip << _("Weapon: ") << "<b>" << at.name() << "</b>\n"
687  << _("Damage: ") << "<b>" << damage << "</b>\n";
688 
689  if ( tod_bonus || leader_bonus || slowed || specials_damage != base_damage )
690  {
691  tooltip << '\t' << _("Base damage: ") << base_damage << '\n';
692  if ( specials_damage != base_damage ) {
693  tooltip << '\t' << _("With specials: ") << specials_damage << '\n';
694  }
695  if (tod_bonus) {
696  tooltip << '\t' << _("Time of day: ")
697  << utils::signed_percent(tod_bonus) << '\n';
698  }
699  if (leader_bonus) {
700  tooltip << '\t' << _("Leadership: ")
701  << utils::signed_percent(leader_bonus) << '\n';
702  }
703  if (slowed) {
704  tooltip << '\t' << _("Slowed: ") << "/ 2" << '\n';
705  }
706  }
707 
708  tooltip << _("Attacks: ") << "<b>" << num_attacks << "</b>\n";
709  if ( max_attacks != min_attacks && cur_hp != max_hp ) {
710  if ( max_attacks < min_attacks ) {
711  // "Reverse swarm"
712  tooltip << '\t' << _("Max swarm bonus: ") << (min_attacks-max_attacks) << '\n';
713  tooltip << '\t' << _("Swarm: ") << "* "<< (100 - cur_hp*100/max_hp) << "%\n";
714  tooltip << '\t' << _("Base attacks: ") << '+' << base_attacks << '\n';
715  // The specials line will not necessarily match up with how the
716  // specials are calculated, but for an unusual case, simple brevity
717  // trumps complexities.
718  if ( max_attacks != base_attacks ) {
719  int attack_diff = int(max_attacks) - int(base_attacks);
720  tooltip << '\t' << _("Specials: ") << utils::signed_value(attack_diff) << '\n';
721  }
722  }
723  else {
724  // Regular swarm
725  tooltip << '\t' << _("Base attacks: ") << base_attacks << '\n';
726  if ( max_attacks != base_attacks ) {
727  tooltip << '\t' << _("With specials: ") << max_attacks << '\n';
728  }
729  if ( min_attacks != 0 ) {
730  tooltip << '\t' << _("Subject to swarm: ") << (max_attacks-min_attacks) << '\n';
731  }
732  tooltip << '\t' << _("Swarm: ") << "* "<< (cur_hp*100/max_hp) << "%\n";
733  }
734  }
735  else if ( num_attacks != base_attacks ) {
736  tooltip << '\t' << _("Base attacks: ") << base_attacks << '\n';
737  tooltip << '\t' << _("With specials: ") << num_attacks << '\n';
738  }
739 
740  add_text(res, flush(str), flush(tooltip));
741 
742  std::string range = string_table["range_" + at.range()];
743  std::string lang_type = string_table["type_" + at.type()];
744 
745  str << span_color(font::weapon_details_color) << " " << " "
746  << range << font::weapon_details_sep
747  << lang_type << "</span>\n";
748 
749  tooltip << _("Weapon range: ") << "<b>" << range << "</b>\n"
750  << _("Damage type: ") << "<b>" << lang_type << "</b>\n"
751  << _("Damage versus: ") << '\n';
752 
753  // Show this weapon damage and resistance against all the different units.
754  // We want weak resistances (= good damage) first.
755  std::map<int, std::set<std::string>, std::greater<int> > resistances;
756  std::set<std::string> seen_types;
757  const team &unit_team = rc.teams()[u.side() - 1];
758  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
759  for (const unit &enemy : rc.units())
760  {
761  if (enemy.incapacitated()) //we can't attack statues so don't display them in this tooltip
762  continue;
763  if (!unit_team.is_enemy(enemy.side()))
764  continue;
765  const map_location &loc = enemy.get_location();
766  if (viewing_team.fogged(loc) ||
767  (viewing_team.is_enemy(enemy.side()) && enemy.invisible(loc)))
768  continue;
769  bool new_type = seen_types.insert(enemy.type_id()).second;
770  if (new_type) {
771  int resistance = enemy.resistance_against(at, false, loc);
772  resistances[resistance].insert(enemy.type_name());
773  }
774  }
775 
776  typedef std::pair<int, std::set<std::string> > resist_units;
777  for (const resist_units &resist : resistances) {
778  int damage = round_damage(specials_damage, damage_multiplier * resist.first, damage_divisor);
779  tooltip << "<b>" << damage << "</b> "
780  << "<i>(" << utils::signed_percent(resist.first-100) << ")</i> : "
781  << utils::join(resist.second, ", ") << '\n';
782  }
783  add_text(res, flush(str), flush(tooltip));
784 
785  const std::string &accuracy_parry = at.accuracy_parry_description();
786  if (!accuracy_parry.empty())
787  {
789  << " " << accuracy_parry << "</span>\n";
790  int accuracy = at.accuracy();
791  if (accuracy) {
792  tooltip << _("Accuracy:") << "<b>"
793  << utils::signed_percent(accuracy) << "</b>\n";
794  }
795  int parry = at.parry();
796  if (parry) {
797  tooltip << _("Parry:") << "<b>"
798  << utils::signed_percent(parry) << "</b>\n";
799  }
800  add_text(res, flush(str), flush(tooltip));
801  }
802 
804  std::vector<bool> active;
805  const std::vector<std::pair<t_string, t_string> > &specials = at.special_tooltips(&active);
806  const size_t specials_size = specials.size();
807  for ( size_t i = 0; i != specials_size; ++i )
808  {
809  // Aliases for readability:
810  const t_string &name = specials[i].first;
811  const t_string &description = specials[i].second;
812  const SDL_Color &details_color = active[i] ? font::weapon_details_color :
814 
815  str << span_color(details_color) << " " << " " << name << naps << '\n';
816  std::string help_page = "weaponspecial_" + name.base_str();
817  tooltip << _("Weapon special: ") << "<b>" << name << "</b>";
818  if ( !active[i] )
819  tooltip << "<i>" << _(" (inactive)") << "</i>";
820  tooltip << '\n' << description;
821 
822  add_text(res, flush(str), flush(tooltip), help_page);
823  }
824  return damage;
825 }
826 
827 // Conversion routine for both unscathed and damage change percentage.
828 static void format_prob(char str_buf[10], double prob)
829 {
830 
831  if(prob > 0.9995) {
832  snprintf(str_buf, 10, "100 %%");
833  } else if(prob >= 0.1) {
834  snprintf(str_buf, 10, "%4.1f %%", 100.0 * prob);
835  } else {
836  snprintf(str_buf, 10, " %3.1f %%", 100.0 * prob);
837  }
838 
839  str_buf[9] = '\0'; //prevents _snprintf error
840 }
841 
842 static void format_hp(char str_buf[10], int hp)
843 {
844  if(hp < 10) {
845  snprintf(str_buf, 10, " %i", hp);
846  } else if(hp < 99) {
847  snprintf(str_buf, 10, " %i", hp);
848  } else {
849  snprintf(str_buf, 10, " %i", hp);
850  }
851 
852  str_buf[9] = '\0'; //prevents _snprintf error
853 }
854 
855 static config unit_weapons(reports::context & rc, const unit *attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
856 {
857  if (!attacker || !defender) return config();
858 
859  const unit* u = show_attacker ? attacker : defender;
860  const map_location unit_loc = show_attacker ? attacker_pos : defender->get_location();
861 
862  std::ostringstream str, tooltip;
863  config res;
864 
865  std::vector<battle_context> weapons;
866  for (unsigned int i = 0; i < attacker->attacks().size(); i++) {
867  // skip weapons with attack_weight=0
868  if (attacker->attacks()[i].attack_weight() > 0) {
869  battle_context weapon(rc.units(), attacker_pos, defender->get_location(), i, -1, 0.0, nullptr, attacker);
870  weapons.push_back(weapon);
871  }
872  }
873 
874  for (const battle_context& weapon : weapons) {
875 
876  // Predict the battle outcome.
877  combatant attacker_combatant(weapon.get_attacker_stats());
878  combatant defender_combatant(weapon.get_defender_stats());
879  attacker_combatant.fight(defender_combatant);
880 
881  const battle_context_unit_stats& context_unit_stats =
882  show_attacker ? weapon.get_attacker_stats() : weapon.get_defender_stats();
883 
884  int total_damage = 0;
885  int base_damage = 0;
886  int num_blows = 0;
887  int chance_to_hit = 0;
888  t_string weapon_name = _("None");
889 
890  SDL_Color dmg_color = font::weapon_color;
891  if (context_unit_stats.weapon) {
892  base_damage = attack_info(rc, *context_unit_stats.weapon, res, *u, unit_loc);
893  total_damage = context_unit_stats.damage;
894  num_blows = context_unit_stats.num_blows;
895  chance_to_hit = context_unit_stats.chance_to_hit;
896  weapon_name = context_unit_stats.weapon->name();
897 
898  if ( total_damage > base_damage )
899  dmg_color = font::good_dmg_color;
900  else if ( total_damage < base_damage )
901  dmg_color = font::bad_dmg_color;
902  } else {
903  str << span_color(font::weapon_color) << weapon_name << naps << "\n";
904  tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
905  << _("Damage: ") << "<b>" << "0" << "</b>\n";
906  }
907 
908  SDL_Color chance_color = int_to_color(game_config::red_to_green(chance_to_hit));
909 
910  // Total damage.
911  str << " " << span_color(dmg_color) << total_damage << naps << span_color(font::weapon_color)
912  << utils::unicode_en_dash << num_blows
913  << " (" << span_color(chance_color) << chance_to_hit << "%" << naps << ")"
914  << naps << "\n";
915 
916  tooltip << _("Weapon: ") << "<b>" << weapon_name << "</b>\n"
917  << _("Total damage") << "<b>" << total_damage << "</b>\n";
918 
919  // Create the hitpoints distribution.
920  std::vector<std::pair<int, double> > hp_prob_vector;
921 
922  // First, we sort the probabilities in ascending order.
923  std::vector<std::pair<double, int> > prob_hp_vector;
924  int i;
925 
926  combatant* c = show_attacker ? &attacker_combatant : &defender_combatant;
927 
928  for(i = 0; i < static_cast<int>(c->hp_dist.size()); i++) {
929  double prob = c->hp_dist[i];
930 
931  // We keep only values above 0.1%.
932  if(prob > 0.001)
933  prob_hp_vector.push_back(std::pair<double, int>(prob, i));
934  }
935 
936  std::sort(prob_hp_vector.begin(), prob_hp_vector.end());
937 
938  //TODO fendrin -- make that dynamically
939  int max_hp_distrib_rows_ = 10;
940 
941  // We store a few of the highest probability hitpoint values.
942  int nb_elem = std::min<int>(max_hp_distrib_rows_, prob_hp_vector.size());
943 
944  for(i = prob_hp_vector.size() - nb_elem;
945  i < static_cast<int>(prob_hp_vector.size()); i++) {
946 
947  hp_prob_vector.push_back(std::pair<int, double>
948  (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;
957  i < static_cast<int>(hp_prob_vector.size()); i++) {
958 
959  int hp = hp_prob_vector[i].first;
960  double prob = hp_prob_vector[i].second;
961 
962  char prob_buf[10];
963  format_prob(prob_buf, prob);
964  char hp_buf[10];
965  format_hp(hp_buf, hp);
966 
967  SDL_Color prob_color = int_to_color(game_config::blue_to_white(prob * 100.0, true));
968 
969  str << span_color(font::weapon_details_color) << " " << " "
970  << span_color(u->hp_color(hp)) << hp_buf << naps
971  << " " << font::weapon_numbers_sep << " "
972  << span_color(prob_color) << prob_buf << naps
973  << naps << "\n";
974  }
975 
976  add_text(res, flush(str), flush(tooltip));
977  }
978  return res;
979 }
980 
981 static config unit_weapons(reports::context & rc, const unit *u)
982 {
983  if (!u || u->attacks().empty()) return config();
984  map_location displayed_unit_hex = rc.screen().displayed_unit_hex();
985  config res;
986 
987  //TODO enable after the string frezze is lifted
988  //const std::string attack_headline =
989  // ( u->attacks().size() > 1 ) ? N_("Attacks") : N_("Attack");
990 
991  //add_text(res, /*span_color(font::weapon_details_color)
992  // +*/ attack_headline /*+ "</span>\n"*/ + '\n', "");
993 
994  for (const attack_type &at : u->attacks())
995  {
996  attack_info(rc, at, res, *u, displayed_unit_hex);
997  }
998  return res;
999 }
1001 {
1002  const unit *u = get_visible_unit(rc);
1003  if (!u) return config();
1004 
1005  return unit_weapons(rc, u);
1006 }
1007 REPORT_GENERATOR(highlighted_unit_weapons, rc)
1008 {
1009  const unit *u = get_selected_unit(rc);
1010  const unit *sec_u = get_visible_unit(rc);
1011 
1012  if (!u) return config();
1013  if (!sec_u || u == sec_u) return unit_weapons(rc, sec_u);
1014 
1015  map_location highlighted_hex = rc.screen().displayed_unit_hex();
1016  map_location attack_loc;
1017  if (rc.mhb())
1018  attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1019 
1020  if (!attack_loc.valid())
1021  return unit_weapons(rc, sec_u);
1022 
1023  return unit_weapons(rc, u, attack_loc, sec_u, false);
1024 }
1025 REPORT_GENERATOR(selected_unit_weapons, rc)
1026 {
1027  const unit *u = get_selected_unit(rc);
1028  const unit *sec_u = get_visible_unit(rc);
1029 
1030  if (!u) return config();
1031  if (!sec_u || u == sec_u) return unit_weapons(rc, u);
1032 
1033  map_location highlighted_hex = rc.screen().displayed_unit_hex();
1034  map_location attack_loc;
1035  if (rc.mhb())
1036  attack_loc = rc.mhb()->current_unit_attacks_from(highlighted_hex);
1037 
1038  if (!attack_loc.valid())
1039  return unit_weapons(rc, u);
1040 
1041  return unit_weapons(rc, u, attack_loc, sec_u, true);
1042 }
1043 
1044 REPORT_GENERATOR(unit_image,rc)
1045 {
1046  const unit *u = get_visible_unit(rc);
1047  if (!u) return config();
1048  return image_report(u->absolute_image() + u->image_mods());
1049 }
1050 REPORT_GENERATOR(selected_unit_image, rc)
1051 {
1052  const unit *u = get_selected_unit(rc);
1053  if (!u) return config();
1054  return image_report(u->absolute_image() + u->image_mods());
1055 }
1056 
1057 REPORT_GENERATOR(selected_unit_profile, rc)
1058 {
1059  const unit *u = get_selected_unit(rc);
1060  if (!u) return config();
1061  return image_report(u->small_profile());
1062 }
1063 REPORT_GENERATOR(unit_profile, rc)
1064 {
1065  const unit *u = get_visible_unit(rc);
1066  if (!u) return config();
1067  return image_report(u->small_profile());
1068 }
1069 
1070 REPORT_GENERATOR(tod_stats, rc)
1071 {
1072  std::ostringstream tooltip;
1073  std::ostringstream text;
1074 
1075  const map_location& selected_hex = rc.screen().selected_hex();
1076  const map_location& mouseover_hex = rc.screen().mouseover_hex();
1077 
1078  const map_location& hex = mouseover_hex.valid() ? mouseover_hex : selected_hex;
1079 
1080  const std::vector<time_of_day>& schedule = rc.tod().times(hex);
1081 
1082  int current = rc.tod().get_current_time(hex);
1083  int i = 0;
1084  for (const time_of_day& tod : schedule) {
1085  if (i == current) tooltip << "<big><b>";
1086  tooltip << tod.name << "\n";
1087  if (i == current) tooltip << "</b></big>";
1088  i++;
1089  }
1090 
1091  int times = schedule.size();
1092  text << current + 1 << "/" << times;
1093 
1094  return text_report(text.str(), tooltip.str(), "..schedule");
1095 }
1096 
1097 static config time_of_day_at(reports::context & rc, const map_location& mouseover_hex)
1098 {
1099  std::ostringstream tooltip;
1100  time_of_day tod;
1101  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1102  if (viewing_team.shrouded(mouseover_hex)) {
1103  // Don't show time on shrouded tiles.
1104  tod = rc.tod().get_time_of_day();
1105  } else if (viewing_team.fogged(mouseover_hex)) {
1106  // Don't show illuminated time on fogged tiles.
1107  tod = rc.tod().get_time_of_day(mouseover_hex);
1108  } else {
1109  tod = rc.tod().get_illuminated_time_of_day(rc.units(), rc.map(), mouseover_hex);
1110  }
1111 
1112  int b = tod.lawful_bonus;
1113 
1114  std::string lawful_color("white");
1115  std::string chaotic_color("white");
1116  std::string liminal_color("white");
1117 
1118  if (b != 0) {
1119  lawful_color = (b > 0) ? "green" : "red";
1120  chaotic_color = (b < 0) ? "green" : "red";
1121  liminal_color = "red";
1122  }
1123  tooltip << tod.name << '\n'
1124  << _("Lawful units: ") << "<span foreground=\"" << lawful_color << "\">"
1125  << utils::signed_percent(b) << "</span>\n"
1126  << _("Neutral units: ") << utils::signed_percent(0) << '\n'
1127  << _("Chaotic units: ") << "<span foreground=\"" << chaotic_color << "\">"
1128  << utils::signed_percent(-b) << "</span>\n"
1129  << _("Liminal units: ") << "<span foreground=\"" << liminal_color << "\">"
1130  << utils::signed_percent(-(abs(b))) << "</span>\n";
1131 
1132  std::string tod_image = tod.image;
1133  if (tod.bonus_modified > 0) tod_image += "~BRIGHTEN()";
1134  else if (tod.bonus_modified < 0) tod_image += "~DARKEN()";
1135 
1136  return image_report(tod_image, tooltip.str(), "time_of_day_" + tod.id);
1137 }
1139 {
1140  map_location mouseover_hex = rc.screen().mouseover_hex();
1141  if (mouseover_hex.valid()) return time_of_day_at(rc, mouseover_hex);
1142  return time_of_day_at(rc, rc.screen().selected_hex());
1143 }
1144 
1145 static config unit_box_at(reports::context & rc, const map_location& mouseover_hex)
1146 {
1147  std::ostringstream tooltip;
1148  time_of_day local_tod;
1149  time_of_day global_tod = rc.tod().get_time_of_day();
1150  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1151  if (viewing_team.shrouded(mouseover_hex)) {
1152  // Don't show time on shrouded tiles.
1153  local_tod = global_tod;
1154  } else if (viewing_team.fogged(mouseover_hex)) {
1155  // Don't show illuminated time on fogged tiles.
1156  local_tod = rc.tod().get_time_of_day(mouseover_hex);
1157  } else {
1158  local_tod = rc.tod().get_illuminated_time_of_day(rc.units(), rc.map(),mouseover_hex);
1159  }
1160 
1161  int bonus = local_tod.lawful_bonus;
1162 
1163  std::string lawful_color("white");
1164  std::string chaotic_color("white");
1165  std::string liminal_color("white");
1166 
1167  if (bonus != 0) {
1168  lawful_color = (bonus > 0) ? "green" : "red";
1169  chaotic_color = (bonus < 0) ? "green" : "red";
1170  liminal_color = "red";
1171  }
1172  tooltip << local_tod.name << '\n'
1173  << _("Lawful units: ") << "<span foreground=\"" << lawful_color << "\">"
1174  << utils::signed_percent(bonus) << "</span>\n"
1175  << _("Neutral units: ") << utils::signed_percent(0) << '\n'
1176  << _("Chaotic units: ") << "<span foreground=\"" << chaotic_color << "\">"
1177  << utils::signed_percent(-bonus) << "</span>\n"
1178  << _("Liminal units: ") << "<span foreground=\"" << liminal_color << "\">"
1179  << utils::signed_percent(-(abs(bonus))) << "</span>\n";
1180 
1181  std::string local_tod_image = "themes/classic/" + local_tod.image;
1182  std::string global_tod_image = "themes/classic/" + global_tod.image;
1183  if (local_tod.bonus_modified > 0) local_tod_image += "~BRIGHTEN()";
1184  else if (local_tod.bonus_modified < 0) local_tod_image += "~DARKEN()";
1185 
1186  const gamemap &map = rc.map();
1187  t_translation::t_terrain terrain = map.get_terrain(mouseover_hex);
1188 
1189  //if (terrain == t_translation::OFF_MAP_USER)
1190  // return config();
1191 
1192  //if (map.is_keep(mouseover_hex)) {
1193  // add_image(cfg, "icons/terrain/terrain_type_keep.png", "");
1194  //}
1195 
1196  const t_translation::t_list& underlying_terrains = map.underlying_union_terrain(terrain);
1197 
1198  std::string bg_terrain_image;
1199 
1200  for (const t_translation::t_terrain& underlying_terrain : underlying_terrains) {
1201  const std::string& terrain_id = map.get_terrain_info(underlying_terrain).id();
1202  bg_terrain_image = "~BLIT(unit_env/terrain/terrain-" + terrain_id + ".png)" + bg_terrain_image;
1203  }
1204 
1205  std::stringstream color;
1206  color << local_tod.color;
1207 
1208  bg_terrain_image = bg_terrain_image + "~CS(" + color.str() + ")";
1209 
1210  const unit *u = get_visible_unit(rc);
1211  std::string unit_image;
1212  if (u)
1213  unit_image = "~BLIT(" + u->absolute_image() + u->image_mods() + ",35,22)";
1214 
1215  std::string tod_image = global_tod_image + "~BLIT(" + local_tod_image + ")";
1216 
1217  return image_report(tod_image + bg_terrain_image + unit_image, tooltip.str(), "time_of_day");
1218 }
1219 REPORT_GENERATOR(unit_box, rc)
1220 {
1221  map_location mouseover_hex = rc.screen().mouseover_hex();
1222  return unit_box_at(rc, mouseover_hex);
1223 }
1224 
1225 
1227 {
1228  std::ostringstream str;
1229  str << rc.tod().turn();
1230  int nb = rc.tod().number_of_turns();
1231  if (nb != -1) str << '/' << nb;
1232  return text_report(str.str());
1233 }
1234 
1236 {
1237  std::ostringstream str;
1238  int viewing_side = rc.screen().viewing_side();
1239  // Suppose the full unit map is applied.
1240  int fake_gold = rc.teams()[viewing_side - 1].gold();
1241 
1242  if (rc.wb())
1243  fake_gold -= rc.wb()->get_spent_gold_for(viewing_side);
1244  char const *end = naps;
1245  if (viewing_side != rc.screen().playing_side()) {
1246  str << span_color(font::GRAY_COLOR);
1247  }
1248  else if (fake_gold < 0) {
1249  str << span_color(font::BAD_COLOR);
1250  }
1251  else {
1252  end = "";
1253  }
1254  str << utils::half_signed_value(fake_gold) << end;
1255  return text_report(str.str());
1256 }
1257 
1258 REPORT_GENERATOR(villages, rc)
1259 {
1260  std::ostringstream str;
1261  int viewing_side = rc.screen().viewing_side();
1262  const team &viewing_team = rc.teams()[viewing_side - 1];
1263  team_data td = rc.dc().calculate_team_data(viewing_team, viewing_side);
1264  str << td.villages << '/';
1265  if (viewing_team.uses_shroud()) {
1266  int unshrouded_villages = 0;
1267  for (const map_location &loc : rc.map().villages()) {
1268  if (!viewing_team.shrouded(loc))
1269  ++unshrouded_villages;
1270  }
1271  str << unshrouded_villages;
1272  } else {
1273  str << rc.map().villages().size();
1274  }
1275  return gray_inactive(rc,str.str());
1276 }
1277 
1278 REPORT_GENERATOR(num_units, rc)
1279 {
1280  return gray_inactive(rc, std::to_string(rc.dc().side_units(rc.screen().viewing_side())));
1281 }
1282 
1283 REPORT_GENERATOR(upkeep, rc)
1284 {
1285  std::ostringstream str;
1286  int viewing_side = rc.screen().viewing_side();
1287  const team &viewing_team = rc.teams()[viewing_side - 1];
1288  team_data td = rc.dc().calculate_team_data(viewing_team, viewing_side);
1289  str << td.expenses << " (" << td.upkeep << ")";
1290  return gray_inactive(rc,str.str());
1291 }
1292 
1293 REPORT_GENERATOR(expenses, rc)
1294 {
1295  int viewing_side = rc.screen().viewing_side();
1296  const team &viewing_team = rc.teams()[viewing_side - 1];
1297  team_data td = rc.dc().calculate_team_data(viewing_team, rc.screen().viewing_side());
1298  return gray_inactive(rc,std::to_string(td.expenses));
1299 }
1300 
1301 REPORT_GENERATOR(income, rc)
1302 {
1303  std::ostringstream str;
1304  int viewing_side = rc.screen().viewing_side();
1305  const team &viewing_team = rc.teams()[viewing_side - 1];
1306  team_data td = rc.dc().calculate_team_data(viewing_team, viewing_side);
1307  char const *end = naps;
1308  if (viewing_side != rc.screen().playing_side()) {
1309  if (td.net_income < 0) {
1310  td.net_income = - td.net_income;
1311  str << span_color(font::GRAY_COLOR);
1312  str << utils::unicode_minus;
1313  }
1314  else {
1315  str << span_color(font::GRAY_COLOR);
1316  }
1317  }
1318  else if (td.net_income < 0) {
1319  td.net_income = - td.net_income;
1320  str << span_color(font::BAD_COLOR);
1321  str << utils::unicode_minus;
1322  }
1323  else {
1324  end = "";
1325  }
1326  str << td.net_income << end;
1327  return text_report(str.str());
1328 }
1329 
1330 namespace {
1331 void blit_tced_icon(config &cfg, const std::string &terrain_id, const std::string &icon_image, bool high_res,
1332  const std::string &terrain_name) {
1333  const std::string tc_base = high_res ? "images/buttons/icon-base-32.png" : "images/buttons/icon-base-16.png";
1334  const std::string terrain_image = "terrain/" + icon_image + (high_res ? "_30.png" : ".png");
1335  add_image(cfg, tc_base + "~RC(magenta>" + terrain_id + ")~BLIT(" + terrain_image + ")", terrain_name);
1336 }
1337 }
1338 
1339 REPORT_GENERATOR(terrain_info, rc)
1340 {
1341  const gamemap &map = rc.map();
1342  map_location mouseover_hex = rc.screen().mouseover_hex();
1343 
1344  if (!map.on_board(mouseover_hex))
1345  mouseover_hex = rc.screen().selected_hex();
1346 
1347  if (!map.on_board(mouseover_hex))
1348  return config();
1349 
1350  t_translation::t_terrain terrain = map.get_terrain(mouseover_hex);
1351  if (terrain == t_translation::OFF_MAP_USER)
1352  return config();
1353 
1354  std::ostringstream str;
1355  config cfg;
1356 
1357  bool high_res = false;
1358 
1359  if (display::get_singleton()->shrouded(mouseover_hex)) {
1360  return cfg;
1361  }
1362  //TODO
1363 // if (display::get_singleton()->fogged(mouseover_hex)) {
1364 // blit_tced_icon(cfg, "fog", high_res);
1365 // }
1366 //
1367 // if (map.is_keep(mouseover_hex)) {
1368 // blit_tced_icon(cfg, "keep", high_res);
1369 // }
1370 
1371  const t_translation::t_list& underlying_terrains = map.underlying_union_terrain(terrain);
1372  for (const t_translation::t_terrain& underlying_terrain : underlying_terrains) {
1373 
1374  if (underlying_terrain == t_translation::OFF_MAP_USER)
1375  continue;
1376  const std::string& terrain_id = map.get_terrain_info(underlying_terrain).id();
1377  const std::string& terrain_name = map.get_terrain_string(underlying_terrain);
1378  const std::string& terrain_icon = map.get_terrain_info(underlying_terrain).icon_image();
1379  if (terrain_icon.empty())
1380  continue;
1381  blit_tced_icon(cfg, terrain_id, terrain_icon, high_res, terrain_name);
1382  }
1383  return cfg;
1384 }
1385 
1387 {
1388  const gamemap &map = rc.map();
1389  int viewing_side = rc.screen().viewing_side();
1390  const team &viewing_team = rc.teams()[viewing_side - 1];
1391  map_location mouseover_hex = rc.screen().mouseover_hex();
1392  if (!map.on_board(mouseover_hex) || viewing_team.shrouded(mouseover_hex))
1393  return config();
1394 
1395  t_translation::t_terrain terrain = map.get_terrain(mouseover_hex);
1396  if (terrain == t_translation::OFF_MAP_USER)
1397  return config();
1398 
1399  std::ostringstream str;
1400  if (map.is_village(mouseover_hex))
1401  {
1402  int owner = rc.dc().village_owner(mouseover_hex) + 1;
1403  if (owner == 0 || viewing_team.fogged(mouseover_hex)) {
1404  str << map.get_terrain_info(terrain).income_description();
1405  } else if (owner == viewing_side) {
1406  str << map.get_terrain_info(terrain).income_description_own();
1407  } else if (viewing_team.is_enemy(owner)) {
1408  str << map.get_terrain_info(terrain).income_description_enemy();
1409  } else {
1410  str << map.get_terrain_info(terrain).income_description_ally();
1411  }
1412 
1413  const std::string& underlying_desc = map.get_underlying_terrain_string(terrain);
1414  if(!underlying_desc.empty()) {
1415  str << underlying_desc;
1416  }
1417  } else {
1418  str << map.get_terrain_string(terrain);
1419  }
1420 
1421  return text_report(str.str());
1422 }
1423 
1424 REPORT_GENERATOR(zoom_level, rc)
1425 {
1426  std::ostringstream text;
1427  std::ostringstream tooltip;
1428  std::ostringstream help;
1429 
1430  text << static_cast<int>(rc.screen().get_zoom_factor() * 100) << "%";
1431 
1432  return text_report(text.str(), tooltip.str(), help.str());
1433 }
1434 
1435 REPORT_GENERATOR(position, rc)
1436 {
1437  const gamemap &map = rc.map();
1438  map_location mouseover_hex = rc.screen().mouseover_hex(),
1439  displayed_unit_hex = rc.screen().displayed_unit_hex(),
1440  selected_hex = rc.screen().selected_hex();
1441 
1442  if (!map.on_board(mouseover_hex)) {
1443  if (!map.on_board(selected_hex))
1444  return config();
1445  else {
1446  mouseover_hex = selected_hex;
1447  }
1448  }
1449 
1450  t_translation::t_terrain terrain = map[mouseover_hex];
1451  if (terrain == t_translation::OFF_MAP_USER)
1452  return config();
1453 
1454  std::ostringstream str;
1455  str << mouseover_hex;
1456 
1457  const unit *u = get_visible_unit(rc);
1458  const team &viewing_team = rc.teams()[rc.screen().viewing_team()];
1459  if (!u ||
1460  (displayed_unit_hex != mouseover_hex &&
1461  displayed_unit_hex != rc.screen().selected_hex()) ||
1462  viewing_team.shrouded(mouseover_hex))
1463  return text_report(str.str());
1464 
1465  int move_cost = u->movement_cost(terrain);
1466  int defense = 100 - u->defense_modifier(terrain);
1467  if (move_cost < movetype::UNREACHABLE) {
1468  str << " " << defense << "%," << move_cost;
1469  } else if (mouseover_hex == displayed_unit_hex) {
1470  str << " " << defense << "%,‒";
1471  } else {
1472  str << " ‒";
1473  }
1474  return text_report(str.str());
1475 }
1476 
1477 REPORT_GENERATOR(side_playing, rc)
1478 {
1479  const team &active_team = rc.teams()[rc.screen().playing_team()];
1480  std::string flag_icon = active_team.flag_icon();
1482  std::string new_rgb = team::get_side_color_index(rc.screen().playing_side());
1483  std::string mods = "~RC(" + old_rgb + ">" + new_rgb + ")";
1484  if (flag_icon.empty())
1485  flag_icon = game_config::images::flag_icon;
1486  return image_report(flag_icon + mods, active_team.side_name());
1487 }
1488 
1489 REPORT_GENERATOR(observers, rc)
1490 {
1491  const std::set<std::string> &observers = rc.screen().observers();
1492  if (observers.empty())
1493  return config();
1494 
1495  std::ostringstream str;
1496  str << _("Observers:") << '\n';
1497  for (const std::string &obs : observers) {
1498  str << obs << '\n';
1499  }
1500  return image_report(game_config::images::observer, str.str());
1501 }
1502 
1503 /* TODO unused
1504 REPORT_GENERATOR(selected_terrain)
1505 {
1506  const std::string selected_terrain = editor::get_selected_terrain();
1507  if (selected_terrain.empty())
1508  return config();
1509  else
1510  return text_report(selected_terrain);
1511 }
1512 */
1513 
1514 /* TODO this is unused
1515 REPORT_GENERATOR(edit_left_button_function)
1516 {
1517  const std::string left_button_function = editor::get_left_button_function();
1518  if (left_button_function.empty())
1519  return config();
1520  else
1521  return text_report(left_button_function);
1522 }
1523 */
1524 
1525 REPORT_GENERATOR(report_clock, /*rc*/)
1526 {
1527  time_t t = std::time(nullptr);
1528  struct tm *lt = std::localtime(&t);
1529  if (!lt) return config();
1530  char temp[15];
1531  size_t s = util::strftime(temp, 15,
1532  (preferences::use_twelve_hour_clock_format() ? _("%I:%M %p") : _("%H:%M")),
1533  lt);
1534  return s ? text_report(temp) : config();
1535 
1536 }
1537 
1538 REPORT_GENERATOR(report_countdown, rc)
1539 {
1540  int viewing_side = rc.screen().viewing_side();
1541  const team &viewing_team = rc.teams()[viewing_side - 1];
1542  int min, sec;
1543  if (viewing_team.countdown_time() == 0)
1544  return report_report_clock(rc);
1545  std::ostringstream str;
1546  sec = viewing_team.countdown_time() / 1000;
1547  char const *end = naps;
1548  if (viewing_side != rc.screen().playing_side())
1549  str << span_color(font::GRAY_COLOR);
1550  else if (sec < 60)
1551  str << "<span foreground=\"#c80000\">";
1552  else if (sec < 120)
1553  str << "<span foreground=\"#c8c800\">";
1554  else
1555  end = "";
1556  min = sec / 60;
1557  str << min << ':';
1558  sec = sec % 60;
1559  if (sec < 10) str << '0';
1560  str << sec << end;
1561  return text_report(str.str());
1562 }
1563 
1565 {
1567 }
1568 
1570 {
1571  if (!only_static) {
1572  dynamic_report_generators::const_iterator i = dynamic_generators_.find(name);
1573  if (i != dynamic_generators_.end())
1574  return i->second->generate(rc);
1575  }
1576  static_report_generators::const_iterator j = static_generators.find(name);
1577  if (j != static_generators.end())
1578  return j->second(rc);
1579  return config();
1580 }
1581 
1582 const std::set<std::string> &reports::report_list()
1583 {
1584  if (!all_reports_.empty()) return all_reports_;
1585  for (const static_report_generators::value_type &v : static_generators) {
1586  all_reports_.insert(v.first);
1587  }
1588  for (const dynamic_report_generators::value_type &v : dynamic_generators_) {
1589  all_reports_.insert(v.first);
1590  }
1591  return all_reports_;
1592 }
const SDL_Color good_dmg_color
std::string image_mods() const
Definition: unit.cpp:2430
const t_string & name() const
Definition: attack_type.hpp:35
static config unit_level(const unit *u)
Definition: reports.cpp:232
bool uses_shroud() const
Definition: team.hpp:315
const std::vector< t_string > & trait_descriptions() const
Definition: unit.hpp:281
int total_movement() const
Definition: unit.hpp:218
size_t strftime(char *str, size_t count, const std::string &format, const std::tm *time)
Definition: strftime.cpp:132
t_string unit_description() const
Information about the unit – a detailed description of it.
Definition: unit.hpp:166
static config unit_xp(const unit *u)
Definition: reports.cpp:464
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
const map_location & get_location() const
Definition: unit.hpp:286
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
static int get_acceleration()
Definition: types.cpp:509
std::string absolute_image() const
The name of the file to game_display (used in menus).
Definition: unit.cpp:2262
config(* generator_function)(reports::context &)
Definition: reports.hpp:83
const unit_map & units()
Definition: reports.hpp:53
int max_hitpoints() const
Definition: unit.hpp:169
bool get_state(const std::string &state) const
Definition: unit.cpp:1289
const std::string weapon_details_sep
Definition: unit.hpp:95
SDL_Color create_color(const unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
Definition: utils.cpp:89
void set_specials_context(const map_location &unit_loc, const map_location &other_loc, bool attacking, const attack_type *other_attack) const
Sets the context under which specials will be checked for being active.
Definition: abilities.cpp:677
static config time_of_day_at(reports::context &rc, const map_location &mouseover_hex)
Definition: reports.cpp:1097
const t_string & income_description_enemy() const
Definition: terrain.hpp:70
tod_color color
The color modifications that should be made to the game board to reflect the time of day...
Definition: time_of_day.hpp:89
const t_string & name() const
The unit name for display.
Definition: unit.hpp:158
const t_string & type_name() const
The unit type name.
Definition: unit.hpp:153
std::string get_underlying_terrain_string(const t_translation::t_terrain &terrain) const
Definition: map.cpp:89
const t_string & name(GENDER gender=MALE) const
Definition: race.hpp:34
int experience() const
Definition: unit.hpp:171
bool shrouded(const map_location &loc) const
Definition: team.cpp:567
GLenum GLint * range
Definition: glew.h:3025
int movement_cost(const t_translation::t_terrain &terrain) const
Definition: unit.hpp:308
static config unit_advancement_options(const unit *u)
Definition: reports.cpp:486
const GLfloat * c
Definition: glew.h:12741
int modified_damage(bool is_backstab) const
Returns the damage per attack of this weapon, considering specials.
Definition: abilities.cpp:743
Various functions that implement attacks and attack calculations.
static char const * naps
Definition: reports.cpp:109
std::vector< boost::tuple< t_string, t_string, t_string > > ability_tooltips(std::vector< bool > *active_list=nullptr) const
Tuple of: neutral ability name, gendered ability name, description.
Definition: abilities.cpp:261
int hitpoints() const
Definition: unit.hpp:168
static void format_prob(char str_buf[10], double prob)
Definition: reports.cpp:828
SDL_Color int_to_color(const Uint32 rgb)
Definition: utils.cpp:63
logger & info()
Definition: log.cpp:91
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition: movetype.hpp:85
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
Definition: tod_manager.hpp:56
bool is_village(const map_location &loc) const
Definition: map.cpp:68
static int report(lua_State *L, int status)
Definition: lua.cpp:134
bool is_enemy(int n) const
Definition: team.hpp:247
static void add_status(config &r, char const *path, char const *desc1, char const *desc2)
Definition: reports.cpp:78
std::string id
Definition: time_of_day.hpp:77
void set_specials_context_for_listing() const
Definition: abilities.cpp:704
const std::vector< std::string > advances_to_translated() const
Definition: unit.cpp:1121
static config image_report(const std::string &image, const std::string &tooltip="", const std::string &help="")
Definition: reports.cpp:68
const std::set< std::string > & report_list()
Definition: reports.cpp:1582
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glew.h:3783
const std::string & id() const
Definition: race.hpp:33
int lawful_bonus
The % bonus lawful units receive.
Definition: time_of_day.hpp:70
const t_terrain MINUS
const t_string & name() const
Definition: terrain.hpp:33
static config text_report(const std::string &text, const std::string &tooltip="", const std::string &help="")
Definition: reports.cpp:60
std::string image
The image to be displayed in the game status.
Definition: time_of_day.hpp:74
const std::string & id() const
Definition: terrain.hpp:37
const attack_type * weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
Definition: attack.hpp:51
const t_translation::t_list & union_type() const
Definition: terrain.hpp:49
int side() const
Definition: unit.hpp:201
const t_terrain FOGGED
GLboolean GLboolean g
Definition: glew.h:7319
SDL_Color xp_color() const
Colors for the unit's XP.
Definition: unit.cpp:1075
virtual int playing_side() const
Definition: display.hpp:212
static config unit_side(reports::context &rc, const unit *u)
Definition: reports.cpp:201
static config unit_name(const unit *u)
Definition: reports.cpp:133
static config unit_traits(const unit *u)
Definition: reports.cpp:269
report_generator_helper(const char *name, reports::generator_function g)
Definition: reports.cpp:98
static config unit_type(const unit *u)
Definition: reports.cpp:161
-file sdl_utils.hpp
int parry() const
Definition: attack_type.hpp:44
int accuracy() const
Definition: attack_type.hpp:43
const t_translation::t_list & underlying_union_terrain(const map_location &loc) const
Definition: map.cpp:61
GLdouble GLdouble t
Definition: glew.h:1366
const t_terrain OFF_MAP_USER
std::string small_profile() const
The unit's profile.
Definition: unit.cpp:1020
display & screen()
Definition: reports.hpp:57
std::string get_terrain_string(const map_location &loc) const
Definition: map.cpp:63
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
Definition: attack.hpp:74
Uint32 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...
int defense_modifier(const t_translation::t_terrain &terrain) const
Definition: unit.cpp:1520
std::string span_color(const SDL_Color &color)
Creates pango markup of a color.
int num_attacks() const
Definition: attack_type.hpp:46
const t_string & income_description_own() const
Definition: terrain.hpp:71
const SDL_Color inactive_details_color
static config unit_alignment(reports::context &rc, const unit *u)
Definition: reports.cpp:333
std::string flag_icon
Definition: game_config.cpp:84
const unit_type & type() const
The type of the unit (accounting for gender and variation).
Definition: unit.hpp:144
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
static static_report_generators static_generators
Definition: reports.cpp:94
std::map< std::string, std::string > advancement_icons() const
Definition: unit.cpp:1580
t_string name
Definition: time_of_day.hpp:75
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:48
static config unit_race(const unit *u)
Definition: reports.cpp:182
const std::string & type_id() const
The id of the type of the unit.
Definition: unit.hpp:142
const std::string unicode_minus
const SDL_Color bad_dmg_color
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
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:82
virtual const map_location & displayed_unit_hex() const
Virtual functions shadowed in game_display.
Definition: display.hpp:211
const t_terrain PLUS
int damage
Effective damage of the weapon (all factors accounted for).
Definition: attack.hpp:75
GLsizei const char ** path
Definition: glew.h:4654
const std::string & flag_icon() const
Definition: team.hpp:302
GLuint GLuint end
Definition: glew.h:1221
const SDL_Color BAD_COLOR
Definition: font.cpp:568
unit_type::ALIGNMENT alignment() const
Definition: unit.hpp:368
bool valid() const
Definition: location.hpp:69
const std::string unicode_en_dash
#define REPORT_GENERATOR(n, cn)
Definition: reports.cpp:104
void register_generator(const std::string &name, generator *)
Definition: reports.cpp:1564
const GLdouble * v
Definition: glew.h:1359
std::set< std::string > all_reports_
Definition: reports.hpp:88
std::string base_name(const std::string &file)
Returns the base filename of a file, with directory name stripped.
t_translation::t_terrain number() const
Definition: terrain.hpp:43
config generate_report(const std::string &name, context &ct, bool only_static=false)
Definition: reports.cpp:1569
std::set< t_translation::t_terrain > & encountered_terrains()
Encapsulates the map of the game.
Definition: map.hpp:37
bool show_variations_in_help() const
Whether the unit type has at least one help-visible variation.
Definition: types.cpp:741
Computes the statistics of a battle between an attacker and a defender unit.
Definition: attack.hpp:135
config & add_child(const std::string &key)
Definition: config.cpp:743
void fight(combatant &opponent, bool levelup_considered=true)
Simulate a fight! Can be called multiple times for cumulative calculations.
unit_race::GENDER gender() const
Definition: unit.hpp:203
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:49
static UNUSEDNOWARN std::string gettext(const char *str)
Definition: gettext.hpp:64
int movement_left() const
Returns how far a unit can move this turn (zero if incapacitated).
Definition: unit.hpp:220
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:135
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
const tod_manager & tod()
Definition: reports.hpp:58
const SDL_Color weapon_details_color
int viewing_side() const
Definition: display.hpp:103
bool is_nonnull() const
Definition: terrain.hpp:51
dynamic_report_generators dynamic_generators_
Definition: reports.hpp:90
const std::string & type() const
Definition: attack_type.hpp:37
GLuint color
Definition: glew.h:5801
const std::vector< attack_type > & attacks() const
Definition: unit.hpp:271
bool invisible(const map_location &loc, bool see_all=true) const
Definition: unit.cpp:2291
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:47
std::string flag_rgb
std::string join(T const &v, const std::string &s=",")
Generates a new string joining container items in a list.
static config unit_status(reports::context &rc, const unit *u)
Definition: reports.cpp:299
std::string base_str() const
Definition: tstring.hpp:174
Encapsulates the map of the game.
Definition: location.hpp:38
static const unit * get_visible_unit(reports::context &rc)
Definition: reports.cpp:111
const terrain_type & get_terrain_info(const t_translation::t_terrain &terrain) const
Definition: map.cpp:100
std::vector< std::pair< std::string, std::string > > amla_icons() const
Definition: unit.cpp:1611
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:39
static config unit_box_at(reports::context &rc, const map_location &mouseover_hex)
Definition: reports.cpp:1145
All combat-related info.
GLuint res
Definition: glew.h:9258
std::string escape_text(const std::string &text)
Escapes the markup characters in a text.
Definition: text.cpp:75
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: util.hpp:60
const std::string unicode_figure_dash
static config unit_moves(reports::context &rc, const unit *u)
Definition: reports.cpp:582
std::string resistance_color(const int resistance)
Definition: helper.cpp:36
static const unit * get_selected_unit(reports::context &rc)
Definition: reports.cpp:118
Uint32 blue_to_white(int val, bool for_text)
static void add_image(config &report, const std::string &image, const std::string &tooltip, const std::string &help="")
Definition: reports.cpp:51
const t_string & income_description_ally() const
Definition: terrain.hpp:69
const std::vector< team > & teams()
Definition: reports.hpp:52
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:39
size_t i
Definition: function.cpp:1057
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:717
static std::string flush(std::ostringstream &s)
Definition: reports.cpp:86
const display_context & dc()
Definition: reports.hpp:56
bool fogged(const map_location &loc) const
Definition: team.cpp:575
int level() const
Definition: unit.hpp:175
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
#define N_(String)
Definition: gettext.hpp:90
static int sort(lua_State *L)
Definition: ltablib.cpp:246
std::string observer
Definition: game_config.cpp:84
int resistance_against(const std::string &damage_name, bool attacker, const map_location &loc) const
Definition: unit.cpp:1559
static config unit_defense(reports::context &rc, const unit *u, const map_location &displayed_unit_hex)
Definition: reports.cpp:507
GLuint const GLchar * name
Definition: glew.h:1782
t_translation::t_terrain get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:341
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:467
int damage() const
Definition: attack_type.hpp:45
std::string accuracy_parry_description() const
Definition: attack_type.cpp:76
std::map< std::string, reports::generator_function > static_report_generators
Definition: reports.cpp:93
const t_terrain VOID_TERRAIN
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:649
const SDL_Color weapon_color
int countdown_time() const
Definition: team.hpp:215
int max_experience() const
Definition: unit.hpp:172
const std::string weapon_numbers_sep
const std::vector< t_string > & trait_names() const
Definition: unit.hpp:280
static config gray_inactive(reports::context &rc, const std::string &str)
Definition: reports.cpp:125
const std::string & side_name() const
Definition: team.hpp:307
SDL_Color hp_color() const
Colors for the unit's current hitpoints.
Definition: unit.cpp:1065
#define g
Definition: glew.h:12730
symbol_table string_table
Definition: language.cpp:65
static void add_text(config &report, const std::string &text, const std::string &tooltip, const std::string &help="")
Definition: reports.cpp:42
const SDL_Color GRAY_COLOR
Definition: font.cpp:565
bool is_fearless() const
Definition: unit.hpp:306
bool show_everything() const
Definition: display.hpp:90
this module manages the cache of images.
Definition: image.cpp:75
GLint * first
Definition: glew.h:1496
const t_translation::t_list & underlying_def_terrain(const map_location &loc) const
Definition: map.cpp:59
utils::string_map get_base_resistances() const
Definition: unit.hpp:320
static std::string get_side_color_index(int side)
Definition: team.cpp:840
unsigned int num_blows
Effective number of blows, takes swarm into account.
Definition: attack.hpp:79
static config unit_weapons(reports::context &rc, const unit *attacker, const map_location &attacker_pos, const unit *defender, bool show_attacker)
Definition: reports.cpp:855
Definition: help.cpp:57
size_t viewing_team() const
The viewing team is the team currently viewing the game.
Definition: display.hpp:102
static void format_hp(char str_buf[10], int hp)
Definition: reports.cpp:842
std::string signed_value(int val)
Convert into a signed value (using the Unicode "−" and +0 convention.
const std::string weapon
const SDL_Color inactive_ability_color
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
static std::string alignment_description(ALIGNMENT align, unit_race::GENDER gender=unit_race::MALE)
static config unit_abilities(const unit *u)
Definition: reports.cpp:366
GLdouble s
Definition: glew.h:1358
map_location under_leadership(const unit_map &units, const map_location &loc, int *bonus)
function which tests if the unit at loc is currently affected by leadership.
Definition: attack.cpp:1635
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
const unit_race * race() const
Never returns nullptr, but may point to the null race.
Definition: unit.hpp:371
static config unit_vision(const unit *u)
Definition: reports.cpp:561
int bonus_modified
Definition: time_of_day.hpp:71
const t_string & income_description() const
Definition: terrain.hpp:68
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool use_twelve_hour_clock_format()
const std::string & icon_image() const
Definition: terrain.hpp:29
const map_location & selected_hex() const
Definition: display.hpp:292
const gamemap & map()
Definition: reports.hpp:54
std::vector< t_terrain > t_list
Definition: translation.hpp:75
const std::string valid
Little parts of regex templates used to parse Wml annoations.
int vision() const
Definition: unit.hpp:223
std::vector< std::string > get_traits_list() const
Definition: unit.cpp:883
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:1649
std::vector< std::pair< t_string, t_string > > special_tooltips(std::vector< bool > *active_list=nullptr) const
Returns a vector of names and descriptions for the specials of *this.
Definition: abilities.cpp:612