1 /*
2    Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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 /**
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 
24 #include "ai/lua/aspect_advancements.hpp"
25 #include "attack_prediction.hpp"
26 #include "units/types.hpp"
27 
28 #include <vector>
29 
30 struct map_location;
31 class team;
32 struct time_of_day;
33 class unit;
34 class unit_map;
35 class gamemap;
36 
37 /** Calculates the number of blows resulting from swarm. */
swarm_blows(unsigned min_blows,unsigned max_blows,unsigned hp,unsigned max_hp)38 inline unsigned swarm_blows(unsigned min_blows, unsigned max_blows, unsigned hp, unsigned max_hp)
39 {
40 	return hp >= max_hp
41 		? max_blows
42 		: max_blows < min_blows
43 			? min_blows - (min_blows - max_blows) * hp / max_hp
44 			: min_blows + (max_blows - min_blows) * hp / max_hp;
45 }
46 
47 /** Structure describing the statistics of a unit involved in the battle. */
48 struct battle_context_unit_stats
49 {
50 	const_attack_ptr weapon; /**< The weapon used by the unit to attack the opponent, or nullptr if there is none. */
51 	int attack_num;          /**< Index into unit->attacks() or -1 for none. */
52 	bool is_attacker;        /**< True if the unit is the attacker. */
53 	bool is_poisoned;        /**< True if the unit is poisoned at the beginning of the battle. */
54 	bool is_slowed;          /**< True if the unit is slowed at the beginning of the battle. */
55 	bool slows;              /**< Attack slows opponent when it hits. */
56 	bool drains;             /**< Attack drains opponent when it hits. */
57 	bool petrifies;          /**< Attack petrifies opponent when it hits. */
58 	bool plagues;            /**< Attack turns opponent into a zombie when fatal. */
59 	bool poisons;            /**< Attack poisons opponent when it hits. */
60 	bool backstab_pos;       /**<
61 	                           * True if the attacker is in *position* to backstab the defender (this is used to
62                                * determine whether to apply the backstab bonus in case the attacker has backstab).
63                                */
64 	bool swarm;              /**< Attack has swarm special. */
65 	bool firststrike;        /**< Attack has firststrike special. */
66 	bool disable;            /**< Attack has disable special. */
67 	unsigned int experience, max_experience;
68 	unsigned int level;
69 
70 	unsigned int rounds;        /**< Berserk special can force us to fight more than one round. */
71 	unsigned int hp;            /**< Hitpoints of the unit at the beginning of the battle. */
72 	unsigned int max_hp;        /**< Maximum hitpoints of the unit. */
73 	unsigned int chance_to_hit; /**< Effective chance to hit as a percentage (all factors accounted for). */
74 	int damage;                 /**< Effective damage of the weapon (all factors accounted for). */
75 	int slow_damage;            /**< Effective damage if unit becomes slowed (== damage, if already slowed) */
76 	int drain_percent;          /**< Percentage of damage recovered as health */
77 	int drain_constant;         /**< Base HP drained regardless of damage dealt */
78 	unsigned int num_blows;     /**< Effective number of blows, takes swarm into account. */
79 	unsigned int swarm_min;     /**< Minimum number of blows with swarm (equal to num_blows if swarm isn't used). */
80 	unsigned int swarm_max;     /**< Maximum number of blows with swarm (equal to num_blows if swarm isn't used). */
81 
82 	std::string plague_type; /**< The plague type used by the attack, if any. */
83 
84 	battle_context_unit_stats(const unit& u,
85 			const map_location& u_loc,
86 			int u_attack_num,
87 			bool attacking,
88 			const unit& opp,
89 			const map_location& opp_loc,
90 			const_attack_ptr opp_weapon,
91 			const unit_map& units);
92 
93 	/** Used by AI for combat analysis */
94 	battle_context_unit_stats(const unit_type* u_type,
95 			const_attack_ptr att_weapon,
96 			bool attacking,
97 			const unit_type* opp_type,
98 			const_attack_ptr opp_weapon,
99 			unsigned int opp_terrain_defense,
100 			int lawful_bonus = 0);
101 
~battle_context_unit_statsbattle_context_unit_stats102 	~battle_context_unit_stats()
103 	{
104 	}
105 
106 	/// Calculates the number of blows we would have if we had @a new_hp
107 	// instead of the recorded hp.
calc_blowsbattle_context_unit_stats108 	unsigned int calc_blows(unsigned new_hp) const
109 	{
110 		return swarm_blows(swarm_min, swarm_max, new_hp, max_hp);
111 	}
112 
113 #if defined(BENCHMARK) || defined(CHECK)
114 	/**
115 	 * Special constructor for the stand-alone version of attack_prediction.cpp.
116 	 * (This hardcodes some standard abilities for testing purposes.)
117 	 */
battle_context_unit_statsbattle_context_unit_stats118 	battle_context_unit_stats(int dmg,
119 			int blows,
120 			int hitpoints,
121 			int maximum_hp,
122 			int hit_chance,
123 			bool drain,
124 			bool slows,
125 			bool slowed,
126 			bool berserk,
127 			bool first,
128 			bool do_swarm)
129 		: weapon(nullptr) // Not used in attack prediction.
130 		, attack_num(0) // Not used in attack prediction.
131 		, is_attacker(true) // Not used in attack prediction.
132 		, is_poisoned(false)
133 		, is_slowed(slowed)
134 		, slows(slows)
135 		, drains(drain)
136 		, petrifies(false)
137 		, plagues(false)
138 		, poisons(false)
139 		, backstab_pos(false)
140 		, swarm(do_swarm)
141 		, firststrike(first)
142 		, disable(false)
143 		, experience(0) // No units should advance in the attack prediction tests.
144 		, max_experience(50) // No units should advance in the attack prediction tests.
145 		, level(1) // No units should advance in the attack prediction tests.
146 		, rounds(berserk ? 30 : 1)
147 		, hp(std::max<int>(0, hitpoints))
148 		, max_hp(std::max<int>(1, maximum_hp))
149 		, chance_to_hit(hit_chance)
150 		, damage(std::max(0, dmg))
151 		, slow_damage(round_damage(damage, 1, 2))
152 		, drain_percent(drain ? 50 : 0)
153 		, drain_constant(0)
154 		, num_blows(do_swarm ? blows * hp / max_hp : blows)
155 		, swarm_min(do_swarm ? 0 : blows)
156 		, swarm_max(blows)
157 		, plague_type()
158 	{
159 		if(slowed) {
160 			damage = slow_damage;
161 		}
162 
163 		if(hp > max_hp) {
164 			hp = max_hp; // Keeps the prob_matrix from going out of bounds.
165 		}
166 	}
167 #endif
168 };
169 
170 /** Computes the statistics of a battle between an attacker and a defender unit. */
171 class battle_context
172 {
173 public:
174 	/**
175 	 * If no attacker_weapon is given, we select the best one,
176 	 * based on harm_weight (1.0 means 1 hp lost counters 1 hp damage,
177 	 * 0.0 means we ignore harm weight).
178 	 * prev_def is for predicting multiple attacks against a defender.
179 	 */
180 	battle_context(const unit_map& units,
181 			const map_location& attacker_loc,
182 			const map_location& defender_loc,
183 			int attacker_weapon = -1,
184 			int defender_weapon = -1,
185 			double aggression = 0.0,
186 			const combatant* prev_def = nullptr,
187 			const unit* attacker_ptr = nullptr);
188 
189 	/** Used by the AI which caches battle_context_unit_stats */
190 	battle_context(const battle_context_unit_stats& att, const battle_context_unit_stats& def);
191 
192 	battle_context(const battle_context& other) = delete;
193 	battle_context(battle_context&& other);
194 
195 	battle_context& operator=(const battle_context& other) = delete;
196 	battle_context& operator=(battle_context&& other);
197 
198 	/** This method returns the statistics of the attacker. */
get_attacker_stats() const199 	const battle_context_unit_stats& get_attacker_stats() const
200 	{
201 		return *attacker_stats_;
202 	}
203 
204 	/** This method returns the statistics of the defender. */
get_defender_stats() const205 	const battle_context_unit_stats& get_defender_stats() const
206 	{
207 		return *defender_stats_;
208 	}
209 
210 	/** Get the simulation results. */
211 	const combatant& get_attacker_combatant(const combatant* prev_def = nullptr);
212 	const combatant& get_defender_combatant(const combatant* prev_def = nullptr);
213 
214 	/** Given this harm_weight, is this attack better than that? */
215 	bool better_attack(class battle_context& that, double harm_weight);
216 	/** Given this harm_weight, is this attack better than that? */
217 	bool better_defense(class battle_context& that, double harm_weight);
218 
219 	static bool better_combat(const combatant& us_a,
220 			const combatant& them_a,
221 			const combatant& us_b,
222 			const combatant& them_b,
223 			double harm_weight);
224 
225 	void simulate(const combatant* prev_def);
226 private:
227 	battle_context(
228 			const unit& attacker,
229 			const map_location& attacker_loc,
230 			int attacker_weapon,
231 			const unit& defender,
232 			const map_location& defender_loc,
233 			int defender_weapon,
234 			const unit_map& units);
235 
236 	static battle_context choose_attacker_weapon(const unit& attacker,
237 			const unit& defender,
238 			const unit_map& units,
239 			const map_location& attacker_loc,
240 			const map_location& defender_loc,
241 			double harm_weight,
242 			const combatant* prev_def);
243 
244 	static battle_context choose_defender_weapon(const unit& attacker,
245 			const unit& defender,
246 			unsigned attacker_weapon,
247 			const unit_map& units,
248 			const map_location& attacker_loc,
249 			const map_location& defender_loc,
250 			const combatant* prev_def);
251 
252 	/** Statistics of the units. */
253 	std::unique_ptr<battle_context_unit_stats> attacker_stats_;
254 	std::unique_ptr<battle_context_unit_stats> defender_stats_;
255 
256 	/** Outcome of simulated fight. */
257 	std::unique_ptr<combatant> attacker_combatant_;
258 	std::unique_ptr<combatant> defender_combatant_;
259 };
260 
261 /** Performs an attack. */
262 void attack_unit(const map_location& attacker,
263 		const map_location& defender,
264 		int attack_with,
265 		int defend_with,
266 		bool update_display = true);
267 
268 /** Performs an attack, and advanced the units afterwards */
269 void attack_unit_and_advance(const map_location& attacker,
270 		const map_location& defender,
271 		int attack_with,
272 		int defend_with,
273 		bool update_display = true,
274 		const ai::unit_advancements_aspect& ai_advancement = ai::unit_advancements_aspect());
275 
276 /**
277  * Tests if the unit at loc is currently affected by leadership.
278  * (i.e. has a higher-level unit with the 'leadership' ability next to it).
279  *
280  * Returns the bonus percentage (possibly 0 if there's no leader adjacent).
281  */
282 int under_leadership(const unit &u, const map_location& loc);
283 
284 /**
285  * Returns the amount that a unit's damage should be multiplied by
286  * due to the current time of day.
287  */
288 int combat_modifier(const unit_map& units,
289 		const gamemap& map,
290 		const map_location& loc,
291 		unit_type::ALIGNMENT alignment,
292 		bool is_fearless);
293 
294 /**
295  * Returns the amount that a unit's damage should be multiplied by
296  * due to the current time of day.
297  */
298 int combat_modifier(const time_of_day& effective_tod,
299 		unit_type::ALIGNMENT alignment,
300 		bool is_fearless);
301 
302 /**
303  * Returns the amount that a unit's damage should be multiplied by
304  * due to a given lawful_bonus.
305  */
306 int generic_combat_modifier(int lawful_bonus, unit_type::ALIGNMENT alignment, bool is_fearless);
307 /**
308  * Function to check if an attack will satisfy the requirements for backstab.
309  * Input:
310  * - the location from which the attack will occur,
311  * - the defending unit location,
312  * - the list of units on the map and
313  * - the list of teams.
314  * The defender and opposite units should be in place already.
315  * The attacking unit doesn't need to be, but if it isn't,
316  * an external check should be made to make sure the opposite unit
317  * isn't also the attacker.
318  */
319 bool backstab_check(const map_location& attacker_loc,
320 		const map_location& defender_loc,
321 		const unit_map& units,
322 		const std::vector<team>& teams);
323