1 #pragma once
2 #ifndef CATA_SRC_RELIC_H
3 #define CATA_SRC_RELIC_H
4 
5 #include <climits>
6 #include <cmath>
7 #include <iosfwd>
8 #include <utility>
9 #include <vector>
10 
11 #include "calendar.h"
12 #include "item.h"
13 #include "magic.h"
14 #include "magic_enchantment.h"
15 #include "translations.h"
16 #include "type_id.h"
17 #include "weighted_list.h"
18 
19 class Character;
20 class Creature;
21 class JsonIn;
22 class JsonObject;
23 class JsonOut;
24 class relic;
25 class relic_procgen_data;
26 struct relic_charge_info;
27 struct relic_charge_template;
28 struct tripoint;
29 
30 using relic_procgen_id = string_id<relic_procgen_data>;
31 
32 class relic_procgen_data
33 {
34     public:
35 
36         /*
37          * various procgen values for passive enchantment values
38          * this is a template for the ability to write a little bit
39          * less code and easier maintainability for additional values
40          */
41         template<typename T = int>
42         struct enchantment_value_passive {
43             enchant_vals::mod type;
44             // THIS CANNOT BE 0
45             int power_per_increment = 1;
46             // whatever increment is used for the point values
47             // THIS CANNOT BE 0
48             T increment = 1;
49             T min_value = 0;
50             T max_value = 0;
51 
calc_powerenchantment_value_passive52             int calc_power( T level ) const {
53                 return std::round( level * static_cast<float>( power_per_increment ) /
54                                    static_cast<float>( increment ) );
55             }
56 
57             bool was_loaded = false;
58 
59             void load( const JsonObject &jo );
60             void deserialize( JsonIn &jsin );
61         };
62 
63         struct enchantment_active {
64             spell_id activated_spell;
65             // power cost of spell at level 0
66             int base_power = 0;
67             // power cost increment per spell level increment
68             int power_per_increment = 1;
69             // number of spell levels that give the power per increment at
70             int increment = 1;
71             // min level of the spell allowed
72             int min_level = 0;
73             // max level of the spell allowed
74             int max_level = 0;
75 
calc_powerenchantment_active76             int calc_power( int level ) const {
77                 return base_power + std::round( level *
78                                                 static_cast<float>( power_per_increment ) / static_cast<float>( increment ) );
79             }
80 
81             bool was_loaded = false;
82 
83             void load( const JsonObject &jo );
84             void deserialize( JsonIn &jsin );
85         };
86 
87         struct generation_rules {
88             // the desired power level for the generated artifact
89             int power_level = 0;
90             // the most negative (total) attributes a generated artifact can have
91             int max_negative_power = 0;
92             // the maximum number of attributes a generated artifact can have
93             int max_attributes = INT_MAX;
94 
95             bool was_loaded = false;
96             void load( const JsonObject &jo );
97             void deserialize( JsonIn &jsin );
98         };
99 
100         enum type {
101             passive_enchantment_add,
102             passive_enchantment_mult,
103             hit_you,
104             hit_me,
105             active_enchantment,
106             last
107         };
108     private:
109 
110         weighted_int_list<relic_charge_template> charge_values;
111         weighted_int_list<enchantment_value_passive<int>> passive_add_procgen_values;
112         weighted_int_list<enchantment_value_passive<float>> passive_mult_procgen_values;
113         weighted_int_list<enchantment_active> passive_hit_you;
114         weighted_int_list<enchantment_active> passive_hit_me;
115         weighted_int_list<enchantment_active> active_procgen_values;
116         weighted_int_list<type> type_weights;
117         weighted_int_list<itype_id> item_weights;
118 
119     public:
120         relic_procgen_id id;
121 
122         int power_level( const enchantment &ench ) const;
123         // power level of the active spell
124         int power_level( const fake_spell &sp ) const;
125 
126         item create_item( const relic_procgen_data::generation_rules &rules ) const;
127         relic generate( const generation_rules &rules, const itype_id &it_id ) const;
128 
129         bool was_loaded = false;
130 
131         static void load_relic_procgen_data( const JsonObject &jo, const std::string &src );
132         void load( const JsonObject &jo, const std::string & = "" );
133         void deserialize( JsonIn &jsin );
134 };
135 
136 enum class relic_recharge : int {
137     none,
138     periodic,
139     solar_sunny,
140     num
141 };
142 
143 struct relic_charge_template {
144     std::pair<int, int> max_charges;
145     std::pair<int, int> init_charges;
146     std::pair<int, int> charges_per_use;
147     std::pair<time_duration, time_duration> time;
148     relic_recharge type = relic_recharge::none;
149 
150     int power_level = 0;
151 
152     void deserialize( JsonIn &jsin );
153     void load( const JsonObject &jo );
154     relic_charge_info generate() const;
155 };
156 
157 struct relic_charge_info {
158 
159     bool regenerate_ammo = false;
160     int charges = 0;
161     int charges_per_use = 0;
162     int max_charges = 0;
163     relic_recharge type = relic_recharge::num;
164 
165     time_duration activation_accumulator = 0_seconds;
166     time_duration activation_time = 0_seconds;
167 
168     relic_charge_info() = default;
169 
170     // Because multiple different charge types can overlap, cache the power
171     // level from the charge type we were generated from here to avoid confusion
172     int power = 0;
173 
174     // accumulates time for charge, and increases charge if it has enough accumulated.
175     // assumes exactly one second has passed.
176     void accumulate_charge( item &parent );
177 
178     void deserialize( JsonIn &jsin );
179     void load( const JsonObject &jo );
180     void serialize( JsonOut &jsout ) const;
181 };
182 
183 class relic
184 {
185     private:
186         std::vector<fake_spell> active_effects;
187         std::vector<enchantment> passive_effects;
188 
189         // the item's name will be replaced with this if the string is not empty
190         translation item_name_override;
191 
192         relic_charge_info charge;
193 
194         // activating an artifact overrides all spell casting costs
195         int moves = 0;
196     public:
197         std::string name() const;
198         // returns number of charges that should be consumed
199         int activate( Creature &caster, const tripoint &target );
200         int charges() const;
201         int charges_per_use() const;
202         int max_charges() const;
203 
204         bool has_activation() const;
205         // has a recharge type (which needs to be actively processed)
206         bool has_recharge() const;
207 
208         void try_recharge( item &parent, Character *carrier, const tripoint &pos );
209 
210         void load( const JsonObject &jo );
211 
212         void serialize( JsonOut &jsout ) const;
213         void deserialize( JsonIn &jsin );
214 
215         void add_passive_effect( const enchantment &ench );
216         void add_active_effect( const fake_spell &sp );
217 
218         std::vector<enchantment> get_enchantments() const;
219 
220         int modify_value( enchant_vals::mod value_type, int value ) const;
221         void overwrite_charge( const relic_charge_info &info );
222 
223         // what is the power level of this artifact, given a specific ruleset
224         int power_level( const relic_procgen_id &ruleset ) const;
225 
226         friend bool operator==( const relic &source_relic, const relic &target_relic );
227 };
228 
229 template <typename E> struct enum_traits;
230 
231 template<>
232 struct enum_traits<relic_procgen_data::type> {
233     static constexpr relic_procgen_data::type last = relic_procgen_data::type::last;
234 };
235 
236 template<>
237 struct enum_traits<relic_recharge> {
238     static constexpr relic_recharge last = relic_recharge::num;
239 };
240 
241 #endif // CATA_SRC_RELIC_H
242