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