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