The *achievement command is used to define one or more Achievements able to be awarded to a player for noteworthy feats or accomplishments within the game - solving puzzles or mysteries; overcoming or otherwise surviving especially tough challenges; uncovering 'hidden' elements or hard-to-discover routes; or perhaps simply for attaining especially high Stats during a particular playthrough. Really, just about anything in your game entirely deserving of a hearty pat on the back.
Achievements are declared in the Startup.txt file and must be placed immediately following the list of *create commands, using one *achievement command for each and assigning to each a unique codename for reference. Once properly declared, an Achievement may then be awarded to the player at any point in your actual Scene files using the simple *achieve [codename] command. The absolute maximum number of Achievements possible to include in any single game is 100.
A game featuring Achievements will automatically have a button of that name visible at the top of the screen, alongside the usual 'Show Stats' and 'Restart' buttons. As with the 'Show Stats' button, the player may click the 'Achievements' button at any point in the game to view a separate page containing all of their known Achievements information, before returning to the current page in the game with a 'Next' click.
Unlike the 'Show Stats' button, however, there is no separate game file (e.g. 'choicescript_stats') required for including Achievements in your game - i.e. the page the player views is automatically generated by ChoiceScript itself, and is based entirely on the data provided by your comprehensive *achievement declarations in the Startup file.
As part of the declaration process, Achievements must be defined as either 'visible' or 'hidden'. All Achievements marked as visible are listed on the Achievements page from the very start of the game, with a title and short, "pre-earned" description. When that Achievement is awarded, its entry on the Achievements page is changed to show the "post-earned" description provided in the declaration.
Conversely, a 'hidden' Achievement is not listed on the Achievements page at all until it is actually awarded, at which point the precise details are revealed. At the start of a game, a player is only told how many hidden Achievements actually exist in the game. Future visits to that page will inform the player how many yet remain undiscovered.
Both 'visible' and 'hidden' Achievements must also be given a numerical points value as part of the declaration. The more difficult an Achievement is to earn, the higher this value should be relative to lesser Achievements. A game's Achievements page informs the player of both the total points possible and the total current 'earned' value, giving them yet another reason to replay it in an attempt to achieve the maximum possible.
The maximum points value you can assign to any single Achievement is 100, while the total value of all Achievements in the game must not exceed 1,000 points. It is probably wise to stay well clear of either maximum for a first publication of your game - as well as far below the maximum of 100 actual Achievements in total - thereby granting you the freedom to add more and / or better-value ones in a possible future update.
Achievements are declared in the Startup file - immediately below all *create commands - in the following format.
*achievement [codename] [visible/hidden] [points value] [title]
Note that the codename is used to reference the Achievement within your actual scripting when using the *achieve command, and so must be unique (in much the same way as variable names). Unlike the actual 'title' text on the end, however, the 'codename' is never displayed to the player.
For a 'visible' Achievement, a declaration might look something like this:
*achievement mystery1 visible 10 Lost Souls
Investigate what became of the missing villagers.
Discovered the fate of the hapless villagers.
At the very start of the game this would be listed on the Achievements page as follows:
Lost Souls: Investigate what became of the missing villagers. (10 points)
After the Achievement has been earned in-game, its listing on the Achievements page would change to:
Lost Souls: Discovered the fate of the hapless villagers. (10 points)
A 'hidden' Achievement declaration is slightly different. As it is not actually listed on the Achievements page prior to being earned, it does not require a pre-earned description. Use the place-holder 'hidden' for that line instead, as follows:
*achievement mystery2 hidden 25 The Grand Grimoire
Recovered the Lost Mysteries of the Ancients.
Once a 'hidden' Achievement has been earned in-game, its entry will finally appear on the Achievements page as follows:
The Grand Grimoire: Recovered the Lost Mysteries of the Ancients. (25 points)
Achievements properly declared in the Startup file may be awarded to the player within your actual game scripting at any point in the story, using the *achieve command to simply reference the Achievement codename, as follows
Awarding the same achievement multiple times
There is no limit to the number of times that - or points in the story where - any single Achievement may be awarded, and each such occasion will trigger a pop-up banner announcement to that effect. From a technical point of view, however, it should be noted that Achievements are more or less the same as simple true / false booleans, meaning that once it has been set true (i.e. has been earned) it remains true with each successive *achieve referencing that same codename. By the same token, neither do multiple awards of the same Achievement add any additional 'points value' to the current total earned.
It is, however possible to allow a particular Achievement to potentially be in multiple places, but for only the very first such occasion to actually trigger a pop-up banner announcement. This is possible using the related *check_achievements command.
This command effectively creates a new true / false boolean *temp variable for each Achievement declared in the game, with the variable name -
- where 'codename' will be the actual codename originally declared for that Achievement, e.g.
The *temp variables for Earned Achievements will contain a value of 'true', while not-yet-earned Achievements will of course be 'false', thereby allowing the actual *achieve command to be made conditional on the latter state, as follows:
In this example, the Achievement with the codename 'mystery1' will be visibly awarded to the player at this point in the game only if that Achievement has not already been earned.
Do bear in mind that *check_achievements creates (or overwrites) temporary variables - which are of course lost from memory with each new scene file load - so that command must be repeated before each and every conditional check of this nature, exactly as shown above, to avoid a 'non-existent variable name' error.
Using *check_achievements we can also award new Achievements based entirely on Achievements already earned. These are known as Meta Achievements and are awarded as follows:
*if ((choice_achieved_code1 and choice_achieved_code2) and choice_achieved_code3)
In this example, the Achievement with the codename 'code4' will be awarded to the player at this point in the game if the Achievements 'code1', 'code2' and 'code3' have all been earned by the player at any point in the past, during this or any previous playthrough.
Achievements are mostly persistent (i.e. they are not actually reset with each subsequent playthrough), so as well as being congratulatory they are also a good way to encourage more replays of your game in an attempt to earn that "perfect score" - if not simply in an effort to discover what those remaining 'hidden' Achievements actually are...
The persistence of ChoiceScript Achievements does however depend on the method used by the player to play your game. On iOS devices and Steam, Apple and Valve - respectively - provide official mechanisms for storing permanent Achievements, and ChoiceScript takes full advantage of this. On Android devices and the Chrome Web Store, however, earned Achievements will persist only so long as the app remains installed. And on the web, of course, it's very easy to lose any and all game Achievements (e.g. if the player wipes all cookies and local storage). Overall, however, it's definitely worth taking the time to include Achievements in your Choice Game as the pros definitely outweigh the cons... in the opinion of most players, at least.
Some would say it's probably best to avoid awarding Achievements at the mere drop of a hat - as has become all too common in some sectors of the games industry but is increasingly frowned upon by actual players.
The argument goes that Achievements should feel like they've been deservedly earned, otherwise their regularity and very ordinariness simply devalues the impact of genuine Achievements for the player when those tougher feats are actually managed. For a Choice Game especially, consider aiming for quality over quantity, not just a thoughtful balance where relative points values are concerned. Where possible, you might try eliciting the opinion of beta testers to help achieve and maintain a fair balance - and maybe also ask them to keep an eye out for places in the story where they felt they fully deserved a pat on the back but where none was actually forthcoming!
It's also worth bearing in mind that some players actually intensely dislike the very notion of Achievements in interactive fiction, feeling that a pop-up Achievement award can sometimes spoil their immersion in the role they're playing in the story, essentially making the whole thing too "gamey" for their particular tastes. For this reason, it might be worth considering making all of your actual *achieve awards conditional on yet another true / false boolean, and simply ask the player their personal preference - and *set that boolean accordingly - at the very start of the game.
- Forum topic: Achievements - the Dilemma of Development
- Forum topic: Achievement Unlocked - do you like achievements?
|More commands / functions|
|Choice||*choice, *fake_choice, *disable_reuse, *hide_reuse, *allow_reuse, *selectable_if|
|Variable||*create, *temp, *set, Arithmetic operators, *delete, *input_number, *input_text, *print, *rand|
|Conditional||*if, *elseif, *else, Multireplace|
|Goto||*label, *goto, *goto_scene, *goto_random_scene, *gosub, *gosub_scene, *finish|
|Formatting||Bold text, Italic text, *image, *line_break, *page_break, *link, *stat_chart|
|Miscellaneous||*comment, *scene_list, *title, *author, *achieve, *achievement, *check_achievements, *bug, *ending, *more_games, *share_this_game, *show_password, *script, Implicit Control Flow|