diff --git a/src/game.cpp b/src/game.cpp index 055bb42550607..ee844df4251c4 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -121,6 +121,7 @@ #include "overmap_ui.h" #include "overmapbuffer.h" #include "panels.h" +#include "past_games_info.h" #include "path_info.h" #include "pickup.h" #include "player.h" @@ -284,6 +285,29 @@ static void achievement_attained( const achievement *a, bool achievements_enable if( achievements_enabled ) { add_msg( m_good, _( "You completed the achievement \"%s\"." ), a->name() ); + std::string popup_option = get_option( "ACHIEVEMENT_COMPLETED_POPUP" ); + bool show_popup; + if( test_mode || popup_option == "never" ) { + show_popup = false; + } else if( popup_option == "always" ) { + show_popup = true; + } else if( popup_option == "first" ) { + const achievement_completion_info *past_info = get_past_games().achievement( a->id ); + show_popup = !past_info || past_info->games_completed.empty(); + } else { + debugmsg( "Unexpected ACHIEVEMENT_COMPLETED_POPUP option value %s", popup_option ); + show_popup = false; + } + + if( show_popup ) { + std::string message = colorize( _( "Achievement completed!" ), c_light_green ); + message += "\n\n"; + message += get_achievements().ui_text_for( a ); + message += "\n"; + message += colorize( _( "Achievement completion popups can be\nconfigured via the " + "Interface options" ), c_dark_gray ); + popup( message ); + } } get_event_bus().send( a->id, achievements_enabled ); } diff --git a/src/options.cpp b/src/options.cpp index 3698317eb4e56..3ea560f81906b 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -1545,6 +1545,17 @@ void options_manager::add_options_interface() false ); + add( "ACHIEVEMENT_COMPLETED_POPUP", "interface", + translate_marker( "Popup window when achievmement completed" ), + translate_marker( "Whether to trigger a popup window when completing an achievement. " + "First: when completing an achievement that has not been completed in " + "a previous game." ), { + { "never", translate_marker( "Never" ) }, + { "always", translate_marker( "Always" ) }, + { "first", translate_marker( "First" ) } + }, + "first" ); + add( "LOOKAROUND_POSITION", "interface", translate_marker( "Look around position" ), translate_marker( "Switch between look around panel being left or right." ), { { "left", translate_marker( "Left" ) }, { "right", translate_marker( "Right" ) } }, diff --git a/src/past_games_info.cpp b/src/past_games_info.cpp index 8b03b5d814c2b..005bd0b69fab0 100644 --- a/src/past_games_info.cpp +++ b/src/past_games_info.cpp @@ -13,6 +13,11 @@ static void no_op( const achievement *, bool ) {} +class too_old_memorial_file_error : std::runtime_error +{ + using runtime_error::runtime_error; +}; + past_game_info::past_game_info( JsonIn &jsin ) { JsonObject jo = jsin.get_object(); @@ -33,6 +38,9 @@ past_game_info::past_game_info( JsonIn &jsin ) event_multiset &events = stats_->get_events( event_type::game_start ); const event_multiset::summaries_type &counts = events.counts(); if( counts.size() != 1 ) { + if( counts.empty() ) { + throw too_old_memorial_file_error( "memorial file lacks game_start event" ); + } debugmsg( "Unexpected number of game start events: %d\n", counts.size() ); return; } @@ -99,6 +107,8 @@ void past_games_info::ensure_loaded() info_.push_back( past_game_info( jsin ) ); } catch( const JsonError &err ) { debugmsg( "Error reading memorial file %s: %s", filename, err.what() ); + } catch( const too_old_memorial_file_error & ) { + // do nothing } }