Skip to content

Commit

Permalink
Merge pull request #72558 from Procyonae/SetStartParameters
Browse files Browse the repository at this point in the history
Allows setting fixed special scoped parameters for start locations
  • Loading branch information
I-am-Erk authored Apr 4, 2024
2 parents 1143055 + 4f303b3 commit 0a6c239
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 26 deletions.
12 changes: 10 additions & 2 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,16 +852,21 @@ bool game::start_game()
const start_location &start_loc = u.random_start_location ? scen->random_start_location().obj() :
u.start_location.obj();
tripoint_abs_omt omtstart = overmap::invalid_tripoint;
std::unordered_map<std::string, std::string> associated_parameters;
const bool select_starting_city = get_option<bool>( "SELECT_STARTING_CITY" );
do {
if( select_starting_city ) {
if( !u.starting_city.has_value() ) {
u.starting_city = random_entry( city::get_all() );
u.world_origin = u.starting_city->pos_om;
}
omtstart = start_loc.find_player_initial_location( u.starting_city.value() );
auto ret = start_loc.find_player_initial_location( u.starting_city.value() );
omtstart = ret.first;
associated_parameters = ret.second;
} else {
omtstart = start_loc.find_player_initial_location( u.world_origin.value_or( point_abs_om() ) );
auto ret = start_loc.find_player_initial_location( u.world_origin.value_or( point_abs_om() ) );
omtstart = ret.first;
associated_parameters = ret.second;
}
if( omtstart == overmap::invalid_tripoint ) {

Expand All @@ -875,6 +880,9 @@ bool game::start_game()
}
} while( omtstart == overmap::invalid_tripoint );

// Set parameter(s) if specified in chosen start_loc
start_loc.set_parameters( omtstart, associated_parameters );

start_loc.prepare_map( omtstart );

