Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Achievements: add support for time constraints #39686

Merged

Conversation

jbytheway
Copy link
Contributor

Summary

SUMMARY: Features "Achievements can now have time constraints"

Purpose of change

It is common for achievements in games to require you to do something within a certain amount of time. We want to support that use case. Moreover, we would like to support achievements with a lower time bound (like "survive for a month").

Describe the solution

A new field "time_constraint" on achievements that allows enforcing a lower or upper bound on the time an achievement can be captured (but not both).

Comes with the following associated changes:

  • There's a new calendar::start_of_game to keep a record of when the game started for reference. In legacy saves this will default to start_of_cataclysm.
  • Upper bounds on statistics in achievement requirements.
  • A concept of "failed" achievements when it becomes provable that an achievement is impossible of the rest of the game (in most cases this will be because it had a time constraint and that time has passed).
  • Make score descriptions optional. When the underlying statistic has a description, use that in a reasonable default format.
  • Move achievements to a new, separate, json file since the scores.json was starting to get cluttered.
  • If you have completed an achievement then the achievements tab now tells you when you did.
  • Added a new achievement for killing a monster in the first minute of the game to test these features.

Describe alternatives you've considered

One limitation is that you can't directly write an achievement which fires at a particular time. Achievements are only considered when a relevant event fires. So if you want to write e.g. a "survive for a month" achievement then it still needs to have an associated event (via a statistic), and won't fire until that event happens. We could add (or link into) a timer system for additional triggers beyond events, but I think that's not really necessary.

Testing

Added some new unit tests.

Tested in game long enough to capture the below screenshots.

Additional context

(The pictures below have an off-by-one error in the day of printed times; I fixed that after taking the screenshots).

How things look initially:
achievement-times-initial
Getting both achievements by killing a zombie fast:
achievement-times-log
Achievements window now looks like:
achievement-times-both-success
If instead you wait until after a minute then:
achievement-times-after-waiting
And then, after killing a zombie:
achievement-times-one-success

@jbytheway jbytheway force-pushed the achievement_time_constraints branch 2 times, most recently from 1363e8d to 65ee146 Compare April 18, 2020 17:13
@kevingranade
Copy link
Member

achievments_tracker

  kills

-------------------------------------------------------------------------------

stats_tracker_test.cpp:240

...............................................................................

stats_tracker_test.cpp:286: FAILED:

  CHECK( a.ui_text_for( achievements_completed.at( a_kill_zombie ) ) == "<color_c_light_green>One down, billions to go…</color>\n" "  <color_c_light_green>Completed Year 1, Spring, day 1 0010.00</color>\n" "  <color_c_green>1/1 Number of zombies killed</color>\n" )

with expansion:

  "<color_c_light_green>One down, billions to go…</color>

    <color_c_light_green>Completed Year 1, Spring, day 1 12:10:00AM</color>

    <color_c_green>1/1 Number of zombies killed</color>

  "

  ==

  "<color_c_light_green>One down, billions to go…</color>

    <color_c_light_green>Completed Year 1, Spring, day 1 0010.00</color>

    <color_c_green>1/1 Number of zombies killed</color>

  "

with message:

  time_since_game_start := {?}

Comment on lines 211 to 214
if( equals_statistic_ && ( *equals_statistic_ )->monotonicity() != monotonically::constant ) {
return false;
}
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested by clang-tidy readability-simplify-boolean-expr

Suggested change
if( equals_statistic_ && ( *equals_statistic_ )->monotonicity() != monotonically::constant ) {
return false;
}
return true;
return !equals_statistic_ || ( *equals_statistic_ )->monotonicity() == monotonically::constant );

It makes more sense to name the statistics, since both scores and
achievements are based on them, and we would only end up writing the
same information twice.

So, if a score has no description, derive one from its statistic.
Currently we track the time of the cataclysm, but not the time of the
game starting.  This is needed for achievements (and potentially other
things, like missions) so add it.

In legacy saves, it will default to the same time as the cataclysm.
Add new enumerator, and move into header.
Allow for achievements to specify a minimum or maximum time bound within
which they must be completed.

Test this with a new "kill within the first minute" achievement.

With this change, achievements can now become "failed", meaning that it
is impossible to ever achieve them in this game.  Failed achievements
get sorted to the bottom of the list, and get a new colour scheme.

As a side-effect, other requirements can also get a "<=" constraint,
which also means they can become impossible to satisfy, and can lead to
achievements being failed.  To support this we need to track which
statistics are monotonic, so we know when such failures are
irreversible.
Was printing e.g. "day 0" when it was "day 1".
To ensure consistent output from achievement tests.
@jbytheway jbytheway force-pushed the achievement_time_constraints branch from 618c47a to 9dfdf4f Compare April 20, 2020 02:33
@ZhilkinSerg ZhilkinSerg added <Enhancement / Feature> New features, or enhancements on existing [C++] Changes (can be) made in C++. Previously named `Code` labels Apr 20, 2020
@ZhilkinSerg ZhilkinSerg merged commit 5e936ea into CleverRaven:master Apr 21, 2020
@jbytheway jbytheway deleted the achievement_time_constraints branch April 21, 2020 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[C++] Changes (can be) made in C++. Previously named `Code` <Enhancement / Feature> New features, or enhancements on existing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants