The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
unit_attack.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2016 by Mark de Wever <[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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
20 
22 #include "gui/widgets/button.hpp"
23 #include "gui/widgets/label.hpp"
24 #include "gui/widgets/image.hpp"
25 #ifdef GUI2_EXPERIMENTAL_LISTBOX
26 #include "gui/widgets/list.hpp"
27 #else
28 #include "gui/widgets/listbox.hpp"
29 #endif
30 #include "gui/widgets/settings.hpp"
31 #include "gui/widgets/window.hpp"
32 #include "game_config.hpp"
33 #include "gettext.hpp"
34 #include "help/help.hpp"
35 #include "language.hpp"
36 #include "marked-up_text.hpp"
37 #include "resources.hpp"
38 #include "team.hpp"
39 #include "units/unit.hpp"
40 
41 #include "utils/functional.hpp"
42 
43 namespace gui2
44 {
45 
46 /*WIKI
47  * @page = GUIWindowDefinitionWML
48  * @order = 2_unit_attack
49  *
50  * == Unit attack ==
51  *
52  * This shows the dialog for attacking units.
53  *
54  * @begin{table}{dialog_widgets}
55  * attacker_portrait & & image & o & Shows the portrait of the attacking unit.
56  * $
57  * attacker_icon & & image & o & Shows the icon of the attacking unit. $
58  * attacker_name & & control & o & Shows the name of the attacking unit. $
59  *
60  * defender_portrait & & image & o & Shows the portrait of the defending unit.
61  * $
62  * defender_icon & & image & o & Shows the icon of the defending unit. $
63  * defender_name & & control & o & Shows the name of the defending unit. $
64  *
65  *
66  * weapon_list & & listbox & m & The list with weapons to choose from. $
67  * -attacker_weapon & & control & o & The weapon for the attacker to use. $
68  * -defender_weapon & & control & o & The weapon for the defender to use. $
69  *
70  * @end{table}
71  */
72 
74 
75 tunit_attack::tunit_attack(const unit_map::iterator& attacker_itor,
76  const unit_map::iterator& defender_itor,
77  const std::vector<battle_context>& weapons,
78  const int best_weapon)
79  : selected_weapon_(-1)
80  , attacker_itor_(attacker_itor)
81  , defender_itor_(defender_itor)
82  , weapons_(weapons)
83  , best_weapon_(best_weapon)
84 {
85 }
86 
87 template <class T>
88 static void
89 set_label(twindow& window, const std::string& id, const std::string& label)
90 {
91  T* widget = find_widget<T>(&window, id, false, false);
92  if(widget) {
93  widget->set_label(label);
94  }
95 }
96 
97 static std::string format_stats(const unit& u)
98 {
99  const std::string name = "<span size='large'>" + (!u.name().empty() ? u.name() : " ") + "</span>";
100  std::string traits;
101 
102  for(const std::string& trait : u.trait_names()) {
103  traits += (traits.empty() ? "" : ", ") + trait;
104  }
105 
106  if (traits.empty()) {
107  traits = " ";
108  }
109 
110  std::stringstream str;
111 
112  str << name << "\n";
113 
114  str << "<small>";
115 
116  str << "<span color='#f5e6c1'>" << u.type_name() << "</span>" << "\n";
117 
118  str << "Lvl " << u.level() << "\n";
119 
120  str << u.alignment() << "\n";
121 
122  str << traits << "\n";
123 
124  str << font::span_color(u.hp_color())
125  << _("HP: ") << u.hitpoints() << "/" << u.max_hitpoints() << "</span>" << "\n";
126  str << font::span_color(u.xp_color())
127  << _("XP: ") << u.experience() << "/" << u.max_experience() << "</span>";
128 
129  str << "</small>";
130 
131  return str.str();
132 }
133 
135 {
137  = "~RC(" + u.team_color() + ">" + team::get_side_color_index(u.side()) + ")";
138 
139  if (u.can_recruit()) {
140  res += "~BLIT(" + unit::leader_crown() + ")";
141  }
142 
143  for(const std::string& overlay : u.overlays()) {
144  res += "~BLIT(" + overlay + ")";
145  }
146 
147  return res;
148 }
149 
150 static void set_attacker_info(twindow& window, const unit& u)
151 {
152  set_label<timage>(window, "attacker_image", u.absolute_image() + get_image_mods(u));
153 
154  tcontrol& attacker_name =
155  find_widget<tcontrol>(&window, "attacker_stats", false);
156 
157  attacker_name.set_use_markup(true);
158  attacker_name.set_label(format_stats(u));
159 }
160 
161 static void set_defender_info(twindow& window, const unit& u)
162 {
163  // Ensure the defender image is always facing left
164  set_label<timage>(window, "defender_image", u.absolute_image() + "~FL(horiz)" + get_image_mods(u));
165 
166  tcontrol& defender_name =
167  find_widget<tcontrol>(&window, "defender_stats", false);
168 
169  defender_name.set_use_markup(true);
170  defender_name.set_label(format_stats(u));
171 }
172 
173 static void set_weapon_info(twindow& window,
174  const std::vector<battle_context>& weapons,
175  const int best_weapon)
176 {
177  tlistbox& weapon_list
178  = find_widget<tlistbox>(&window, "weapon_list", false);
179  window.keyboard_capture(&weapon_list);
180 
181  const config empty;
182  const attack_type no_weapon(empty);
183 
184  for(const auto & weapon : weapons)
185  {
186  const battle_context_unit_stats& attacker = weapon.get_attacker_stats();
187  const battle_context_unit_stats& defender = weapon.get_defender_stats();
188 
189  const attack_type& attacker_weapon =
190  *attacker.weapon;
191  const attack_type& defender_weapon = defender.weapon ?
192  *defender.weapon : no_weapon;
193 
194  const SDL_Color a_cth_color =
196  const SDL_Color d_cth_color =
198 
199  const std::string attw_name = !attacker_weapon.name().empty() ? attacker_weapon.name() : " ";
200  const std::string defw_name = !defender_weapon.name().empty() ? defender_weapon.name() : " ";
201 
202  std::string range = attacker_weapon.range().empty() ? defender_weapon.range() : attacker_weapon.range();
203  if (!range.empty()) {
204  range = string_table["range_" + range];
205  }
206 
207  const std::string& attw_apecials =
208  !attacker_weapon.weapon_specials().empty() ? " " + attacker_weapon.weapon_specials() : "";
209  const std::string& defw_specials =
210  !defender_weapon.weapon_specials().empty() ? " " + defender_weapon.weapon_specials() : "";
211 
212  std::stringstream attacker_stats, defender_stats;
213 
214  attacker_stats << "<b>" << attw_name << "</b>" << "\n"
215  << attacker.damage << font::weapon_numbers_sep << attacker_weapon.num_attacks()
216  << attw_apecials << "\n"
217  << font::span_color(a_cth_color) << attacker.chance_to_hit << "%</span>";
218 
219  defender_stats << "<b>" << defw_name << "</b>" << "\n"
220  << defender.damage << font::weapon_numbers_sep << defender_weapon.num_attacks()
221  << defw_specials << "\n"
222  << font::span_color(d_cth_color) << defender.chance_to_hit << "%</span>";
223 
224  std::map<std::string, string_map> data;
225  string_map item;
226 
227  item["label"] = attacker_weapon.icon();
228  data.insert(std::make_pair("attacker_weapon_icon", item));
229 
230  item["label"] = attacker_stats.str();
231  item["use_markup"] = "true";
232  data.insert(std::make_pair("attacker_weapon", item));
233 
234  item["label"] = "<span color='#a69275'>" + utils::unicode_em_dash + " " + range + " " + utils::unicode_em_dash + "</span>";
235  item["use_markup"] = "true";
236  data.insert(std::make_pair("range", item));
237 
238  item["label"] = defender_stats.str();
239  item["use_markup"] = "true";
240  data.insert(std::make_pair("defender_weapon", item));
241 
242  item["label"] = defender_weapon.icon();
243  data.insert(std::make_pair("defender_weapon_icon", item));
244 
245  weapon_list.add_row(data);
246  }
247 
248  assert(best_weapon < static_cast<int>(weapon_list.get_item_count()));
249  weapon_list.select_row(best_weapon);
250 }
251 
253 {
254  help::show_unit_help(window.video(), type);
255 }
256 
258 {
259  const int selection
260  = find_widget<tlistbox>(&window, "weapon_list", false).get_selected_row();
261 
262  attack_prediction_displayer predition_dialog(weapons_, (*attacker_itor_).get_location(), (*defender_itor_).get_location());
263  predition_dialog.button_pressed(selection);
264 }
265 
267 {
269  find_widget<tbutton>(&window, "attacker_profile", false),
270  std::bind(&tunit_attack::profile_button_callback, this, std::ref(window),
271  (*attacker_itor_).type_id()));
272 
274  find_widget<tbutton>(&window, "defender_profile", false),
275  std::bind(&tunit_attack::profile_button_callback, this, std::ref(window),
276  (*defender_itor_).type_id()));
277 
279  find_widget<tbutton>(&window, "damage_calculation", false),
280  std::bind(&tunit_attack::damage_calc_callback, this, std::ref(window)));
281 
284 
285  selected_weapon_ = -1;
287 }
288 
290 {
291  if(get_retval() == twindow::OK) {
292  selected_weapon_ = find_widget<tlistbox>(&window, "weapon_list", false)
293  .get_selected_row();
294  }
295 }
296 
297 } // namespace gui2
const t_string & name() const
Definition: attack_type.hpp:35
void post_show(twindow &window)
Inherited from tdialog.
std::string absolute_image() const
The name of the file to game_display (used in menus).
Definition: unit.cpp:2262
const std::string & team_color() const
Definition: unit.hpp:202
int get_retval() const
Definition: dialog.hpp:161
int max_hitpoints() const
Definition: unit.hpp:169
Definition: unit.hpp:95
static void set_defender_info(twindow &window, const unit &u)
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
int experience() const
Definition: unit.hpp:171
void unit_attack(display *disp, game_board &board, const map_location &a, const map_location &b, int damage, const attack_type &attack, const attack_type *secondary_attack, int swing, std::string hit_text, int drain_amount, std::string att_text, const std::vector< std::string > *extra_hit_sounds)
Make the unit on tile 'a' attack the unit on tile 'b'.
Definition: udisplay.cpp:572
GLenum GLint * range
Definition: glew.h:3025
CVideo & video()
Definition: window.hpp:411
void damage_calc_callback(twindow &window)
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
int hitpoints() const
Definition: unit.hpp:168
SDL_Color int_to_color(const Uint32 rgb)
Definition: utils.cpp:63
This file contains the window object, this object is a top level container which has the event manage...
bool select_row(const unsigned row, const bool select=true)
Selectes a row.
Definition: listbox.cpp:228
REGISTER_DIALOG(label_settings)
void connect_signal_mouse_left_click(tdispatcher &dispatcher, const tsignal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.hpp:710
STL namespace.
const attack_type * weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
Definition: attack.hpp:51
int side() const
Definition: unit.hpp:201
SDL_Color xp_color() const
Colors for the unit's XP.
Definition: unit.cpp:1075
int best_weapon_
The best weapon, aka the one high-lighted.
Definition: unit_attack.hpp:67
-file sdl_utils.hpp
std::string weapon_specials(bool only_active=false, bool is_backstab=false) const
Returns a comma-separated string of active names for the specials of *this.
Definition: abilities.cpp:649
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
const std::string & icon() const
Definition: attack_type.hpp:38
static void set_weapon_info(twindow &window, const std::vector< battle_context > &weapons, const int best_weapon)
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...
std::string span_color(const SDL_Color &color)
Creates pango markup of a color.
int num_attacks() const
Definition: attack_type.hpp:46
std::vector< battle_context > weapons_
List of all battle contexts used for getting the weapons.
Definition: unit_attack.hpp:64
int selected_weapon_
The index of the selected weapon.
Definition: unit_attack.hpp:55
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
virtual void set_use_markup(bool use_markup)
Definition: control.cpp:342
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
static const std::string & leader_crown()
The path to the leader crown overlay.
Definition: unit.cpp:234
int damage
Effective damage of the weapon (all factors accounted for).
Definition: attack.hpp:75
Dialog is closed with ok button.
Definition: window.hpp:125
const std::vector< std::string > & overlays() const
Definition: unit.hpp:260
This file contains the settings handling of the widget library.
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:138
unit_type::ALIGNMENT alignment() const
Definition: unit.hpp:368
void pre_show(twindow &window)
Inherited from tdialog.
void add_row(const string_map &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:74
bool can_recruit() const
Definition: unit.hpp:207
unit_map::iterator attacker_itor_
Iterator pointing to the attacker.
Definition: unit_attack.hpp:58
Computes the statistics of a battle between an attacker and a defender unit.
Definition: attack.hpp:135
static std::string format_stats(const unit &u)
Definition: unit_attack.cpp:97
const std::string unicode_em_dash
static size_t id
Ids for the timers.
Definition: timer.cpp:39
Structure describing the statistics of a unit involved in the battle.
Definition: attack.hpp:49
std::map< std::string, t_string > string_map
Definition: generator.hpp:23
GLuint res
Definition: glew.h:9258
static std::string get_image_mods(const unit &u)
void profile_button_callback(twindow &window, const std::string &type)
The listbox class.
Definition: listbox.hpp:39
const std::string & range() const
Definition: attack_type.hpp:39
int level() const
Definition: unit.hpp:175
Base class for all visible items.
Definition: control.hpp:34
GLuint const GLchar * name
Definition: glew.h:1782
GLenum GLint ref
Definition: glew.h:1813
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
SDL_Color hp_color() const
Colors for the unit's current hitpoints.
Definition: unit.cpp:1065
symbol_table string_table
Definition: language.cpp:65
Container associating units to locations.
Definition: map.hpp:90
unit_map::iterator defender_itor_
Iterator pointing to the defender.
Definition: unit_attack.hpp:61
static std::string get_side_color_index(int side)
Definition: team.cpp:840
static void set_label(twindow &window, const std::string &id, const std::string &label)
Definition: unit_attack.cpp:89
void show_unit_help(CVideo &video, const std::string &show_topic, bool has_variations, bool hidden, int xloc, int yloc)
Open the help browser, show unit with id unit_id.
Definition: help.cpp:127
const std::string weapon
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool empty() const
Definition: tstring.hpp:166
static void set_attacker_info(twindow &window, const unit &u)