diff --git a/doc/OVERMAP.md b/doc/OVERMAP.md index 29a90a9693c12..6aff6c05ea7a9 100644 --- a/doc/OVERMAP.md +++ b/doc/OVERMAP.md @@ -389,6 +389,7 @@ original intersection. | `city_distance` | Min/max distance from a city edge that the special may be placed. Use -1 for unbounded. | | `city_sizes` | Min/max city size for a city that the special may be placed near. Use -1 for unbounded. | | `occurrences` | Min/max number of occurrences when placing the special. If UNIQUE flag is set, becomes X of Y chance. | +| `priority` | **Warning: Do not use this unnecessarily.** The generation process is executed in the order of specials with the highest value. Can be used when maps are difficult to generate. (large maps, maps that are or require dependencies etc) It is **strongly recommended** to set it to 1 (HIGH priority) or -1 (LOW priority) if used. (default = 0) | | `flags` | See `Overmap specials` in [JSON_FLAGS.md](JSON_FLAGS.md). | | `rotate` | Whether the special can rotate. True if not specified. | diff --git a/src/omdata.h b/src/omdata.h index 880ef8b37c5a3..3831c92717374 100644 --- a/src/omdata.h +++ b/src/omdata.h @@ -537,6 +537,9 @@ class overmap_special return flags_; } bool has_flag( const std::string & ) const; + int get_priority() const { + return priority_; + } int longest_side() const; std::vector preview_terrains() const; std::vector required_locations() const; @@ -578,6 +581,7 @@ class overmap_special bool rotatable_ = true; overmap_special_spawns monster_spawns_; cata::flat_set flags_; + int priority_ = 0; // These locations are the default values if ones are not specified for the individual OMTs. cata::flat_set> default_locations_; diff --git a/src/overmap.cpp b/src/overmap.cpp index 0476066c54e4a..713346ffb6de1 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -2773,6 +2773,7 @@ void overmap_special::load( const JsonObject &jo, const std::string &src ) assign( jo, "city_sizes", constraints_.city_size, strict ); assign( jo, "city_distance", constraints_.city_distance, strict ); + assign( jo, "priority", priority_, strict ); } assign( jo, "spawns", monster_spawns_, strict ); @@ -6296,31 +6297,40 @@ bool overmap::place_special_attempt( const city &nearest_city = get_nearest_city( p ); std::shuffle( enabled_specials.begin(), enabled_specials.end(), rng_get_engine() ); - for( auto iter = enabled_specials.begin(); iter != enabled_specials.end(); ++iter ) { - const overmap_special &special = *iter->special_details; - const overmap_special_placement_constraints &constraints = special.get_constraints(); - // If we haven't finished placing minimum instances of all specials, - // skip specials that are at their minimum count already. - if( !place_optional && iter->instances_placed >= constraints.occurrences.min ) { - continue; - } - // City check is the fastest => it goes first. - if( !special.can_belong_to_city( p, nearest_city ) ) { - continue; - } - // See if we can actually place the special there. - const om_direction::type rotation = random_special_rotation( special, p, must_be_unexplored ); - if( rotation == om_direction::type::invalid ) { - continue; - } + std::set priorities; + for( const overmap_special_placement &os : enabled_specials ) { + priorities.emplace( os.special_details->get_priority() ); + } + for( auto pri_iter = priorities.rbegin(); pri_iter != priorities.rend(); ++pri_iter ) { + for( auto iter = enabled_specials.begin(); iter != enabled_specials.end(); ++iter ) { + const overmap_special &special = *iter->special_details; + if( *pri_iter != special.get_priority() ) { + continue; + } + const overmap_special_placement_constraints &constraints = special.get_constraints(); + // If we haven't finished placing minimum instances of all specials, + // skip specials that are at their minimum count already. + if( !place_optional && iter->instances_placed >= constraints.occurrences.min ) { + continue; + } + // City check is the fastest => it goes first. + if( !special.can_belong_to_city( p, nearest_city ) ) { + continue; + } + // See if we can actually place the special there. + const om_direction::type rotation = random_special_rotation( special, p, must_be_unexplored ); + if( rotation == om_direction::type::invalid ) { + continue; + } - place_special( special, p, rotation, nearest_city, false, must_be_unexplored ); + place_special( special, p, rotation, nearest_city, false, must_be_unexplored ); - if( ++iter->instances_placed >= constraints.occurrences.max ) { - enabled_specials.erase( iter ); - } + if( ++iter->instances_placed >= constraints.occurrences.max ) { + enabled_specials.erase( iter ); + } - return true; + return true; + } } return false;