Skip to content

Commit

Permalink
Add support for hiding achievements
Browse files Browse the repository at this point in the history
Allow one achievement to be hidden by another.  It will not appear in
the list until that other has been completed.

Add several new survival achievements, each of which hides the next, for
progressively longer periods.
  • Loading branch information
jbytheway committed May 3, 2020
1 parent 789d3b2 commit bcdb7ca
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
37 changes: 37 additions & 0 deletions data/json/achievements.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
32 changes: 30 additions & 2 deletions src/achievement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ const achievement &string_id<achievement>::obj() const
return achievement_factory.obj( *this );
}

/** @relates string_id */
template<>
bool string_id<achievement>::is_valid() const
{
return achievement_factory.is_valid( *this );
}

namespace io
{

Expand Down Expand Up @@ -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<achievement> &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,
Expand Down Expand Up @@ -599,6 +613,20 @@ achievement_completion achievements_tracker::is_completed( const string_id<achie
return it->second.completion;
}

bool achievements_tracker::is_hidden( const achievement *ach ) const
{
if( is_completed( ach->id ) == achievement_completion::completed ) {
return false;
}

for( const string_id<achievement> &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 );
Expand Down
6 changes: 6 additions & 0 deletions src/achievement.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ class achievement
return description_;
}

const std::vector<string_id<achievement>> &hidden_by() const {
return hidden_by_;
}

class time_bound
{
public:
Expand Down Expand Up @@ -98,6 +102,7 @@ class achievement
private:
translation name_;
translation description_;
std::vector<string_id<achievement>> hidden_by_;
cata::optional<time_bound> time_constraint_;
std::vector<achievement_requirement> requirements_;
};
Expand Down Expand Up @@ -170,6 +175,7 @@ class achievements_tracker : public event_subscriber
void report_achievement( const achievement *, achievement_completion );

achievement_completion is_completed( const string_id<achievement> & ) const;
bool is_hidden( const achievement * ) const;
std::string ui_text_for( const achievement * ) const;

void clear();
Expand Down
5 changes: 5 additions & 0 deletions src/scores_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ static std::string get_achievements_text( const achievements_tracker &achievemen
{
std::string os;
std::vector<const achievement *> 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<achievement_completion, std::string, const achievement *>;
std::vector<sortable_achievement> sortable_achievements;
Expand Down

0 comments on commit bcdb7ca

Please sign in to comment.