From 0890bcab3c85a9ef0864c64730c273bbcd5698be Mon Sep 17 00:00:00 2001 From: Olanti Date: Sat, 25 Jun 2022 19:39:42 +0300 Subject: [PATCH 1/3] Fix generation of parallel elevated bridges --- src/mapgen.cpp | 6 +-- src/omdata.h | 15 ++++++ src/overmap.cpp | 137 +++++++++++++++++++++++++----------------------- src/overmap.h | 16 ++++-- 4 files changed, 100 insertions(+), 74 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 1cf7f84cb88b..2f98d9a7790b 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -6555,11 +6555,11 @@ bool update_mapgen_function_json::update_map( mapgendata &md, const point &offse { public: rotation_guard( const mapgendata &md ) - : md( md ), rotation( oter_get_rotation( md.terrain_type() ) ) { + : md( md ), rotation( oter_get_rotations( md.terrain_type() ) ) { // If the existing map is rotated, we need to rotate it back to the north // orientation before applying our updates. if( rotation != 0 ) { - md.m.rotate( rotation, true ); + md.m.rotate( 4 - rotation, true ); } } @@ -6567,7 +6567,7 @@ bool update_mapgen_function_json::update_map( mapgendata &md, const point &offse // If we rotated the map before applying updates, we now need to rotate // it back to where we found it. if( rotation != 0 ) { - md.m.rotate( 4 - rotation, true ); + md.m.rotate( rotation, true ); } } private: diff --git a/src/omdata.h b/src/omdata.h index 374597013f99..fe088f3a4fd9 100644 --- a/src/omdata.h +++ b/src/omdata.h @@ -61,6 +61,21 @@ enum class type : int { const std::array all = {{ type::north, type::east, type::south, type::west }}; const size_t size = all.size(); +const std::array all_suffixes = {{ "_north", "_east", "_south", "_west" }}; +const std::array all_cw_rotations = {{ 0, 1, 2, 3 }}; + +/** Returns directional suffix associated with the value, e.g. _north or _west. */ +constexpr const std::string &get_suffix( type dir ) +{ + return all_suffixes[static_cast( dir )]; +} + +/** Returns number of clockwise rotations needed to reach this direction from 'north'. */ +constexpr int get_num_cw_rotations( type dir ) +{ + return all_cw_rotations[static_cast( dir )]; +} + /** Number of bits needed to store directions. */ const size_t bits = static_cast( -1 ) >> ( CHAR_BIT *sizeof( size_t ) - size ); diff --git a/src/overmap.cpp b/src/overmap.cpp index 88d1780e48bf..9e1d806fa31f 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -1915,6 +1915,51 @@ bool overmap::generate_sub( const int z ) return requires_sub; } +static void elevate_bridges( + overmap &om, + const std::vector &bridge_points, + const std::string &bridge_overpass_id, + const std::string &bridge_under_id, + const std::string &bridgehead_ground_id, + const std::string &bridgehead_ramp_id ) +{ + // Check bridgeheads + std::vector> bridgehead_points; + for( const point_om_omt &bp : bridge_points ) { + tripoint_om_omt bp_om( bp, 0 ); + + const oter_id &ot_here = om.ter( bp_om ); + const std::string &type_here = ot_here->get_type_id().str(); + const om_direction::type dir = oter_get_rotation_dir( ot_here ); + if( dir == om_direction::type::invalid ) { + // Shouldn't happen + continue; + } + point vec = om_direction::displace( dir ); + const bool is_bridge_fwd = is_ot_match( type_here, om.ter( bp_om + vec ), ot_match_type::type ); + const bool is_bridge_bck = is_ot_match( type_here, om.ter( bp_om - vec ), ot_match_type::type ); + + if( is_bridge_fwd ^ is_bridge_bck ) { + om_direction::type ramp_facing = is_bridge_fwd ? om_direction::opposite( dir ) : dir; + bridgehead_points.emplace_back( bp, ramp_facing ); + } + } + // Put bridge points + for( const point_om_omt &bp : bridge_points ) { + tripoint_om_omt p( bp, 0 ); + const std::string &rot_sfx = oter_get_rotation_string( om.ter( p ) ); + om.ter_set( p + tripoint_above, oter_id( bridge_overpass_id + rot_sfx ) ); + om.ter_set( p, oter_id( bridge_under_id + rot_sfx ) ); + } + // Put bridgeheads + for( const std::pair &bhp : bridgehead_points ) { + tripoint_om_omt p( bhp.first, 0 ); + const std::string &dir_suffix = om_direction::all_suffixes[static_cast( bhp.second )]; + om.ter_set( p, oter_id( bridgehead_ground_id + dir_suffix ) ); + om.ter_set( p + tripoint_above, oter_id( bridgehead_ramp_id + dir_suffix ) ); + } +} + bool overmap::generate_over( const int z ) { bool requires_over = false; @@ -1944,46 +1989,17 @@ bool overmap::generate_over( const int z ) } if( is_ot_match( "bridge", oter_ground, ot_match_type::type ) ) { - ter_set( p, oter_id( "bridge_road" + oter_get_rotation_string( oter_ground ) ) ); - ter_set( p_below, oter_id( "bridge_under" + oter_get_rotation_string( oter_ground ) ) ); bridge_points.emplace_back( i, j ); } } } } - // Check and put bridgeheads - std::vector> bridgehead_points; - for( const point_om_omt &bp : bridge_points ) { - tripoint_om_omt bp_om( bp, 0 ); - const oter_id oter_ground_north = ter( bp_om + tripoint_north ); - const oter_id oter_ground_south = ter( bp_om + tripoint_south ); - const oter_id oter_ground_east = ter( bp_om + tripoint_east ); - const oter_id oter_ground_west = ter( bp_om + tripoint_west ); - const bool is_bridge_north = is_ot_match( "bridge_under", oter_ground_north, ot_match_type::type ); - const bool is_bridge_south = is_ot_match( "bridge_under", oter_ground_south, ot_match_type::type ); - const bool is_bridge_east = is_ot_match( "bridge_under", oter_ground_east, ot_match_type::type ); - const bool is_bridge_west = is_ot_match( "bridge_under", oter_ground_west, ot_match_type::type ); - - if( is_bridge_north ^ is_bridge_south || is_bridge_east ^ is_bridge_west ) { - std::string ramp_facing; - if( is_bridge_north ) { - ramp_facing = "_south"; - } else if( is_bridge_south ) { - ramp_facing = "_north"; - } else if( is_bridge_east ) { - ramp_facing = "_west"; - } else { - ramp_facing = "_east"; - } - bridgehead_points.emplace_back( bp, ramp_facing ); - } - } - for( const std::pair &bhp : bridgehead_points ) { - tripoint_om_omt p( bhp.first, 0 ); - ter_set( p, oter_id( "bridgehead_ground" + bhp.second ) ); - ter_set( p + tripoint_above, oter_id( "bridgehead_ramp" + bhp.second ) ); - } + elevate_bridges( *this, bridge_points, + "bridge_road", + "bridge_under", + "bridgehead_ground", + "bridgehead_ramp" ); return requires_over; } @@ -4935,44 +4951,33 @@ std::string oter_no_dir( const oter_id &oter ) return base_oter_id; } -int oter_get_rotation( const oter_id &oter ) +om_direction::type oter_get_rotation_dir( const oter_id &oter ) { - std::string base_oter_id = oter.id().c_str(); - size_t oter_len = base_oter_id.size(); - if( oter_len > 7 ) { - if( base_oter_id.substr( oter_len - 6, 6 ) == "_south" ) { - return 2; - } else if( base_oter_id.substr( oter_len - 6, 6 ) == "_north" ) { - return 0; - } - } - if( oter_len > 6 ) { - if( base_oter_id.substr( oter_len - 5, 5 ) == "_west" ) { - return 1; - } else if( base_oter_id.substr( oter_len - 5, 5 ) == "_east" ) { - return 3; + for( const om_direction::type &rot : om_direction::all ) { + const std::string &rot_s = om_direction::all_suffixes[static_cast( rot )]; + if( string_ends_with( oter.id().str(), rot_s ) ) { + return rot; } } - return 0; + return om_direction::type::invalid; } -std::string oter_get_rotation_string( const oter_id &oter ) +int oter_get_rotations( const oter_id &oter ) { - std::string base_oter_id = oter.id().c_str(); - size_t oter_len = base_oter_id.size(); - if( oter_len > 7 ) { - if( base_oter_id.substr( oter_len - 6, 6 ) == "_south" ) { - return "_south"; - } else if( base_oter_id.substr( oter_len - 6, 6 ) == "_north" ) { - return "_north"; - } + om_direction::type rot = oter_get_rotation_dir( oter ); + if( rot == om_direction::type::invalid ) { + rot = om_direction::type::none; } - if( oter_len > 6 ) { - if( base_oter_id.substr( oter_len - 5, 5 ) == "_west" ) { - return "_west"; - } else if( base_oter_id.substr( oter_len - 5, 5 ) == "_east" ) { - return "_east"; - } + return om_direction::get_num_cw_rotations( rot ); +} + +const std::string &oter_get_rotation_string( const oter_id &oter ) +{ + om_direction::type rot = oter_get_rotation_dir( oter ); + if( rot == om_direction::type::invalid ) { + static const std::string ret_invalid; + return ret_invalid; + } else { + return om_direction::get_suffix( rot ); } - return ""; } diff --git a/src/overmap.h b/src/overmap.h index 229d0c1c7d60..8a095c349b6b 100644 --- a/src/overmap.h +++ b/src/overmap.h @@ -572,13 +572,19 @@ om_special_sectors get_sectors( int sector_width ); std::string oter_no_dir( const oter_id &oter ); /** -* Return 0, 1, 2, 3 respectively if the suffix is _north, _west, _south, _east -* Return 0 if there's no suffix + * Returns oter rotation direction value. + */ +om_direction::type oter_get_rotation_dir( const oter_id &oter ); + +/** +* Returns number of clockwise rotations 0, 1, 2, 3 respectively +* if the suffix is _north, _east, _south, _west. +* Returns 0 if there's no suffix. */ -int oter_get_rotation( const oter_id &oter ); +int oter_get_rotations( const oter_id &oter ); /** -* Return the directional suffix or "" if there isn't one. +* Returns the directional suffix or "" if there isn't one. */ -std::string oter_get_rotation_string( const oter_id &oter ); +const std::string &oter_get_rotation_string( const oter_id &oter ); #endif // CATA_SRC_OVERMAP_H From 277ca67f640a9966f89644bb37f7ab005dc630ee Mon Sep 17 00:00:00 2001 From: Olanti Date: Sun, 26 Jun 2022 01:59:56 +0300 Subject: [PATCH 2/3] Tidy --- src/basecamp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/basecamp.cpp b/src/basecamp.cpp index 66dcdf78aa7e..af28336d1379 100644 --- a/src/basecamp.cpp +++ b/src/basecamp.cpp @@ -193,7 +193,7 @@ void basecamp::define_camp( const tripoint_abs_omt &p, const std::string &camp_t e.cur_level = -1; e.pos = omt_pos; expansions[base_camps::base_dir] = e; - const std::string direction = oter_get_rotation_string( omt_ref ); + const std::string &direction = oter_get_rotation_string( omt_ref ); const oter_id bcid( direction.empty() ? "faction_base_camp_0" : "faction_base_camp_new_0" + direction ); overmap_buffer.ter_set( omt_pos, bcid ); From f23370561d1d21dd7b58ddf88d308c9dacfbfb69 Mon Sep 17 00:00:00 2001 From: Olanti Date: Sat, 2 Jul 2022 13:40:58 +0300 Subject: [PATCH 3/3] Changes per review --- src/omdata.h | 14 ++++++++++++-- src/overmap.cpp | 17 ++++------------- src/overmap.h | 2 ++ src/string_utils.h | 8 ++++++++ 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/omdata.h b/src/omdata.h index fe088f3a4fd9..c7164f971aaf 100644 --- a/src/omdata.h +++ b/src/omdata.h @@ -62,18 +62,28 @@ const std::array all = {{ type::north, type::east, type::south, type::w const size_t size = all.size(); const std::array all_suffixes = {{ "_north", "_east", "_south", "_west" }}; +const std::string invalid_dir_suffix; const std::array all_cw_rotations = {{ 0, 1, 2, 3 }}; +const int invalid_dir_rotations = 0; /** Returns directional suffix associated with the value, e.g. _north or _west. */ constexpr const std::string &get_suffix( type dir ) { - return all_suffixes[static_cast( dir )]; + if( dir == type::invalid ) { + return invalid_dir_suffix; + } else { + return all_suffixes[static_cast( dir )]; + } } /** Returns number of clockwise rotations needed to reach this direction from 'north'. */ constexpr int get_num_cw_rotations( type dir ) { - return all_cw_rotations[static_cast( dir )]; + if( dir == type::invalid ) { + return invalid_dir_rotations; + } else { + return all_cw_rotations[static_cast( dir )]; + } } /** Number of bits needed to store directions. */ diff --git a/src/overmap.cpp b/src/overmap.cpp index 9e1d806fa31f..83d991055f01 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -1933,6 +1933,7 @@ static void elevate_bridges( const om_direction::type dir = oter_get_rotation_dir( ot_here ); if( dir == om_direction::type::invalid ) { // Shouldn't happen + debugmsg( "Potential bridgehead %s at %s has invalid rotation.", ot_here.id(), bp_om.to_string() ); continue; } point vec = om_direction::displace( dir ); @@ -4954,7 +4955,7 @@ std::string oter_no_dir( const oter_id &oter ) om_direction::type oter_get_rotation_dir( const oter_id &oter ) { for( const om_direction::type &rot : om_direction::all ) { - const std::string &rot_s = om_direction::all_suffixes[static_cast( rot )]; + const std::string &rot_s = om_direction::get_suffix( rot ); if( string_ends_with( oter.id().str(), rot_s ) ) { return rot; } @@ -4964,20 +4965,10 @@ om_direction::type oter_get_rotation_dir( const oter_id &oter ) int oter_get_rotations( const oter_id &oter ) { - om_direction::type rot = oter_get_rotation_dir( oter ); - if( rot == om_direction::type::invalid ) { - rot = om_direction::type::none; - } - return om_direction::get_num_cw_rotations( rot ); + return om_direction::get_num_cw_rotations( oter_get_rotation_dir( oter ) ); } const std::string &oter_get_rotation_string( const oter_id &oter ) { - om_direction::type rot = oter_get_rotation_dir( oter ); - if( rot == om_direction::type::invalid ) { - static const std::string ret_invalid; - return ret_invalid; - } else { - return om_direction::get_suffix( rot ); - } + return om_direction::get_suffix( oter_get_rotation_dir( oter ) ); } diff --git a/src/overmap.h b/src/overmap.h index 8a095c349b6b..377d74da58a9 100644 --- a/src/overmap.h +++ b/src/overmap.h @@ -585,6 +585,8 @@ int oter_get_rotations( const oter_id &oter ); /** * Returns the directional suffix or "" if there isn't one. +* +* Returned reference is kept alive during the whole program execution. */ const std::string &oter_get_rotation_string( const oter_id &oter ); #endif // CATA_SRC_OVERMAP_H diff --git a/src/string_utils.h b/src/string_utils.h index 0628922ad77b..aef9ab73dc6c 100644 --- a/src/string_utils.h +++ b/src/string_utils.h @@ -41,6 +41,8 @@ bool match_include_exclude( const std::string &text, std::string filter ); /** * \brief Returns true if s1 starts with s2 + * + * TODO: Switch to starts_with method of std::string when we move to C++20 */ bool string_starts_with( const std::string &s1, const std::string &s2 ); @@ -48,6 +50,8 @@ bool string_starts_with( const std::string &s1, const std::string &s2 ); * Returns true if s1 starts with s2. * This version accepts constant string literals and is ≈1.5 times faster than std::string version. * Note: N is (size+1) for null-terminated strings. + * + * TODO: Maybe switch to std::string::starts_with + std::string_view when we move to C++20 */ template inline bool string_starts_with( const std::string &s1, const char( &s2 )[N] ) @@ -57,6 +61,8 @@ inline bool string_starts_with( const std::string &s1, const char( &s2 )[N] ) /** * \brief Returns true if s1 ends with s2 + * + * TODO: Switch to ends_with method of std::string when we move to C++20 */ bool string_ends_with( const std::string &s1, const std::string &s2 ); @@ -64,6 +70,8 @@ bool string_ends_with( const std::string &s1, const std::string &s2 ); * Returns true iff s1 ends with s2. * This version accepts constant string literals and is ≈1.5 times faster than std::string version. * Note: N is (size+1) for null-terminated strings. + * + * TODO: Maybe switch to std::string::ends_with + std::string_view when we move to C++20 */ template inline bool string_ends_with( const std::string &s1, const char( &s2 )[N] )