1 #ifndef _Species_h_ 2 #define _Species_h_ 3 4 5 #include "EnumsFwd.h" 6 #include "../util/Export.h" 7 #include "../util/Serialize.h" 8 #include "../util/Pending.h" 9 10 #include <boost/algorithm/string/case_conv.hpp> 11 #include <boost/serialization/nvp.hpp> 12 #include <boost/iterator/filter_iterator.hpp> 13 #include <boost/optional/optional.hpp> 14 15 #include <map> 16 #include <memory> 17 #include <set> 18 #include <string> 19 #include <vector> 20 21 22 namespace Condition { 23 struct Condition; 24 } 25 namespace Effect { 26 class EffectsGroup; 27 } 28 29 FO_COMMON_API extern const int ALL_EMPIRES; 30 31 /** A setting that a ResourceCenter can be assigned to influence what it 32 * produces. Doesn't directly affect the ResourceCenter, but effectsgroups 33 * can use activation or scope conditions that check whether a potential 34 * target has a particular focus. By this method, techs or buildings or 35 * species can act on planets or other ResourceCenters depending what their 36 * focus setting is. */ 37 class FO_COMMON_API FocusType { 38 public: 39 /** \name Structors */ //@{ FocusType()40 FocusType() : 41 m_name(), 42 m_description(), 43 m_location(), 44 m_graphic() 45 {} 46 47 FocusType(const std::string& name, const std::string& description, 48 std::unique_ptr<Condition::Condition>&& location, 49 const std::string& graphic); 50 51 ~FocusType(); 52 //@} 53 54 /** \name Accessors */ //@{ Name()55 const std::string& Name() const { return m_name; } ///< returns the name for this focus type Description()56 const std::string& Description() const { return m_description; } ///< returns a text description of this focus type Location()57 const Condition::Condition* Location() const { return m_location.get(); }///< returns the condition that determines whether an UniverseObject can use this FocusType Graphic()58 const std::string& Graphic() const { return m_graphic; } ///< returns the name of the grapic file for this focus type 59 std::string Dump(unsigned short ntabs = 0) const; ///< returns a data file format representation of this object 60 61 /** Returns a number, calculated from the contained data, which should be 62 * different for different contained data, and must be the same for 63 * the same contained data, and must be the same on different platforms 64 * and executions of the program and the function. Useful to verify that 65 * the parsed content is consistent without sending it all between 66 * clients and server. */ 67 unsigned int GetCheckSum() const; 68 //@} 69 70 private: 71 std::string m_name; 72 std::string m_description; 73 std::shared_ptr<const Condition::Condition> m_location; 74 std::string m_graphic; 75 }; 76 77 /** Used by parser due to limits on number of sub-items per parsed main item. */ 78 struct SpeciesParams { SpeciesParamsSpeciesParams79 SpeciesParams() 80 {} SpeciesParamsSpeciesParams81 SpeciesParams(bool playable_, bool native_, bool can_colonize_, bool can_produce_ships_) : 82 playable(playable_), 83 native(native_), 84 can_colonize(can_colonize_), 85 can_produce_ships(can_produce_ships_) 86 {} 87 bool playable = false; 88 bool native = false; 89 bool can_colonize = false; 90 bool can_produce_ships = false; 91 }; 92 93 /** Used by parser due to limits on number of sub-items per parsed main item. */ 94 struct SpeciesStrings { SpeciesStringsSpeciesStrings95 SpeciesStrings() 96 {} SpeciesStringsSpeciesStrings97 SpeciesStrings(const std::string& name_, const std::string& desc_, 98 const std::string& gameplay_desc_) : 99 name(name_), 100 desc(desc_), 101 gameplay_desc(gameplay_desc_) 102 {} 103 std::string name; 104 std::string desc; 105 std::string gameplay_desc; 106 }; 107 108 /** A predefined type of population that can exist on a PopulationCenter. 109 * Species have associated sets of EffectsGroups, and various other 110 * properties that affect how the object on which they reside functions. 111 * Each kind of Species must have a \a unique name string, by which it can be 112 * looked up using GetSpecies(). */ 113 class FO_COMMON_API Species { 114 public: 115 /** \name Structors */ //@{ 116 Species(const SpeciesStrings& strings, 117 const std::vector<FocusType>& foci, 118 const std::string& preferred_focus, 119 const std::map<PlanetType, PlanetEnvironment>& planet_environments, 120 std::vector<std::unique_ptr<Effect::EffectsGroup>>&& effects, 121 std::unique_ptr<Condition::Condition>&& combat_targets, 122 const SpeciesParams& params, 123 const std::set<std::string>& tags, 124 const std::string& graphic); 125 126 ~Species(); 127 //@} 128 129 /** \name Accessors */ //@{ Name()130 const std::string& Name() const { return m_name; } ///< returns the unique name for this type of species Description()131 const std::string& Description() const { return m_description; } ///< returns a text description of this type of species 132 /** returns a text description of this type of species */ 133 std::string GameplayDescription() const; 134 Homeworlds()135 const std::set<int>& Homeworlds() const { return m_homeworlds; } ///< returns the ids of objects that are homeworlds for this species EmpireOpinions()136 const std::map<int, double>& EmpireOpinions() const { return m_empire_opinions; } ///< returns the positive/negative opinions of this species about empires OtherSpeciesOpinions()137 const std::map<std::string, double>& OtherSpeciesOpinions() const{ return m_other_species_opinions; }///< returns the positive/negative opinions of this species about other species 138 Location()139 const Condition::Condition* Location() const { return m_location.get(); } ///< returns the condition determining what planets on which this species may spawn CombatTargets()140 const Condition::Condition* CombatTargets() const { return m_combat_targets.get(); } ///< returns the condition for possible targets. may be nullptr if no condition was specified. 141 142 std::string Dump(unsigned short ntabs = 0) const; ///< returns a data file format representation of this object Foci()143 const std::vector<FocusType>& Foci() const { return m_foci; } ///< returns the focus types this species can use PreferredFocus()144 const std::string& PreferredFocus() const { return m_preferred_focus; } ///< returns the name of the planetary focus this species prefers. Default for new colonies and may affect happiness if on a different focus? PlanetEnvironments()145 const std::map<PlanetType, PlanetEnvironment>& PlanetEnvironments() const { return m_planet_environments; } ///< returns a map from PlanetType to the PlanetEnvironment this Species has on that PlanetType 146 PlanetEnvironment GetPlanetEnvironment(PlanetType planet_type) const; ///< returns the PlanetEnvironment this species has on PlanetType \a planet_type 147 PlanetType NextBetterPlanetType(PlanetType initial_planet_type) const; ///< returns the next better PlanetType for this species from the \a initial_planet_type specified 148 149 /** Returns the EffectsGroups that encapsulate the effects that species of 150 this type have. */ Effects()151 const std::vector<std::shared_ptr<Effect::EffectsGroup>>& Effects() const 152 { return m_effects; } 153 Playable()154 bool Playable() const { return m_playable; } ///< returns whether this species is a suitable starting species for players Native()155 bool Native() const { return m_native; } ///< returns whether this species is a suitable native species (for non player-controlled planets) CanColonize()156 bool CanColonize() const { return m_can_colonize; } ///< returns whether this species can colonize planets CanProduceShips()157 bool CanProduceShips() const { return m_can_produce_ships; } ///< returns whether this species can produce ships Tags()158 const std::set<std::string>& Tags() const { return m_tags; } Graphic()159 const std::string& Graphic() const { return m_graphic; } ///< returns the name of the grapic file for this species 160 161 /** Returns a number, calculated from the contained data, which should be 162 * different for different contained data, and must be the same for 163 * the same contained data, and must be the same on different platforms 164 * and executions of the program and the function. Useful to verify that 165 * the parsed content is consistent without sending it all between 166 * clients and server. */ 167 unsigned int GetCheckSum() const; 168 //@} 169 170 /** \name Mutators */ //@{ 171 void AddHomeworld(int homeworld_id); 172 void RemoveHomeworld(int homeworld_id); 173 void SetHomeworlds(const std::set<int>& homeworld_ids); 174 void SetEmpireOpinions(const std::map<int, double>& opinions); 175 void SetEmpireOpinion(int empire_id, double opinion); 176 void SetOtherSpeciesOpinions(const std::map<std::string, double>& opinions); 177 void SetOtherSpeciesOpinion(const std::string& species_name, double opinion); 178 //@} 179 180 private: 181 void Init(); 182 183 std::string m_name; 184 std::string m_description; 185 std::string m_gameplay_description; 186 187 std::set<int> m_homeworlds; 188 std::map<int, double> m_empire_opinions; // positive/negative rating of how this species views empires in the game 189 std::map<std::string, double> m_other_species_opinions; // positive/negative rating of how this species views other species in the game 190 191 std::vector<FocusType> m_foci; 192 std::string m_preferred_focus; 193 std::map<PlanetType, PlanetEnvironment> m_planet_environments; 194 195 std::vector<std::shared_ptr<Effect::EffectsGroup>> m_effects; 196 std::unique_ptr<Condition::Condition> m_location; 197 std::unique_ptr<Condition::Condition> m_combat_targets; 198 199 bool m_playable; 200 bool m_native; 201 bool m_can_colonize; 202 bool m_can_produce_ships; 203 std::set<std::string> m_tags; 204 std::string m_graphic; 205 }; 206 207 208 /** Holds all FreeOrion species. Types may be looked up by name. */ 209 class FO_COMMON_API SpeciesManager { 210 private: 211 struct FO_COMMON_API PlayableSpecies 212 { bool operator()(const std::map<std::string, std::unique_ptr<Species>>::value_type& species_entry) const; }; 213 struct FO_COMMON_API NativeSpecies 214 { bool operator()(const std::map<std::string, std::unique_ptr<Species>>::value_type& species_entry) const; }; 215 216 public: 217 using SpeciesTypeMap = std::map<std::string, std::unique_ptr<Species>>; 218 using CensusOrder = std::vector<std::string>; 219 using iterator = SpeciesTypeMap::const_iterator; 220 typedef boost::filter_iterator<PlayableSpecies, iterator> playable_iterator; 221 typedef boost::filter_iterator<NativeSpecies, iterator> native_iterator; 222 223 /** \name Accessors */ //@{ 224 /** returns the building type with the name \a name; you should use the 225 * free function GetSpecies() instead, mainly to save some typing. */ 226 const Species* GetSpecies(const std::string& name) const; 227 Species* GetSpecies(const std::string& name); 228 229 /** returns a unique numeric id for reach species, or -1 for an invalid species name. */ 230 int GetSpeciesID(const std::string& name) const; 231 232 /** iterators for all species */ 233 iterator begin() const; 234 iterator end() const; 235 236 /** iterators for playble species. */ 237 playable_iterator playable_begin() const; 238 playable_iterator playable_end() const; 239 240 /** iterators for native species. */ 241 native_iterator native_begin() const; 242 native_iterator native_end() const; 243 244 /** returns an ordered list of tags that should be considered for census listings. */ 245 const CensusOrder& census_order() const; 246 247 /** returns true iff this SpeciesManager is empty. */ 248 bool empty() const; 249 250 /** returns the number of species stored in this manager. */ 251 int NumSpecies() const; 252 int NumPlayableSpecies() const; 253 int NumNativeSpecies() const; 254 255 /** returns the name of a species in this manager, or an empty string if 256 * this manager is empty. */ 257 const std::string& RandomSpeciesName() const; 258 259 /** returns the name of a playable species in this manager, or an empty 260 * string if there are no playable species. */ 261 const std::string& RandomPlayableSpeciesName() const; 262 const std::string& SequentialPlayableSpeciesName(int id) const; 263 264 /** returns a map from species name to a set of object IDs that are the 265 * homeworld(s) of that species in the current game. */ 266 std::map<std::string, std::set<int>> 267 GetSpeciesHomeworldsMap(int encoding_empire = ALL_EMPIRES) const; 268 269 /** returns a map from species name to a map from empire id to each the 270 * species' opinion of the empire */ 271 const std::map<std::string, std::map<int, float>>& 272 GetSpeciesEmpireOpinionsMap(int encoding_empire = ALL_EMPIRES) const; 273 274 /** returns opinion of species with name \a species_name about empire with 275 * id \a empire_id or 0.0 if there is no such opinion yet recorded. */ 276 float SpeciesEmpireOpinion(const std::string& species_name, int empire_id) const; 277 278 /** returns a map from species name to a map from other species names to the 279 * opinion of the first species about the other species. */ 280 const std::map<std::string, std::map<std::string, float>>& 281 GetSpeciesSpeciesOpinionsMap(int encoding_empire = ALL_EMPIRES) const; 282 283 /** returns opinion of species with name \a opinionated_species_name about 284 * other species with name \a rated_species_name or 0.0 if there is no 285 * such opinion yet recorded. */ 286 float SpeciesSpeciesOpinion(const std::string& opinionated_species_name, 287 const std::string& rated_species_name) const; 288 289 /** returns the instance of this singleton class; you should use the free 290 * function GetSpeciesManager() instead */ 291 static SpeciesManager& GetSpeciesManager(); 292 293 /** Returns a number, calculated from the contained data, which should be 294 * different for different contained data, and must be the same for 295 * the same contained data, and must be the same on different platforms 296 * and executions of the program and the function. Useful to verify that 297 * the parsed content is consistent without sending it all between 298 * clients and server. */ 299 unsigned int GetCheckSum() const; 300 //@} 301 302 /** \name Mutators */ //@{ 303 /** sets all species to have no homeworlds. this is useful when generating 304 * a new game, when any homeworlds species had in the previous game should 305 * be removed before the new game's homeworlds are added. */ 306 void ClearSpeciesHomeworlds(); 307 308 /** sets the opinions of species (indexed by name string) of empires (indexed 309 * by id) as a double-valued number. */ 310 void SetSpeciesEmpireOpinions(const std::map<std::string, std::map<int, float>>& species_empire_opinions); 311 void SetSpeciesEmpireOpinion(const std::string& species_name, int empire_id, float opinion); 312 313 /** sets the opinions of species (indexed by name string) of other species 314 * (indexed by name string) as a double-valued number. */ 315 void SetSpeciesSpeciesOpinions(const std::map<std::string, std::map<std::string, float>>& species_species_opinions); 316 void SetSpeciesSpeciesOpinion(const std::string& opinionated_species, const std::string& rated_species, float opinion); 317 318 /** clears all species opinion data */ 319 void ClearSpeciesOpinions(); 320 321 void UpdatePopulationCounter(); 322 323 std::map<std::string, std::map<int, float>>& SpeciesObjectPopulations(int encoding_empire = ALL_EMPIRES); 324 std::map<std::string, std::map<std::string, int>>& SpeciesShipsDestroyed(int encoding_empire = ALL_EMPIRES); 325 326 /** Sets species types to the value of \p future. */ 327 void SetSpeciesTypes(Pending::Pending<std::pair<SpeciesTypeMap, CensusOrder>>&& future); 328 //@} 329 330 private: 331 SpeciesManager(); 332 333 /** sets the homeworld ids of species in this SpeciesManager to those 334 * specified in \a species_homeworld_ids */ 335 void SetSpeciesHomeworlds(const std::map<std::string, std::set<int>>& species_homeworld_ids); 336 337 /** Assigns any m_pending_types to m_species. */ 338 void CheckPendingSpeciesTypes() const; 339 340 /** Future types being parsed by parser. mutable so that it can 341 be assigned to m_species_types when completed.*/ 342 mutable boost::optional<Pending::Pending<std::pair<SpeciesTypeMap, CensusOrder>>> m_pending_types = boost::none; 343 344 mutable SpeciesTypeMap m_species; 345 mutable CensusOrder m_census_order; 346 std::map<std::string, std::map<int, float>> m_species_empire_opinions; 347 std::map<std::string, std::map<std::string, float>> m_species_species_opinions; 348 349 std::map<std::string, std::map<int, float>> m_species_object_populations; 350 std::map<std::string, std::map<std::string, int>> m_species_species_ships_destroyed; 351 352 static SpeciesManager* s_instance; 353 354 friend class boost::serialization::access; 355 template <typename Archive> 356 void serialize(Archive& ar, const unsigned int version); 357 }; 358 359 extern template 360 FO_COMMON_API void SpeciesManager::serialize<freeorion_bin_oarchive>(freeorion_bin_oarchive& ar, const unsigned int version); 361 extern template 362 FO_COMMON_API void SpeciesManager::serialize<freeorion_xml_oarchive>(freeorion_xml_oarchive& ar, const unsigned int version); 363 extern template 364 FO_COMMON_API void SpeciesManager::serialize<freeorion_bin_iarchive>(freeorion_bin_iarchive& ar, const unsigned int version); 365 extern template 366 FO_COMMON_API void SpeciesManager::serialize<freeorion_xml_iarchive>(freeorion_xml_iarchive& ar, const unsigned int version); 367 368 /** returns the singleton species manager */ 369 FO_COMMON_API SpeciesManager& GetSpeciesManager(); 370 371 /** Returns the Species object used to represent species of type \a name. 372 * If no such Species exists, 0 is returned instead. */ 373 FO_COMMON_API const Species* GetSpecies(const std::string& name); 374 375 #endif // _Species_h_ 376