if( scen->has_map_extra() ) {
Expand Down
10 changes: 8 additions & 2 deletions src/mapgendata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,20 @@ mapgendata::mapgendata( const tripoint_abs_omt &over, map &mp, const float densi
set_neighbour( 6, direction::SOUTHWEST );
set_neighbour( 7, direction::NORTHWEST );
if( std::optional<mapgen_arguments> *maybe_args = overmap_buffer.mapgen_args( over ) ) {
if( *maybe_args ) {
if( *maybe_args && !overmap_buffer.externally_set_args ) {
mapgen_args_ = **maybe_args;
} else {
// We are the first omt from this overmap_special to be generated,
// so now is the time to generate the arguments
if( std::optional<overmap_special_id> s = overmap_buffer.overmap_special_at( over ) ) {
const overmap_special &special = **s;
*maybe_args = special.get_args( *this );
mapgen_arguments internally_set_args = special.get_args( *this );
if( overmap_buffer.externally_set_args ) {
maybe_args->value().map.merge( internally_set_args.map );
overmap_buffer.externally_set_args = false;
} else {
*maybe_args = internally_set_args;
}
mapgen_args_ = **maybe_args;
} else {
debugmsg( "mapgen params expected but no overmap special found for terrain %s",
Expand Down
2 changes: 2 additions & 0 deletions src/overmapbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ class overmapbuffer
public:
overmapbuffer();

bool externally_set_args = false;

static cata_path terrain_filename( const point_abs_om & );
static cata_path player_filename( const point_abs_om & );

Expand Down
103 changes: 85 additions & 18 deletions src/start_location.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ std::string start_location::name() const

int start_location::targets_count() const
{
return _omt_types.size();
return _locations.size();
}

std::pair<std::string, ot_match_type> start_location::random_target() const
omt_types_parameters start_location::random_target() const
{
return random_entry( _omt_types );
return random_entry( _locations );
}

bool start_location::requires_city() const
Expand Down Expand Up @@ -106,14 +106,21 @@ void start_location::load( const JsonObject &jo, const std::string &src )
std::string ter;
for( const JsonValue entry : jo.get_array( "terrain" ) ) {
ot_match_type ter_match_type = ot_match_type::type;
std::unordered_map<std::string, std::string> parameter_map;
if( entry.test_string() ) {
ter = entry.get_string();
} else {
JsonObject jot = entry.get_object();
ter = jot.get_string( "om_terrain" );
ter_match_type = jot.get_enum_value<ot_match_type>( "om_terrain_match_type", ter_match_type );
if( jot.has_string( "om_terrain_match_type" ) ) {
ter_match_type = jot.get_enum_value<ot_match_type>( "om_terrain_match_type", ter_match_type );
}
if( jot.has_object( "parameters" ) ) {
std::unordered_map<std::string, std::string> parameter_map;
jot.read( "parameters", parameter_map );
}
}
_omt_types.emplace_back( ter, ter_match_type );
_locations.emplace_back( omt_types_parameters{ ter, ter_match_type, parameter_map } );
}
if( jo.has_array( "city_sizes" ) ) {
assign( jo, "city_sizes", constraints_.city_size, strict );
Expand Down Expand Up @@ -235,49 +242,109 @@ void start_location::prepare_map( tinymap &m ) const
}
}

tripoint_abs_omt start_location::find_player_initial_location( const point_abs_om &origin ) const
std::pair<tripoint_abs_omt, std::unordered_map<std::string, std::string>>
start_location::find_player_initial_location( const point_abs_om &origin ) const
{
// Spiral out from the world origin scanning for a compatible starting location,
// creating overmaps as necessary.
const int radius = 3;
const omt_types_parameters chosen_target = random_target();
for( const point_abs_om &omp : closest_points_first( origin, radius ) ) {
overmap &omap = overmap_buffer.get( omp );
const tripoint_om_omt omtstart = omap.find_random_omt( random_target() );
const tripoint_om_omt omtstart = omap.find_random_omt( std::make_pair( chosen_target.omt,
chosen_target.omt_type ) );
if( omtstart.raw() != tripoint_min ) {
return project_combine( omp, omtstart );
return std::make_pair( project_combine( omp, omtstart ), chosen_target.parameters );
}
}
// Should never happen, if it does we messed up.
popup( _( "Unable to generate a valid starting location %s [%s] in a radius of %d overmaps, please report this failure." ),
name(), id.str(), radius );
return overmap::invalid_tripoint;
return std::make_pair( overmap::invalid_tripoint, chosen_target.parameters );
}

tripoint_abs_omt start_location::find_player_initial_location( const city &origin ) const
std::pair<tripoint_abs_omt, std::unordered_map<std::string, std::string>>
start_location::find_player_initial_location( const city &origin ) const
{
overmap &omap = overmap_buffer.get( origin.pos_om );
std::vector<tripoint_om_omt> valid;
std::vector<std::pair<tripoint_om_omt, omt_types_parameters>> valid;
for( const point_om_omt &omp : closest_points_first( origin.pos, origin.size ) ) {
for( int k = constraints_.allowed_z_levels.min; k <= constraints_.allowed_z_levels.max; k++ ) {
tripoint_om_omt p( omp, k );
if( !can_belong_to_city( p, origin ) ) {
continue;
}
for( const auto &target : _omt_types ) {
if( is_ot_match( target.first, omap.ter( p ), target.second ) ) {
valid.push_back( p );
}
auto target_is_ot_match = [&]( const omt_types_parameters & target ) {
return is_ot_match( target.omt, omap.ter( p ), target.omt_type );
};
auto it = std::find_if( _locations.begin(), _locations.end(),
target_is_ot_match );
if( it != _locations.end() ) {
valid.emplace_back( p, *it );
}
}
}
const tripoint_om_omt omtstart = random_entry( valid, tripoint_om_omt( tripoint_min ) );
const std::pair<tripoint_om_omt, omt_types_parameters> random_valid = random_entry( valid,
std::make_pair( tripoint_om_omt( tripoint_min ), omt_types_parameters() ) );
const tripoint_om_omt omtstart = random_valid.first;
if( omtstart.raw() != tripoint_min ) {
return project_combine( origin.pos_om, omtstart );
return std::make_pair( project_combine( origin.pos_om, omtstart ), random_valid.second.parameters );
}
// Should never happen, if it does we messed up.
popup( _( "Unable to generate a valid starting location %s [%s] in a city [%s], please report this failure." ),
name(), id.str(), origin.name );
return overmap::invalid_tripoint;
return std::make_pair( overmap::invalid_tripoint, random_valid.second.parameters );
}

void start_location::set_parameters( const tripoint_abs_omt &omtstart,
const std::unordered_map<std::string, std::string> &parameters_to_set ) const
{
if( parameters_to_set.empty() ) {
return;
}
overmap_buffer.externally_set_args = true;
std::optional<mapgen_arguments> *maybe_args = overmap_buffer.mapgen_args( omtstart );
if( !maybe_args ) {
debugmsg( "No overmap special args at start location." );
return;
}
std::optional<overmap_special_id> s = overmap_buffer.overmap_special_at( omtstart );
if( !s ) {
debugmsg( "No overmap special at start location from which to fetch parameters." );
return;
}
const overmap_special &special = **s;
const mapgen_parameters &params = special.get_params();
mapgen_arguments args;
for( const auto &param_to_set : parameters_to_set ) {
const std::string &param_name_to_set = param_to_set.first;
const std::string &value_to_set = param_to_set.second;
auto param_it = params.map.find( param_name_to_set );
if( param_it == params.map.end() ) {
debugmsg( "Parameter %s not found", param_name_to_set );
continue;
}
const mapgen_parameter &param = param_it->second;
if( param.scope() != mapgen_parameter_scope::overmap_special ) {
debugmsg( "Parameter %s is not of scope overmap_special", param_name_to_set );
continue;
}
std::vector<std::string> possible_values = param.all_possible_values( params );
auto value_it = std::find( possible_values.begin(), possible_values.end(), value_to_set );
if( value_it == possible_values.end() ) {
debugmsg( "Parameter value %s for parameter %s not found", value_to_set, param_name_to_set );
continue;
}
if( *maybe_args ) {
maybe_args->value().map[param_name_to_set] =
cata_variant::from_string( param.type(), std::move( *value_it ) );
} else {
mapgen_arguments args;
args.map[param_name_to_set] =
cata_variant::from_string( param.type(), std::move( *value_it ) );
*maybe_args = args;
}
}
}

void start_location::prepare_map( const tripoint_abs_omt &omtstart ) const
Expand Down
21 changes: 17 additions & 4 deletions src/start_location.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ struct start_location_placement_constraints {
numeric_interval<int> allowed_z_levels{ -OVERMAP_DEPTH, OVERMAP_HEIGHT };
};

struct omt_types_parameters {
std::string omt;
ot_match_type omt_type;
std::unordered_map<std::string, std::string> parameters;
};

class start_location
{
public:
Expand All @@ -39,7 +45,7 @@ class start_location

std::string name() const;
int targets_count() const;
std::pair<std::string, ot_match_type> random_target() const;
omt_types_parameters random_target() const;
const std::set<std::string> &flags() const;

/**
Expand All @@ -48,14 +54,21 @@ class start_location
* It may return `overmap::invalid_tripoint` if no suitable starting location could be found
* in the world.
*/
tripoint_abs_omt find_player_initial_location( const point_abs_om &origin ) const;
std::pair<tripoint_abs_omt, std::unordered_map<std::string, std::string>>
find_player_initial_location( const point_abs_om &origin ) const;
/**
* Find a suitable start location on the overmap in specific city.
* @return Global, absolute overmap terrain coordinates where the player should spawn.
* It may return `overmap::invalid_tripoint` if no suitable starting location could be found
* in the world.
*/
tripoint_abs_omt find_player_initial_location( const city &origin ) const;
std::pair<tripoint_abs_omt, std::unordered_map<std::string, std::string>>
find_player_initial_location( const city &origin ) const;
/**
* Set any parameters assigned to the chosen start location
*/
void set_parameters( const tripoint_abs_omt &omtstart,
const std::unordered_map<std::string, std::string> &parameters_to_set ) const;
/**
* Initialize the map at players start location using @ref prepare_map.
* @param omtstart Global overmap terrain coordinates where the player is to be spawned.
Expand Down Expand Up @@ -95,7 +108,7 @@ class start_location
bool can_belong_to_city( const tripoint_om_omt &p, const city &cit ) const;
private:
translation _name;
std::vector<std::pair<std::string, ot_match_type>> _omt_types;
std::vector<omt_types_parameters> _locations;
std::set<std::string> _flags;
start_location_placement_constraints constraints_;

Expand Down

0 comments on commit 0a6c239

Please sign in to comment.