diff --git a/src/overmap.cpp b/src/overmap.cpp index 79c745e2e6322..ee87163bd84ad 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -4062,6 +4062,9 @@ bool overmap::can_place_special( const overmap_special &special, const tripoint_ if( !special.id ) { return false; } + if( special.flags.count( "UNIQUE" ) > 0 && overmap_buffer.contains_unique_special( special.id ) ) { + return false; + } return std::all_of( special.terrains.begin(), special.terrains.end(), [&]( const overmap_special_terrain & elem ) { @@ -4097,6 +4100,9 @@ void overmap::place_special( if( !force ) { cata_assert( can_place_special( special, p, dir, must_be_unexplored ) ); } + if( special.flags.count( "UNIQUE" ) > 0 ) { + overmap_buffer.add_unique_special( special.id ); + } const bool blob = special.flags.count( "BLOB" ) > 0; @@ -4256,10 +4262,11 @@ void overmap::place_specials( overmap_special_batch &enabled_specials ) } if( iter->special_details->flags.count( "UNIQUE" ) > 0 ) { + const overmap_special_id &id = iter->special_details->id; const int min = iter->special_details->occurrences.min; const int max = iter->special_details->occurrences.max; - if( x_in_y( min, max ) ) { + if( !overmap_buffer.contains_unique_special( id ) && x_in_y( min, max ) ) { // Min and max are overloaded to be the chance of occurrence, // so reset instances placed to one short of max so we don't place several. iter->instances_placed = max - 1; diff --git a/src/overmapbuffer.cpp b/src/overmapbuffer.cpp index e021bbc878cb9..4495be3984c72 100644 --- a/src/overmapbuffer.cpp +++ b/src/overmapbuffer.cpp @@ -205,6 +205,7 @@ void overmapbuffer::clear() { overmaps.clear(); known_non_existing.clear(); + placed_unique_specials.clear(); last_requested_overmap = nullptr; } @@ -883,6 +884,19 @@ bool overmapbuffer::check_overmap_special_type( const overmap_special_id &id, return om_loc.om->check_overmap_special_type( id, om_loc.local ); } +void overmapbuffer::add_unique_special( const overmap_special_id &id ) +{ + if( contains_unique_special( id ) ) { + debugmsg( "Unique overmap special placed more than once: %s", id.str() ); + } + placed_unique_specials.emplace( id ); +} + +bool overmapbuffer::contains_unique_special( const overmap_special_id &id ) const +{ + return placed_unique_specials.find( id ) != placed_unique_specials.end(); +} + static omt_find_params assign_params( const std::string &type, int const radius, bool must_be_seen, ot_match_type match_type, bool existing_overmaps_only, diff --git a/src/overmapbuffer.h b/src/overmapbuffer.h index 95ab2ca641b1e..58ff215946a32 100644 --- a/src/overmapbuffer.h +++ b/src/overmapbuffer.h @@ -491,6 +491,8 @@ class overmapbuffer mutable std::set known_non_existing; // Cached result of previous call to overmapbuffer::get_existing overmap mutable *last_requested_overmap; + // Set of globally unique overmap specials that have already been placed + std::unordered_set placed_unique_specials; /** * Get a list of notes in the (loaded) overmaps. @@ -524,6 +526,15 @@ class overmapbuffer const tripoint_abs_omt &loc ); bool check_overmap_special_type_existing( const overmap_special_id &id, const tripoint_abs_omt &loc ); + + /** + * Adds the given globally unique overmap special to the list of placed specials. + */ + void add_unique_special( const overmap_special_id &id ); + /** + * Returns true if the given globally unique overmap special has already been placed. + */ + bool contains_unique_special( const overmap_special_id &id ) const; private: /** * Go thorough the monster groups of the overmap and move out-of-bounds