The Battle for Wesnoth  1.15.2+dev
unit_attack.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://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 
19 #include "font/text_formatting.hpp"
22 #include "gui/widgets/button.hpp"
23 #include "gui/widgets/label.hpp"
24 #include "gui/widgets/image.hpp"
25 #include "gui/widgets/listbox.hpp"
26 #include "gui/widgets/settings.hpp"
28 #include "gui/widgets/window.hpp"
29 #include "game_config.hpp"
30 #include "game_display.hpp"
31 #include "gettext.hpp"
32 #include "help/help.hpp"
33 #include "language.hpp"
34 #include "color.hpp"
35 #include "units/unit.hpp"
36 
37 #include "utils/functional.hpp"
38 
39 namespace gui2
40 {
41 namespace dialogs
42 {
43 
44 /*WIKI
45  * @page = GUIWindowDefinitionWML
46  * @order = 2_unit_attack
47  *
48  * == Unit attack ==
49  *
50  * This shows the dialog for attacking units.
51  *
52  * @begin{table}{dialog_widgets}
53  * $
54  * attacker_icon & & image & o & Shows the icon of the attacking unit. $
55  * attacker_name & & styled_widget & o & Shows the name of the attacking unit. $
56  *
57  * defender_portrait & & image & o & Shows the portrait of the defending unit.
58  * $
59  * defender_icon & & image & o & Shows the icon of the defending unit. $
60  * defender_name & & styled_widget & o & Shows the name of the defending unit. $
61  *
62  *
63  * weapon_list & & listbox & m & The list with weapons to choose from. $
64  * -attacker_weapon & & styled_widget & o & The weapon for the attacker to use. $
65  * -defender_weapon & & styled_widget & o & The weapon for the defender to use. $
66  *
67  * @end{table}
68  */
69 
71 
72 unit_attack::unit_attack(const unit_map::iterator& attacker_itor,
73  const unit_map::iterator& defender_itor,
74  std::vector<battle_context>&& weapons,
75  const int best_weapon)
76  : selected_weapon_(-1)
77  , attacker_itor_(attacker_itor)
78  , defender_itor_(defender_itor)
79  , weapons_(std::move(weapons))
80  , best_weapon_(best_weapon)
81 {
82 }
83 
85 {
86  const std::size_t index = find_widget<listbox>(&window, "weapon_list", false).get_selected_row();
87  attack_predictions::display(weapons_[index], *attacker_itor_, *defender_itor_);
88 }
89 
91 {
93  find_widget<button>(&window, "damage_calculation", false),
94  std::bind(&unit_attack::damage_calc_callback, this, std::ref(window)));
95 
96  find_widget<unit_preview_pane>(&window, "attacker_pane", false)
97  .set_displayed_unit(*attacker_itor_);
98 
99  find_widget<unit_preview_pane>(&window, "defender_pane", false)
100  .set_displayed_unit(*defender_itor_);
101 
102  selected_weapon_ = -1;
103 
104  listbox& weapon_list = find_widget<listbox>(&window, "weapon_list", false);
105  window.keyboard_capture(&weapon_list);
106 
107  // Possible TODO: If a "blank weapon" is generally useful, add it as a static member in attack_type.
108  static const config empty;
109  static const_attack_ptr no_weapon(new attack_type(empty));
110 
111  for(const auto & weapon : weapons_) {
112  const battle_context_unit_stats& attacker = weapon.get_attacker_stats();
113  const battle_context_unit_stats& defender = weapon.get_defender_stats();
114 
115  const attack_type& attacker_weapon =
116  *attacker.weapon;
117  const attack_type& defender_weapon = defender.weapon ?
118  *defender.weapon : *no_weapon;
119 
120  const color_t a_cth_color = game_config::red_to_green(attacker.chance_to_hit);
121  const color_t d_cth_color = game_config::red_to_green(defender.chance_to_hit);
122 
123  const std::string attw_name = !attacker_weapon.name().empty() ? attacker_weapon.name() : " ";
124  const std::string defw_name = !defender_weapon.name().empty() ? defender_weapon.name() : " ";
125 
126  std::string range = attacker_weapon.range().empty() ? defender_weapon.range() : attacker_weapon.range();
127  if (!range.empty()) {
128  range = string_table["range_" + range];
129  }
130 
131  auto a_ctx = attacker_weapon.specials_context(
134  attacker_itor_->get_location(),
135  defender_itor_->get_location(), true, defender.weapon
136  );
137 
138  auto d_ctx = defender_weapon.specials_context(
141  defender_itor_->get_location(),
142  attacker_itor_->get_location(), false, attacker.weapon
143  );
144 
145  std::string attw_specials = attacker_weapon.weapon_specials(true, attacker.backstab_pos);
146  std::string defw_specials = defender_weapon.weapon_specials(true);
147 
148  if(!attw_specials.empty()) {
149  attw_specials = " " + attw_specials;
150  }
151 
152  if(!defw_specials.empty()) {
153  defw_specials = " " + defw_specials;
154  }
155 
156  std::stringstream attacker_stats, defender_stats;
157 
158  // Use attacker/defender.num_blows instead of attacker/defender_weapon.num_attacks() because the latter does not consider the swarm weapon special
159  attacker_stats << "<b>" << attw_name << "</b>" << "\n"
160  << attacker.damage << font::weapon_numbers_sep << attacker.num_blows
161  << attw_specials << "\n"
162  << font::span_color(a_cth_color) << attacker.chance_to_hit << "%</span>";
163 
164  defender_stats << "<b>" << defw_name << "</b>" << "\n"
165  << defender.damage << font::weapon_numbers_sep << defender.num_blows
166  << defw_specials << "\n"
167  << font::span_color(d_cth_color) << defender.chance_to_hit << "%</span>";
168 
169  std::map<std::string, string_map> data;
171 
172  item["use_markup"] = "true";
173 
174  item["label"] = attacker_weapon.icon();
175  data.emplace("attacker_weapon_icon", item);
176 
177  item["label"] = attacker_stats.str();
178  data.emplace("attacker_weapon", item);
179 
180  item["label"] = "<span color='#a69275'>" + font::unicode_em_dash + " " + range + " " + font::unicode_em_dash + "</span>";
181  data.emplace("range", item);
182 
183  item["label"] = defender_stats.str();
184  data.emplace("defender_weapon", item);
185 
186  item["label"] = defender_weapon.icon();
187  data.emplace("defender_weapon_icon", item);
188 
189  weapon_list.add_row(data);
190  }
191 
192  // If these two aren't the same size, we can't use list selection incides
193  // to access to weapons list!
194  assert(weapons_.size() == weapon_list.get_item_count());
195 
196  weapon_list.select_row(best_weapon_);
197 }
198 
200 {
201  if(get_retval() == retval::OK) {
202  selected_weapon_ = find_widget<listbox>(&window, "weapon_list", false).get_selected_row();
203  }
204 }
205 
206 } // namespace dialogs
207 } // namespace gui2
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
Definition: attack.hpp:50
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:814
int best_weapon_
The best weapon, aka the one high-lighted.
Definition: unit_attack.hpp:66
This file contains the window object, this object is a top level container which has the event manage...
STL namespace.
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
Definition: attack.hpp:73
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:250
std::vector< battle_context > weapons_
List of all battle contexts used for getting the weapons.
Definition: unit_attack.hpp:63
Generic file dialog.
Definition: field-fwd.hpp:22
The listbox class.
Definition: listbox.hpp:40
bool backstab_pos
True if the attacker is in position to backstab the defender (this is used to determine whether to ap...
Definition: attack.hpp:60
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
int damage
Effective damage of the weapon (all factors accounted for).
Definition: attack.hpp:74
This file contains the settings handling of the widget library.
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:233
const t_string & name() const
Definition: attack_type.hpp:40
void damage_calc_callback(window &window)
Definition: unit_attack.cpp:84
Computes the statistics of a battle between an attacker and a defender unit.
Definition: attack.hpp:171
virtual void post_show(window &window) override
Inherited from modal_dialog.
const std::string & range() const
Definition: attack_type.hpp:44
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:131
const std::string & icon() const
Definition: attack_type.hpp:43
Structure describing the statistics of a unit involved in the battle.
Definition: attack.hpp:48
Various uncategorised dialogs.
pointer get_shared_ptr() const
This is exactly the same as operator-> but it&#39;s slightly more readable, and can replace &*iter syntax...
Definition: map.hpp:220
int selected_weapon_
The index of the selected weapon.
Definition: unit_attack.hpp:54
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
grid & 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:66
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
bool empty() const
Definition: tstring.hpp:182
const std::string weapon_numbers_sep
Definition: constants.cpp:45
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...
symbol_table string_table
Definition: language.cpp:63
const std::string unicode_em_dash
Definition: constants.cpp:40
unit_map::iterator attacker_itor_
Iterator pointing to the attacker.
Definition: unit_attack.hpp:57
Container associating units to locations.
Definition: map.hpp:99
unsigned int num_blows
Effective number of blows, takes swarm into account.
Definition: attack.hpp:78
specials_context_t specials_context(unit_const_ptr self, unit_const_ptr other, const map_location &unit_loc, const map_location &other_loc, bool attacking, const_attack_ptr other_attack) const
Dialog was closed with the OK button.
Definition: retval.hpp:34
void unit_attack(display *disp, game_board &board, const map_location &a, const map_location &b, int damage, const attack_type &attack, const_attack_ptr secondary_attack, int swing, const std::string &hit_text, int drain_amount, const std::string &att_text, const std::vector< std::string > *extra_hit_sounds)
Make the unit on tile &#39;a&#39; attack the unit on tile &#39;b&#39;.
Definition: udisplay.cpp:596
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
std::shared_ptr< const attack_type > const_attack_ptr
Definition: ptr.hpp:37
virtual void pre_show(window &window) override
Inherited from modal_dialog.
Definition: unit_attack.cpp:90
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:371
unit_map::iterator defender_itor_
Iterator pointing to the defender.
Definition: unit_attack.hpp:60