diff --git a/src/output.cpp b/src/output.cpp index 9797bf8f664c6..f6d340d5c6a66 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -61,8 +61,6 @@ int OVERMAP_WINDOW_TERM_HEIGHT; int OVERMAP_LEGEND_WIDTH; -static std::string rm_prefix( std::string str, char c1 = '<', char c2 = '>' ); - scrollingcombattext SCT; // utf8 version @@ -162,9 +160,9 @@ std::string remove_color_tags( const std::string &s ) return ret; } -static color_tag_parse_result::tag_type update_color_stack( +color_tag_parse_result::tag_type update_color_stack( std::stack &color_stack, const std::string &seg, - const report_color_error color_error = report_color_error::yes ) + const report_color_error color_error ) { color_tag_parse_result tag = get_color_from_tag( seg, color_error ); switch( tag.type ) { diff --git a/src/output.h b/src/output.h index aabed23bdf32b..6a6b1108833a5 100644 --- a/src/output.h +++ b/src/output.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -199,8 +200,21 @@ nc_color msgtype_to_color( game_message_type type, bool bOldMsg = false ); * color tags. For example `utf8_width("text")` would return 23, but * `utf8_width("text", true)` returns 4 (the length of "text"). */ - /*@{*/ + +/** + * Removes the prefix starting at the first occurrence of c1 until the first occurrence of c2 + */ +std::string rm_prefix( std::string str, char c1 = '<', char c2 = '>' ); + +/** + * Adds the color represented by the next color tag found in the string to the top of the stack. + * If color_error == report_color_error::yes a debugmsg will be shown when the tag is not valid. + */ +color_tag_parse_result::tag_type update_color_stack( + std::stack &color_stack, const std::string &seg, + const report_color_error color_error = report_color_error::yes ); + /** * Removes the color tags from the input string. This might be required when the string is to * be used for functions that don't handle color tags. diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index 0a375abb828c4..bafe65d3c21c2 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -617,10 +617,10 @@ static void draw_ascii( std::vector path_route; std::vector player_path_route; std::unordered_map npc_color; + auto npcs_near_player = overmap_buffer.get_npcs_near_player( sight_points ); if( blink ) { // get seen NPCs - const auto &npcs = overmap_buffer.get_npcs_near_player( sight_points ); - for( const auto &np : npcs ) { + for( const auto &np : npcs_near_player ) { if( np->posz() != center.z() ) { continue; } @@ -900,9 +900,11 @@ static void draw_ascii( } } - for( const auto &npc : overmap_buffer.get_npcs_near_omt( center, 0 ) ) { - if( !npc->marked_for_death ) { - corner_text.emplace_back( npc->basic_symbol_color(), npc->name ); + if( has_debug_vision || overmap_buffer.seen( center ) ) { + for( const auto &npc : npcs_near_player ) { + if( !npc->marked_for_death && npc->global_omt_location() == center ) { + corner_text.emplace_back( npc->basic_symbol_color(), npc->name ); + } } } diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index 8a0d109937d8b..56fb5fc866e66 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -698,7 +699,8 @@ static cata::optional> get_mission_arro return std::make_pair( mission_target, mission_arrow_variant ); } - const std::vector mission_trajectory = line_to( center.raw(), mission_target.raw() ); + const std::vector mission_trajectory = line_to( center.raw(), + tripoint( mission_target.raw().xy(), center.raw().z ) ); cata::optional prev; int z = 0; @@ -804,6 +806,24 @@ std::string cata_tiles::get_omt_id_rotation_and_subtile( return ot_type_id.id().str(); } +static point draw_string( Font &font, + const SDL_Renderer_Ptr &renderer, + const GeometryRenderer_Ptr &geometry, + const std::string &str, + point p, + const unsigned char color ) +{ + const char *cstr = str.c_str(); + int len = str.length(); + while( len > 0 ) { + const uint32_t ch32 = UTF8_getch( &cstr, &len ); + const std::string ch = utf32_to_utf8( ch32 ); + font.OutputChar( renderer, geometry, ch, p, color ); + p.x += mk_wcwidth( ch32 ) * font.width; + } + return p; +} + void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt ¢er_abs_omt, bool blink ) { if( !g ) { @@ -831,10 +851,6 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt ¢er_abs_ geometry->rect( renderer, clipRect, SDL_Color() ); } - // color blocks overlay; drawn on top of tiles and on top of overlay strings (if any). - color_block_overlay_container color_blocks; - // Strings with colors do be drawn with map_font on top of tiles. - std::multimap overlay_strings; point s; get_window_tile_counts( width, height, s.x, s.y ); @@ -1007,10 +1023,12 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt ¢er_abs_ } } + auto npcs_near_player = overmap_buffer.get_npcs_near_player( sight_points ); + // draw nearby seen npcs - for( const shared_ptr_fast &guy : overmap_buffer.get_npcs_near_player( sight_points ) ) { + for( const shared_ptr_fast &guy : npcs_near_player ) { const tripoint_abs_omt &guy_loc = guy->global_omt_location(); - if( overmap_buffer.seen( guy_loc ) ) { + if( guy_loc.z() == center_abs_omt.z() && ( has_debug_vision || overmap_buffer.seen( guy_loc ) ) ) { draw_entity_with_overlays( *guy, global_omt_to_draw_position( guy_loc ), lit_level::LIT, height_3d ); } @@ -1022,6 +1040,13 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt ¢er_abs_ false ); if( blink ) { + // Draw path for auto-travel + for( auto &elem : you.omt_path ) { + tripoint_abs_omt pos( elem.xy(), you.posz() ); + draw_from_id_string( "highlight", global_omt_to_draw_position( pos ), 0, 0, lit_level::LIT, + false ); + } + // reduce the area where the map cursor is drawn so it doesn't get cut off inclusive_cuboid map_cursor_area = overmap_area; map_cursor_area.p_max.y--; @@ -1033,30 +1058,28 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt ¢er_abs_ } } - // Labels need to be drawn last, as anything that attempts to draw a sprite after will fail. if( !viewing_weather && uistate.overmap_show_city_labels ) { const auto abs_sm_to_draw_label = [&]( const tripoint_abs_sm & city_pos, const int label_length ) { const tripoint tile_draw_pos = global_omt_to_draw_position( project_to ( city_pos ) ) - o; - point draw_point( tile_draw_pos.x * width / max_col, tile_draw_pos.y * height / max_row ); - draw_point.x -= label_length * font->width; - draw_point.x += width / max_col; + point draw_point( tile_draw_pos.x * tile_width + dest.x, + tile_draw_pos.y * tile_height + dest.y ); + // center text on the tile + draw_point += point( ( tile_width - label_length * fontwidth ) / 2, + ( tile_height - fontheight ) / 2 ); return draw_point; }; // draws a black rectangle behind a label for visibility and legibility const auto label_bg = [&]( const tripoint_abs_sm & pos, const std::string & name ) { - const int name_length = name.length(); + const int name_length = utf8_width( name ); const point draw_pos = abs_sm_to_draw_label( pos, name_length ); SDL_Rect clipRect = { draw_pos.x, draw_pos.y, name_length * fontwidth, fontheight }; - printErrorIf( SDL_RenderSetClipRect( renderer.get(), &clipRect ) != 0, - "SDL_RenderSetClipRect failed" ); geometry->rect( renderer, clipRect, SDL_Color() ); - const point label_pos( draw_pos + point( -( name.length() * fontwidth / 2 ), 0 ) ); - map_font->OutputChar( renderer, geometry, name, label_pos, 11 ); + draw_string( *font, renderer, geometry, name, draw_pos, 11 ); }; // the tiles on the overmap are overmap tiles, so we need to use @@ -1080,6 +1103,119 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt ¢er_abs_ } } } + + std::vector> notes_window_text; + + if( uistate.overmap_show_map_notes ) { + const std::string ¬e_text = overmap_buffer.note( center_abs_omt ); + if( !note_text.empty() ) { + const std::tuple note_info = overmap_ui::get_note_display_info( + note_text ); + const size_t pos = std::get<2>( note_info ); + if( pos != std::string::npos ) { + notes_window_text.emplace_back( std::get<1>( note_info ), note_text.substr( pos ) ); + } + if( overmap_buffer.is_marked_dangerous( center_abs_omt ) ) { + notes_window_text.emplace_back( c_red, _( "DANGEROUS AREA!" ) ); + } + } + } + + if( has_debug_vision || overmap_buffer.seen( center_abs_omt ) ) { + for( const auto &npc : npcs_near_player ) { + if( !npc->marked_for_death && npc->global_omt_location() == center_abs_omt ) { + notes_window_text.emplace_back( npc->basic_symbol_color(), npc->name ); + } + } + } + + for( auto &v : overmap_buffer.get_vehicle( center_abs_omt ) ) { + notes_window_text.emplace_back( c_white, v.name ); + } + + if( !notes_window_text.empty() ) { + constexpr int padding = 2; + + const auto draw_note_text = [&]( const point & draw_pos, const std::string & name, + nc_color & color ) { + char note_fg_color = color == c_yellow ? 11 : + cata_cursesport::colorpairs[color.to_color_pair_index()].FG; + return draw_string( *font, renderer, geometry, name, draw_pos, note_fg_color ); + }; + + // Find screen coordinates to the right of the center tile + auto center_sm = coords::project_to( tripoint_abs_omt( center_abs_omt.x() + 1, + center_abs_omt.y(), center_abs_omt.z() ) ); + const tripoint tile_draw_pos = global_omt_to_draw_position( project_to + ( center_sm ) ) - o; + point draw_point( tile_draw_pos.x * tile_width + dest.x, + tile_draw_pos.y * tile_height + dest.y ); + draw_point += point( padding, padding ); + + // Draw notes header. Very simple label at the moment + nc_color header_color = c_white; + const std::string header_string = _( "-- Notes: --" ); + SDL_Rect header_background_rect = { + draw_point.x - padding, + draw_point.y - padding, + fontwidth * utf8_width( header_string ) + padding * 2, + fontheight + padding * 2 + }; + geometry->rect( renderer, header_background_rect, SDL_Color{ 0, 0, 0, 175 } ); + draw_note_text( draw_point, header_string, header_color ); + draw_point.y += fontheight + padding * 2; + + const int starting_x = draw_point.x; + + for( auto &line : notes_window_text ) { + const auto color_segments = split_by_color( line.second ); + std::stack color_stack; + nc_color default_color = std::get<0>( line ); + color_stack.push( default_color ); + std::vector> colored_lines; + + draw_point.x = starting_x; + + int line_length = 0; + for( auto seg : color_segments ) { + if( seg.empty() ) { + continue; + } + + if( seg[0] == '<' ) { + const color_tag_parse_result::tag_type type = update_color_stack( + color_stack, seg, report_color_error::no ); + if( type != color_tag_parse_result::non_color_tag ) { + seg = rm_prefix( seg ); + } + } + + nc_color &color = color_stack.empty() ? default_color : color_stack.top(); + colored_lines.emplace_back( color, seg ); + line_length += utf8_width( seg ); + } + + // Draw background first for the whole line + SDL_Rect background_rect = { + draw_point.x - padding, + draw_point.y - padding, + fontwidth *line_length + padding * 2, + fontheight + padding * 2 + }; + geometry->rect( renderer, background_rect, SDL_Color{ 0, 0, 0, 175 } ); + + // Draw colored text segments + for( auto &colored_line : colored_lines ) { + std::string &text = std::get<1>( colored_line ); + draw_point.x = draw_note_text( draw_point, text, std::get<0>( colored_line ) ).x; + } + + draw_point.y += fontheight + padding; + } + } + + printErrorIf( SDL_RenderSetClipRect( renderer.get(), nullptr ) != 0, + "SDL_RenderSetClipRect failed" ); } static bool draw_window( Font_Ptr &font, const catacurses::window &w, const point &offset ) @@ -2307,6 +2443,7 @@ void draw_quick_shortcuts() text_x = ( ( i + 0.5f ) * width - ( font->width * utf8_width( text ) ) * text_scale * 0.5f ) / text_scale; } + // TODO use draw_string instead text_y = ( WindowHeight - ( height + font->height * text_scale ) * 0.5f ) / text_scale; font->OutputChar( renderer, geometry, text, point( text_x + 1, text_y + 1 ), 0, get_option( "ANDROID_SHORTCUT_OPACITY_SHADOW" ) * 0.01f );