Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix graphical overmap notes displays & mission arrow #50190

Merged
merged 14 commits into from
Aug 6, 2021
Merged
6 changes: 2 additions & 4 deletions src/output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<nc_color> &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 ) {
Expand Down
16 changes: 15 additions & 1 deletion src/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <iosfwd>
#include <iterator>
#include <map>
#include <stack>
#include <string>
#include <type_traits>
#include <utility>
Expand Down Expand Up @@ -199,8 +200,21 @@ nc_color msgtype_to_color( game_message_type type, bool bOldMsg = false );
* color tags. For example `utf8_width("<color_red>text</color>")` would return 23, but
* `utf8_width("<color_red>text</color>", 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<nc_color> &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.
Expand Down
12 changes: 7 additions & 5 deletions src/overmap_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,10 +617,10 @@ static void draw_ascii(
std::vector<tripoint_abs_omt> path_route;
std::vector<tripoint_abs_omt> player_path_route;
std::unordered_map<tripoint_abs_omt, npc_coloring> 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;
}
Expand Down Expand Up @@ -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 ) ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this part be moved to a new PR so it can be backported?

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 );
}
}
}

Expand Down
169 changes: 153 additions & 16 deletions src/sdltiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <map>
#include <memory>
#include <set>
#include <stack>
#include <stdexcept>
#include <type_traits>
#include <vector>
Expand Down Expand Up @@ -698,7 +699,8 @@ static cata::optional<std::pair<tripoint_abs_omt, std::string>> get_mission_arro
return std::make_pair( mission_target, mission_arrow_variant );
}

const std::vector<tripoint> mission_trajectory = line_to( center.raw(), mission_target.raw() );
const std::vector<tripoint> mission_trajectory = line_to( center.raw(),
tripoint( mission_target.raw().xy(), center.raw().z ) );

cata::optional<tripoint> prev;
int z = 0;
Expand Down Expand Up @@ -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 &center_abs_omt, bool blink )
{
if( !g ) {
Expand Down Expand Up @@ -831,10 +851,6 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt &center_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<point, formatted_text> overlay_strings;
point s;
get_window_tile_counts( width, height, s.x, s.y );

Expand Down Expand Up @@ -1007,10 +1023,12 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt &center_abs_
}
}

auto npcs_near_player = overmap_buffer.get_npcs_near_player( sight_points );

// draw nearby seen npcs
for( const shared_ptr_fast<npc> &guy : overmap_buffer.get_npcs_near_player( sight_points ) ) {
for( const shared_ptr_fast<npc> &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 );
}
Expand All @@ -1022,6 +1040,13 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt &center_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( "cursor", 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<tripoint> map_cursor_area = overmap_area;
map_cursor_area.p_max.y--;
Expand All @@ -1033,30 +1058,28 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt &center_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<coords::omt>
( 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,
GoLoT marked this conversation as resolved.
Show resolved Hide resolved
"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
Expand All @@ -1080,6 +1103,119 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt &center_abs_
}
}
}

std::vector<std::pair<nc_color, std::string>> notes_window_text;

if( uistate.overmap_show_map_notes ) {
const std::string &note_text = overmap_buffer.note( center_abs_omt );
if( !note_text.empty() ) {
const std::tuple<char, nc_color, size_t> 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<coords::sm>( 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<coords::omt>
( 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 ) {
Copy link
Member

@KorGgenT KorGgenT Aug 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for( auto &line : notes_window_text ) {
for( std::pair<nc_color, std::string> &line : notes_window_text ) {

we generally like to limit our usage of auto.

const auto color_segments = split_by_color( line.second );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const auto color_segments = split_by_color( line.second );
const std::vector<std::string> color_segments = split_by_color( line.second );

as here

std::stack<nc_color> color_stack;
nc_color default_color = std::get<0>( line );
color_stack.push( default_color );
std::vector<std::tuple<nc_color, std::string>> colored_lines;

draw_point.x = starting_x;

int line_length = 0;
for( auto seg : color_segments ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for( auto seg : color_segments ) {
for( std::string seg : color_segments ) {

and here

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 ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for( auto &colored_line : colored_lines ) {
for( std::pair<nc_color, std::string> &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 )
Expand Down Expand Up @@ -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<int>( "ANDROID_SHORTCUT_OPACITY_SHADOW" ) * 0.01f );
Expand Down