From 18e7ce1fc91ca79f65b70d7b62d3a92e0231c41e Mon Sep 17 00:00:00 2001 From: ipcyborg Date: Sat, 21 Dec 2019 15:25:23 +0200 Subject: [PATCH 1/2] Extracted `mon_info_update` from `mon_info` to make safe mode work independent of the compass. --- src/game.cpp | 256 ++++++++++++++++++++++++++------------------------- src/game.h | 8 ++ 2 files changed, 139 insertions(+), 125 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 475dab42018f6..8db65d10f37c1 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1540,6 +1540,7 @@ bool game::do_turn() } } update_stair_monsters(); + mon_info_update(); u.process_turn(); if( u.moves < 0 && get_option( "FORCE_REDRAW" ) ) { draw(); @@ -3810,19 +3811,142 @@ void game::mon_info( const catacurses::window &w, int hor_padding ) const int startrow = 0; + // Print the direction headings + // Reminder: + // 7 0 1 unique_types uses these indices; + // 6 8 2 0-7 are provide by direction_from() + // 5 4 3 8 is used for local monsters (for when we explain them below) + + const std::array dir_labels = {{ + _( "North:" ), _( "NE:" ), _( "East:" ), _( "SE:" ), + _( "South:" ), _( "SW:" ), _( "West:" ), _( "NW:" ) + } + }; + std::array widths; + for( int i = 0; i < 8; i++ ) { + widths[i] = utf8_width( dir_labels[i] ); + } + std::array xcoords; + const std::array ycoords = {{ 0, 0, 1, 2, 2, 2, 1, 0 }}; + xcoords[0] = xcoords[4] = width / 3; + xcoords[1] = xcoords[3] = xcoords[2] = ( width / 3 ) * 2; + xcoords[5] = xcoords[6] = xcoords[7] = 0; + //for the alignment of the 1,2,3 rows on the right edge + xcoords[2] -= utf8_width( _( "East:" ) ) - utf8_width( _( "NE:" ) ); + for( int i = 0; i < 8; i++ ) { + nc_color c = unique_types[i].empty() && unique_mons[i].empty() ? c_dark_gray + : ( dangerous[i] ? c_light_red : c_light_gray ); + mvwprintz( w, point( xcoords[i] + hor_padding, ycoords[i] + startrow ), c, dir_labels[i] ); + } + + // Print the symbols of all monsters in all directions. + for( int i = 0; i < 8; i++ ) { + point pr( xcoords[i] + widths[i] + 1, ycoords[i] + startrow ); + + // The list of symbols needs a space on each end. + int symroom = ( width / 3 ) - widths[i] - 2; + const int typeshere_npc = unique_types[i].size(); + const int typeshere_mon = unique_mons[i].size(); + const int typeshere = typeshere_mon + typeshere_npc; + for( int j = 0; j < typeshere && j < symroom; j++ ) { + nc_color c; + std::string sym; + if( symroom < typeshere && j == symroom - 1 ) { + // We've run out of room! + c = c_white; + sym = "+"; + } else if( j < typeshere_npc ) { + switch( unique_types[i][j]->get_attitude() ) { + case NPCATT_KILL: + c = c_red; + break; + case NPCATT_FOLLOW: + c = c_light_green; + break; + default: + c = c_pink; + break; + } + sym = "@"; + } else { + const mtype &mt = *unique_mons[i][j - typeshere_npc]; + c = mt.color; + sym = mt.sym; + } + mvwprintz( w, pr, c, sym ); + + pr.x++; + } + } + + // Now we print their full names! + + std::set listed_mons; + + // Start printing monster names on row 4. Rows 0-2 are for labels, and row 3 + // is blank. + point pr( hor_padding, 4 + startrow ); + + // Print monster names, starting with those at location 8 (nearby). + for( int j = 8; j >= 0 && pr.y < maxheight; j-- ) { + // Separate names by some number of spaces (more for local monsters). + int namesep = ( j == 8 ? 2 : 1 ); + for( const mtype *type : unique_mons[j] ) { + if( pr.y >= maxheight ) { + // no space to print to anyway + break; + } + if( listed_mons.count( type ) > 0 ) { + // this type is already printed. + continue; + } + listed_mons.insert( type ); + + const mtype &mt = *type; + const std::string name = mt.nname(); + + // Move to the next row if necessary. (The +2 is for the "Z "). + if( pr.x + 2 + utf8_width( name ) >= width ) { + pr.y++; + pr.x = hor_padding; + } + + if( pr.y < maxheight ) { // Don't print if we've overflowed + mvwprintz( w, pr, mt.color, mt.sym ); + pr.x += 2; // symbol and space + nc_color danger = c_dark_gray; + if( mt.difficulty >= 30 ) { + danger = c_red; + } else if( mt.difficulty >= 16 ) { + danger = c_light_red; + } else if( mt.difficulty >= 8 ) { + danger = c_white; + } else if( mt.agro > 0 ) { + danger = c_light_gray; + } + mvwprintz( w, pr, danger, name ); + pr.x += utf8_width( name ) + namesep; + } + } + } +} + +void game::mon_info_update( ) +{ int newseen = 0; const int iProxyDist = ( get_option( "SAFEMODEPROXIMITY" ) <= 0 ) ? MAX_VIEW_DISTANCE : get_option( "SAFEMODEPROXIMITY" ); // 7 0 1 unique_types uses these indices; // 6 8 2 0-7 are provide by direction_from() // 5 4 3 8 is used for local monsters (for when we explain them below) - std::vector unique_types[9]; - std::vector unique_mons[9]; - // dangerous_types tracks whether we should print in red to warn the player - bool dangerous[8]; - for( auto &dangerou : dangerous ) { - dangerou = false; + + for( auto &t : unique_types ) { + t.clear(); } + for( auto &m : unique_mons ) { + m.clear(); + } + std::fill( dangerous, dangerous + sizeof( dangerous ), false ); tripoint view = u.pos() + u.view_offset; new_seen_mon.clear(); @@ -3993,127 +4117,9 @@ void game::mon_info( const catacurses::window &w, int hor_padding ) previous_turn = current_turn; mostseen = newseen; - - // Print the direction headings - // Reminder: - // 7 0 1 unique_types uses these indices; - // 6 8 2 0-7 are provide by direction_from() - // 5 4 3 8 is used for local monsters (for when we explain them below) - - const std::array dir_labels = {{ - _( "North:" ), _( "NE:" ), _( "East:" ), _( "SE:" ), - _( "South:" ), _( "SW:" ), _( "West:" ), _( "NW:" ) - } - }; - std::array widths; - for( int i = 0; i < 8; i++ ) { - widths[i] = utf8_width( dir_labels[i] ); - } - std::array xcoords; - const std::array ycoords = {{ 0, 0, 1, 2, 2, 2, 1, 0 }}; - xcoords[0] = xcoords[4] = width / 3; - xcoords[1] = xcoords[3] = xcoords[2] = ( width / 3 ) * 2; - xcoords[5] = xcoords[6] = xcoords[7] = 0; - //for the alignment of the 1,2,3 rows on the right edge - xcoords[2] -= utf8_width( _( "East:" ) ) - utf8_width( _( "NE:" ) ); - for( int i = 0; i < 8; i++ ) { - nc_color c = unique_types[i].empty() && unique_mons[i].empty() ? c_dark_gray - : ( dangerous[i] ? c_light_red : c_light_gray ); - mvwprintz( w, point( xcoords[i] + hor_padding, ycoords[i] + startrow ), c, dir_labels[i] ); - } - - // Print the symbols of all monsters in all directions. - for( int i = 0; i < 8; i++ ) { - point pr( xcoords[i] + widths[i] + 1, ycoords[i] + startrow ); - - // The list of symbols needs a space on each end. - int symroom = ( width / 3 ) - widths[i] - 2; - const int typeshere_npc = unique_types[i].size(); - const int typeshere_mon = unique_mons[i].size(); - const int typeshere = typeshere_mon + typeshere_npc; - for( int j = 0; j < typeshere && j < symroom; j++ ) { - nc_color c; - std::string sym; - if( symroom < typeshere && j == symroom - 1 ) { - // We've run out of room! - c = c_white; - sym = "+"; - } else if( j < typeshere_npc ) { - switch( unique_types[i][j]->get_attitude() ) { - case NPCATT_KILL: - c = c_red; - break; - case NPCATT_FOLLOW: - c = c_light_green; - break; - default: - c = c_pink; - break; - } - sym = "@"; - } else { - const mtype &mt = *unique_mons[i][j - typeshere_npc]; - c = mt.color; - sym = mt.sym; - } - mvwprintz( w, pr, c, sym ); - - pr.x++; - } - } - - // Now we print their full names! - - std::set listed_mons; - - // Start printing monster names on row 4. Rows 0-2 are for labels, and row 3 - // is blank. - point pr( hor_padding, 4 + startrow ); - - // Print monster names, starting with those at location 8 (nearby). - for( int j = 8; j >= 0 && pr.y < maxheight; j-- ) { - // Separate names by some number of spaces (more for local monsters). - int namesep = ( j == 8 ? 2 : 1 ); - for( const mtype *type : unique_mons[j] ) { - if( pr.y >= maxheight ) { - // no space to print to anyway - break; - } - if( listed_mons.count( type ) > 0 ) { - // this type is already printed. - continue; - } - listed_mons.insert( type ); - - const mtype &mt = *type; - const std::string name = mt.nname(); - - // Move to the next row if necessary. (The +2 is for the "Z "). - if( pr.x + 2 + utf8_width( name ) >= width ) { - pr.y++; - pr.x = hor_padding; - } - - if( pr.y < maxheight ) { // Don't print if we've overflowed - mvwprintz( w, pr, mt.color, mt.sym ); - pr.x += 2; // symbol and space - nc_color danger = c_dark_gray; - if( mt.difficulty >= 30 ) { - danger = c_red; - } else if( mt.difficulty >= 16 ) { - danger = c_light_red; - } else if( mt.difficulty >= 8 ) { - danger = c_white; - } else if( mt.agro > 0 ) { - danger = c_light_gray; - } - mvwprintz( w, pr, danger, name ); - pr.x += utf8_width( name ) + namesep; - } - } - } } + void game::cleanup_dead() { // Dead monsters need to stay in the tracker until everything else that needs to die does so diff --git a/src/game.h b/src/game.h index 50b913cbc15d9..a59828610e2b9 100644 --- a/src/game.h +++ b/src/game.h @@ -788,6 +788,7 @@ class game void set_critter_died(); void mon_info( const catacurses::window &, int hor_padding = 0 ); // Prints a list of nearby monsters + void mon_info_update( ); //Update seen monsters information void cleanup_dead(); // Delete any dead NPCs/monsters bool is_dangerous_tile( const tripoint &dest_loc ) const; std::vector get_dangerous_tile( const tripoint &dest_loc ) const; @@ -1004,6 +1005,13 @@ class game std::string list_item_downvote; std::vector> new_seen_mon; + // 7 0 1 unique_types uses these indices; + // 6 8 2 0-7 are provide by direction_from() + // 5 4 3 8 is used for local monsters (for when we explain them below) + std::vector unique_types[9]; + std::vector unique_mons[9]; + bool dangerous[8]; + bool safe_mode_warning_logged; bool bVMonsterLookFire; character_id next_npc_id; From 4c11a4819cb3d3eadc50f842e1c0e4666e71f54f Mon Sep 17 00:00:00 2001 From: ipcyborg Date: Sun, 22 Dec 2019 12:16:59 +0200 Subject: [PATCH 2/2] Struct `monster_visible_info` moved to avatar. Removed `auto` where apropriate --- src/avatar.h | 24 ++++++++++++++++++++++++ src/game.cpp | 35 +++++++++++++++++++++++++---------- src/game.h | 8 -------- src/handle_action.cpp | 2 +- 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/avatar.h b/src/avatar.h index 92eda70fc169c..167f7bd2314fc 100644 --- a/src/avatar.h +++ b/src/avatar.h @@ -22,11 +22,29 @@ class JsonObject; class JsonOut; class mission; class npc; +class monster; namespace debug_menu { class mission_debug; } // namespace debug_menu struct points_left; +struct mtype; + +// Monster visible in different directions (safe mode & compass) +struct monster_visible_info { + // New monsters visible from last update + std::vector> new_seen_mon; + + // Unique monsters (and types of monsters) visible in different directions + // 7 0 1 unique_types uses these indices; + // 6 8 2 0-7 are provide by direction_from() + // 5 4 3 8 is used for local monsters (for when we explain them below) + std::vector unique_types[9]; + std::vector unique_mons[9]; + + // If the moster visible in this direction is dangerous + bool dangerous[8]; +}; class avatar : public player { @@ -187,6 +205,10 @@ class avatar : public player bool invoke_item( item *, const std::string &, const tripoint &pt ) override; bool invoke_item( item *, const std::string & ) override; + monster_visible_info &get_mon_visible() { + return mon_visible; + } + private: map_memory player_map_memory; bool show_map_memory; @@ -224,6 +246,8 @@ class avatar : public player int dex_upgrade = 0; int int_upgrade = 0; int per_upgrade = 0; + + monster_visible_info mon_visible; }; struct points_left { diff --git a/src/game.cpp b/src/game.cpp index 8db65d10f37c1..bedd284a4c89c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3806,6 +3806,11 @@ std::vector game::get_fishable_monsters( std::unordered_set // Print monster info to the given window void game::mon_info( const catacurses::window &w, int hor_padding ) { + const monster_visible_info &mon_visible = u.get_mon_visible(); + const auto &unique_types = mon_visible.unique_types; + const auto &unique_mons = mon_visible.unique_mons; + const auto &dangerous = mon_visible.dangerous; + const int width = getmaxx( w ) - 2 * hor_padding; const int maxheight = getmaxy( w ); @@ -3934,12 +3939,19 @@ void game::mon_info( const catacurses::window &w, int hor_padding ) void game::mon_info_update( ) { int newseen = 0; - const int iProxyDist = ( get_option( "SAFEMODEPROXIMITY" ) <= 0 ) ? MAX_VIEW_DISTANCE : - get_option( "SAFEMODEPROXIMITY" ); + const int safe_proxy_dist = get_option( "SAFEMODEPROXIMITY" ); + const int iProxyDist = ( safe_proxy_dist <= 0 ) ? MAX_VIEW_DISTANCE : + safe_proxy_dist; + + monster_visible_info &mon_visible = u.get_mon_visible(); + auto &new_seen_mon = mon_visible.new_seen_mon; + auto &unique_types = mon_visible.unique_types; + auto &unique_mons = mon_visible.unique_mons; + auto &dangerous = mon_visible.dangerous; + // 7 0 1 unique_types uses these indices; // 6 8 2 0-7 are provide by direction_from() // 5 4 3 8 is used for local monsters (for when we explain them below) - for( auto &t : unique_types ) { t.clear(); } @@ -3948,7 +3960,7 @@ void game::mon_info_update( ) } std::fill( dangerous, dangerous + sizeof( dangerous ), false ); - tripoint view = u.pos() + u.view_offset; + const tripoint view = u.pos() + u.view_offset; new_seen_mon.clear(); static int previous_turn = 0; @@ -3956,10 +3968,10 @@ void game::mon_info_update( ) const int current_turn = to_turns( calendar::turn - calendar::turn_zero ); const int sm_ignored_turns = get_option( "SAFEMODEIGNORETURNS" ); - for( auto &c : u.get_visible_creatures( MAPSIZE_X ) ) { - const auto m = dynamic_cast( c ); - const auto p = dynamic_cast( c ); - const auto dir_to_mon = direction_from( view.xy(), point( c->posx(), c->posy() ) ); + for( Creature *c : u.get_visible_creatures( MAPSIZE_X ) ) { + monster *m = dynamic_cast( c ); + npc *p = dynamic_cast( c ); + const direction dir_to_mon = direction_from( view.xy(), point( c->posx(), c->posy() ) ); const int mx = POSX + ( c->posx() - view.x ); const int my = POSY + ( c->posy() - view.y ); int index = 8; @@ -4020,7 +4032,7 @@ void game::mon_info_update( ) if( m != nullptr ) { //Safemode monster check - auto &critter = *m; + monster &critter = *m; const monster_attitude matt = critter.attitude( &u ); const int mon_dist = rl_dist( u.pos(), critter.pos() ); @@ -4052,7 +4064,7 @@ void game::mon_info_update( ) } } - auto &vec = unique_mons[index]; + std::vector &vec = unique_mons[index]; if( std::find( vec.begin(), vec.end(), critter.type ) == vec.end() ) { vec.push_back( critter.type ); } @@ -8670,6 +8682,9 @@ bool game::check_safe_mode_allowed( bool repeat_safe_mode_warnings ) } // Monsters around and we don't want to run std::string spotted_creature_name; + const monster_visible_info &mon_visible = u.get_mon_visible(); + const auto &new_seen_mon = mon_visible.new_seen_mon; + if( new_seen_mon.empty() ) { // naming consistent with code in game::mon_info spotted_creature_name = _( "a survivor" ); diff --git a/src/game.h b/src/game.h index a59828610e2b9..ac18d3724e419 100644 --- a/src/game.h +++ b/src/game.h @@ -1004,14 +1004,6 @@ class game std::string list_item_upvote; std::string list_item_downvote; - std::vector> new_seen_mon; - // 7 0 1 unique_types uses these indices; - // 6 8 2 0-7 are provide by direction_from() - // 5 4 3 8 is used for local monsters (for when we explain them below) - std::vector unique_types[9]; - std::vector unique_mons[9]; - bool dangerous[8]; - bool safe_mode_warning_logged; bool bVMonsterLookFire; character_id next_npc_id; diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 73eb61c4f5f04..99eddb35a34a9 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -2108,7 +2108,7 @@ bool game::handle_action() case ACTION_IGNORE_ENEMY: if( safe_mode == SAFE_MODE_STOP ) { add_msg( m_info, _( "Ignoring enemy!" ) ); - for( auto &elem : new_seen_mon ) { + for( auto &elem : u.get_mon_visible().new_seen_mon ) { monster &critter = *elem; critter.ignoring = rl_dist( u.pos(), critter.pos() ); }