diff --git a/data/json/furniture_and_terrain/furniture-regional-pseudo.json b/data/json/furniture_and_terrain/furniture-regional-pseudo.json new file mode 100644 index 0000000000000..a8315106bf942 --- /dev/null +++ b/data/json/furniture_and_terrain/furniture-regional-pseudo.json @@ -0,0 +1,13 @@ +[ + { + "type": "furniture", + "id": "f_region_flower", + "name": "this should never actually show up, it's a pseudo furniture", + "description": "this should never actually show up, it's a pseudo furniture", + "symbol": " ", + "color": "black", + "move_cost_mod": 0, + "required_str": 0, + "flags": [ "TRANSPARENT", "NOITEM" ] + } +] diff --git a/data/json/furniture_and_terrain/terrain-regional-pseudo.json b/data/json/furniture_and_terrain/terrain-regional-pseudo.json new file mode 100644 index 0000000000000..655e608c77641 --- /dev/null +++ b/data/json/furniture_and_terrain/terrain-regional-pseudo.json @@ -0,0 +1,32 @@ +[ + { + "type": "terrain", + "id": "t_region_groundcover", + "name": "this should never actually show up, it's a pseudo terrain", + "description": "this should never actually show up, it's a pseudo terrain", + "symbol": " ", + "color": "black", + "move_cost": 0, + "flags": [ "TRANSPARENT", "NOITEM" ] + }, + { + "type": "terrain", + "id": "t_region_tree", + "name": "this should never actually show up, it's a pseudo terrain", + "description": "this should never actually show up, it's a pseudo terrain", + "symbol": " ", + "color": "black", + "move_cost": 0, + "flags": [ "TRANSPARENT", "NOITEM" ] + }, + { + "type": "terrain", + "id": "t_region_shrub", + "name": "this should never actually show up, it's a pseudo terrain", + "description": "this should never actually show up, it's a pseudo terrain", + "symbol": " ", + "color": "black", + "move_cost": 0, + "flags": [ "TRANSPARENT", "NOITEM" ] + } +] diff --git a/data/json/mapgen/trailhead.json b/data/json/mapgen/trailhead.json index 9caa266816662..b185257d29b9e 100644 --- a/data/json/mapgen/trailhead.json +++ b/data/json/mapgen/trailhead.json @@ -20,9 +20,20 @@ ":": "t_window_bars", "c": "t_woodchips", "W": "t_water_pump", - "T": "t_floor" + "T": "t_floor", + "7": [ "t_region_tree", "t_region_shrub" ], + "f": "t_dirt" + }, + "furniture": { + "b": "f_boulder_small", + "s": "f_sign", + "B": "f_bench", + "=": "f_bench", + "w": "f_woodstove", + ",": [ [ "f_region_flower", 1 ], [ "f_null", 100 ] ], + ";": [ [ "f_region_flower", 1 ], [ "f_null", 100 ] ], + ".": [ [ "f_region_flower", 1 ], [ "f_null", 100 ] ] }, - "furniture": { "b": "f_boulder_small", "s": "f_sign", "B": "f_bench", "=": "f_bench", "w": "f_woodstove" }, "toilets": { "T": { } } }, { @@ -54,8 +65,8 @@ ";;;.. ;;;;;", ";;;;. ;;;;;", ";;;;; ;;;;;", - ";;;;;tttt tttt;;;;;", - ";;;;;b..b ss b..b;;;;;" + ";77;;tttt tttt;;;;;", + "7777;b..b ss b..b;;;;;" ], "palettes": [ "trailhead" ], "place_vehicles": [ @@ -91,11 +102,11 @@ ";;;... ...;;", ";;... |-|;;", ";;... . . . +T|;;", - ";;;.. . |-|;;", - ";;;;. . . . +T|;;", + ";;;.. . |-|;7", + ";;;;. . . . +T|;7", ";;;;; ;|-|;;", - ";;;;;==== sss;;;;;;", - ";;;;;;;;; ;;;;;;;;;" + ";;;;;==== sss;;;;;7", + ";;;;77;77 ;;;;;;;7;" ], "palettes": [ "trailhead" ], "place_vehicles": [ { "chance": 100, "fuel": 0, "rotation": 0, "status": 1, "vehicle": "campground_vehicles", "x": 17, "y": 9 } ], @@ -136,7 +147,7 @@ ";;;;. . . . ;;;;;", ";;;;; ;;;;;", ";;;;;tttt tttt;;;;;", - ";;;;;b..b s s b..b;;;;;" + ";;7;;b..b s s b..b;;7;;" ], "palettes": [ "trailhead" ], "place_vehicles": [ @@ -175,8 +186,8 @@ ";;;c|B###+ ..;;;;;;;b", ";;;c|BB#w|s ..;;;;;;;;", ";;;c|--:-| ;;;;;;;;;", - ";;;ccccccc ;;;;;;b;;", - ";;;b;b;b; ;;b;;;;;;" + ";7;ccccccc ;;;;;;b;;", + ";;;b;b;b; ;;b;;;;7;" ], "palettes": [ "trailhead" ], "place_items": [ { "item": "camping", "x": [ 5, 5 ], "y": [ 18, 20 ], "chance": 70 } ], diff --git a/data/json/regional_map_settings.json b/data/json/regional_map_settings.json index 2a9430e9f0f93..a473f0c119d0f 100644 --- a/data/json/regional_map_settings.json +++ b/data/json/regional_map_settings.json @@ -3,7 +3,67 @@ "type": "region_settings", "id": "default", "default_oter": "field", - "default_groundcover": [ [ "t_grass", 4 ], [ "t_grass_long", 2 ], [ "t_dirt", 1 ] ], + "default_groundcover": [ [ "t_region_groundcover", 1 ] ], + "region_terrain_and_furniture": { + "terrain": { + "t_region_groundcover": { "t_grass": 4, "t_grass_long": 2, "t_dirt": 1 }, + "t_region_shrub": { + "t_underbrush": 30, + "t_shrub": 5, + "t_shrub_blueberry": 1, + "t_shrub_strawberry": 1, + "t_shrub_blackberry": 1, + "t_shrub_raspberry": 1, + "t_shrub_huckleberry": 1, + "t_shrub_grape": 1, + "t_shrub_rose": 1, + "t_shrub_hydrangea": 1, + "t_shrub_lilac": 1 + }, + "t_region_tree": { + "t_tree": 128, + "t_tree_young": 128, + "t_tree_birch": 16, + "t_tree_elm": 16, + "t_tree_cottonwood": 16, + "t_tree_pine": 32, + "t_tree_maple": 32, + "t_tree_willow": 32, + "t_tree_hickory": 16, + "t_tree_walnut": 8, + "t_tree_chestnut": 8, + "t_tree_hazelnut": 2, + "t_tree_beech": 2, + "t_tree_blackjack": 8, + "t_tree_coffee": 2, + "t_tree_apple": 2, + "t_tree_apricot": 2, + "t_tree_cherry": 2, + "t_tree_juniper": 2, + "t_tree_peach": 2, + "t_tree_pear": 2, + "t_tree_plum": 2, + "t_tree_elderberry": 2, + "t_tree_mulberry": 2, + "t_tree_deadpine": 16, + "t_tree_hickory_dead": 16, + "t_tree_dead": 16 + } + }, + "furniture": { + "f_region_flower": { + "f_black_eyed_susan": 1, + "f_lily": 1, + "f_flower_tulip": 1, + "f_flower_spurge": 1, + "f_chamomile": 1, + "f_dandelion": 1, + "f_datura": 1, + "f_dahlia": 1, + "f_bluebell": 1 + } + } + }, "river_scale": 1.0, "field_coverage": { "percent_coverage": 0.9333, diff --git a/data/json/test_regions.json b/data/json/test_regions.json index a714d3edc2f6e..806e5676544e0 100644 --- a/data/json/test_regions.json +++ b/data/json/test_regions.json @@ -3,7 +3,15 @@ "type": "region_settings", "id": "desert_test", "default_oter": "field", - "default_groundcover": [ [ "t_searth_test", 3 ], [ "t_sand", 1 ] ], + "default_groundcover": [ [ "t_region_groundcover", 1 ] ], + "region_terrain_and_furniture": { + "terrain": { + "t_region_groundcover": { "t_searth_test": 3, "t_sand": 1 }, + "t_region_shrub": { "t_shrub": 1 }, + "t_region_tree": { "t_tree_willow": 1, "t_tree_dead": 1 } + }, + "furniture": { "f_region_flower": { "f_mutcactus_test": 1 } } + }, "field_coverage": { "percent_coverage": 1.9333, "default_ter": "t_sand", diff --git a/data/mods/desert_region/desert_regional_map_settings.json b/data/mods/desert_region/desert_regional_map_settings.json index 4e9d72e617aaf..9d1c6cc964bc3 100644 --- a/data/mods/desert_region/desert_regional_map_settings.json +++ b/data/mods/desert_region/desert_regional_map_settings.json @@ -3,7 +3,15 @@ "type": "region_settings", "id": "default", "default_oter": "desert", - "default_groundcover": [ [ "t_searth_test", 4 ], [ "t_sand", 1 ] ], + "default_groundcover": [ [ "t_region_groundcover", 1 ] ], + "region_terrain_and_furniture": { + "terrain": { + "t_region_groundcover": { "t_searth_test": 4, "t_sand": 1 }, + "t_region_shrub": { "t_shrub": 1 }, + "t_region_tree": { "t_tree_willow": 1, "t_tree_dead": 1 } + }, + "furniture": { "f_region_flower": { "f_mutcactus_test": 1 } } + }, "river_scale": 0.0, "field_coverage": { "percent_coverage": 0.1333, diff --git a/doc/REGION_SETTINGS.md b/doc/REGION_SETTINGS.md index 4861dc1d8a31f..29f6805f71330 100644 --- a/doc/REGION_SETTINGS.md +++ b/doc/REGION_SETTINGS.md @@ -4,17 +4,18 @@ The **region_settings** define the attributes for map generation that apply to a The general settings define the default overmap terrain and ground cover. Additional sections are as follows: -| Section | Description | -| ------------------------------- | ------------------------------------------------------------------- | -| `field_coverage` | Defines the flora that cover the `field` overmap terrain. | -| `overmap_lake_settings` | Defines parameters for generating lakes in the region. | -| `overmap_forest_settings` | Defines parameters for generating forests and swamps in the region. | -| `forest_mapgen_settings` | Defines flora (and "stuff") that cover the `forest` terrain types. | -| `forest_trail_settings` | Defines the overmap and local structure of forest trails. | -| `city` | Defines the structural compositions of cities. | -| `map_extras` | Defines the map extra groups referenced by overmap terrains. | -| `weather` | Defines the base weather attributes for the region. | -| `overmap_feature_flag_settings` | Defines operations on overmap features based on their flags. | +| Section | Description | +| ------------------------------- | --------------------------------------------------------------------- | +| `region_terrain_and_furniture` | Defines the resolution of regional terrain/furniture to actual types. | +| `field_coverage` | Defines the flora that cover the `field` overmap terrain. | +| `overmap_lake_settings` | Defines parameters for generating lakes in the region. | +| `overmap_forest_settings` | Defines parameters for generating forests and swamps in the region. | +| `forest_mapgen_settings` | Defines flora (and "stuff") that cover the `forest` terrain types. | +| `forest_trail_settings` | Defines the overmap and local structure of forest trails. | +| `city` | Defines the structural compositions of cities. | +| `map_extras` | Defines the map extra groups referenced by overmap terrains. | +| `weather` | Defines the base weather attributes for the region. | +| `overmap_feature_flag_settings` | Defines operations on overmap features based on their flags. | Note that for the default region, all attributes and sections are required. @@ -41,6 +42,49 @@ Note that for the default region, all attributes and sections are required. } ``` +## Region Terrain / Furniture + +The **region_terrain_and_furniture** section defines the resolution of regional terrain/furniture +to their actual terrain and furniture types for the region, with a weighted list for +terrain/furniture entry that defines the relative weight of a given entry when mapgen resolves the +regional entry to an actual entry. + +### Fields + +| Identifier | Description | +| ----------- | ------------------------------------------------------------------ | +| `terrain` | List of regional terrain and their corresponding weighted lists. | +| `furniture` | List of regional furniture and their corresponding weighted lists. | + +### Example +```json +{ + "region_terrain_and_furniture": { + "terrain": { + "t_region_groundcover": { + "t_grass": 4, + "t_grass_long": 2, + "t_dirt": 1 + } + }, + "furniture": { + "f_region_flower": { + "f_black_eyed_susan": 1, + "f_lily": 1, + "f_flower_tulip": 1, + "f_flower_spurge": 1, + "f_chamomile": 1, + "f_dandelion": 1, + "f_datura": 1, + "f_dahlia": 1, + "f_bluebell": 1 + } + } + } +} +``` + + ## Field Coverage The **field_coverage** section defines the furniture and terrain that make up the flora that diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 3ceae2a25f1b6..264fb933708e9 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -2599,6 +2599,8 @@ void mapgen_function_json::generate( mapgendata &md ) objects.apply( md, point_zero ); + resolve_regional_terrain_and_furniture( md ); + m->rotate( rotation.get() ); if( md.terrain_type()->is_rotatable() ) { @@ -2620,6 +2622,8 @@ void mapgen_function_json_nested::nest( mapgendata &dat, const point &offset ) c } objects.apply( dat, offset ); + + resolve_regional_terrain_and_furniture( dat ); } /* @@ -6263,6 +6267,8 @@ void map::draw_connections( mapgendata &dat ) } } } + + resolve_regional_terrain_and_furniture( dat ); } void map::place_spawns( const mongroup_id &group, const int chance, @@ -7754,6 +7760,8 @@ bool update_mapgen_function_json::update_map( mapgendata &md, const point &offse } objects.apply( md, offset ); + resolve_regional_terrain_and_furniture( md ); + return true; } diff --git a/src/mapgen_functions.cpp b/src/mapgen_functions.cpp index 44a95877bf011..a7a22e79a85de 100644 --- a/src/mapgen_functions.cpp +++ b/src/mapgen_functions.cpp @@ -4608,3 +4608,19 @@ void place_stairs( mapgendata &dat ) } } } + +void resolve_regional_terrain_and_furniture( const mapgendata &dat ) +{ + for( const tripoint &p : dat.m.points_on_zlevel() ) { + const ter_id tid_before = dat.m.ter( p ); + const ter_id tid_after = dat.region.region_terrain_and_furniture.resolve( tid_before ); + if( tid_after != tid_before ) { + dat.m.ter_set( p, tid_after ); + } + const furn_id fid_before = dat.m.furn( p ); + const furn_id fid_after = dat.region.region_terrain_and_furniture.resolve( fid_before ); + if( fid_after != fid_before ) { + dat.m.furn_set( p, fid_after ); + } + } +} diff --git a/src/mapgen_functions.h b/src/mapgen_functions.h index d9fbc04c930d2..264e7184c5f16 100644 --- a/src/mapgen_functions.h +++ b/src/mapgen_functions.h @@ -99,4 +99,7 @@ bool run_mapgen_update_func( const std::string &update_mapgen_id, const tripoint bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ); std::pair, std::map> get_changed_ids_from_update( const std::string &update_mapgen_id ); + +void resolve_regional_terrain_and_furniture( const mapgendata &dat ); + #endif diff --git a/src/regional_settings.cpp b/src/regional_settings.cpp index af1c4f921a916..9e6135ef916e1 100644 --- a/src/regional_settings.cpp +++ b/src/regional_settings.cpp @@ -359,6 +359,72 @@ static void load_overmap_lake_settings( JsonObject &jo, } } +static void load_region_terrain_and_furniture_settings( JsonObject &jo, + region_terrain_and_furniture_settings ®ion_terrain_and_furniture_settings, + const bool strict, const bool overlay ) +{ + if( !jo.has_object( "region_terrain_and_furniture" ) ) { + if( strict ) { + jo.throw_error( "\"region_terrain_and_furniture\": { … } required for default" ); + } + } else { + JsonObject region_terrain_and_furniture_settings_jo = + jo.get_object( "region_terrain_and_furniture" ); + + if( !region_terrain_and_furniture_settings_jo.has_object( "terrain" ) ) { + if( !overlay ) { + region_terrain_and_furniture_settings_jo.throw_error( "terrain required" ); + } + } else { + JsonObject template_terrain_jo = region_terrain_and_furniture_settings_jo.get_object( "terrain" ); + std::set template_terrain_ids = template_terrain_jo.get_member_names(); + for( const auto &template_terrain_id : template_terrain_ids ) { + if( template_terrain_id == "//" ) { + continue; + } + JsonObject terrain_jo = template_terrain_jo.get_object( template_terrain_id ); + std::set terrain_ids = terrain_jo.get_member_names(); + for( const auto &terrain_id : terrain_ids ) { + if( terrain_id == "//" ) { + continue; + } + int weight = 0; + if( terrain_jo.read( terrain_id, weight ) ) { + region_terrain_and_furniture_settings.unfinalized_terrain[template_terrain_id][terrain_id] = weight; + } + } + } + } + + if( !region_terrain_and_furniture_settings_jo.has_object( "furniture" ) ) { + if( !overlay ) { + region_terrain_and_furniture_settings_jo.throw_error( "furniture required" ); + } + } else { + JsonObject template_furniture_jo = + region_terrain_and_furniture_settings_jo.get_object( "furniture" ); + std::set template_furniture_ids = template_furniture_jo.get_member_names(); + for( const auto &template_furniture_id : template_furniture_ids ) { + if( template_furniture_id == "//" ) { + continue; + } + JsonObject furniture_jo = template_furniture_jo.get_object( template_furniture_id ); + std::set furniture_ids = furniture_jo.get_member_names(); + for( const auto &furniture_id : furniture_ids ) { + if( furniture_id == "//" ) { + continue; + } + int weight = 0; + if( furniture_jo.read( furniture_id, weight ) ) { + region_terrain_and_furniture_settings.unfinalized_furniture[template_furniture_id][furniture_id] = + weight; + } + } + } + } + } +} + void load_region_settings( JsonObject &jo ) { regional_settings new_region; @@ -539,6 +605,9 @@ void load_region_settings( JsonObject &jo ) load_overmap_lake_settings( jo, new_region.overmap_lake, strict, false ); + load_region_terrain_and_furniture_settings( jo, new_region.region_terrain_and_furniture, strict, + false ); + region_settings_map[new_region.id] = new_region; } @@ -701,6 +770,8 @@ void apply_region_overlay( JsonObject &jo, regional_settings ®ion ) load_overmap_forest_settings( jo, region.overmap_forest, false, true ); load_overmap_lake_settings( jo, region.overmap_lake, false, true ); + + load_region_terrain_and_furniture_settings( jo, region.region_terrain_and_furniture, false, true ); } void groundcover_extra::finalize() // FIXME: return bool for failure @@ -899,6 +970,67 @@ void overmap_lake_settings::finalize() } } +void region_terrain_and_furniture_settings::finalize() +{ + for( auto const &template_pr : unfinalized_terrain ) { + const ter_str_id template_tid( template_pr.first ); + if( !template_tid.is_valid() ) { + debugmsg( "Tried to add invalid regional template terrain %s to region_terrain_and_furniture terrain.", + template_tid.c_str() ); + continue; + } + for( auto const &actual_pr : template_pr.second ) { + const ter_str_id tid( actual_pr.first ); + if( !tid.is_valid() ) { + debugmsg( "Tried to add invalid regional terrain %s to region_terrain_and_furniture terrain template %s.", + tid.c_str(), template_tid.c_str() ); + continue; + } + terrain[template_tid.id()].add( tid.id(), actual_pr.second ); + } + } + + for( auto const &template_pr : unfinalized_furniture ) { + const furn_str_id template_fid( template_pr.first ); + if( !template_fid.is_valid() ) { + debugmsg( "Tried to add invalid regional template furniture %s to region_terrain_and_furniture furniture.", + template_fid.c_str() ); + continue; + } + for( auto const &actual_pr : template_pr.second ) { + const furn_str_id fid( actual_pr.first ); + if( !fid.is_valid() ) { + debugmsg( "Tried to add invalid regional furniture %s to region_terrain_and_furniture furniture template %s.", + fid.c_str(), template_fid.c_str() ); + continue; + } + furniture[template_fid.id()].add( fid.id(), actual_pr.second ); + } + } +} + +ter_id region_terrain_and_furniture_settings::resolve( const ter_id tid ) const +{ + ter_id result = tid; + auto region_list = terrain.find( result ); + while( region_list != terrain.end() ) { + result = *region_list->second.pick(); + region_list = terrain.find( result ); + } + return result; +} + +furn_id region_terrain_and_furniture_settings::resolve( const furn_id fid ) const +{ + furn_id result = fid; + auto region_list = furniture.find( result ); + while( region_list != furniture.end() ) { + result = *region_list->second.pick(); + region_list = furniture.find( result ); + } + return result; +} + void regional_settings::finalize() { if( default_groundcover_str != nullptr ) { @@ -912,6 +1044,7 @@ void regional_settings::finalize() forest_composition.finalize(); forest_trail.finalize(); overmap_lake.finalize(); + region_terrain_and_furniture.finalize(); get_options().add_value( "DEFAULT_REGION", id, no_translation( id ) ); } } diff --git a/src/regional_settings.h b/src/regional_settings.h index d3804845eeab5..cf3c7b765d90c 100644 --- a/src/regional_settings.h +++ b/src/regional_settings.h @@ -214,6 +214,18 @@ struct map_extras { map_extras( const unsigned int embellished ) : chance( embellished ) {} }; +struct region_terrain_and_furniture_settings { + std::map> unfinalized_terrain; + std::map> unfinalized_furniture; + std::map> terrain; + std::map> furniture; + + void finalize(); + ter_id resolve( ter_id ) const; + furn_id resolve( furn_id ) const; + region_terrain_and_furniture_settings() = default; +}; + /* * Spationally relevant overmap and mapgen variables grouped into a set of suggested defaults; * eventually region mapping will modify as required and allow for transitions of biomes / demographics in a smoooth fashion @@ -233,6 +245,7 @@ struct regional_settings { overmap_feature_flag_settings overmap_feature_flag; overmap_forest_settings overmap_forest; overmap_lake_settings overmap_lake; + region_terrain_and_furniture_settings region_terrain_and_furniture; std::unordered_map region_extras;