1 #ifndef _Effect_h_ 2 #define _Effect_h_ 3 4 5 #include "EnumsFwd.h" 6 7 #include <boost/container/flat_map.hpp> 8 #include <boost/serialization/access.hpp> 9 10 #include <memory> 11 #include <map> 12 #include <string> 13 #include <vector> 14 #include <unordered_map> 15 16 #include "../util/Export.h" 17 18 FO_COMMON_API extern const int INVALID_OBJECT_ID; 19 20 class UniverseObject; 21 struct ScriptingContext; 22 23 namespace Condition { 24 struct Condition; 25 } 26 27 namespace Effect { 28 struct AccountingInfo; 29 class EffectsGroup; 30 31 typedef std::vector<std::shared_ptr<UniverseObject>> TargetSet; 32 /** Effect accounting information for all meters of all objects that are 33 * acted on by effects. */ 34 typedef std::unordered_map<int, boost::container::flat_map<MeterType, std::vector<AccountingInfo>>> AccountingMap; 35 36 /** Description of cause of an effect: the general cause type, and the 37 * specific cause. eg. Building and a particular BuildingType. */ 38 struct FO_COMMON_API EffectCause { 39 explicit EffectCause(); 40 EffectCause(EffectsCauseType cause_type_, const std::string& specific_cause_, 41 const std::string& custom_label_ = ""); 42 EffectsCauseType cause_type; ///< general type of effect cause, eg. tech, building, special... 43 std::string specific_cause; ///< name of specific cause, eg. "Wonder Farm", "Antenna Mk. VI" 44 std::string custom_label; ///< script-specified accounting label for this effect cause 45 }; 46 47 /** Combination of targets and cause for an effects group. */ 48 struct TargetsAndCause { 49 explicit TargetsAndCause(); 50 TargetsAndCause(const TargetSet& target_set_, const EffectCause& effect_cause_); 51 TargetSet target_set; 52 EffectCause effect_cause; 53 }; 54 55 /** Combination of an EffectsGroup and the id of a source object. */ 56 struct SourcedEffectsGroup { 57 explicit SourcedEffectsGroup(); 58 SourcedEffectsGroup(int source_object_id_, const EffectsGroup* effects_group_); 59 bool operator<(const SourcedEffectsGroup& right) const; 60 int source_object_id = INVALID_OBJECT_ID; 61 const EffectsGroup* effects_group = nullptr; 62 }; 63 64 /** Map from (effects group and source object) to target set of for 65 * that effects group with that source object. A multimap is used 66 * so that a single source object can have multiple instances of the 67 * same effectsgroup. This is useful when a Ship has multiple copies 68 * of the same effects group due to having multiple copies of the same 69 * ship part in its design. */ 70 typedef std::vector<std::pair<SourcedEffectsGroup, TargetsAndCause>> SourcesEffectsTargetsAndCausesVec; 71 72 /** The base class for all Effects. When an Effect is executed, the source 73 * object (the object to which the Effect or its containing EffectGroup is 74 * attached) and the target object are both required. Note that this means 75 * that ValueRefs contained within Effects can refer to values in either the 76 * source or target objects. */ 77 class FO_COMMON_API Effect { 78 public: 79 virtual ~Effect(); 80 81 virtual void Execute(ScriptingContext& context) const = 0; 82 83 virtual void Execute(ScriptingContext& context, const TargetSet& targets) const; 84 85 virtual void Execute(ScriptingContext& context, 86 const TargetSet& targets, 87 AccountingMap* accounting_map, 88 const EffectCause& effect_cause, 89 bool only_meter_effects = false, 90 bool only_appearance_effects = false, 91 bool include_empire_meter_effects = false, 92 bool only_generate_sitrep_effects = false) const; 93 94 virtual std::string Dump(unsigned short ntabs = 0) const = 0; 95 IsMeterEffect()96 virtual bool IsMeterEffect() const { return false; } IsEmpireMeterEffect()97 virtual bool IsEmpireMeterEffect() const { return false; } IsAppearanceEffect()98 virtual bool IsAppearanceEffect() const { return false; } IsSitrepEffect()99 virtual bool IsSitrepEffect() const { return false; } IsConditionalEffect()100 virtual bool IsConditionalEffect() const { return false; } 101 102 // TODO: source-invariant? 103 104 virtual void SetTopLevelContent(const std::string& content_name) = 0; 105 virtual unsigned int GetCheckSum() const; 106 107 private: 108 friend class boost::serialization::access; 109 template <typename Archive> 110 void serialize(Archive& ar, const unsigned int version); 111 }; 112 113 /** Accounting information about what the causes are and changes produced 114 * by effects groups acting on meters of objects. */ 115 struct FO_COMMON_API AccountingInfo : public EffectCause { 116 explicit AccountingInfo(); 117 AccountingInfo(int source_id_, EffectsCauseType cause_type_, float meter_change_, 118 float running_meter_total_, const std::string& specific_cause_ = "", 119 const std::string& custom_label_ = ""); 120 121 bool operator==(const AccountingInfo& rhs) const; 122 123 int source_id = INVALID_OBJECT_ID; ///< source object of effect 124 float meter_change = 0.0f; ///< net change on meter due to this effect, as best known by client's empire 125 float running_meter_total = 0.0f; ///< meter total as of this effect. 126 }; 127 128 /** Contains one or more Effects, a Condition which indicates the objects in 129 * the scope of the Effect(s), and a Condition which indicates whether or not 130 * the Effect(s) will be executed on the objects in scope during the current 131 * turn. Since Conditions operate on sets of objects (usually all objects in 132 * the universe), the activation condition bears some explanation. It exists 133 * to allow an EffectsGroup to be activated or suppressed based on the source 134 * object only (the object to which the EffectsGroup is attached). It does 135 * this by considering the "universe" containing only the source object. If 136 * the source object meets the activation condition, the EffectsGroup will be 137 * active in the current turn. */ 138 class FO_COMMON_API EffectsGroup { 139 public: 140 EffectsGroup(std::unique_ptr<Condition::Condition>&& scope, 141 std::unique_ptr<Condition::Condition>&& activation, 142 std::vector<std::unique_ptr<Effect>>&& effects, 143 const std::string& accounting_label = "", 144 const std::string& stacking_group = "", 145 int priority = 0, 146 const std::string& description = "", 147 const std::string& content_name = ""); 148 virtual ~EffectsGroup(); 149 150 /** execute all effects in group */ 151 void Execute(ScriptingContext& source_context, 152 const TargetsAndCause& targets_cause, 153 AccountingMap* accounting_map = nullptr, 154 bool only_meter_effects = false, 155 bool only_appearance_effects = false, 156 bool include_empire_meter_effects = false, 157 bool only_generate_sitrep_effects = false) const; 158 StackingGroup()159 const std::string& StackingGroup() const { return m_stacking_group; } Scope()160 Condition::Condition* Scope() const { return m_scope.get(); } Activation()161 Condition::Condition* Activation() const { return m_activation.get(); } 162 const std::vector<Effect*> EffectsList() const; 163 const std::string& GetDescription() const; AccountingLabel()164 const std::string& AccountingLabel() const { return m_accounting_label; } Priority()165 int Priority() const { return m_priority; } 166 std::string Dump(unsigned short ntabs = 0) const; 167 bool HasMeterEffects() const; 168 bool HasAppearanceEffects() const; 169 bool HasSitrepEffects() const; 170 171 void SetTopLevelContent(const std::string& content_name); TopLevelContent()172 const std::string& TopLevelContent() const { return m_content_name; } 173 174 virtual unsigned int GetCheckSum() const; 175 176 protected: 177 std::unique_ptr<Condition::Condition> m_scope; 178 std::unique_ptr<Condition::Condition> m_activation; 179 std::string m_stacking_group; 180 std::vector<std::unique_ptr<Effect>> m_effects; 181 std::string m_accounting_label; 182 int m_priority; // constructor sets this, so don't need a default value here 183 std::string m_description; 184 std::string m_content_name; 185 186 private: 187 friend class boost::serialization::access; 188 template <typename Archive> 189 void serialize(Archive& ar, const unsigned int version); 190 }; 191 192 /** Returns a single string which `Dump`s a vector of EffectsGroups. */ 193 FO_COMMON_API std::string Dump(const std::vector<std::shared_ptr<EffectsGroup>>& effects_groups); 194 } 195 196 #endif 197