This article describes a number of useful techniques worth thinking about once you feel comfortable with basic ChoiceScript coding. However, it assumes that the reader is already familiar with most aspects of ChoiceScript - if this is not the case, the best place to start would be with A Basic Tutorial.
Scene Jump-and-Return System
Although using the *finish command in conjunction with the *scene_list section of startup.txt is fine for moving from one scene .txt file to the next in a strictly sequential order, for something a little more flexible it's possible to use the *goto_scene command for a "Jump-and-Return" system between any named scenes -- including, incidentally, any scene .txt file not actually included in the *scene_list.
We begin by creating two new permanent string variables in startup.txt, with a default blank starting value using double quotes:
*create return_to_scene "" *create return_to_label ""
At any point in your scene scripting where you want the game to jump to a completely different scene, those two variables are *set accordingly followed by a *goto_scene command. For example, if jumping from chapter1 to chapter4, but with the intention of later returning to chapter1, you would use:
*set return_to_scene "chapter1" *set return_to_label "label_name1" *goto_scene chapter4
Somewhere within chapter4 itself you will need to add a *label section as follows, to handle the return to the originating scene name after running whatever scripting the game came here to do:
*label redirect *if return_to_scene = "chapter1" *goto_scene chapter1 *elseif return_to_scene = "chapter2" *goto_scene chapter2 *elseif return_to_scene = "chapter3" *goto_scene chapter3 (etc.) *else *finish (or whatever -- if not a return_to_scene situation)
Near the very start of chapter1 you would then need to add additional scripting to determine what to do if the game has indeed returned to here from another scene (as opposed to being a new game start, or loaded sequentially via the *scene_list system and a *finish command in the previous sequential scene), e.g.
*if return_to_scene = "chapter1" *set return_to_scene "" *if return_to_label = "label_name1" *set return_to_label "" *goto label_name1 *if return_to_label = "label_name2" *set return_to_label "" *goto label_name2 *if return_to_label = "label_name3" *set return_to_label "" *goto label_name3 (etc.)
Note that resetting return_to_scene and return_to_label back to "" (blank), once each has served its purpose, is probably not needed in many cases -- depending on how much you adapt the above code to suit your particular needs. However, "Better safe than sorry..." is always a great motto by which to script!
Local Alpha Testing System
It can be a pain to regularly run the automated testing systems provided with ChoiceScript (much less so with the helpful guidelines provided in this Wiki article), but including some test scripting in your own scene files can help you find many of the most common game-stopping errors quickly and easily, simply by playing through the options yourself. And you'll spot more spelling mistakes, simple typos, and such as any formatting problems with conditional text, by first testing the game properly yourself.
So, how do we make alpha testing relatively easy and actually enjoyable to do ourselves, instead of being a painful, monotonous chore, always having to restart from the very beginning and work our way through to the new section now in need of testing?
STEP 1: Add a boolean variable called alpha_testing to startup.txt, with a default value of false. This will prevent any of your testing script appearing / being used in the normal game (e.g. when uploaded online). When you do want to test locally, all you have to do is edit startup.txt and change the default value to true.
STEP 2: Immediately following your list of *create commands in startup.txt, add the following lines:
*if not (alpha_testing) *goto (or *goto_scene - a label or scene name for your normal game start)
With those two lines, when not testing (i.e. alpha_testing is false) your game will run as normal -- just make sure that *goto (or *goto_scene) line jumps to a *label (or scene) for the very start of your normal scripting.
When alpha_testing is set to true, however, it will fail the above condition and continue into the TESTING SCRIPT section below, which should immediately follow the above two lines in startup.txt.
STEP 3: Add the following lines, being sure to carry out the numbered instructions as written here:
*comment TESTING SCRIPT STARTS HERE *choice #Start Alpha Testing *goto test_start #Start Normal New Game *goto (or *goto_scene - your normal game start) *label test_start 1. Paste here the entire *create variable list from earlier in startup.txt 2. Turn the whole list into *set commands instead, and; 3. Alter the default values accordingly *goto_scene (test_scene_name) *comment TESTING SCRIPT ENDS HERE
Now when you run your game with alpha_testing set to true, you will be presented with the option to either Start Alpha Testing or Start Normal New Game, as you prefer. Only you will ever see this *choice -- provided that you remember to only ever upload startup.txt with alpha_testing having a default value of false.
The most onerous part of this setup is copy-pasting your variables list from startup.txt, where indicated above, and turning that entire list into a series of *set commands instead, so that you can now manually tweak the value of each variable as required for testing purposes without having to actually change the default values of all your *create commands. However, once you have this set up, it becomes very easy to test every aspect of your game.
Note that at the end of the series of *set commands there is a solitary *goto_scene. This is where you will change the (test_scene_name) to load the one you are currently testing.
STEP 4: And finally, near the very top of each of your other scene files (following only the creation and default setting of any *temp variables used anywhere in this particular scene) add the following simple two lines:
*if (alpha_testing) *goto (label_name)
If alpha_testing is not currently set to true in startup.txt, the scene will play as normal. If true, however, it will jump to the section currently being tested, so you just need to edit and give it a new (label_name) to jump to as you progress with your development and complete new sections ready for testing.
Alternatively, you could also use the *input_text and *gotoref commands like so:
*if (alpha_testing) *input_text selected_label *gotoref selected_label
Which, when alpha testing, will prompt you to type in the precise label name to jump to for testing. In this case you should first define selected_label as a string variable in startup.txt.
To now properly, thoroughly (and most of all, easily) test any label section of any scene anywhere in your game, you just have to do the following:
1. Edit startup.txt and set alpha_testing to true.
2. Tweak those *set commands in the TESTING SCRIPT section so all your variables better suit the stage of the game you are about to test (default starting character stats may need increasing, for instance).
3. Make sure the *goto_scene command at the end of those *set commands is loading the correct scene for testing.
4. In the scene to be tested, make sure the *goto at the top is referencing the correct label name for testing, or is prompting you to enter the actual label name so you jump straight there.
If you ever again upload your game online still containing such as simple "Bad label", "Non-existent variable name", "Expected choice body" or any Indentation-related errors, then shame on you! All common errors can be easily found and eliminated in advance using this Alpha Testing system, allowing your actual public beta testers to focus on providing constructive gameplay and narrative feedback, instead of just finding your basic scripting errors for you and themselves always frustratingly having to start over and over again...
A Soft Save is Not Hard!
For public "Beta Testing" purposes note that there is a plug-in available for a "hard save" system using the browser's localStorage, which you can learn about and download from the forum topic on the subject.
It is worth considering adopting that excellent system for your game once you have a significant chunk of the early part of your game done & tested, so your beta testers don't always have to start again from the very beginning just to test a new section. However, until such time, it is probably best to use a "soft save" system as described below, as any line changes made to early game files will simply break a "hard save" system and render the saved positions useless / cause game errors when attempting to load a saved position.
Note that when CoG releases a finished game, whether Official or Hosted, they will add a permanent "hard save" feature if your game warrants one. For that final release you will first need to remove any existing "hard save" system scripting from your game, as it is not presently supported by CoG.
To clarify, first of all, a "soft save" exists for the current browser session only. Once the session has ended (i.e. the browser tab in which the game is running is closed) all saved data is lost and it will be necessary to restart from the very beginning of the game on the next new session. It is however ideal for such as "checkpoint" / End of Chapter saves while a game is in public playtest (or at least, up to a point), and can also make your own testing easier and more efficient.
STEP 1: Add a save_load boolean variable to startup.txt with a default value of false, and extend your list of variables by adding a duplicate of each changeable one and preceding it with the letter 's' as shown below. This makes each a new, unique variable name. Note that you do not need to include a duplicate of those variables which do not actually change at all during the course of a game -- such as a character's name, for instance.
*create save_load false *create name "Unknown" *create gold 0 *create weapon 0 *create shield 0 *create armor 0 *create sgold 0 *create sweapon 0 *create sshield 0 *create sarmor 0
STEP 2: Once you've added your list of required duplicate variables, create a new file in the scenes folder called savegame.txt. Note that this does not need adding to the *scene_list section of startup.txt as it will be used only to save and restore game data as needed, and is therefore accessed with the *goto_scene command.
In savegame.txt you need to duplicate your changeable variables, turning these into two lists of *set commands as follows:
*if (save_load) *set sgold gold *set sweapon weapon *set sshield shield *set sarmor armor *goto endsaveload *else *set gold sgold *set weapon sweapon *set shield sshield *set armor sarmor *goto endsaveload
In this example, when save_load is set to true it will "save" the current game data (e.g. the current value of "gold" as the new value of "sgold"), else, if save_load is currently false, it will treat this as a restore and will overwrite the normal variables with the last-saved data stored in the 's'-name variables.
Beneath that section of savegame.txt you will need to add a *label endsaveload section to handle what to do in both instances. For example, if this is a 'checkpoint' save, it will need to point to the next new scene file to load; if this is a restore, it will need to go back to the start of the scene from whence it came (i.e. to the point where the game data was last saved). Appropriate messages should also be given to the player in either case.
STEP 3: An example of a a typical *label endsaveload follows:
*label endsaveload *if (save_load) PROGRESS SAVED . . . Should you die during the next Chapter you will be able to replay from this exact point. Please note that this option applies only to this session. After quitting the game, the next time you play will be from the very beginning. *page_break Begin Next Chapter *goto redirect *else GAME RESET - START OF CURRENT CHAPTER Are you ready to resume? *page_break Restart Chapter *goto redirect *label redirect *if return_to_scene = "chapter1" *goto_scene chapter1 *if return_to_scene = "chapter2" *goto_scene chapter2 *if return_to_scene = "chapter3" *goto_scene chapter3
In this example we have used a string variable called return_to_scene (which does not itself require an 's'-name duplicate) to carry the necessary information for redirecting the game after savegame.txt. This variable will have been set as appropriate (along with the actual save_load boolean) in the actual scene file immediately before it loaded savegame.txt with the *goto_scene command, as explained below.
STEP 4: Include the 'checkpoint' save game scripting in your various scene files. For example, at the end of Chapter One you may do the following:
*label checkpoint_save *page_break End of Chapter *set save_load true *set return_to_scene "chapter2" *goto_scene savegame
In this example we are setting save_load to true so that savegame.txt knows this is a save, not a restore, and we are setting the return_to_scene string variable as "chapter2" to indicate the next file to load in this instance, after it has saved. Those two essential variables set accordingly, we then end the scene by loading savegame.txt using *goto_scene savegame.
STEP 5: At any point in any scene where the character may die, or be otherwise unable to continue in the game, we now just need to add the restore scripting, to reload the last-saved data and ultimately return the player back to resume play from that particular checkpoint. For example, if the player-character dies during Chapter Three, we will need to restore the last-saved data from the end of Chapter Two and return the player to the very beginning of Chapter Three:
*label fatal_end *page_break Restart Chapter Three *set save_load false *set return_to_scene "chapter3" *goto_scene savegame
In this example we are setting save_load to false so that savegame.txt knows this is a restore, not a save, and we are setting the return_to_scene string variable as "chapter3" to indicate the next file to load in this instance, after it has restored the data back to the last 'checkpoint' save. Those two essential variables set accordingly, we then end the scene by loading savegame.txt using *goto_scene savegame.
Using Checkpoint Saves for Thorough Testing
Once you have implemented a "soft save" feature in your game you can use this for both local "Alpha Testing" and public "Beta Testing" purposes, as you can implement a Checkpoint Save / Reload at any point within a particular scene file, not just at the very end / beginning of a scene, using the basic principles of the "Scene Jump & Return System" (explained above) in combination with your new "soft save" feature.
This is perhaps best described as "Rinse & Repeat" testing as it allows either yourself or a public playtester to thoroughly explore each & every possible branch or route of a particular mini-scene / vignette using a particular character build, before either restarting with a new character build or continuing with the game past that particular point. By thoroughly testing every possible route within a particular mini-scene before continuing on, every possible ChoiceScript bug, game design error or narrative inconsistency can be more easily revealed and resolved.
For this purpose the savegame.txt file will first need creating as described above, and the following variables need to be defined in startup.txt:
*create save_load false *create return_to_scene "" *create return_to_label ""
The following PLAYTEST CHECKPOINT SAVE scripting should then be inserted at the start of the particular mini-scene being tested in this fashion, immediately following its own *label name but before any other scripting:
*label (your normal label name for start of this mini-scene) *page_break End of Scene *comment PLAYTEST CHECKPOINT SAVE START *if return_to_label = "(your normal label name for start of this mini-scene)" *set return_to_label "" *goto resume_playtest *else *set save_load true *set return_to_scene "(this scene name)" *set return_to_label "(your normal label name for start of this mini-scene)" *goto_scene savegame *label resume_playtest *comment PLAYTEST CHECKPOINT SAVE END
By this means, when done with testing, all you need to do is delete everything between (and including) the two *comment lines and the game will in future run as normal.
The above example will save the game data at this 'checkpoint' if it has not already just done so. If it has only just saved (or has only just restored the previous save) it will instead *goto resume_playtest and display the first page of this mini-scene.
At the very top of the current scene you will need to add the following "Jump & Return" scripting, to return to the precise *label name of the mini-scene in question after a save / restore:
*if return_to_scene = "(this scene name)" *set return_to_scene "" *if return_to_label = "(your normal label name for start of this mini-scene)" *goto (your normal label name for start of this mini-scene)
The above example ensures that the game will jump to the correct *label after either saving or restoring the data.
And finally, the following *label section should be inserted at the very end of the mini-scene being tested in this fashion, and all routes within that mini-scene should end with a *goto referencing *label rinse_repeat.
*comment PLAYTEST CHECKPOINT RESTORE START *label rinse_repeat *page_break End of Scene End of playtest section. Please select an option: *choice #Reload from Checkpoint Save *set save_load false *set return_to_scene "(this scene name)" *set return_to_label "(your normal label name for start of this mini-scene)" *goto_scene savegame #Start again with a New Character *ending #Continue Game *goto (next normal mini-scene label name) *comment PLAYTEST CHECKPOINT RESTORE END
If the default option is selected, the game will reload the saved data from the last checkpoint and return the player to the start of that particular mini-scene, in order to test a different route with the same character build. Other options here allow for a restart (to test with a different character build) or to continue as normal if the thorough testing of every route through this mini-scene is now complete.
Note that when testing is done and you remove the above scripting, you will need to use the Find-Replace feature of your Text Editor to replace all *goto rinse_repeat lines with *goto (your next normal scene name) instead.