diff --git a/data/json/achievements.json b/data/json/achievements.json index 175b076da198d..07e329328c9ba 100644 --- a/data/json/achievements.json +++ b/data/json/achievements.json @@ -16,9 +16,46 @@ "id": "achievement_survive_one_day", "type": "achievement", "name": "The first day of the rest of their unlives", + "description": "Survive for a day and find a safe place to sleep", "time_constraint": { "since": "game_start", "is": ">=", "target": "1 day" }, "requirements": [ { "event_statistic": "num_avatar_wake_ups", "is": "anything" } ] }, + { + "id": "achievement_survive_7_days", + "type": "achievement", + "name": "Thank God it's Friday", + "description": "Survive for a week", + "hidden_by": [ "achievement_survive_one_day" ], + "time_constraint": { "since": "game_start", "is": ">=", "target": "7 days" }, + "requirements": [ { "event_statistic": "num_avatar_wake_ups", "is": "anything" } ] + }, + { + "id": "achievement_survive_28_days", + "type": "achievement", + "name": "28 days later", + "description": "Survive for a month", + "hidden_by": [ "achievement_survive_7_days" ], + "time_constraint": { "since": "game_start", "is": ">=", "target": "28 days" }, + "requirements": [ { "event_statistic": "num_avatar_wake_ups", "is": "anything" } ] + }, + { + "id": "achievement_survive_91_days", + "type": "achievement", + "name": "A time to every purpose under heaven", + "description": "Survive for a season", + "hidden_by": [ "achievement_survive_28_days" ], + "time_constraint": { "since": "game_start", "is": ">=", "target": "91 days" }, + "requirements": [ { "event_statistic": "num_avatar_wake_ups", "is": "anything" } ] + }, + { + "id": "achievement_survive_365_days", + "type": "achievement", + "name": "Brighter days ahead?", + "description": "Survive for a year", + "hidden_by": [ "achievement_survive_91_days" ], + "time_constraint": { "since": "game_start", "is": ">=", "target": "365 days" }, + "requirements": [ { "event_statistic": "num_avatar_wake_ups", "is": "anything" } ] + }, { "id": "achievement_marathon", "type": "achievement", diff --git a/src/achievement.cpp b/src/achievement.cpp index 312e59c79a00b..79f0771f1dca0 100644 --- a/src/achievement.cpp +++ b/src/achievement.cpp @@ -50,6 +50,13 @@ const achievement &string_id::obj() const return achievement_factory.obj( *this ); } +/** @relates string_id */ +template<> +bool string_id::is_valid() const +{ + return achievement_factory.is_valid( *this ); +} + namespace io { @@ -310,18 +317,25 @@ void achievement::load( const JsonObject &jo, const std::string & ) { mandatory( jo, was_loaded, "name", name_ ); optional( jo, was_loaded, "description", description_ ); + optional( jo, was_loaded, "hidden_by", hidden_by_ ); optional( jo, was_loaded, "time_constraint", time_constraint_ ); mandatory( jo, was_loaded, "requirements", requirements_ ); } void achievement::check() const { - for( const achievement_requirement &req : requirements_ ) { - req.check( id ); + for( const string_id &a : hidden_by_ ) { + if( !a.is_valid() ) { + debugmsg( "Achievement %s specifies hidden_by achievement %s, but the latter does not " + "exist.", id.str(), a.str() ); + } } if( time_constraint_ ) { time_constraint_->check( id ); } + for( const achievement_requirement &req : requirements_ ) { + req.check( id ); + } } static std::string text_for_requirement( const achievement_requirement &req, @@ -599,6 +613,20 @@ achievement_completion achievements_tracker::is_completed( const string_idsecond.completion; } +bool achievements_tracker::is_hidden( const achievement *ach ) const +{ + if( is_completed( ach->id ) == achievement_completion::completed ) { + return false; + } + + for( const string_id &hidden_by : ach->hidden_by() ) { + if( is_completed( hidden_by ) != achievement_completion::completed ) { + return true; + } + } + return false; +} + std::string achievements_tracker::ui_text_for( const achievement *ach ) const { auto state_it = achievements_status_.find( ach->id ); diff --git a/src/achievement.h b/src/achievement.h index bd7b47ab2a4a5..82d196fc44418 100644 --- a/src/achievement.h +++ b/src/achievement.h @@ -67,6 +67,10 @@ class achievement return description_; } + const std::vector> &hidden_by() const { + return hidden_by_; + } + class time_bound { public: @@ -98,6 +102,7 @@ class achievement private: translation name_; translation description_; + std::vector> hidden_by_; cata::optional time_constraint_; std::vector requirements_; }; @@ -170,6 +175,7 @@ class achievements_tracker : public event_subscriber void report_achievement( const achievement *, achievement_completion ); achievement_completion is_completed( const string_id & ) const; + bool is_hidden( const achievement * ) const; std::string ui_text_for( const achievement * ) const; void clear(); diff --git a/src/scores_ui.cpp b/src/scores_ui.cpp index 58a43a21f7008..59f837fe1642c 100644 --- a/src/scores_ui.cpp +++ b/src/scores_ui.cpp @@ -22,6 +22,11 @@ static std::string get_achievements_text( const achievements_tracker &achievemen { std::string os; std::vector valid_achievements = achievements.valid_achievements(); + valid_achievements.erase( + std::remove_if( valid_achievements.begin(), valid_achievements.end(), + [&]( const achievement * a ) { + return achievements.is_hidden( a ); + } ), valid_achievements.end() ); using sortable_achievement = std::tuple; std::vector sortable_achievements;