diff --git a/src/map_extras.cpp b/src/map_extras.cpp index caf08d0a45d4b..0cd274ad9dd3e 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -2832,9 +2832,6 @@ void map_extra::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "autonote", autonote, false ); } -extern std::map> > oter_mapgen; -extern std::map> > - nested_mapgen; extern std::map> > update_mapgen; @@ -2850,13 +2847,6 @@ void map_extra::check() const break; } case map_extra_method::mapgen: { - /* - const auto fmapit = oter_mapgen.find( generator_id ); - const oter_id extra_oter( generator_id ); - if( ( fmapit == oter_mapgen.end() || !fmapit->second.empty() ) && !extra_oter.is_valid() ) { - debugmsg( "invalid mapgen function (%s) defined for map extra (%s)", generator_id, id.str() ); - } - */ break; } case map_extra_method::update_mapgen: { diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 619b6b77d8fa4..a3ab89369b589 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -15,6 +15,7 @@ #include #include "clzones.h" +#include "generic_factory.h" #include "computer.h" #include "coordinate_conversions.h" #include "coordinates.h" @@ -193,44 +194,148 @@ void mapgen_function_builtin::generate( mapgendata &mgd ) ///// mapgen_function class. ///// all sorts of ways to apply our hellish reality to a grid-o-squares +class mapgen_basic_container +{ + private: + std::vector> mapgens_; + weighted_int_list> weights_; + + public: + int add( const std::shared_ptr ptr ) { + assert( ptr ); + mapgens_.push_back( ptr ); + return mapgens_.size() - 1; + } + /** + * Pick a mapgen function randomly and call its generate function. + * This basically runs the mapgen functions with the given @ref mapgendata + * as argument. + * @return Whether the mapgen function has been run. It may not get run if + * the list of mapgen functions is effectively empty. + * @p hardcoded_weight Weight for an additional entry. If that entry is chosen, + * false is returned. If unsure, just use 0 for it. + */ + bool generate( mapgendata &dat, const int hardcoded_weight ) const { + if( hardcoded_weight > 0 && + rng( 1, weights_.get_weight() + hardcoded_weight ) > weights_.get_weight() ) { + return false; + } + const std::shared_ptr *const ptr = weights_.pick(); + if( !ptr ) { + return false; + } + assert( *ptr ); + ( *ptr )->generate( dat ); + return true; + } + /** + * Calls @ref mapgen_function::setup and sets up the internal weighted list using + * the **current** value of @ref mapgen_function::weight. This value may have + * changed since it was first added, so this is needed to recalculate the weighted list. + */ + void setup() { + for( const std::shared_ptr &ptr : mapgens_ ) { + const int weight = ptr->weight; + if( weight < 1 ) { + continue; // rejected! + } + weights_.add( ptr, weight ); + ptr->setup(); + } + // Not needed anymore, pointers are now stored in weights_ (or not used at all) + mapgens_.clear(); + } + void check_consistency( const std::string &key ) { + for( auto &mapgen_function_ptr : mapgens_ ) { + mapgen_function_ptr->check( key ); + } + } +}; + +class mapgen_factory +{ + private: + std::map mapgens_; + + /// Collect all the possible and expected keys that may get used with @ref pick. + static std::set get_usages() { + std::set result; + for( const oter_t &elem : overmap_terrains::get_all() ) { + result.insert( elem.get_mapgen_id() ); + result.insert( elem.id.str() ); + } + // Why do I have to repeat the MapExtras here? Wouldn't "MapExtras::factory" be enough? + for( const map_extra &elem : MapExtras::mapExtraFactory().get_all() ) { + if( elem.generator_method == map_extra_method::mapgen ) { + result.insert( elem.generator_id ); + } + } + // Used in C++ code only, see calls to `oter_mapgen.generate()` below + result.insert( "lab_1side" ); + result.insert( "lab_4side" ); + result.insert( "lab_finale_1level" ); + return result; + } + + public: + void reset() { + mapgens_.clear(); + } + /// @see mapgen_basic_container::setup + void setup() { + for( std::pair &omw : mapgens_ ) { + omw.second.setup(); + } + // Dummy entry, overmap terrain null should never appear and is therefor never generated. + mapgens_.erase( "null" ); + } + void check_consistency() { + // Cache all strings that may get looked up here so we don't have to go through + // all the sources for them upon each loop. + const std::set usages = get_usages(); + for( std::pair &omw : mapgens_ ) { + omw.second.check_consistency( omw.first ); + if( usages.count( omw.first ) == 0 ) { + debugmsg( "Mapgen %s is not used by anything!", omw.first ); + } + } + } + /** + * Checks whether we have an entry for the given key. + * Note that the entry itself may not contain any valid mapgen instance + * (could all have been removed via @ref erase). + */ + bool has( const std::string &key ) const { + return mapgens_.count( key ) != 0; + } + /// @see mapgen_basic_container::add + int add( const std::string &key, const std::shared_ptr ptr ) { + return mapgens_[key].add( ptr ); + } + /// @see mapgen_basic_container::generate + bool generate( mapgendata &dat, const std::string &key, const int hardcoded_weight = 0 ) const { + const auto iter = mapgens_.find( key ); + if( iter == mapgens_.end() ) { + return false; + } + return iter->second.generate( dat, hardcoded_weight ); + } +}; + +static mapgen_factory oter_mapgen; + /* - * ptr storage. + * stores function ref and/or required data */ -std::map> > oter_mapgen; std::map> > nested_mapgen; std::map> > update_mapgen; /* - * index to the above, adjusted to allow for rarity - */ -std::map > oter_mapgen_weights; - -/* - * setup oter_mapgen_weights which mapgen uses to diceroll. Also setup mapgen_function_json + * setup mapgen_basic_container::weights_ which mapgen uses to diceroll. Also setup mapgen_function_json */ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup too { - oter_mapgen_weights.clear(); - for( auto &omw : oter_mapgen ) { - int funcnum = 0; - int wtotal = 0; - oter_mapgen_weights[ omw.first ] = std::map(); - for( auto fit = omw.second.begin(); fit != omw.second.end(); ++fit ) { - // - int weight = ( *fit )->weight; - if( weight < 1 ) { - dbg( D_INFO ) << "wcalc " << omw.first << "(" << funcnum << "): (rej(1), " << weight << ") = " << - wtotal; - ++funcnum; - continue; // rejected! - } - ( *fit )->setup(); - wtotal += weight; - oter_mapgen_weights[ omw.first ][ wtotal ] = funcnum; - dbg( D_INFO ) << "wcalc " << omw.first << "(" << funcnum << "): +" << weight << " = " << wtotal; - ++funcnum; - } - } + oter_mapgen.setup(); // Not really calculate weights, but let's keep it here for now for( auto &pr : nested_mapgen ) { for( std::unique_ptr &ptr : pr.second ) { @@ -247,11 +352,7 @@ void calculate_mapgen_weights() // TODO: rename as it runs jsonfunction setup void check_mapgen_definitions() { - for( auto &oter_definition : oter_mapgen ) { - for( auto &mapgen_function_ptr : oter_definition.second ) { - mapgen_function_ptr->check( oter_definition.first ); - } - } + oter_mapgen.check_consistency(); for( auto &oter_definition : nested_mapgen ) { for( auto &mapgen_function_ptr : oter_definition.second ) { mapgen_function_ptr->check( oter_definition.first ); @@ -292,53 +393,28 @@ static void set_mapgen_defer( const JsonObject &jsi, const std::string &member, * load a single mapgen json structure; this can be inside an overmap_terrain, or on it's own. */ std::shared_ptr -load_mapgen_function( const JsonObject &jio, const std::string &id_base, - int default_idx, const point &offset ) +load_mapgen_function( const JsonObject &jio, const std::string &id_base, const point &offset ) { int mgweight = jio.get_int( "weight", 1000 ); std::shared_ptr ret; if( mgweight <= 0 || jio.get_bool( "disabled", false ) ) { - const std::string mgtype = jio.get_string( "method" ); - if( default_idx != -1 && mgtype == "builtin" ) { - if( jio.has_string( "name" ) ) { - const std::string mgname = jio.get_string( "name" ); - if( mgname == id_base ) { - oter_mapgen[id_base][ default_idx ]->weight = 0; - } - } - } jio.allow_omitted_members(); return nullptr; // nothing - } else if( jio.has_string( "method" ) ) { - const std::string mgtype = jio.get_string( "method" ); - if( mgtype == "builtin" ) { // c-function - if( jio.has_string( "name" ) ) { - const std::string mgname = jio.get_string( "name" ); - if( const auto ptr = get_mapgen_cfunction( mgname ) ) { - ret = std::make_shared( ptr, mgweight ); - oter_mapgen[id_base].push_back( ret ); - } else { - debugmsg( "oter_t[%s]: builtin mapgen function \"%s\" does not exist.", id_base.c_str(), - mgname ); - } - } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"name\" value).", id_base.c_str() ); - } - } else if( mgtype == "json" ) { - if( jio.has_object( "object" ) ) { - JsonObject jo = jio.get_object( "object" ); - std::string jstr = jo.str(); - ret = std::make_shared( jstr, mgweight, offset ); - oter_mapgen[id_base].push_back( ret ); - } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"object\" object)", id_base.c_str() ); - } + } + const std::string mgtype = jio.get_string( "method" ); + if( mgtype == "builtin" ) { + if( const auto ptr = get_mapgen_cfunction( jio.get_string( "name" ) ) ) { + ret = std::make_shared( ptr, mgweight ); + oter_mapgen.add( id_base, ret ); } else { - debugmsg( "oter_t[%s]: Invalid mapgen function type: %s", id_base.c_str(), mgtype.c_str() ); + jio.throw_error( "function does not exist", "name" ); } + } else if( mgtype == "json" ) { + const std::string jstr = jio.get_object( "object" ).str(); + ret = std::make_shared( jstr, mgweight, offset ); + oter_mapgen.add( id_base, ret ); } else { - debugmsg( "oter_t[%s]: Invalid mapgen function (missing \"method\" value, must be \"builtin\" or \"json\").", - id_base.c_str() ); + jio.throw_error( R"(invalid value: must be "builtin" or "json")", "method" ); } return ret; } @@ -391,9 +467,9 @@ void load_mapgen( const JsonObject &jo ) point offset; for( JsonArray row_items : ja ) { for( const std::string mapgenid : row_items ) { - const auto mgfunc = load_mapgen_function( jo, mapgenid, -1, offset ); + const auto mgfunc = load_mapgen_function( jo, mapgenid, offset ); if( mgfunc ) { - oter_mapgen[ mapgenid ].push_back( mgfunc ); + oter_mapgen.add( mapgenid, mgfunc ); } offset.x++; } @@ -407,16 +483,16 @@ void load_mapgen( const JsonObject &jo ) } if( !mapgenid_list.empty() ) { const std::string mapgenid = mapgenid_list[0]; - const auto mgfunc = load_mapgen_function( jo, mapgenid, -1 ); + const auto mgfunc = load_mapgen_function( jo, mapgenid, point_zero ); if( mgfunc ) { for( auto &i : mapgenid_list ) { - oter_mapgen[ i ].push_back( mgfunc ); + oter_mapgen.add( i, mgfunc ); } } } } } else if( jo.has_string( "om_terrain" ) ) { - load_mapgen_function( jo, jo.get_string( "om_terrain" ), -1 ); + load_mapgen_function( jo, jo.get_string( "om_terrain" ), point_zero ); } else if( jo.has_string( "nested_mapgen_id" ) ) { load_nested_mapgen( jo, jo.get_string( "nested_mapgen_id" ) ); } else if( jo.has_string( "update_mapgen_id" ) ) { @@ -429,7 +505,7 @@ void load_mapgen( const JsonObject &jo ) void reset_mapgens() { - oter_mapgen.clear(); + oter_mapgen.reset(); nested_mapgen.clear(); update_mapgen.clear(); } @@ -3466,18 +3542,8 @@ void map::draw_lab( mapgendata &dat ) //A lab area with only one entrance if( boarders == 1 ) { - const std::string function_key = "lab_1side"; // terrain_type->get_mapgen_id(); - const auto fmapit = oter_mapgen.find( function_key ); - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast ); - - const int fidx = weightit->second.lower_bound( roll )->second; - - fmapit->second[fidx]->generate( dat ); + // If you remove the usage of "lab_1side" here, remove it from mapgen_factory::get_usages above as well. + if( oter_mapgen.generate( dat, "lab_1side" ) ) { if( tw == 2 ) { rotate( 2 ); } @@ -3493,75 +3559,57 @@ void map::draw_lab( mapgendata &dat ) maybe_insert_stairs( dat.above(), t_stairs_up ); maybe_insert_stairs( terrain_type, t_stairs_down ); } else { - const std::string function_key = "lab_4side"; - const auto fmapit = oter_mapgen.find( function_key ); const int hardcoded_4side_map_weight = 1500; // weight of all hardcoded maps. - bool use_hardcoded_4side_map = false; - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast + hardcoded_4side_map_weight ); - - if( roll <= rlast ) { - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); - - // If the map template hasn't handled borders, handle them in code. - // Rotated maps cannot handle borders and have to be caught in code. - // We determine if a border isn't handled by checking the east-facing - // border space where the door normally is -- it should be a wall or door. - tripoint east_border( 23, 11, abs_sub.z ); - if( !has_flag_ter( "WALL", east_border ) && - !has_flag_ter( "DOOR", east_border ) ) { - // TODO: create a ter_reset function that does ter_set, - // furn_set, and i_clear? - ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : - t_concrete_wall; - ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : - t_concrete_wall; - for( int i = 0; i < SEEX * 2; i++ ) { - ter_set( point( 23, i ), rw_type ); - furn_set( point( 23, i ), f_null ); - i_clear( tripoint( 23, i, get_abs_sub().z ) ); - - ter_set( point( i, 23 ), bw_type ); - furn_set( point( i, 23 ), f_null ); - i_clear( tripoint( i, 23, get_abs_sub().z ) ); - - if( lw == 2 ) { - ter_set( point( 0, i ), lw_type ); - furn_set( point( 0, i ), f_null ); - i_clear( tripoint( 0, i, get_abs_sub().z ) ); - } - if( tw == 2 ) { - ter_set( point( i, 0 ), tw_type ); - furn_set( point( i, 0 ), f_null ); - i_clear( tripoint( i, 0, get_abs_sub().z ) ); - } - } - if( rw != 2 ) { - ter_set( point( 23, 11 ), t_door_metal_c ); - ter_set( point( 23, 12 ), t_door_metal_c ); + // If you remove the usage of "lab_4side" here, remove it from mapgen_factory::get_usages above as well. + if( oter_mapgen.generate( dat, "lab_4side", hardcoded_4side_map_weight ) ) { + // If the map template hasn't handled borders, handle them in code. + // Rotated maps cannot handle borders and have to be caught in code. + // We determine if a border isn't handled by checking the east-facing + // border space where the door normally is -- it should be a wall or door. + tripoint east_border( 23, 11, abs_sub.z ); + if( !has_flag_ter( "WALL", east_border ) && + !has_flag_ter( "DOOR", east_border ) ) { + // TODO: create a ter_reset function that does ter_set, + // furn_set, and i_clear? + ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : + t_concrete_wall; + ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : + t_concrete_wall; + for( int i = 0; i < SEEX * 2; i++ ) { + ter_set( point( 23, i ), rw_type ); + furn_set( point( 23, i ), f_null ); + i_clear( tripoint( 23, i, get_abs_sub().z ) ); + + ter_set( point( i, 23 ), bw_type ); + furn_set( point( i, 23 ), f_null ); + i_clear( tripoint( i, 23, get_abs_sub().z ) ); + + if( lw == 2 ) { + ter_set( point( 0, i ), lw_type ); + furn_set( point( 0, i ), f_null ); + i_clear( tripoint( 0, i, get_abs_sub().z ) ); } - if( bw != 2 ) { - ter_set( point( 11, 23 ), t_door_metal_c ); - ter_set( point( 12, 23 ), t_door_metal_c ); + if( tw == 2 ) { + ter_set( point( i, 0 ), tw_type ); + furn_set( point( i, 0 ), f_null ); + i_clear( tripoint( i, 0, get_abs_sub().z ) ); } } + if( rw != 2 ) { + ter_set( point( 23, 11 ), t_door_metal_c ); + ter_set( point( 23, 12 ), t_door_metal_c ); + } + if( bw != 2 ) { + ter_set( point( 11, 23 ), t_door_metal_c ); + ter_set( point( 12, 23 ), t_door_metal_c ); + } + } - maybe_insert_stairs( dat.above(), t_stairs_up ); - maybe_insert_stairs( terrain_type, t_stairs_down ); - } else { // then weighted roll was in the hardcoded section - use_hardcoded_4side_map = true; - } // end json maps + maybe_insert_stairs( dat.above(), t_stairs_up ); + maybe_insert_stairs( terrain_type, t_stairs_down ); } else { // then no json maps for lab_4side were found - use_hardcoded_4side_map = true; - } // end if no lab_4side was found. - if( use_hardcoded_4side_map ) { switch( rng( 1, 3 ) ) { case 1: // Cross shaped @@ -4056,69 +4104,50 @@ void map::draw_lab( mapgendata &dat ) bw = is_ot_match( "lab", dat.south(), ot_match_type::contains ) ? 1 : 2; lw = is_ot_match( "lab", dat.west(), ot_match_type::contains ) ? 0 : 2; - const std::string function_key = "lab_finale_1level"; - const auto fmapit = oter_mapgen.find( function_key ); const int hardcoded_finale_map_weight = 500; // weight of all hardcoded maps. - bool use_hardcoded_finale_map = false; - - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - function_key ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast + hardcoded_finale_map_weight ); - - if( roll <= rlast ) { - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); - - // If the map template hasn't handled borders, handle them in code. - // Rotated maps cannot handle borders and have to be caught in code. - // We determine if a border isn't handled by checking the east-facing - // border space where the door normally is -- it should be a wall or door. - tripoint east_border( 23, 11, abs_sub.z ); - if( !has_flag_ter( "WALL", east_border ) && !has_flag_ter( "DOOR", east_border ) ) { - // TODO: create a ter_reset function that does ter_set, furn_set, and i_clear? - ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; - ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : t_concrete_wall; - ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : t_concrete_wall; - for( int i = 0; i < SEEX * 2; i++ ) { - ter_set( point( 23, i ), rw_type ); - furn_set( point( 23, i ), f_null ); - i_clear( tripoint( 23, i, get_abs_sub().z ) ); - - ter_set( point( i, 23 ), bw_type ); - furn_set( point( i, 23 ), f_null ); - i_clear( tripoint( i, 23, get_abs_sub().z ) ); - - if( lw == 2 ) { - ter_set( point( 0, i ), lw_type ); - furn_set( point( 0, i ), f_null ); - i_clear( tripoint( 0, i, get_abs_sub().z ) ); - } - if( tw == 2 ) { - ter_set( point( i, 0 ), tw_type ); - furn_set( point( i, 0 ), f_null ); - i_clear( tripoint( i, 0, get_abs_sub().z ) ); - } - } - if( rw != 2 ) { - ter_set( point( 23, 11 ), t_door_metal_c ); - ter_set( point( 23, 12 ), t_door_metal_c ); + // If you remove the usage of "lab_finale_1level" here, remove it from mapgen_factory::get_usages above as well. + if( oter_mapgen.generate( dat, "lab_finale_1level", hardcoded_finale_map_weight ) ) { + // If the map template hasn't handled borders, handle them in code. + // Rotated maps cannot handle borders and have to be caught in code. + // We determine if a border isn't handled by checking the east-facing + // border space where the door normally is -- it should be a wall or door. + tripoint east_border( 23, 11, abs_sub.z ); + if( !has_flag_ter( "WALL", east_border ) && !has_flag_ter( "DOOR", east_border ) ) { + // TODO: create a ter_reset function that does ter_set, furn_set, and i_clear? + ter_id lw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id tw_type = tower_lab ? t_reinforced_glass : t_concrete_wall; + ter_id rw_type = tower_lab && rw == 2 ? t_reinforced_glass : t_concrete_wall; + ter_id bw_type = tower_lab && bw == 2 ? t_reinforced_glass : t_concrete_wall; + for( int i = 0; i < SEEX * 2; i++ ) { + ter_set( point( 23, i ), rw_type ); + furn_set( point( 23, i ), f_null ); + i_clear( tripoint( 23, i, get_abs_sub().z ) ); + + ter_set( point( i, 23 ), bw_type ); + furn_set( point( i, 23 ), f_null ); + i_clear( tripoint( i, 23, get_abs_sub().z ) ); + + if( lw == 2 ) { + ter_set( point( 0, i ), lw_type ); + furn_set( point( 0, i ), f_null ); + i_clear( tripoint( 0, i, get_abs_sub().z ) ); } - if( bw != 2 ) { - ter_set( point( 11, 23 ), t_door_metal_c ); - ter_set( point( 12, 23 ), t_door_metal_c ); + if( tw == 2 ) { + ter_set( point( i, 0 ), tw_type ); + furn_set( point( i, 0 ), f_null ); + i_clear( tripoint( i, 0, get_abs_sub().z ) ); } } - } else { // then weighted roll was in the hardcoded section - use_hardcoded_finale_map = true; - } // end json maps + if( rw != 2 ) { + ter_set( point( 23, 11 ), t_door_metal_c ); + ter_set( point( 23, 12 ), t_door_metal_c ); + } + if( bw != 2 ) { + ter_set( point( 11, 23 ), t_door_metal_c ); + ter_set( point( 12, 23 ), t_door_metal_c ); + } + } } else { // then no json maps for lab_finale_1level were found - use_hardcoded_finale_map = true; - } // end if no lab_4side was found. - - if( use_hardcoded_finale_map ) { // Start by setting up a large, empty room. for( int i = 0; i < SEEX * 2; i++ ) { for( int j = 0; j < SEEY * 2; j++ ) { @@ -7292,15 +7321,18 @@ std::pair, std::map> get_changed_ids_from_up bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ) { - const auto fmapit = oter_mapgen.find( mapgen_id ); - if( fmapit != oter_mapgen.end() && !fmapit->second.empty() ) { - std::map >::const_iterator weightit = oter_mapgen_weights.find( - mapgen_id ); - const int rlast = weightit->second.rbegin()->first; - const int roll = rng( 1, rlast ); - const int fidx = weightit->second.lower_bound( roll )->second; - fmapit->second[fidx]->generate( dat ); - return true; + return oter_mapgen.generate( dat, mapgen_id ); +} + +int register_mapgen_function( const std::string &key ) +{ + if( const auto ptr = get_mapgen_cfunction( key ) ) { + return oter_mapgen.add( key, std::make_shared( ptr ) ); } - return false; + return -1; +} + +bool has_mapgen_for( const std::string &key ) +{ + return oter_mapgen.has( key ); } diff --git a/src/mapgen.h b/src/mapgen.h index 6c9e31034673d..8e051518b3673 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -371,21 +371,24 @@ class mapgen_function_json_nested : public mapgen_function_json_base * Load mapgen function of any type from a json object */ std::shared_ptr load_mapgen_function( const JsonObject &jio, - const std::string &id_base, int default_idx, const point &offset = point_zero ); + const std::string &id_base, const point &offset ); /* * Load the above directly from a file via init, as opposed to riders attached to overmap_terrain. Added check - * for oter_mapgen / oter_mapgen_weights key, multiple possible ( ie, [ "house", "house_base" ] ) + * for oter_mapgen key, multiple possible ( ie, [ "house", "house_base" ] ) */ void load_mapgen( const JsonObject &jo ); void reset_mapgens(); -/* - * stores function ref and/or required data +/** + * Attempts to register the build-in function @p key as mapgen for the overmap terrain @p key. + * If there is no matching function, it does nothing (no error message) and returns -1. + * Otherwise it returns the index of the added entry in the vector of @ref oter_mapgen. */ -extern std::map> > oter_mapgen; -/* - * random selector list for the nested vector above, as per individual mapgen_function_::weight value +// @TODO this should go away. It is only used for old build-in mapgen. Mapgen should be done via JSON. +int register_mapgen_function( const std::string &key ); +/** + * Check that @p key is present in @ref oter_mapgen. */ -extern std::map > oter_mapgen_weights; +bool has_mapgen_for( const std::string &key ); /* * Sets the above after init, and initializes mapgen_function_json instances as well */ diff --git a/src/overmap.cpp b/src/overmap.cpp index 932ccf174a185..a507431fe369c 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -529,17 +529,10 @@ static void load_overmap_terrain_mapgens( const JsonObject &jo, const std::strin { const std::string fmapkey( id_base + suffix ); const std::string jsonkey( "mapgen" + suffix ); - bool default_mapgen = jo.get_bool( "default_mapgen", true ); - int default_idx = -1; - if( default_mapgen ) { - if( const auto ptr = get_mapgen_cfunction( fmapkey ) ) { - oter_mapgen[fmapkey].push_back( std::make_shared( ptr ) ); - default_idx = oter_mapgen[fmapkey].size() - 1; - } - } + register_mapgen_function( fmapkey ); if( jo.has_array( jsonkey ) ) { for( JsonObject jio : jo.get_array( jsonkey ) ) { - load_mapgen_function( jio, fmapkey, default_idx ); + load_mapgen_function( jio, fmapkey, point_zero ); } } } @@ -792,9 +785,8 @@ void overmap_terrains::check_consistency() } const bool exists_hardcoded = elem.is_hardcoded(); - const bool exists_loaded = oter_mapgen.find( mid ) != oter_mapgen.end(); - if( exists_loaded ) { + if( has_mapgen_for( mid ) ) { if( test_mode && exists_hardcoded ) { debugmsg( "Mapgen terrain \"%s\" exists in both JSON and a hardcoded function. Consider removing the latter.", mid.c_str() );