The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
attack.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
3 by David White <dave@whitevine.net>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16/**
17 * @file
18 * Various functions that implement attacks and attack calculations.
19 * Unit advancements are also included, as they usually occur as a
20 * result of combat.
21 */
22
23#pragma once
24
25#include "attack_prediction.hpp"
26#include "units/ptr.hpp"
29#include "utils/math.hpp"
30
31#include <vector>
32
33
34struct map_location;
35class team;
36struct time_of_day;
37class unit_type;
38class unit;
39class unit_map;
40class gamemap;
41
42namespace randomness
43{
44class rng;
45}
47
48namespace biased_rng
49{
50/** Returns true if the current game uses the biased random mode with a local RNG. */
51bool enabled();
52
53/** Rolls the credit a combatant starts a fight with. */
55
56/** Rolls one strike. @a strikes_left includes this strike. */
57bool roll_hit(randomness::rng& rng, int strikes_left, int chance_to_hit, int& credit);
58} // namespace biased_rng
59
60/** Calculates the number of blows resulting from swarm. */
61inline unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp, unsigned max_hp)
62{
63 return hp >= max_hp
64 ? max_blows
65 : max_blows < min_blows
66 ? min_blows - (min_blows - max_blows) * hp / max_hp
67 : min_blows + (max_blows - min_blows) * hp / max_hp;
68}
69
70/** Structure describing the statistics of a unit involved in the battle. */
72{
73 const_attack_ptr weapon; /**< The weapon used by the unit to attack the opponent, or nullptr if there is none. */
74 int attack_num; /**< Index into unit->attacks() or -1 for none. */
75 bool is_attacker; /**< True if the unit is the attacker. */
76 bool is_poisoned; /**< True if the unit is poisoned at the beginning of the battle. */
77 bool is_slowed; /**< True if the unit is slowed at the beginning of the battle. */
78 bool slows; /**< Attack slows opponent when it hits. */
79 bool drains; /**< Attack drains opponent when it hits. */
80 bool petrifies; /**< Attack petrifies opponent when it hits. */
81 bool plagues; /**< Attack turns opponent into a zombie when fatal. */
82 bool poisons; /**< Attack poisons opponent when it hits. */
83 bool swarm; /**< Attack has swarm special. */
84 bool firststrike; /**< Attack has firststrike special. */
85 bool disable; /**< Attack has disable special. */
86 bool can_advance; /**< The unit can advance */
89 unsigned int level;
90
91 unsigned int rounds; /**< Berserk special can force us to fight more than one round. */
92 unsigned int hp; /**< Hitpoints of the unit at the beginning of the battle. */
93 unsigned int max_hp; /**< Maximum hitpoints of the unit. */
94 unsigned int chance_to_hit; /**< Effective chance to hit as a percentage (all factors accounted for). */
95 int damage; /**< Effective damage of the weapon (all factors accounted for). */
96 int slow_damage; /**< Effective damage if unit becomes slowed (== damage, if already slowed) */
97 int drain_percent; /**< Percentage of damage recovered as health */
98 int drain_constant; /**< Base HP drained regardless of damage dealt */
99 unsigned int num_blows; /**< Effective number of blows, takes swarm into account. */
100 unsigned int swarm_min; /**< Minimum number of blows with swarm (equal to num_blows if swarm isn't used). */
101 unsigned int swarm_max; /**< Maximum number of blows with swarm (equal to num_blows if swarm isn't used). */
102
103 std::string plague_type; /**< The plague type used by the attack, if any. */
104
106 const map_location& u_loc,
107 int u_attack_num,
108 bool attacking,
110 const map_location& opp_loc,
111 const const_attack_ptr& opp_weapon,
112 utils::optional<int> opp_terrain_defense = {},
113 utils::optional<int> lawful_bonus = {}
114 );
115
119
120 /** Calculates the number of blows we would have if we had @a new_hp instead of the recorded hp. */
121 unsigned int calc_blows(unsigned new_hp) const
122 {
123 return swarm_blows(swarm_min, swarm_max, new_hp, max_hp);
124 }
125
126 /**
127 * Special constructor for the stand-alone version of attack_prediction.cpp and the statistis dialog.
128 * (This hardcodes some standard abilities for testing purposes.)
129 */
131 int blows,
132 int hitpoints,
133 int maximum_hp,
134 int hit_chance,
135 bool drain = false,
136 bool slows = false,
137 bool slowed = false,
138 bool berserk = false,
139 bool first = false,
140 bool do_swarm = false)
141 : weapon(nullptr) // Not used in attack prediction.
142 , attack_num(0) // Not used in attack prediction.
143 , is_attacker(true) // Not used in attack prediction.
144 , is_poisoned(false)
145 , is_slowed(slowed)
146 , slows(slows)
147 , drains(drain)
148 , petrifies(false)
149 , plagues(false)
150 , poisons(false)
151 , swarm(do_swarm)
152 , firststrike(first)
153 , disable(false)
155 , experience(0) // No units should advance in the attack prediction tests.
156 , max_experience(1000000) // No units should advance in the attack prediction tests.
157 , level(1) // No units should advance in the attack prediction tests.
158 , rounds(berserk ? 30 : 1)
159 , hp(std::max<int>(0, hitpoints))
160 , max_hp(std::max<int>(1, maximum_hp))
161 , chance_to_hit(hit_chance)
162 , damage(std::max(0, dmg))
164 , drain_percent(drain ? 50 : 0)
165 , drain_constant(0)
166 , num_blows(do_swarm ? blows * hp / max_hp : blows)
167 , swarm_min(do_swarm ? 0 : blows)
168 , swarm_max(blows)
169 , plague_type()
170 {
171 if(slowed) {
173 }
174
175 if(hp > max_hp) {
176 hp = max_hp; // Keeps the prob_matrix from going out of bounds.
177 }
178 }
179};
180
181/** Computes the statistics of a battle between an attacker and a defender unit. */
183{
184public:
185 /**
186 * If no attacker_weapon is given, we select the best one,
187 * based on harm_weight (1.0 means 1 hp lost counters 1 hp damage,
188 * 0.0 means we ignore harm weight).
189 * prev_def is for predicting multiple attacks against a defender.
190 * use_biased_rng determines whether or not to simulate fights in Reduced RNG mode.
191 */
192 battle_context(const unit_map& units,
193 const map_location& attacker_loc,
194 const map_location& defender_loc,
195 int attacker_weapon = -1,
196 int defender_weapon = -1,
197 double aggression = 0.0,
198 const combatant* prev_def = nullptr,
199 unit_const_ptr attacker_ptr = unit_const_ptr(),
200 unit_const_ptr defender_ptr = unit_const_ptr(),
201 bool use_biased_rng = false);
202
203 /** Used by the AI which caches battle_context_unit_stats */
205
206 battle_context(battle_context&& other) = default;
207
209
210 /** This method returns the statistics of the attacker. */
212 {
213 return *attacker_stats_;
214 }
215
216 /** This method returns the statistics of the defender. */
218 {
219 return *defender_stats_;
220 }
221
222 /** Get the simulation results. */
223 const combatant& get_attacker_combatant(const combatant* prev_def = nullptr);
224 const combatant& get_defender_combatant(const combatant* prev_def = nullptr);
225
226 /** Given this harm_weight, is this attack better than that? */
227 bool better_attack(class battle_context& that, double harm_weight);
228 /** Given this harm_weight, is this attack better than that? */
229 bool better_defense(class battle_context& that, double harm_weight);
230
231 static bool better_combat(const combatant& us_a,
232 const combatant& them_a,
233 const combatant& us_b,
234 const combatant& them_b,
235 double harm_weight);
236
237 void simulate(const combatant* prev_def);
238private:
241 const map_location& attacker_loc,
242 int attacker_weapon,
244 const map_location& defender_loc,
245 int defender_weapon,
246 bool use_biased_rng = false);
247
249 const nonempty_unit_const_ptr& defender,
250 const map_location& attacker_loc,
251 const map_location& defender_loc,
252 double harm_weight,
253 const combatant* prev_def,
254 bool use_biased_rng);
255
258 unsigned attacker_weapon,
259 const map_location& attacker_loc,
260 const map_location& defender_loc,
261 const combatant* prev_def,
262 bool use_biased_rng);
263
264 /** Statistics of the units. */
265 std::unique_ptr<battle_context_unit_stats> attacker_stats_;
266 std::unique_ptr<battle_context_unit_stats> defender_stats_;
267
268 /** Outcome of simulated fight. */
269 std::unique_ptr<combatant> attacker_combatant_;
270 std::unique_ptr<combatant> defender_combatant_;
271
272 bool use_biased_rng_ = false;
273};
274
275/** Performs an attack. */
276void attack_unit(const map_location& attacker,
277 const map_location& defender,
278 int attack_with,
279 int defend_with,
280 bool update_display = true);
281
282/** Performs an attack, and advanced the units afterwards */
283void attack_unit_and_advance(const map_location& attacker,
284 const map_location& defender,
285 int attack_with,
286 int defend_with,
287 bool update_display = true);
288
289/**
290 * Tests if the unit at loc is currently affected by leadership.
291 * (i.e. has a higher-level unit with the 'leadership' ability next to it).
292 *
293 * Returns the bonus percentage (possibly 0 if there's no leader adjacent).
294 */
295int under_leadership(const unit& u, const map_location& loc);
296int under_leadership(const unit& u, const specials_context_t& loc);
297
298/**
299 * Returns the amount that a unit's damage should be multiplied by
300 * due to the current time of day.
301 */
302int combat_modifier(const unit_map& units,
303 const gamemap& map,
304 const map_location& loc,
305 unit_alignments::type alignment,
306 bool is_fearless);
307
308/**
309 * Returns the amount that a unit's damage should be multiplied by
310 * due to the current time of day.
311 */
312int combat_modifier(const time_of_day& effective_tod,
313 unit_alignments::type alignment,
314 bool is_fearless);
315
316/**
317 * Returns the amount that a unit's damage should be multiplied by
318 * due to a given lawful_bonus.
319 */
320int generic_combat_modifier(int lawful_bonus, unit_alignments::type alignment, bool is_fearless, int max_liminal_bonus);
321/**
322 * Function to check if an attack will satisfy the requirements for backstab.
323 * Input:
324 * - the location from which the attack will occur,
325 * - the defending unit location,
326 * - the list of units on the map and
327 * - the list of teams.
328 * The defender and opposite units should be in place already.
329 * The attacking unit doesn't need to be, but if it isn't,
330 * an external check should be made to make sure the opposite unit
331 * isn't also the attacker.
332 */
333bool backstab_check(const map_location& attacker_loc,
334 const map_location& defender_loc,
335 const unit_map& units,
336 const std::vector<team>& teams);
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:1475
int generic_combat_modifier(int lawful_bonus, unit_alignments::type alignment, bool is_fearless, int max_liminal_bonus)
Returns the amount that a unit's damage should be multiplied by due to a given lawful_bonus.
Definition attack.cpp:1538
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:1566
int combat_modifier(const unit_map &units, const gamemap &map, const map_location &loc, unit_alignments::type 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:1518
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:61
int under_leadership(const unit &u, const map_location &loc)
Tests if the unit at loc is currently affected by leadership.
Definition attack.cpp:1504
void attack_unit_and_advance(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display=true)
Performs an attack, and advanced the units afterwards.
Definition attack.cpp:1485
map_location loc
Definition move.cpp:172
Computes the statistics of a battle between an attacker and a defender unit.
Definition attack.hpp:183
std::unique_ptr< battle_context_unit_stats > defender_stats_
Definition attack.hpp:266
std::unique_ptr< combatant > defender_combatant_
Definition attack.hpp:270
std::unique_ptr< battle_context_unit_stats > attacker_stats_
Statistics of the units.
Definition attack.hpp:265
const battle_context_unit_stats & get_attacker_stats() const
This method returns the statistics of the attacker.
Definition attack.hpp:211
std::unique_ptr< combatant > attacker_combatant_
Outcome of simulated fight.
Definition attack.hpp:269
void simulate(const combatant *prev_def)
Definition attack.cpp:291
static battle_context choose_defender_weapon(nonempty_unit_const_ptr attacker, nonempty_unit_const_ptr defender, unsigned attacker_weapon, const map_location &attacker_loc, const map_location &defender_loc, const combatant *prev_def, bool use_biased_rng)
Definition attack.cpp:502
battle_context & operator=(battle_context &&other)=default
static battle_context choose_attacker_weapon(nonempty_unit_const_ptr attacker, const nonempty_unit_const_ptr &defender, const map_location &attacker_loc, const map_location &defender_loc, double harm_weight, const combatant *prev_def, bool use_biased_rng)
Definition attack.cpp:447
const combatant & get_attacker_combatant(const combatant *prev_def=nullptr)
Get the simulation results.
Definition attack.cpp:361
const battle_context_unit_stats & get_defender_stats() const
This method returns the statistics of the defender.
Definition attack.hpp:217
battle_context(battle_context &&other)=default
const combatant & get_defender_combatant(const combatant *prev_def=nullptr)
Definition attack.cpp:368
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:400
bool better_defense(class battle_context &that, double harm_weight)
Given this harm_weight, is this attack better than that?
Definition attack.cpp:388
bool better_attack(class battle_context &that, double harm_weight)
Given this harm_weight, is this attack better than that?
Definition attack.cpp:376
bool use_biased_rng_
Definition attack.hpp:272
Encapsulates the map of the game.
Definition map.hpp:176
this class does not give synced random results derived classes might do.
Definition random.hpp:28
This class stores all the data for a single 'side' (in game nomenclature).
Definition team.hpp:74
Container associating units to locations.
Definition map.hpp:98
A single unit type that the player may recruit.
Definition types.hpp:43
This class represents a single unit of a specific type.
Definition unit.hpp:39
General math utility functions.
constexpr int round_damage(double 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:78
int roll_credit(randomness::rng &rng)
Rolls the credit a combatant starts a fight with.
Definition attack.cpp:83
bool enabled()
Returns true if the current game uses the biased random mode with a local RNG.
Definition attack.cpp:78
bool roll_hit(randomness::rng &rng, int strikes_left, int chance_to_hit, int &credit)
Rolls one strike.
Definition attack.cpp:88
STL namespace.
std::shared_ptr< const unit > unit_const_ptr
Definition ptr.hpp:27
std::shared_ptr< const attack_type > const_attack_ptr
Definition ptr.hpp:34
Structure describing the statistics of a unit involved in the battle.
Definition attack.hpp:72
bool slows
Attack slows opponent when it hits.
Definition attack.hpp:78
unsigned int num_blows
Effective number of blows, takes swarm into account.
Definition attack.hpp:99
std::string plague_type
The plague type used by the attack, if any.
Definition attack.hpp:103
bool petrifies
Attack petrifies opponent when it hits.
Definition attack.hpp:80
int drain_percent
Percentage of damage recovered as health.
Definition attack.hpp:97
unsigned int hp
Hitpoints of the unit at the beginning of the battle.
Definition attack.hpp:92
int slow_damage
Effective damage if unit becomes slowed (== damage, if already slowed)
Definition attack.hpp:96
unsigned int max_experience
Definition attack.hpp:88
bool drains
Attack drains opponent when it hits.
Definition attack.hpp:79
unsigned int swarm_min
Minimum number of blows with swarm (equal to num_blows if swarm isn't used).
Definition attack.hpp:100
bool swarm
Attack has swarm special.
Definition attack.hpp:83
bool is_attacker
True if the unit is the attacker.
Definition attack.hpp:75
battle_context_unit_stats(int dmg, int blows, int hitpoints, int maximum_hp, int hit_chance, bool drain=false, bool slows=false, bool slowed=false, bool berserk=false, bool first=false, bool do_swarm=false)
Special constructor for the stand-alone version of attack_prediction.cpp and the statistis dialog.
Definition attack.hpp:130
bool is_poisoned
True if the unit is poisoned at the beginning of the battle.
Definition attack.hpp:76
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
Definition attack.hpp:73
bool is_slowed
True if the unit is slowed at the beginning of the battle.
Definition attack.hpp:77
unsigned int rounds
Berserk special can force us to fight more than one round.
Definition attack.hpp:91
unsigned int swarm_max
Maximum number of blows with swarm (equal to num_blows if swarm isn't used).
Definition attack.hpp:101
unsigned int calc_blows(unsigned new_hp) const
Calculates the number of blows we would have if we had new_hp instead of the recorded hp.
Definition attack.hpp:121
unsigned int max_hp
Maximum hitpoints of the unit.
Definition attack.hpp:93
int damage
Effective damage of the weapon (all factors accounted for).
Definition attack.hpp:95
bool can_advance
The unit can advance.
Definition attack.hpp:86
bool disable
Attack has disable special.
Definition attack.hpp:85
bool poisons
Attack poisons opponent when it hits.
Definition attack.hpp:82
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
Definition attack.hpp:94
int drain_constant
Base HP drained regardless of damage dealt.
Definition attack.hpp:98
bool firststrike
Attack has firststrike special.
Definition attack.hpp:84
int attack_num
Index into unit->attacks() or -1 for none.
Definition attack.hpp:74
bool plagues
Attack turns opponent into a zombie when fatal.
Definition attack.hpp:81
unsigned int experience
Definition attack.hpp:88
All combat-related info.
Encapsulates the map of the game.
Definition location.hpp:46
Object which defines a time of day with associated bonuses, image, sounds etc.