Skip to content

Commit

Permalink
Fix graphical overmap notes displays & mission arrow (#50190)
Browse files Browse the repository at this point in the history
* Fix graphical overmap notes display & mission arrow

* Invalidate region to properly refresh overmap windows

* Avoid SDL_RenderSetClipRect() calls

* Draw NPCs only on their Z level

* Add missing SDL_RenderSetClipRect() reset at the end of draw_om()

* Update src/sdltiles.cpp

Co-authored-by: Jianxiang Wang (王健翔) <[email protected]>

* Remove unneeded comment

* Add color tag support to graphical overmap notes

* You didn't see this. Don't make me rebase.

* Remove unused variables

* Fix city label & note position

* Fix NPC notes displaying when NPCs aren't visible

* Change auto-travel path to use higlight instead of cursor sprite

Co-authored-by: Jianxiang Wang (王健翔) <[email protected]>
  • Loading branch information
GoLoT and Qrox authored Aug 6, 2021
1 parent 1a5362d commit 0b250e7
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 26 deletions.
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 ) ) {
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 @@ -701,7 +702,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 @@ -807,6 +809,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 @@ -834,10 +854,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 @@ -1010,10 +1026,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 @@ -1025,6 +1043,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( "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<tripoint> map_cursor_area = overmap_area;
map_cursor_area.p_max.y--;
Expand All @@ -1036,30 +1061,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,
"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 @@ -1083,6 +1106,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 ) {
const auto color_segments = split_by_color( line.second );
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 ) {
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 )
Expand Down Expand Up @@ -2310,6 +2446,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

0 comments on commit 0b250e7

Please sign in to comment.