The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
attack.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2017 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Various functions that implement attacks and attack calculations.
18  * Unit advancements are also included, as they usually occur as a
19  * result of combat.
20  */
21 
22 #pragma once
23 
25 #include "attack_prediction.hpp"
26 #include "units/types.hpp"
27 
28 #include <vector>
29 
30 struct map_location;
31 class team;
32 class unit;
33 class unit_map;
34 class gamemap;
35 
36 /** Calculates the number of blows resulting from swarm. */
37 inline unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp, unsigned max_hp)
38 {
39  return hp >= max_hp
40  ? max_blows
41  : max_blows < min_blows
42  ? min_blows - (min_blows - max_blows) * hp / max_hp
43  : min_blows + (max_blows - min_blows) * hp / max_hp;
44 }
45 
46 /** Structure describing the statistics of a unit involved in the battle. */
48 {
49  const_attack_ptr weapon; /**< The weapon used by the unit to attack the opponent, or nullptr if there is none. */
50  int attack_num; /**< Index into unit->attacks() or -1 for none. */
51  bool is_attacker; /**< True if the unit is the attacker. */
52  bool is_poisoned; /**< True if the unit is poisoned at the beginning of the battle. */
53  bool is_slowed; /**< True if the unit is slowed at the beginning of the battle. */
54  bool slows; /**< Attack slows opponent when it hits. */
55  bool drains; /**< Attack drains opponent when it hits. */
56  bool petrifies; /**< Attack petrifies opponent when it hits. */
57  bool plagues; /**< Attack turns opponent into a zombie when fatal. */
58  bool poisons; /**< Attack poisons opponent when it hits. */
59  bool backstab_pos; /**<
60  * True if the attacker is in *position* to backstab the defender (this is used to
61  * determine whether to apply the backstab bonus in case the attacker has backstab).
62  */
63  bool swarm; /**< Attack has swarm special. */
64  bool firststrike; /**< Attack has firststrike special. */
65  bool disable; /**< Attack has disable special. */
66  unsigned int experience, max_experience;
67  unsigned int level;
68 
69  unsigned int rounds; /**< Berserk special can force us to fight more than one round. */
70  unsigned int hp; /**< Hitpoints of the unit at the beginning of the battle. */
71  unsigned int max_hp; /**< Maximum hitpoints of the unit. */
72  unsigned int chance_to_hit; /**< Effective chance to hit as a percentage (all factors accounted for). */
73  int damage; /**< Effective damage of the weapon (all factors accounted for). */
74  int slow_damage; /**< Effective damage if unit becomes slowed (== damage, if already slowed) */
75  int drain_percent; /**< Percentage of damage recovered as health */
76  int drain_constant; /**< Base HP drained regardless of damage dealt */
77  unsigned int num_blows; /**< Effective number of blows, takes swarm into account. */
78  unsigned int swarm_min; /**< Minimum number of blows with swarm (equal to num_blows if swarm isn't used). */
79  unsigned int swarm_max; /**< Maximum number of blows with swarm (equal to num_blows if swarm isn't used). */
80 
81  std::string plague_type; /**< The plague type used by the attack, if any. */
82 
84  const map_location& u_loc,
85  int u_attack_num,
86  bool attacking,
87  const unit& opp,
88  const map_location& opp_loc,
89  const_attack_ptr opp_weapon,
90  const unit_map& units);
91 
92  /** Used by AI for combat analysis */
94  const_attack_ptr att_weapon,
95  bool attacking,
96  const unit_type* opp_type,
97  const_attack_ptr opp_weapon,
98  unsigned int opp_terrain_defense,
99  int lawful_bonus = 0);
100 
102  {
103  }
104 
105  /// Calculates the number of blows we would have if we had @a new_hp
106  // instead of the recorded hp.
107  unsigned int calc_blows(unsigned new_hp) const
108  {
109  return swarm_blows(swarm_min, swarm_max, new_hp, max_hp);
110  }
111 
112 #if defined(BENCHMARK) || defined(CHECK)
113  /**
114  * Special constructor for the stand-alone version of attack_prediction.cpp.
115  * (This hardcodes some standard abilities for testing purposes.)
116  */
118  int blows,
119  int hitpoints,
120  int maximum_hp,
121  int hit_chance,
122  bool drain,
123  bool slows,
124  bool slowed,
125  bool berserk,
126  bool first,
127  bool do_swarm)
128  : weapon(nullptr) // Not used in attack prediction.
129  , attack_num(0) // Not used in attack prediction.
130  , is_attacker(true) // Not used in attack prediction.
131  , is_poisoned(false)
132  , is_slowed(slowed)
133  , slows(slows)
134  , drains(drain)
135  , petrifies(false)
136  , plagues(false)
137  , poisons(false)
138  , backstab_pos(false)
139  , swarm(do_swarm)
140  , firststrike(first)
141  , disable(false)
142  , experience(0) // No units should advance in the attack prediction tests.
143  , max_experience(50) // No units should advance in the attack prediction tests.
144  , level(1) // No units should advance in the attack prediction tests.
145  , rounds(berserk ? 30 : 1)
146  , hp(std::max<int>(0, hitpoints))
147  , max_hp(std::max<int>(1, maximum_hp))
148  , chance_to_hit(hit_chance)
149  , damage(std::max(0, dmg))
150  , slow_damage(round_damage(damage, 1, 2))
151  , drain_percent(drain ? 50 : 0)
152  , drain_constant(0)
153  , num_blows(do_swarm ? blows * hp / max_hp : blows)
154  , swarm_min(do_swarm ? 0 : blows)
155  , swarm_max(blows)
156  , plague_type()
157  {
158  if(slowed) {
159  damage = slow_damage;
160  }
161 
162  if(hp > max_hp) {
163  hp = max_hp; // Keeps the prob_matrix from going out of bounds.
164  }
165  }
166 #endif
167 };
168 
169 /** Computes the statistics of a battle between an attacker and a defender unit. */
171 {
172 public:
173  /**
174  * If no attacker_weapon is given, we select the best one,
175  * based on harm_weight (1.0 means 1 hp lost counters 1 hp damage,
176  * 0.0 means we ignore harm weight).
177  * prev_def is for predicting multiple attacks against a defender.
178  */
180  const map_location& attacker_loc,
181  const map_location& defender_loc,
182  int attacker_weapon = -1,
183  int defender_weapon = -1,
184  double aggression = 0.0,
185  const combatant* prev_def = nullptr,
186  const unit* attacker_ptr = nullptr);
187 
188  /** Used by the AI which caches battle_context_unit_stats */
190 
191  battle_context(const battle_context& other);
192 
193  battle_context& operator=(const battle_context& other);
194 
195  /** This method returns the statistics of the attacker. */
197  {
198  return *attacker_stats_;
199  }
200 
201  /** This method returns the statistics of the defender. */
203  {
204  return *defender_stats_;
205  }
206 
207  /** Get the simulation results. */
208  const combatant& get_attacker_combatant(const combatant* prev_def = nullptr);
209  const combatant& get_defender_combatant(const combatant* prev_def = nullptr);
210 
211  /** Given this harm_weight, is this attack better than that? */
212  bool better_attack(class battle_context& that, double harm_weight);
213 
214  static bool better_combat(const combatant& us_a,
215  const combatant& them_a,
216  const combatant& us_b,
217  const combatant& them_b,
218  double harm_weight);
219 
220 private:
221  int choose_attacker_weapon(const unit& attacker,
222  const unit& defender,
223  const unit_map& units,
224  const map_location& attacker_loc,
225  const map_location& defender_loc,
226  double harm_weight,
227  int* defender_weapon,
228  const combatant* prev_def);
229 
230  int choose_defender_weapon(const unit& attacker,
231  const unit& defender,
232  unsigned attacker_weapon,
233  const unit_map& units,
234  const map_location& attacker_loc,
235  const map_location& defender_loc,
236  const combatant* prev_def);
237 
238  /** Statistics of the units. */
239  std::unique_ptr<battle_context_unit_stats> attacker_stats_;
240  std::unique_ptr<battle_context_unit_stats> defender_stats_;
241 
242  /** Outcome of simulated fight. */
243  std::unique_ptr<combatant> attacker_combatant_;
244  std::unique_ptr<combatant> defender_combatant_;
245 };
246 
247 /** Performs an attack. */
248 void attack_unit(const map_location& attacker,
249  const map_location& defender,
250  int attack_with,
251  int defend_with,
252  bool update_display = true);
253 
254 /** Performs an attack, and advanced the units afterwards */
255 void attack_unit_and_advance(const map_location& attacker,
256  const map_location& defender,
257  int attack_with,
258  int defend_with,
259  bool update_display = true,
261 
262 /**
263  * Tests if the unit at loc is currently affected by leadership.
264  * (i.e. has a higher-level unit with the 'leadership' ability next to it).
265  *
266  * Returns a pair of bonus percentage and the leader's location if the unit is affected,
267  * or 0 and map_location::null_location() otherwise.
268  */
269 std::pair<int, map_location> under_leadership(const unit_map& units, const map_location& loc);
270 
271 /**
272  * Returns the amount that a unit's damage should be multiplied by
273  * due to the current time of day.
274  */
275 int combat_modifier(const unit_map& units,
276  const gamemap& map,
277  const map_location& loc,
278  unit_type::ALIGNMENT alignment,
279  bool is_fearless);
280 
281 /**
282  * Returns the amount that a unit's damage should be multiplied by
283  * due to a given lawful_bonus.
284  */
285 int generic_combat_modifier(int lawful_bonus, unit_type::ALIGNMENT alignment, bool is_fearless);
286 /**
287  * Function to check if an attack will satisfy the requirements for backstab.
288  * Input:
289  * - the location from which the attack will occur,
290  * - the defending unit location,
291  * - the list of units on the map and
292  * - the list of teams.
293  * The defender and opposite units should be in place already.
294  * The attacking unit doesn't need to be, but if it isn't,
295  * an external check should be made to make sure the opposite unit
296  * isn't also the attacker.
297  */
298 bool backstab_check(const map_location& attacker_loc,
299  const map_location& defender_loc,
300  const unit_map& units,
301  const std::vector<team>& teams);
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
Definition: attack.hpp:49
std::unique_ptr< combatant > attacker_combatant_
Outcome of simulated fight.
Definition: attack.hpp:243
unsigned int calc_blows(unsigned new_hp) const
Calculates the number of blows we would have if we had new_hp.
Definition: attack.hpp:107
std::vector< char_t > string
std::string plague_type
The plague type used by the attack, if any.
Definition: attack.hpp:81
This class represents a single unit of a specific type.
Definition: unit.hpp:101
unsigned int hp
Hitpoints of the unit at the beginning of the battle.
Definition: attack.hpp:70
int choose_defender_weapon(const unit &attacker, const unit &defender, unsigned attacker_weapon, const unit_map &units, const map_location &attacker_loc, const map_location &defender_loc, const combatant *prev_def)
Definition: attack.cpp:653
static bool better_combat(const combatant &us_a, const combatant &them_a, const combatant &us_b, const combatant &them_b, double harm_weight)
Definition: attack.cpp:495
const combatant & get_attacker_combatant(const combatant *prev_def=nullptr)
Get the simulation results.
Definition: attack.cpp:452
bool is_slowed
True if the unit is slowed at the beginning of the battle.
Definition: attack.hpp:53
STL namespace.
battle_context(const unit_map &units, const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon=-1, int defender_weapon=-1, double aggression=0.0, const combatant *prev_def=nullptr, const unit *attacker_ptr=nullptr)
If no attacker_weapon is given, we select the best one, based on harm_weight (1.0 means 1 hp lost cou...
Definition: attack.cpp:350
bool slows
Attack slows opponent when it hits.
Definition: attack.hpp:54
int drain_constant
Base HP drained regardless of damage dealt.
Definition: attack.hpp:76
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
Definition: attack.hpp:72
A single unit type that the player may recruit.
Definition: types.hpp:43
void attack_unit(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display=true)
Performs an attack.
Definition: attack.cpp:1539
void attack_unit_and_advance(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display=true, const ai::unit_advancements_aspect &ai_advancement=ai::unit_advancements_aspect())
Performs an attack, and advanced the units afterwards.
Definition: attack.cpp:1549
std::pair< int, map_location > under_leadership(const unit_map &units, const map_location &loc)
Tests if the unit at loc is currently affected by leadership.
Definition: attack.cpp:1569
bool poisons
Attack poisons opponent when it hits.
Definition: attack.hpp:58
const combatant & get_defender_combatant(const combatant *prev_def=nullptr)
Definition: attack.cpp:467
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:59
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:44
int damage
Effective damage of the weapon (all factors accounted for).
Definition: attack.hpp:73
unsigned int level
Definition: attack.hpp:67
unsigned int rounds
Berserk special can force us to fight more than one round.
Definition: attack.hpp:69
unsigned int swarm_min
Minimum number of blows with swarm (equal to num_blows if swarm isn't used).
Definition: attack.hpp:78
const battle_context_unit_stats & get_defender_stats() const
This method returns the statistics of the defender.
Definition: attack.hpp:202
std::unique_ptr< battle_context_unit_stats > defender_stats_
Definition: attack.hpp:240
bool plagues
Attack turns opponent into a zombie when fatal.
Definition: attack.hpp:57
bool better_attack(class battle_context &that, double harm_weight)
Given this harm_weight, is this attack better than that?
Definition: attack.cpp:483
Encapsulates the map of the game.
Definition: map.hpp:34
Computes the statistics of a battle between an attacker and a defender unit.
Definition: attack.hpp:170
int attack_num
Index into unit->attacks() or -1 for none.
Definition: attack.hpp:50
Structure describing the statistics of a unit involved in the battle.
Definition: attack.hpp:47
int choose_attacker_weapon(const unit &attacker, const unit &defender, const unit_map &units, const map_location &attacker_loc, const map_location &defender_loc, double harm_weight, int *defender_weapon, const combatant *prev_def)
Definition: attack.cpp:537
std::unique_ptr< battle_context_unit_stats > attacker_stats_
Statistics of the units.
Definition: attack.hpp:239
bool backstab_check(const map_location &attacker_loc, const map_location &defender_loc, const unit_map &units, const std::vector< team > &teams)
Function to check if an attack will satisfy the requirements for backstab.
Definition: attack.cpp:1619
Encapsulates the map of the game.
Definition: location.hpp:40
int round_damage(int base_damage, int bonus, int divisor)
round (base_damage * bonus / divisor) to the closest integer, but up or down towards base_damage ...
Definition: math.hpp:57
unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp, unsigned max_hp)
Calculates the number of blows resulting from swarm.
Definition: attack.hpp:37
All combat-related info.
battle_context & operator=(const battle_context &other)
Definition: attack.cpp:434
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:1580
bool swarm
Attack has swarm special.
Definition: attack.hpp:63
int slow_damage
Effective damage if unit becomes slowed (== damage, if already slowed)
Definition: attack.hpp:74
std::unique_ptr< combatant > defender_combatant_
Definition: attack.hpp:244
int generic_combat_modifier(int lawful_bonus, unit_type::ALIGNMENT alignment, bool is_fearless)
Returns the amount that a unit's damage should be multiplied by due to a given lawful_bonus.
Definition: attack.cpp:1591
unsigned int experience
Definition: attack.hpp:66
bool disable
Attack has disable special.
Definition: attack.hpp:65
bool firststrike
Attack has firststrike special.
Definition: attack.hpp:64
bool is_poisoned
True if the unit is poisoned at the beginning of the battle.
Definition: attack.hpp:52
int drain_percent
Percentage of damage recovered as health.
Definition: attack.hpp:75
battle_context_unit_stats(const unit &u, const map_location &u_loc, int u_attack_num, bool attacking, const unit &opp, const map_location &opp_loc, const_attack_ptr opp_weapon, const unit_map &units)
Definition: attack.cpp:65
Container associating units to locations.
Definition: map.hpp:99
unsigned int num_blows
Effective number of blows, takes swarm into account.
Definition: attack.hpp:77
unsigned int max_hp
Maximum hitpoints of the unit.
Definition: attack.hpp:71
const battle_context_unit_stats & get_attacker_stats() const
This method returns the statistics of the attacker.
Definition: attack.hpp:196
bool is_attacker
True if the unit is the attacker.
Definition: attack.hpp:51
unsigned int max_experience
Definition: attack.hpp:66
bool petrifies
Attack petrifies opponent when it hits.
Definition: attack.hpp:56
std::shared_ptr< const attack_type > const_attack_ptr
Definition: ptr.hpp:37
bool drains
Attack drains opponent when it hits.
Definition: attack.hpp:55
unit_map * units
Definition: resources.cpp:34
unsigned int swarm_max
Maximum number of blows with swarm (equal to num_blows if swarm isn't used).
Definition: attack.hpp:79