diff --git a/src/input_context.cpp b/src/input_context.cpp index b0be192c505f2..927363df459bd 100644 --- a/src/input_context.cpp +++ b/src/input_context.cpp @@ -1222,6 +1222,17 @@ std::optional input_context::get_coordinates( const catacurses: } #endif +std::optional input_context::get_coordinates_rel_omt( const catacurses::window + &capture_win, const point &offset, const bool center_cursor ) const +{ + // Sometimes off by one with tiles but I think that's due to the centre changing with zoom level + tileset size so I don't think it can be easily fixed here + const std::optional p = get_coordinates( capture_win, offset, center_cursor ); + if( p ) { + return tripoint_rel_omt( p->raw() ); + } + return std::nullopt; +} + std::optional input_context::get_coordinates_text( const catacurses::window &capture_win ) const { diff --git a/src/input_context.h b/src/input_context.h index 2520b1a47da1d..c97b38b253d0b 100644 --- a/src/input_context.h +++ b/src/input_context.h @@ -307,6 +307,8 @@ class input_context */ std::optional get_coordinates( const catacurses::window &capture_win_, const point &offset = point::zero, bool center_cursor = false ) const; + std::optional get_coordinates_rel_omt( const catacurses::window &capture_win_, + const point &offset = point::zero, bool center_cursor = false ) const; // Below here are shortcuts for registering common key combinations. void register_directions(); diff --git a/src/map.cpp b/src/map.cpp index 33a3b870386e1..25a4afc8b7535 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -8596,7 +8596,7 @@ ter_str_id uniform_terrain( const oter_id &oter ) // Does not create or require a temporary map and does its own saving bool generate_uniform( const tripoint_abs_sm &p, const ter_str_id &ter ) { - if( MAPBUFFER.lookup_submap( p ) ) { + if( MAPBUFFER.submap_exists( p ) ) { return false; } @@ -8646,7 +8646,7 @@ void map::loadn( const point_bub_sm &grid, bool update_vehicles ) for( int gridy = 0; gridy <= 1; gridy++ ) { for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { const tripoint grid_pos( gridx, gridy, gridz ); - if( MAPBUFFER.lookup_submap( grid_sm_base.xy() + grid_pos ) == nullptr ) { + if( !MAPBUFFER.submap_exists( grid_sm_base.xy() + grid_pos ) ) { map_incomplete = true; break; } @@ -8662,8 +8662,7 @@ void map::loadn( const point_bub_sm &grid, bool update_vehicles ) for( int gridz = -OVERMAP_DEPTH; gridz <= OVERMAP_HEIGHT; gridz++ ) { const tripoint_abs_sm pos = {grid_sm_base.xy(), gridz }; - submap *tmpsub = MAPBUFFER.lookup_submap( pos ); - if( tmpsub == nullptr ) { + if( !MAPBUFFER.submap_exists( pos ) ) { dbg( D_ERROR ) << "failed to generate a submap at " << pos; debugmsg( "failed to generate a submap at %s", pos.to_string() ); return; diff --git a/src/mapbuffer.cpp b/src/mapbuffer.cpp index dfb62798e4691..6a5e7a5d9bd32 100644 --- a/src/mapbuffer.cpp +++ b/src/mapbuffer.cpp @@ -121,6 +121,7 @@ submap *mapbuffer::lookup_submap( const tripoint_abs_sm &p ) bool mapbuffer::submap_exists( const tripoint_abs_sm &p ) { + // Could so with a second check against a std::unordered_set of already checked existing but not loaded submaps before resorting to unserializing? const auto iter = submaps.find( p ); if( iter == submaps.end() ) { try { @@ -134,6 +135,24 @@ bool mapbuffer::submap_exists( const tripoint_abs_sm &p ) return true; } +bool mapbuffer::submap_exists_approx( const tripoint_abs_sm &p ) +{ + const auto iter = submaps.find( p ); + if( iter == submaps.end() ) { + try { + const tripoint_abs_omt om_addr = project_to( p ); + const cata_path dirname = find_dirname( om_addr ); + cata_path quad_path = find_quad_path( dirname, om_addr ); + return file_exist( quad_path ); + } catch( const std::exception &err ) { + debugmsg( "Failed to load submap %s: %s", p.to_string(), err.what() ); + } + return false; + } + + return true; +} + void mapbuffer::save( bool delete_after_save ) { assure_dir_exist( PATH_INFO::world_base_save_path() / "maps" ); diff --git a/src/mapbuffer.h b/src/mapbuffer.h index 8ab0f5696ca72..7c748f94f9a71 100644 --- a/src/mapbuffer.h +++ b/src/mapbuffer.h @@ -65,6 +65,8 @@ class mapbuffer // Cheaper version of the above for when you only care about whether the // submap exists or not. bool submap_exists( const tripoint_abs_sm &p ); + // Cheaper version of the above for when you don't mind some false results + bool submap_exists_approx( const tripoint_abs_sm &p ); private: using submap_map_t = std::map>; @@ -82,6 +84,7 @@ class mapbuffer // if not handled carefully, this can erase in-use submaps and crash the game. void remove_submap( const tripoint_abs_sm &addr ); submap *unserialize_submaps( const tripoint_abs_sm &p ); + bool submap_file_exists( const tripoint_abs_sm &p ); void deserialize( const JsonArray &ja ); void save_quad( const cata_path &dirname, const cata_path &filename, diff --git a/src/npctalk.cpp b/src/npctalk.cpp index b7a23d982f11c..d07b6a4acea75 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -4457,18 +4457,17 @@ talk_effect_fun_t::func f_revert_location( const JsonObject &jo, std::string_vie // maptile is 4 submaps so queue up 4 submap reverts const tripoint_abs_sm revert_sm_base = project_to( omt_pos ); + if( !MAPBUFFER.submap_exists( revert_sm_base ) ) { + tinymap tm; + // This creates the submaps if they didn't already exist. + // Note that all four submaps are loaded/created by this + // call, so the submap lookup can fail at most once. + tm.load( omt_pos, true ); + } for( int x = 0; x < 2; x++ ) { for( int y = 0; y < 2; y++ ) { const tripoint_abs_sm revert_sm = revert_sm_base + point( x, y ); submap *sm = MAPBUFFER.lookup_submap( revert_sm ); - if( sm == nullptr ) { - tinymap tm; - // This creates the submaps if they didn't already exist. - // Note that all four submaps are loaded/created by this - // call, so the submap lookup can fail at most once. - tm.load( omt_pos, true ); - sm = MAPBUFFER.lookup_submap( revert_sm ); - } get_timed_events().add( timed_event_type::REVERT_SUBMAP, tif, -1, project_to( revert_sm ), 0, "", sm->get_revert_submap(), key.evaluate( d ) ); diff --git a/src/overmap.cpp b/src/overmap.cpp index e336a99ff8728..ec2fa40233104 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -7755,9 +7755,7 @@ bool overmap::is_omt_generated( const tripoint_om_omt &loc ) const tripoint_abs_sm global_sm_loc = project_to( project_combine( pos(), loc ) ); - const bool is_generated = MAPBUFFER.lookup_submap( global_sm_loc ) != nullptr; - - return is_generated; + return MAPBUFFER.submap_exists( global_sm_loc ); } overmap_special_id overmap_specials::create_building_from( const string_id &base ) diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index 9eeed620ec0f0..9e7574efb3bc1 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -543,8 +543,19 @@ static bool get_and_assign_los( int &los, avatar &player_character, const tripoi return los; } -static void draw_ascii( - const catacurses::window &w, overmap_draw_data_t &data ) +static std::unordered_map generated_omts; + +bool is_generated_omt( const point_abs_omt &omp ) +{ + if( const auto it = generated_omts.find( omp ); it != generated_omts.end() ) { + return it->second; + } + const bool generated = MAPBUFFER.submap_exists_approx( { project_to( omp ), 0 } ); + generated_omts.insert( { omp, generated } ); + return generated; +} + +static void draw_ascii( const catacurses::window &w, overmap_draw_data_t &data ) { const tripoint_abs_omt &orig = data.origin_pos; const tripoint_abs_omt &cursor_pos = data.cursor_pos; @@ -796,7 +807,7 @@ static void draw_ascii( } } // Highlight areas that already have been generated - if( MAPBUFFER.lookup_submap( project_to( omp ) ) ) { + if( is_generated_omt( omp.xy() ) ) { ter_color = red_background( ter_color ); } } @@ -1508,6 +1519,9 @@ static void place_ter_or_special( const ui_adaptor &om_ui, tripoint_abs_omt &cur input_context ctxt( "OVERMAP_EDITOR" ); ctxt.register_directions(); + ctxt.register_action( "SELECT" ); + ctxt.register_action( "LEVEL_UP" ); + ctxt.register_action( "LEVEL_DOWN" ); ctxt.register_action( "zoom_in" ); ctxt.register_action( "zoom_out" ); ctxt.register_action( "CONFIRM" ); @@ -1558,14 +1572,14 @@ static void place_ter_or_special( const ui_adaptor &om_ui, tripoint_abs_omt &cur _( "Highlighted regions already have map content generated. Their overmap id will change, but not their contents." ) ); if( ( terrain && uistate.place_terrain->is_rotatable() ) || ( !terrain && uistate.place_special->is_rotatable() ) ) { - mvwprintz( w_editor, point( 1, 11 ), c_white, _( "[%s] Rotate" ), + mvwprintz( w_editor, point( 1, 10 ), c_white, _( "[%s] Rotate" ), ctxt.get_desc( "ROTATE" ) ); } - mvwprintz( w_editor, point( 1, 12 ), c_white, _( "[%s] Place" ), + mvwprintz( w_editor, point( 1, 11 ), c_white, _( "[%s] Place" ), ctxt.get_desc( "CONFIRM_MULTIPLE" ) ); - mvwprintz( w_editor, point( 1, 13 ), c_white, _( "[%s] Place and close" ), + mvwprintz( w_editor, point( 1, 12 ), c_white, _( "[%s] Place and close" ), ctxt.get_desc( "CONFIRM" ) ); - mvwprintz( w_editor, point( 1, 14 ), c_white, _( "[ESCAPE/Q] Cancel" ) ); + mvwprintz( w_editor, point( 1, 13 ), c_white, _( "[ESCAPE/Q] Cancel" ) ); wnoutrefresh( w_editor ); } ); @@ -1576,8 +1590,17 @@ static void place_ter_or_special( const ui_adaptor &om_ui, tripoint_abs_omt &cur action = ctxt.handle_input( get_option( "BLINK_SPEED" ) ); - if( const std::optional vec = ctxt.get_direction( action ) ) { - curs += vec->xy(); + if( const std::optional vec = ctxt.get_direction_rel_omt( action ) ) { + curs += *vec; + } else if( action == "LEVEL_DOWN" && curs.z() > -OVERMAP_DEPTH ) { + curs.z()--; + } else if( action == "LEVEL_UP" && curs.z() < OVERMAP_HEIGHT ) { + curs.z()++; + } else if( action == "SELECT" ) { + if( std::optional mouse_pos = ctxt.get_coordinates_rel_omt( g->w_overmap, + point::zero, true ); mouse_pos ) { + curs = curs + mouse_pos->xy(); + } } else if( action == "zoom_out" ) { g->zoom_out_overmap(); om_ui.mark_resize(); @@ -1597,9 +1620,6 @@ static void place_ter_or_special( const ui_adaptor &om_ui, tripoint_abs_omt &cur } } } - if( action == "CONFIRM" ) { - break; - } } else if( action == "ROTATE" && can_rotate ) { uistate.omedit_rotation = om_direction::turn_right( uistate.omedit_rotation ); if( terrain ) { @@ -1609,7 +1629,7 @@ static void place_ter_or_special( const ui_adaptor &om_ui, tripoint_abs_omt &cur if( uistate.overmap_blinking ) { uistate.overmap_show_overlays = !uistate.overmap_show_overlays; } - } while( action != "QUIT" ); + } while( action != "CONFIRM" && action != "QUIT" ); uistate.place_terrain = nullptr; uistate.place_special = nullptr; @@ -1945,7 +1965,7 @@ static tripoint_abs_omt display() std::string action; data.show_explored = true; int fast_scroll_offset = get_option( "FAST_SCROLL_OFFSET" ); - std::optional mouse_pos; + std::optional mouse_pos; std::chrono::time_point last_blink = std::chrono::steady_clock::now(); std::chrono::time_point last_advance = std::chrono::steady_clock::now(); auto display_path_iter = display_path.rbegin(); @@ -2000,7 +2020,7 @@ static tripoint_abs_omt display() curs += edge_scroll; } } else if( action == "SELECT" && - ( mouse_pos = ictxt.get_coordinates( g->w_overmap, point::zero, true ) ) ) { + ( mouse_pos = ictxt.get_coordinates_rel_omt( g->w_overmap, point::zero, true ) ) ) { curs += mouse_pos->xy().raw(); } else if( action == "look" ) { tripoint_abs_ms pos = project_combine( curs, g->overmap_data.origin_remainder ); @@ -2572,6 +2592,7 @@ std::optional ui::omap::select_city( uilist &cities_menu, void ui::omap::force_quit() { + overmap_ui::generated_omts.clear(); g->overmap_data.ui.reset(); g->overmap_data.fast_traveling = false; } diff --git a/src/overmap_ui.h b/src/overmap_ui.h index ae10d59a05870..63e869750e5d6 100644 --- a/src/overmap_ui.h +++ b/src/overmap_ui.h @@ -154,6 +154,7 @@ extern tiles_redraw_info redraw_info; weather_type_id get_weather_at_point( const tripoint_abs_omt &pos ); std::tuple get_note_display_info( std::string_view note ); +bool is_generated_omt( const point_abs_omt &omp ); } // namespace overmap_ui #endif // CATA_SRC_OVERMAP_UI_H diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index efff97cc498f5..cc9fa46776b41 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -918,11 +918,10 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt ¢er_abs_ } } - if( uistate.place_terrain || uistate.place_special ) { + if( ( uistate.place_terrain || uistate.place_special ) && + overmap_ui::is_generated_omt( omp.xy() ) ) { // Highlight areas that already have been generated - if( MAPBUFFER.lookup_submap( project_to( omp ) ) ) { - draw_from_id_string( "highlight", omp.raw(), 0, 0, lit_level::LIT, false ); - } + draw_from_id_string( "highlight", omp.raw(), 0, 0, lit_level::LIT, false ); } if( draw_overlays && overmap_buffer.has_vehicle( omp ) ) {