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 #pragma once
16 
17 #include "map/location.hpp"
18 #include "tstring.hpp"
19 #include "config.hpp"
20 #include <string>
21 #include <vector>
22 #include <cassert>
23 
24 #include <boost/iterator/indirect_iterator.hpp>
25 #include <boost/range/iterator_range.hpp>
26 #include <boost/dynamic_bitset_fwd.hpp>
27 
28 #include "units/ptr.hpp" // for attack_ptr
29 
30 class unit_ability_list;
31 class unit_type;
32 
33 //the 'attack type' is the type of attack, how many times it strikes,
34 //and how much damage it does.
35 class attack_type : public std::enable_shared_from_this<attack_type>
36 {
37 public:
38 
39 	explicit attack_type(const config& cfg);
name() const40 	const t_string& name() const { return description_; }
id() const41 	const std::string& id() const { return id_; }
type() const42 	const std::string& type() const { return type_; }
icon() const43 	const std::string& icon() const { return icon_; }
range() const44 	const std::string& range() const { return range_; }
min_range() const45 	int min_range() const { return min_range_; }
max_range() const46 	int max_range() const { return max_range_; }
47 	std::string accuracy_parry_description() const;
accuracy() const48 	int accuracy() const { return accuracy_; }
parry() const49 	int parry() const { return parry_; }
damage() const50 	int damage() const { return damage_; }
num_attacks() const51 	int num_attacks() const { return num_attacks_; }
attack_weight() const52 	double attack_weight() const { return attack_weight_; }
defense_weight() const53 	double defense_weight() const { return defense_weight_; }
specials() const54 	const config &specials() const { return specials_; }
55 
set_name(const t_string & value)56 	void set_name(const t_string& value) { description_  = value; }
set_id(const std::string & value)57 	void set_id(const std::string& value) { id_ = value; }
set_type(const std::string & value)58 	void set_type(const std::string& value) { type_ = value; }
set_icon(const std::string & value)59 	void set_icon(const std::string& value) { icon_ = value; }
set_range(const std::string & value)60 	void set_range(const std::string& value) { range_ = value; }
set_accuracy(int value)61 	void set_accuracy(int value) { accuracy_ = value; }
set_parry(int value)62 	void set_parry(int value) { parry_ = value; }
set_damage(int value)63 	void set_damage(int value) { damage_ = value; }
set_num_attacks(int value)64 	void set_num_attacks(int value) { num_attacks_ = value; }
set_attack_weight(double value)65 	void set_attack_weight(double value) { attack_weight_ = value; }
set_defense_weight(double value)66 	void set_defense_weight(double value) { defense_weight_ = value; }
set_specials(config value)67 	void set_specials(config value) { specials_ = value; }
68 
69 
70 	// In unit_abilities.cpp:
71 
72 	bool get_special_bool(const std::string& special, bool simple_check=false) const;
73 	unit_ability_list get_specials(const std::string& special) const;
74 	std::vector<std::pair<t_string, t_string>> special_tooltips(boost::dynamic_bitset<>* active_list = nullptr) const;
75 	std::string weapon_specials(bool only_active=false, bool is_backstab=false) const;
76 
77 	/// Calculates the number of attacks this weapon has, considering specials.
78 	void modified_attacks(bool is_backstab, unsigned & min_attacks,
79 	                      unsigned & max_attacks) const;
80 	/// Returns the damage per attack of this weapon, considering specials.
81 	int modified_damage(bool is_backstab) const;
82 
83 	// In unit_types.cpp:
84 
85 	bool matches_filter(const config& filter) const;
86 	bool apply_modification(const config& cfg);
87 	bool describe_modification(const config& cfg,std::string* description);
88 
movement_used() const89 	int movement_used() const { return movement_used_; }
set_movement_used(int value)90 	void set_movement_used(int value) { movement_used_ = value; }
91 
92 	void write(config& cfg) const;
to_config() const93 	inline config to_config() const { config c; write(c); return c; }
94 
95 private:
96 	// In unit_abilities.cpp:
97 
98 	// Configured as a bit field, in case that is useful.
99 	enum AFFECTS { AFFECT_SELF=1, AFFECT_OTHER=2, AFFECT_EITHER=3 };
100 	bool special_active(const config& special, AFFECTS whom,
101 	                    bool include_backstab=true) const;
102 
103 	// Used via specials_context() to control which specials are
104 	// considered active.
105 	friend class specials_context_t;
106 	mutable map_location self_loc_, other_loc_;
107 	mutable unit_const_ptr self_;
108 	mutable unit_const_ptr other_;
109 	mutable bool is_attacker_;
110 	mutable const_attack_ptr other_attack_;
111 	mutable bool is_for_listing_ = false;
112 public:
113 	class specials_context_t {
114 		std::shared_ptr<const attack_type> parent;
115 		friend class attack_type;
116 		/// Initialize weapon specials context for listing
117 		explicit specials_context_t(const attack_type& weapon, bool attacking);
118 		/// Initialize weapon specials context for a unit type
119 		specials_context_t(const attack_type& weapon, const unit_type& self_type, const map_location& loc, bool attacking = true);
120 		/// Initialize weapon specials context for a single unit
121 		specials_context_t(const attack_type& weapon, const_attack_ptr other_weapon,
122 			unit_const_ptr self, unit_const_ptr other,
123 			const map_location& self_loc, const map_location& other_loc,
124 			bool attacking);
125 		/// Initialize weapon specials context for a pair of units
126 		specials_context_t(const attack_type& weapon, unit_const_ptr self, const map_location& loc, bool attacking);
127 		specials_context_t(const specials_context_t&) = delete;
128 		// Default assignment is needed as a base for the move assignment
129 		specials_context_t& operator=(const specials_context_t&) = default;
130 		bool was_moved = false;
131 	public:
132 		// Destructor at least needs to be public for all this to work.
133 		~specials_context_t();
134 		specials_context_t(specials_context_t&&);
135 		specials_context_t& operator=(specials_context_t&&);
136 	};
137 	// Set up a specials context.
138 	// Usage: auto ctx = weapon.specials_context(...);
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) const139 	specials_context_t specials_context(unit_const_ptr self, unit_const_ptr other,
140 		const map_location& unit_loc, const map_location& other_loc,
141 		bool attacking, const_attack_ptr other_attack) const {
142 		return specials_context_t(*this, other_attack, self, other, unit_loc, other_loc, attacking);
143 	}
specials_context(unit_const_ptr self,const map_location & loc,bool attacking=true) const144 	specials_context_t specials_context(unit_const_ptr self, const map_location& loc, bool attacking = true) const {
145 		return specials_context_t(*this, self, loc, attacking);
146 	}
specials_context(const unit_type & self_type,const map_location & loc,bool attacking=true) const147 	specials_context_t specials_context(const unit_type& self_type, const map_location& loc, bool attacking = true) const {
148 		return specials_context_t(*this, self_type, loc, attacking);
149 	}
specials_context_for_listing(bool attacking=true) const150 	specials_context_t specials_context_for_listing(bool attacking = true) const {
151 		return specials_context_t(*this, attacking);
152 	}
153 private:
154 
155 	t_string description_;
156 	std::string id_;
157 	std::string type_;
158 	std::string icon_;
159 	std::string range_;
160 	int min_range_, max_range_;
161 	int damage_;
162 	int num_attacks_;
163 	double attack_weight_;
164 	double defense_weight_;
165 
166 	int accuracy_;
167 	int movement_used_;
168 	int parry_;
169 	config specials_;
170 };
171 
172 using attack_list = std::vector<attack_ptr>;
173 using attack_itors = boost::iterator_range<boost::indirect_iterator<attack_list::iterator>>;
174 using const_attack_itors = boost::iterator_range<boost::indirect_iterator<attack_list::const_iterator>>;
175 
make_attack_itors(attack_list & atks)176 inline attack_itors make_attack_itors(attack_list& atks) {
177 	return boost::make_iterator_range(boost::make_indirect_iterator(atks.begin()), boost::make_indirect_iterator(atks.end()));
178 }
179 
make_attack_itors(const attack_list & atks)180 inline const_attack_itors make_attack_itors(const attack_list& atks) {
181 	return boost::make_iterator_range(boost::make_indirect_iterator(atks.begin()), boost::make_indirect_iterator(atks.end()));
182 }
183