1 #pragma once
2 #ifndef CATA_SRC_CLZONES_H
3 #define CATA_SRC_CLZONES_H
4 
5 #include <functional>
6 #include <cstddef>
7 #include <iosfwd>
8 #include <map>
9 #include <memory>
10 #include <set>
11 #include <string>
12 #include <unordered_map>
13 #include <unordered_set>
14 #include <utility>
15 #include <vector>
16 
17 #include "memory_fast.h"
18 #include "optional.h"
19 #include "point.h"
20 #include "translations.h"
21 #include "type_id.h"
22 
23 class JsonIn;
24 class JsonObject;
25 class JsonOut;
26 class faction;
27 class item;
28 class map;
29 struct construction;
30 
31 using faction_id = string_id<faction>;
32 static const faction_id your_fac( "your_followers" );
33 const std::string type_fac_hash_str = "__FAC__";
34 
35 class zone_type
36 {
37     private:
38         translation name_;
39         translation desc_;
40     public:
41 
42         zone_type_id id;
43         bool was_loaded = false;
44 
45         zone_type() = default;
zone_type(const translation & name,const translation & desc)46         explicit zone_type( const translation &name, const translation &desc ) : name_( name ),
47             desc_( desc ) {}
48 
49         std::string name() const;
50         std::string desc() const;
51 
52         static void load_zones( const JsonObject &jo, const std::string &src );
53         void load( const JsonObject &jo, const std::string & );
54         /**
55          * All spells in the game.
56          */
57         static const std::vector<zone_type> &get_all();
58         bool is_valid() const;
59 };
60 
61 class zone_options
62 {
63     public:
64         virtual ~zone_options() = default;
65 
66         /* create valid instance for zone type */
67         static shared_ptr_fast<zone_options> create( const zone_type_id &type );
68 
69         /* checks if options is correct base / derived class for zone type */
70         static bool is_valid( const zone_type_id &type, const zone_options &options );
71 
72         /* derived classes must always return true */
has_options()73         virtual bool has_options() const {
74             return false;
75         }
76 
77         /* query only necessary options at zone creation, one by one
78          * returns true if successful, returns false if fails or canceled */
query_at_creation()79         virtual bool query_at_creation() {
80             return true;
81         }
82 
83         /* query options, first uilist should allow to pick an option to edit (if more than one)
84          * returns true if something is changed, otherwise returns false */
query()85         virtual bool query() {
86             return false;
87         }
88 
89         /* suggest a name for the zone, depending on options */
get_zone_name_suggestion()90         virtual std::string get_zone_name_suggestion() const {
91             return "";
92         }
93 
94         /* vector of pairs of each option's description and value */
get_descriptions()95         virtual std::vector<std::pair<std::string, std::string>> get_descriptions() const {
96             return std::vector<std::pair<std::string, std::string>>();
97         }
98 
serialize(JsonOut &)99         virtual void serialize( JsonOut & ) const {}
deserialize(const JsonObject &)100         virtual void deserialize( const JsonObject & ) {}
101 };
102 
103 // mark option interface
104 class mark_option
105 {
106     public:
107         virtual ~mark_option() = default;
108 
109         virtual std::string get_mark() const = 0;
110 };
111 
112 class plot_options : public zone_options, public mark_option
113 {
114     private:
115         itype_id mark;
116         itype_id seed;
117 
118         enum query_seed_result {
119             canceled,
120             successful,
121             changed,
122         };
123 
124         query_seed_result query_seed();
125 
126     public:
get_mark()127         std::string get_mark() const override {
128             return mark.str();
129         }
get_seed()130         itype_id get_seed() const {
131             return seed;
132         }
133 
has_options()134         bool has_options() const override {
135             return true;
136         }
137 
138         bool query_at_creation() override;
139         bool query() override;
140 
141         std::string get_zone_name_suggestion() const override;
142 
143         std::vector<std::pair<std::string, std::string>> get_descriptions() const override;
144 
145         void serialize( JsonOut &json ) const override;
146         void deserialize( const JsonObject &jo_zone ) override;
147 };
148 
149 class blueprint_options : public zone_options, public mark_option
150 {
151     private:
152         // furn/ter id as string.
153         std::string mark;
154         construction_group_str_id group = construction_group_str_id::NULL_ID();
155         construction_id index;
156 
157         enum query_con_result {
158             canceled,
159             successful,
160             changed,
161         };
162 
163         query_con_result query_con();
164 
165     public:
get_mark()166         std::string get_mark() const override {
167             return mark;
168         }
get_index()169         construction_id get_index() const {
170             return index;
171         }
172 
has_options()173         bool has_options() const override {
174             return true;
175         }
176 
177         construction_id get_final_construction(
178             const std::vector<construction> &list_constructions,
179             const construction_id &idx,
180             std::set<construction_id> &skip_index );
181 
182         bool query_at_creation() override;
183         bool query() override;
184 
185         std::string get_zone_name_suggestion() const override;
186 
187         std::vector<std::pair<std::string, std::string>> get_descriptions() const override;
188 
189         void serialize( JsonOut &json ) const override;
190         void deserialize( const JsonObject &jo_zone ) override;
191 };
192 
193 class loot_options : public zone_options, public mark_option
194 {
195     private:
196         // basic item filter.
197         std::string mark;
198 
199         enum query_loot_result {
200             canceled,
201             successful,
202             changed,
203         };
204 
205         query_loot_result query_loot();
206 
207     public:
get_mark()208         std::string get_mark() const override {
209             return mark;
210         }
211 
has_options()212         bool has_options() const override {
213             return true;
214         }
215 
216         bool query_at_creation() override;
217         bool query() override;
218 
219         std::string get_zone_name_suggestion() const override;
220 
221         std::vector<std::pair<std::string, std::string>> get_descriptions() const override;
222 
223         void serialize( JsonOut &json ) const override;
224         void deserialize( const JsonObject &jo_zone ) override;
225 };
226 
227 /**
228  * These are zones the player can designate.
229  */
230 class zone_data
231 {
232     private:
233         std::string name;
234         zone_type_id type;
235         faction_id faction;
236         bool invert;
237         bool enabled;
238         bool is_vehicle;
239         tripoint start;
240         tripoint end;
241         shared_ptr_fast<zone_options> options;
242 
243     public:
zone_data()244         zone_data() {
245             type = zone_type_id( "" );
246             invert = false;
247             enabled = false;
248             is_vehicle = false;
249             start = tripoint_zero;
250             end = tripoint_zero;
251             options = nullptr;
252         }
253 
254         zone_data( const std::string &_name, const zone_type_id &_type, const faction_id &_faction,
255                    bool _invert, const bool _enabled,
256                    const tripoint &_start, const tripoint &_end,
257                    const shared_ptr_fast<zone_options> &_options = nullptr ) {
258             name = _name;
259             type = _type;
260             faction = _faction;
261             invert = _invert;
262             enabled = _enabled;
263             is_vehicle = false;
264             start = _start;
265             end = _end;
266 
267             // ensure that suplied options is of correct class
268             if( _options == nullptr || !zone_options::is_valid( type, *_options ) ) {
269                 options = zone_options::create( type );
270             } else {
271                 options = _options;
272             }
273         }
274 
275         // returns true if name is changed
276         bool set_name();
277         // returns true if type is changed
278         bool set_type();
279         void set_position( const std::pair<tripoint, tripoint> &position, bool manual = true );
280         void set_enabled( bool enabled_arg );
281         void set_is_vehicle( bool is_vehicle_arg );
282 
make_type_hash(const zone_type_id & _type,const faction_id & _fac)283         static std::string make_type_hash( const zone_type_id &_type, const faction_id &_fac ) {
284             return _type.c_str() + type_fac_hash_str + _fac.c_str();
285         }
unhash_type(const std::string & hash_type)286         static zone_type_id unhash_type( const std::string &hash_type ) {
287             size_t end = hash_type.find( type_fac_hash_str );
288             if( end != std::string::npos && end < hash_type.size() ) {
289                 return zone_type_id( hash_type.substr( 0, end ) );
290             }
291             return zone_type_id( "" );
292         }
get_name()293         std::string get_name() const {
294             return name;
295         }
get_faction()296         const faction_id &get_faction() const {
297             return faction;
298         }
get_type_hash()299         std::string get_type_hash() const {
300             return make_type_hash( type, faction );
301         }
get_type()302         const zone_type_id &get_type() const {
303             return type;
304         }
get_invert()305         bool get_invert() const {
306             return invert;
307         }
get_enabled()308         bool get_enabled() const {
309             return enabled;
310         }
get_is_vehicle()311         bool get_is_vehicle() const {
312             return is_vehicle;
313         }
get_start_point()314         tripoint get_start_point() const {
315             return start;
316         }
get_end_point()317         tripoint get_end_point() const {
318             return end;
319         }
320         tripoint get_center_point() const;
has_options()321         bool has_options() const {
322             return options->has_options();
323         }
get_options()324         const zone_options &get_options() const {
325             return *options;
326         }
get_options()327         zone_options &get_options() {
328             return *options;
329         }
has_inside(const tripoint & p)330         bool has_inside( const tripoint &p ) const {
331             return p.x >= start.x && p.x <= end.x &&
332                    p.y >= start.y && p.y <= end.y &&
333                    p.z >= start.z && p.z <= end.z;
334         }
335         void serialize( JsonOut &json ) const;
336         void deserialize( JsonIn &jsin );
337 };
338 
339 class zone_manager
340 {
341     public:
342         using ref_zone_data = std::reference_wrapper<zone_data>;
343         using ref_const_zone_data = std::reference_wrapper<const zone_data>;
344 
345     private:
346         static const int MAX_DISTANCE = 10;
347         std::vector<zone_data> zones;
348         //Containers for Revert functionality for Vehicle Zones
349         //Pointer to added zone to be removed
350         std::vector<zone_data *> added_vzones;
351         //Copy of original data, pointer to the zone
352         std::vector<std::pair<zone_data, zone_data *>> changed_vzones;
353         //copy of original data to be re-added
354         std::vector<zone_data> removed_vzones;
355 
356         std::map<zone_type_id, zone_type> types;
357         std::unordered_map<std::string, std::unordered_set<tripoint>> area_cache;
358         std::unordered_map<std::string, std::unordered_set<tripoint>> vzone_cache;
359         std::unordered_set<tripoint> get_point_set( const zone_type_id &type,
360                 const faction_id &fac = your_fac ) const;
361         std::unordered_set<tripoint> get_vzone_set( const zone_type_id &type,
362                 const faction_id &fac = your_fac ) const;
363 
364         //Cache number of items already checked on each source tile when sorting
365         std::unordered_map<tripoint, int> num_processed;
366 
367     public:
368         zone_manager();
369         ~zone_manager() = default;
370         zone_manager( zone_manager && ) = default;
371         zone_manager( const zone_manager & ) = default;
372         zone_manager &operator=( zone_manager && ) = default;
373         zone_manager &operator=( const zone_manager & ) = default;
374 
get_manager()375         static zone_manager &get_manager() {
376             static zone_manager manager;
377             return manager;
378         }
379 
380         void clear();
381 
382         void add( const std::string &name, const zone_type_id &type, const faction_id &faction,
383                   bool invert, bool enabled,
384                   const tripoint &start, const tripoint &end,
385                   const shared_ptr_fast<zone_options> &options = nullptr );
386         const zone_data *get_zone_at( const tripoint &where, const zone_type_id &type ) const;
387         void create_vehicle_loot_zone( class vehicle &vehicle, const point &mount_point,
388                                        zone_data &new_zone );
389 
390         bool remove( zone_data &zone );
391 
size()392         unsigned int size() const {
393             return zones.size();
394         }
get_types()395         const std::map<zone_type_id, zone_type> &get_types() const {
396             return types;
397         }
398         std::string get_name_from_type( const zone_type_id &type ) const;
399         bool has_type( const zone_type_id &type ) const;
400         bool has_defined( const zone_type_id &type, const faction_id &fac = your_fac ) const;
401         void cache_data();
402         void cache_vzones();
403         bool has( const zone_type_id &type, const tripoint &where,
404                   const faction_id &fac = your_fac ) const;
405         bool has_near( const zone_type_id &type, const tripoint &where, int range = MAX_DISTANCE,
406                        const faction_id &fac = your_fac ) const;
407         bool has_loot_dest_near( const tripoint &where ) const;
408         bool custom_loot_has( const tripoint &where, const item *it ) const;
409         std::unordered_set<tripoint> get_near( const zone_type_id &type, const tripoint &where,
410                                                int range = MAX_DISTANCE, const item *it = nullptr, const faction_id &fac = your_fac ) const;
411         cata::optional<tripoint> get_nearest( const zone_type_id &type, const tripoint &where,
412                                               int range = MAX_DISTANCE, const faction_id &fac = your_fac ) const;
413         zone_type_id get_near_zone_type_for_item( const item &it, const tripoint &where,
414                 int range = MAX_DISTANCE ) const;
415         std::vector<zone_data> get_zones( const zone_type_id &type, const tripoint &where,
416                                           const faction_id &fac = your_fac ) const;
417         const zone_data *get_zone_at( const tripoint &where ) const;
418         const zone_data *get_bottom_zone( const tripoint &where,
419                                           const faction_id &fac = your_fac ) const;
420         cata::optional<std::string> query_name( const std::string &default_name = "" ) const;
421         cata::optional<zone_type_id> query_type() const;
422         void swap( zone_data &a, zone_data &b );
423         void rotate_zones( map &target_map, int turns );
424         // list of tripoints of zones that are loot zones only
425         std::unordered_set<tripoint> get_point_set_loot( const tripoint &where, int radius,
426                 const faction_id &fac = your_fac ) const;
427         std::unordered_set<tripoint> get_point_set_loot( const tripoint &where, int radius,
428                 bool npc_search, const faction_id &fac = your_fac ) const;
429 
430         // 'direct' access to zone_manager::zones, giving direct access was nono
431         std::vector<ref_zone_data> get_zones( const faction_id &fac = your_fac );
432         std::vector<ref_const_zone_data> get_zones( const faction_id &fac = your_fac ) const;
433 
434         bool save_zones();
435         void load_zones();
436         void zone_edited( zone_data &zone );
437         void revert_vzones();
438         void serialize( JsonOut &json ) const;
439         void deserialize( JsonIn &jsin );
440 };
441 
442 #endif // CATA_SRC_CLZONES_H
443