1 #ifndef _Tech_h_ 2 #define _Tech_h_ 3 4 #include "EnumsFwd.h" 5 #include "../util/Export.h" 6 #include "../util/Pending.h" 7 8 #include <boost/multi_index_container.hpp> 9 #include <boost/multi_index/key_extractors.hpp> 10 #include <boost/multi_index/ordered_index.hpp> 11 #include <boost/algorithm/string/case_conv.hpp> 12 #include <boost/optional/optional.hpp> 13 14 #include <set> 15 #include <string> 16 #include <vector> 17 #include <map> 18 19 #include <GG/Clr.h> 20 21 namespace Effect 22 { class EffectsGroup; } 23 namespace ValueRef { 24 template <typename T> 25 struct ValueRef; 26 } 27 class TechManager; 28 struct UnlockableItem; 29 30 /** encasulates the data for a single FreeOrion technology */ 31 class FO_COMMON_API Tech { 32 public: 33 /** Helper struct for parsing tech definitions */ 34 struct TechInfo { 35 TechInfo(); 36 TechInfo(const std::string& name_, const std::string& description_, 37 const std::string& short_description_, const std::string& category_, 38 std::unique_ptr<ValueRef::ValueRef<double>>&& research_cost_, 39 std::unique_ptr<ValueRef::ValueRef<int>>&& research_turns_, 40 bool researchable_, 41 const std::set<std::string>& tags_); 42 ~TechInfo(); 43 44 std::string name; 45 std::string description; 46 std::string short_description; 47 std::string category; 48 std::unique_ptr<ValueRef::ValueRef<double>> research_cost; 49 std::unique_ptr<ValueRef::ValueRef<int>> research_turns; 50 bool researchable; 51 std::set<std::string> tags; 52 }; 53 54 /** \name Structors */ //@{ 55 Tech(const std::string& name, const std::string& description, 56 const std::string& short_description, const std::string& category, 57 std::unique_ptr<ValueRef::ValueRef<double>>&& research_cost, 58 std::unique_ptr<ValueRef::ValueRef<int>>&& research_turns, 59 bool researchable, 60 const std::set<std::string>& tags, 61 const std::vector<std::shared_ptr<Effect::EffectsGroup>>& effects, 62 const std::set<std::string>& prerequisites, 63 const std::vector<UnlockableItem>& unlocked_items, 64 const std::string& graphic); 65 66 /** basic ctor taking helper struct to reduce number of direct parameters 67 * in order to making parsing work. */ 68 Tech(TechInfo& tech_info, 69 std::vector<std::unique_ptr<Effect::EffectsGroup>>&& effects, 70 const std::set<std::string>& prerequisites, 71 const std::vector<UnlockableItem>& unlocked_items, 72 const std::string& graphic); 73 74 ~Tech(); 75 //@} 76 77 /** \name Accessors */ //@{ Name()78 const std::string& Name() const { return m_name; } //!< returns name of this tech Description()79 const std::string& Description() const { return m_description; } //!< Returns the text description of this tech ShortDescription()80 const std::string& ShortDescription() const { return m_short_description; } //!< Returns the single-line short text description of this tech 81 std::string Dump(unsigned short ntabs = 0) const; //!< Returns a text representation of this object Category()82 const std::string& Category() const { return m_category; } //!< retursn the name of the category to which this tech belongs 83 float ResearchCost(int empire_id) const; //!< returns the total research cost in RPs required to research this tech 84 float PerTurnCost(int empire_id) const; //!< returns the maximum number of RPs per turn allowed to be spent on researching this tech 85 int ResearchTime(int empire_id) const; //!< returns the number of turns required to research this tech, if ResearchCost() RPs are spent per turn Researchable()86 bool Researchable() const { return m_researchable; } //!< returns whether this tech is researchable by players and appears on the tech tree 87 Tags()88 const std::set<std::string>& Tags() const { return m_tags; } 89 90 /** returns the effects that are applied to the discovering empire's capital 91 * when this tech is researched; not all techs have effects, in which case 92 * this returns 0 */ Effects()93 const std::vector<std::shared_ptr<Effect::EffectsGroup>>& Effects() const 94 { return m_effects; } 95 Prerequisites()96 const std::set<std::string>& Prerequisites() const { return m_prerequisites; } //!< returns the set of names of all techs required before this one can be researched Graphic()97 const std::string& Graphic() const { return m_graphic; } //!< returns the name of the grapic file for this tech 98 99 //! Returns the set all items that are unlocked by researching this tech UnlockedItems()100 const std::vector<UnlockableItem>& UnlockedItems() const 101 { return m_unlocked_items; } 102 UnlockedTechs()103 const std::set<std::string>& UnlockedTechs() const { return m_unlocked_techs; } //!< returns the set of names of all techs for which this one is a prerequisite 104 105 /** Returns a number, calculated from the contained data, which should be 106 * different for different contained data, and must be the same for 107 * the same contained data, and must be the same on different platforms 108 * and executions of the program and the function. Useful to verify that 109 * the parsed content is consistent without sending it all between 110 * clients and server. */ 111 unsigned int GetCheckSum() const; 112 //@} 113 114 private: 115 Tech(const Tech&); // disabled 116 const Tech& operator=(const Tech&); // disabled 117 void Init(); 118 119 std::string m_name; 120 std::string m_description; 121 std::string m_short_description; 122 std::string m_category; 123 std::unique_ptr<ValueRef::ValueRef<double>> m_research_cost; 124 std::unique_ptr<ValueRef::ValueRef<int>> m_research_turns; 125 bool m_researchable; 126 std::set<std::string> m_tags; 127 std::vector<std::shared_ptr<Effect::EffectsGroup>> m_effects; 128 std::set<std::string> m_prerequisites; 129 std::vector<UnlockableItem> m_unlocked_items; 130 std::string m_graphic; 131 std::set<std::string> m_unlocked_techs; 132 133 friend class TechManager; 134 }; 135 136 137 /** specifies a category of techs, with associated \a name, \a graphic (icon), and \a colour.*/ 138 struct FO_COMMON_API TechCategory { TechCategoryTechCategory139 TechCategory() : 140 name(""), 141 graphic(""), 142 colour(GG::Clr(255, 255, 255, 255)) 143 {} TechCategoryTechCategory144 TechCategory(const std::string& name_, const std::string& graphic_, 145 const GG::Clr& colour_): 146 name(name_), 147 graphic(graphic_), 148 colour(colour_) 149 {} 150 std::string name; ///< name of category 151 std::string graphic; ///< icon that represents catetegory 152 GG::Clr colour; ///< colour associatied with category 153 }; 154 155 namespace CheckSums { 156 FO_COMMON_API void CheckSumCombine(unsigned int& sum, const TechCategory& cat); 157 } 158 159 /** holds all FreeOrion techs. Techs may be looked up by name and by category, and the next researchable techs can be querried, 160 given a set of currently-known techs. */ 161 class FO_COMMON_API TechManager { 162 public: 163 struct CategoryIndex {}; 164 struct NameIndex {}; 165 typedef boost::multi_index_container< 166 std::unique_ptr<Tech>, 167 boost::multi_index::indexed_by< 168 boost::multi_index::ordered_non_unique< 169 boost::multi_index::tag<CategoryIndex>, 170 boost::multi_index::const_mem_fun< 171 Tech, 172 const std::string&, 173 &Tech::Category 174 > 175 >, 176 boost::multi_index::ordered_unique< 177 boost::multi_index::tag<NameIndex>, 178 boost::multi_index::const_mem_fun< 179 Tech, 180 const std::string&, 181 &Tech::Name 182 > 183 > 184 > 185 > TechContainer; 186 187 using TechCategoryMap = std::map<std::string, std::unique_ptr<TechCategory>>; 188 189 /** iterator that runs over techs within a category */ 190 typedef TechContainer::index<CategoryIndex>::type::const_iterator category_iterator; 191 192 /** iterator that runs over all techs */ 193 typedef TechContainer::index<NameIndex>::type::const_iterator iterator; 194 195 /** \name Accessors */ //@{ 196 /** returns the tech with the name \a name; you should use the free function GetTech() instead */ 197 const Tech* GetTech(const std::string& name) const; 198 199 /** returns the tech category with the name \a name; you should use the free function GetTechCategory() instead */ 200 const TechCategory* GetTechCategory(const std::string& name) const; 201 202 /** returns the list of category names */ 203 std::vector<std::string> CategoryNames() const; 204 205 /** returns list of all tech names */ 206 std::vector<std::string> TechNames() const; 207 208 /** returns list of names of techs in specified category */ 209 std::vector<std::string> TechNames(const std::string& name) const; 210 211 /** returns all researchable techs */ 212 std::vector<const Tech*> AllNextTechs(const std::set<std::string>& known_techs); 213 214 /** returns the cheapest researchable tech */ 215 const Tech* CheapestNextTech(const std::set<std::string>& known_techs, int empire_id); 216 217 /** returns all researchable techs that progress from the given known techs to the given desired tech */ 218 std::vector<const Tech*> NextTechsTowards(const std::set<std::string>& known_techs, 219 const std::string& desired_tech, 220 int empire_id); 221 222 /** returns the cheapest researchable tech that progresses from the given known techs to the given desired tech */ 223 const Tech* CheapestNextTechTowards(const std::set<std::string>& known_techs, 224 const std::string& desired_tech, 225 int empire_id); 226 227 /** iterator to the first tech */ 228 iterator begin() const; 229 230 /** iterator to the last + 1th tech */ 231 iterator end() const; 232 233 /** iterator to the first tech in category \a name */ 234 category_iterator category_begin(const std::string& name) const; 235 236 /** iterator to the last + 1th tech in category \a name */ 237 category_iterator category_end(const std::string& name) const; 238 239 /** Returns names of indicated tech's prerequisites, and all prereqs of 240 * those techs, etc. recursively. If \a min_required is false then prereqs 241 * will be included and recursed into even if already known to the empire. */ 242 std::vector<std::string> RecursivePrereqs(const std::string& tech_name, int empire_id, bool min_required = true) const; 243 244 /** Returns a number, calculated from the contained data, which should be 245 * different for different contained data, and must be the same for 246 * the same contained data, and must be the same on different platforms 247 * and executions of the program and the function. Useful to verify that 248 * the parsed content is consistent without sending it all between 249 * clients and server. */ 250 unsigned int GetCheckSum() const; 251 //@} 252 253 using TechParseTuple = std::tuple< 254 TechManager::TechContainer, // techs_ 255 std::map<std::string, std::unique_ptr<TechCategory>>, // tech_categories, 256 std::set<std::string> // categories_seen 257 >; 258 /** Sets types to the value of \p future. */ 259 FO_COMMON_API void SetTechs(Pending::Pending<TechParseTuple>&& future); 260 261 262 /** returns the instance of this singleton class; you should use the free function GetTechManager() instead */ 263 static TechManager& GetTechManager(); 264 265 private: 266 TechManager(); 267 268 /** Assigns any m_pending_types to m_techs. */ 269 void CheckPendingTechs() const; 270 271 /** returns an error string indicating the first instance of an illegal prerequisite relationship between 272 two techs in m_techs, or an empty string if there are no illegal dependencies */ 273 std::string FindIllegalDependencies() const; 274 275 /** returns an error string indicating the first prerequisite dependency cycle found in m_techs, or an 276 empty string if there are no dependency cycles */ 277 std::string FindFirstDependencyCycle() const; 278 279 /** returns an error string indicating the first instance of a redundant dependency, or an empty string if there 280 are no redundant dependencies. An example of a redundant dependency is A --> C, if A --> B and B --> C. */ 281 std::string FindRedundantDependency() const; 282 283 void AllChildren(const Tech* tech, std::map<std::string, std::string>& children) const; 284 285 /** Future types being parsed by parser. mutable so that it can 286 be assigned to m_species_types when completed.*/ 287 mutable boost::optional<Pending::Pending<TechParseTuple>> m_pending_types = boost::none; 288 289 mutable TechCategoryMap m_categories; 290 mutable TechContainer m_techs; 291 292 static TechManager* s_instance; 293 }; 294 295 /** returns the singleton tech manager */ 296 FO_COMMON_API TechManager& GetTechManager(); 297 298 //! @brief Returns the ::Tech identified by @p name 299 //! 300 //! @param name 301 //! The identifying name of the requested ::Tech. 302 //! 303 //! @return 304 //! A pointer to the ::Tech matching @p name or nullptr if no ::Tech with that 305 //! name was found. 306 FO_COMMON_API const Tech* GetTech(const std::string& name); 307 308 /** returns a pointer to the tech category with the name \a name, or 0 if no such category exists */ 309 FO_COMMON_API const TechCategory* GetTechCategory(const std::string& name); 310 311 #endif // _Tech_h_ 312