Skip to content

Commit

Permalink
Keep track of placed GLOBALLY_UNIQUE specials
Browse files Browse the repository at this point in the history
  • Loading branch information
eltank authored and anothersimulacrum committed Jul 16, 2022
1 parent 6fee7b3 commit 7af67f0
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 10 deletions.
1 change: 1 addition & 0 deletions doc/JSON_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,7 @@ These branches are also the valid entries for the categories of `dreams` in `dre
- ```SAFE_AT_WORLDGEN``` Location will not spawn overmap monster groups during worldgen (does not affect monsters spawned by mapgen).
- ```TRIFFID``` Location is related to triffids. Used to classify location.
- ```UNIQUE``` Location is unique and will only occur once per overmap. `occurrences` is overridden to define a percent chance (e.g. `"occurrences" : [75, 100]` is 75%)
- ```GLOBALLY_UNIQUE``` Location will only occur once per world. `occurrences` is overridden to define a percent chance (e.g. `"occurrences" : [75, 100]` is 75%)
- ```URBAN```
- ```WILDERNESS```
- ```MAN_MADE``` - For location, created by human. For Innawood mod purposes
Expand Down
7 changes: 4 additions & 3 deletions doc/OVERMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,12 @@ each normal special has a very high chance of being placed at least once per ove
quirks of the code (most notably, the number of specials is only slightly more than the number of slots per
overmap, specials that failed placement don't get disqualified and can be rolled for again, and placement iterates
until all sectors are occupied). For specials that are not common enough to warrant appearing more
than once per overmap please use the "UNIQUE" flag.
than once per overmap please use the "UNIQUE" flag. For specials that should only have one instance
per world use "GLOBALLY_UNIQUE".

### Occurrences ( UNIQUE )
### Occurrences ( UNIQUE, GLOBALLY_UNIQUE )

When the special has the "UNIQUE" flag, instead of defining the minimum and maximum number placed
When the special has the "UNIQUE" or "GLOBALLY_UNIQUE" flag, instead of defining the minimum and maximum number placed.
the occurrences field defines the chance of the special to be included in any one given overmap.
Before any placement rolls, all specials with this flag have to succeed in an x_in_y (first value, second
value) roll to be included in the `overmap_special_batch` for the currently generated overmap;
Expand Down
23 changes: 16 additions & 7 deletions src/overmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,9 @@ void overmap_specials::check_consistency()
const size_t actual_count = std::accumulate( specials.get_all().begin(), specials.get_all().end(),
static_cast< size_t >( 0 ),
[]( size_t sum, const overmap_special & elem ) {
size_t min_occur =
static_cast<size_t>( std::max( elem.get_constraints().occurrences.min, 0 ) );
return sum + ( elem.has_flag( "UNIQUE" ) ? static_cast<size_t>( 0 ) : min_occur );
size_t min_occur = static_cast<size_t>( std::max( elem.get_constraints().occurrences.min, 0 ) );
const bool unique = elem.has_flag( "UNIQUE" ) || elem.has_flag( "GLOBALLY_UNIQUE" );
return sum + ( unique ? 0 : min_occur );
} );

if( actual_count > max_count ) {
Expand Down Expand Up @@ -5948,6 +5948,10 @@ bool overmap::can_place_special( const overmap_special &special, const tripoint_
if( !special.id ) {
return false;
}
if( special.has_flag( "GLOBALLY_UNIQUE" ) &&
overmap_buffer.contains_unique_special( special.id ) ) {
return false;
}

if( special.has_eoc() ) {
dialogue d( get_talker_for( get_avatar() ), nullptr );
Expand Down Expand Up @@ -5992,6 +5996,9 @@ std::vector<tripoint_om_omt> overmap::place_special(
if( !force ) {
cata_assert( can_place_special( special, p, dir, must_be_unexplored ) );
}
if( special.has_flag( "GLOBALLY_UNIQUE" ) ) {
overmap_buffer.add_unique_special( special.id );
}

const bool is_safe_zone = special.has_flag( "SAFE_AT_WORLDGEN" );

Expand Down Expand Up @@ -6140,13 +6147,15 @@ void overmap::place_specials( overmap_special_batch &enabled_specials )
continue;
}

if( iter->special_details->has_flag( "UNIQUE" ) ) {
const overmap_special_placement_constraints &constraints =
iter->special_details->get_constraints();
const bool unique = iter->special_details->has_flag( "UNIQUE" );
const bool globally_unique = iter->special_details->has_flag( "GLOBALLY_UNIQUE" );
if( unique || globally_unique ) {
const overmap_special_id &id = iter->special_details->id;
const overmap_special_placement_constraints &constraints = iter->special_details->get_constraints();
const int min = constraints.occurrences.min;
const int max = constraints.occurrences.max;

if( x_in_y( min, max ) ) {
if( x_in_y( min, max ) && ( !globally_unique || !overmap_buffer.contains_unique_special( id ) ) ) {
// 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;
Expand Down
14 changes: 14 additions & 0 deletions src/overmapbuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ void overmapbuffer::clear()
{
overmaps.clear();
known_non_existing.clear();
placed_unique_specials.clear();
last_requested_overmap = nullptr;
}

Expand Down Expand Up @@ -1086,6 +1087,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,
Expand Down
21 changes: 21 additions & 0 deletions src/overmapbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
#include <new>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "coordinates.h"
#include "enums.h"
#include "json.h"
#include "memory_fast.h"
#include "omdata.h"
#include "optional.h"
Expand Down Expand Up @@ -535,6 +537,8 @@ class overmapbuffer
mutable std::set<point_abs_om> 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<overmap_special_id> placed_unique_specials;

/**
* Get a list of notes in the (loaded) overmaps.
Expand Down Expand Up @@ -569,6 +573,23 @@ 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;
/**
* Writes the placed unique specials as a JSON value.
*/
void serialize_placed_unique_specials( JsonOut &json ) const;
/**
* Reads placed unique specials from JSON and overwrites the global value.
*/
void deserialize_placed_unique_specials( JsonIn &jsin );
private:
/**
* Go thorough the monster groups of the overmap and move out-of-bounds
Expand Down
19 changes: 19 additions & 0 deletions src/savegame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "omdata.h"
#include "options.h"
#include "overmap.h"
#include "overmapbuffer.h"
#include "overmap_types.h"
#include "path_info.h"
#include "regional_settings.h"
Expand Down Expand Up @@ -1450,6 +1451,8 @@ void game::unserialize_master( std::istream &fin )
weather_manager::unserialize_all( jsin );
} else if( name == "timed_events" ) {
timed_event_manager::unserialize_all( jsin );
} else if( name == "placed_unique_specials" ) {
overmap_buffer.deserialize_placed_unique_specials( jsin );
} else {
// silently ignore anything else
jsin.skip_value();
Expand Down Expand Up @@ -1535,6 +1538,8 @@ void game::serialize_master( std::ostream &fout )

json.member( "active_missions" );
mission::serialize_all( json );
json.member( "placed_unique_specials" );
overmap_buffer.serialize_placed_unique_specials( json );

json.member( "timed_events" );
timed_event_manager::serialize_all( json );
Expand Down Expand Up @@ -1659,3 +1664,17 @@ void creature_tracker::serialize( JsonOut &jsout ) const
}
jsout.end_array();
}

void overmapbuffer::serialize_placed_unique_specials( JsonOut &json ) const
{
json.write_as_array( placed_unique_specials );
}

void overmapbuffer::deserialize_placed_unique_specials( JsonIn &jsin )
{
placed_unique_specials.clear();
jsin.start_array();
while( !jsin.end_array() ) {
placed_unique_specials.emplace( jsin.get_string() );
}
}

0 comments on commit 7af67f0

Please sign in to comment.