This article discusses Basic Scene Scripting and is intended for beginners to ChoiceScript Game Development. However, it assumes that the reader is already familiar with some essential basic elements such as the nature of scenes and variables, and the purpose of indentation. If you are not yet familiar with these aspects, we would highly recommend starting with A Basic Tutorial.
Writing your first scene
As a general rule, any ordinary text typed into a scene .txt file will be displayed by ChoiceScript as story narrative in your game. It doesn't require any special commands in order to be displayed as such, nor does it require any particular formatting. In essence, if the very first line of your very first scene reads...
The faint dirt track stretches away before you, winding over the rugged hills.
...that is precisely what will be displayed on the very first page of your game. It's that simple.
A few points are, however, worth noting concerning ordinary story narrative:
1. ChoiceScript does not allow extra spaces or a tab ("indentation") before the first word of each new paragraph as commonly used in such as a "proper English" paper novel. This is because ChoiceScript uses indentation for scripting purposes within each scene file, so adding extra indenting to paragraphs of narrative would cause a game-stopping error.
2. Instead, to space your narrative for easier reading in-game, you should simply leave a completely blank line between each paragraph -- in exactly the same way as the text of this article has been spaced for clarity.
3. Always bear in mind that this is both a global medium and one appealing to all age groups, so local slang terms and particular words or phrasings should be carefully considered before actual use. Unless especially suited to your game for some reason (such as in properly depicting and 'coloring' its actual setting) it may be best to stick to words in more common usage. In addition, if set in a culture not your own, or includes characters from other cultural backgrounds, it is probably best to avoid using derogatory stereotypes.
4. ChoiceScript can handle only Plain Text, not RTF (Rich Text Format) or similar, which is why you should use a text editor like Notepad++, not a word processor like MS-Word. You can, however, use both Bold Text and Italic Text within your narrative, using very simple tags enclosing selected words or phrases.
TIP: You should always spell check your work. If your preferred text editor doesn't allow you to actually spell check your writing, the easiest way is to simply copy the contents of an entire text file (CTRL-A, CTRL-C) and paste it (CTRL-V) into such as MS-Word, then manually apply any necessary changes to your original text file.
The dreaded "Wall of Text"
There may be certain parts of your story in which you feel it necessary to provide extra detail, description, or simply "essential" background information. Likewise, your natural writing style may be somewhat more verbose than that of the average ChoiceScript author. Neither is necessarily a bad thing, but it should always be borne in mind that the attention span of a reader can vary tremendously, especially when presented with the dreaded "Wall of Text" . . . not entirely unlike when reading this article, for instance. ;)
ChoiceScript has a very handy command, called *page_break, which can be placed -- on a line of its own, and not requiring extra indentation -- at any point in your narrative. This inserts a "Next" button in the game, allowing you to easily break up longer stretches of narrative into two or more "pages" and thereby avoid presenting the player with too much text on any single page. You can also change the actual wording of the "Next" button simply by adding some text after the command itself:
*page_break Three hours later . . .
All the same, do still always bear in mind that a ChoiceScript game is supposed to be an interactive experience for the reader. If they wanted to read an actual novel, they'd go out and buy one. You should always strive to keep the reader an active participant in the story, by prompting him or her to interact with the game (and thereby often dictate, or at least alter, the course of events) at fairly regular intervals.
Scripting your first interaction
All actual scripting commands should always be preceded by the asterisk * symbol. This is how ChoiceScript knows the difference between a scripting command and ordinary narrative. In addition, note that the actual Option text (i.e. what the player reads, and has to choose between, when making choices) should always be preceded in your story scripting by the hash # symbol, even when following a conditional command for that specific option. In essence, any line in your scripting not starting with either * or # (no matter how far indented), or the dollar $ symbol (used to display for the player the contents of a variable -- more on this later) will be displayed as narrative in your game. To recap:
* - scripting command # - option text for displaying the various options of a *choice / *fake_choice $ - for displaying the content of a variable; a numeric value or "some text" Anything else will be assumed to be narrative, and will be displayed as such.
The player of a ChoiceScript game interacts with the story by responding to "multiple choice" prompts, each usually offering two or more options from which to choose. There are two similar commands -- *choice and *fake_choice -- intended for this purpose. The differences between those two commands are few but important. However, it's not within the scope of this basic article to fully explain those differences, so do make a point of later investigating both commands more closely, to determine which is best to use for your purposes in each story situation. For the purpose of this beginner's article, we will stick with ordinary *choice.
Mike tells you that he saw Jill having lunch with Ben again, adding that in his opinion they seemed "quite cosy" together. *choice #Thank Mike for letting me know. You thank Mike for letting you know about Jill and Ben, but you cannot help noticing his sly smirk when it appears that you actually believe him. Mike offers to buy you another drink but you decline, saying that Jill was expecting you home an hour ago. Mike snorts his opinion on that subject. *finish #Punch Mike on the nose. *goto bar_fight
The example above would first display the Mike tells you... narrative followed by two options for the player to choose between -- either thank Mike, or punch him on the nose.
These two options are handled quite differently in the subsequent scripting. In the first instance, there is a further narrative response should the player choose to thank Mike, followed by the *finish command to indicate end of scene. By default the *finish command displays a button with the words "Next Chapter". However, as with the *page_break "Next" button mentioned earlier, the *finish button wording can also be changed simply by adding the required text to the command itself. For example, in the above case we might use:
*finish Leave the bar
When the player clicks that button, the *finish command will load the next sequential scene .txt file listed in the *scene_list section of the startup.txt file, skipping everything else in this particular scene.
Scripting a new label section / mini-scene
In the second instance above -- punching Mike on the nose -- we have instead used the *goto (label name) command. This means we must have, elsewhere in this same scene file (either above or below this particular *choice section; either is fine) a command saying...
... following which will be the narrative and any scripting required for that particular mini-scene.
Quite simply, when ChoiceScript hits a *goto line, it will immediately jump to the line containing that particular *label name (in this case, bar_fight). Every *goto command must always have a corresponding *label command elsewhere within the same scene file, but there is no limit to the number of different *goto commands you can have all referencing the exact same *label name. In essence, that bar_fight mini-scene could be made to occur for a number of different reasons / choices throughout this scene, not just as a result of this particular Punch Mike on the nose option.
Ultimately this *label section will also likely end with a *finish command and loading of the next sequential scene .txt file, but for now it is a separate branch (or route) within the current scene.
The most important point to grasp from the above example is that we didn't actually have to use a *goto and separate *label section for the bar_fight mini-scene. That entire thing could have been handled immediately following that option, in much the same way as the text response to the first option immediately followed that particular choice. However, bear in mind:
1. That whole bar fight mini-scene might be planned to involve further *choices, so requiring more indentation with each such choice. Jumping first to a *label back at "level one" indentation therefore keeps things simpler from a scripting / indentation point of view. This would be more pertinent still if that particular *choice was already a third or fourth nested one, in which case it would itself already be heavily indented.
2. As mentioned above, it's entirely possible that we may want to have *choices elsewhere in this scene (on entirely different routes in the story) also culminating in that bar fight -- i.e. a completely different reason for punching Mike on the nose in a bar . . . By giving that particular mini-scene its own *label section, we are able to add other *goto jumps leading directly to it.
Setting a temporary variable
*label bar_fight *temp punched_mike true
In this example, the first thing we have done at the very start of the bar fight is to record the fact that the player-character started it. We have done so by creating a temporary variable called punched_mike using the *temp command, and immediately set this variable to be true. Being a temporary variable, this information will be stored in memory only for the duration of the current scene; as soon as another scene file is loaded with the *finish or *goto_scene command, this information will be lost.
If we wanted to record this fact for possible use much later in the game, we would instead have to declare the punched_mike variable at the very beginning of the game in startup.txt, as a permanent variable using the *create command, and with an initial value of false. In this case we would instead simply *set that existing variable with a new value at this point in the game, as follows:
*label bar_fight *set punched_mike true
Scripting conditional text
We have recorded this vital punched_mike information because we know that later in this particular scene there will be another encounter with Mike, at work the following day. Mike's attitude towards the player-character will be heavily influenced by whether or not he was punched on the nose in the bar. Indeed, towards the end of that fight sequence, we may choose to use another *temp variable to record who actually won the fight, as that information might also be pertinent to the later mini-scene at work with Mike.
*label monday_morning The first thing that strikes you as you stroll into work on Monday morning is that *if (punched_mike) Mike's nose is swollen to twice its normal size, making him the object of much ridicule among his co-workers. He glares hatefully in your direction. *goto office *else the coffee is, as usual, all gone. You mournfully content yourself with a spoonful of freeze-dry, chewing despondently. *goto office *label office (narrative continues here)
In this example we have made use of our earlier temporary punched_mike boolean (true / false) variable to determine the opening paragraph of text when the player-character arrives at work on Monday morning. If that variable is true, we mention Mike's nose and attitude; if not (i.e. else if it's false) we mention something else instead. In either case we continue our narrative by jumping to a new *label below, as any use of *else in combination with *if must always either *finish or *goto, or similar. It is not permissible to simply "fall out" of an *if / *else statement -- ChoiceScript must be told what to do in each instance.
Note that in the above case we have to be careful to add an extra space after the words "...is that " in the opening line, so that whichever of the *if / else conditions applies, the conditional text will continue properly. Without that vital space the narrative would be joined up, so reading "is thatMike's nose" or "is thatthe coffee".
It is not possible to put that necessary extra space on the same line as " Mike's nose..." or " the coffee..." -- i.e. immediately in front of those particular words -- because, being the start of a new line in both cases, doing that would fall foul of the indentation rules and so result in an error.
A slightly different way of using conditional text is as follows:
*label monday_morning *if (punched_mike) The first thing that strikes you as you stroll into work on Monday morning is that Mike's nose is swollen to twice its normal size, making him the object of much ridicule among his co-workers. He glares hatefully in your direction. *line_break *line_break (narrative continues here, no label required)
In this example we have chosen not to display any particular narrative in the event that the player-character never actually punched Mike on the nose earlier in the story, so there is no *else to the *if condition. In this case it will display the opening paragraph only if punched_mike has been set to true. If false, it will simply skip that bit and default to displaying the (narrative continues here) line instead. If true, however, it will display that conditional text and then "fall out" of the *if statement (permissible here, because no *else has been used in this case) to also then display the (narrative continues here) line.
Note that in this case we have used two *line_break commands to force the game to insert a completely blank line after displaying the conditional text, before the (narrative continues here) line. Without those *line_break commands (and without using a *goto a new *label, since those are not needed in this case) it would display it all as one large paragraph, with the (narrative continues here) text immediately following the conditional text.
AARRRGH! Of course it exists!
Error: "Non-existent variable punched_mike"
It's worth noting that the actual creation of that original *temp variable, punched_mike, would result in the above error if, when it reaches *label monday_morning, the player-character had never actually punched Mike earlier but instead had chosen a different option.
The reason for the error is that immediately following that *label monday_morning it uses *if to check that variable, but the way we coded it earlier in the story, the temporary variable is only actually created if and when the player chooses to punch him. If Mike was never punched, that variable would not even exist, so resulting in a "Non-existent variable punched_mike" error when the story finally arrives at *label monday_morning and tries to check if that variable is true or false.
In essence, when creating *temp variables, give very careful consideration to where and how you plan to later make use of the information it contains. In this example, to avoid the potential error we would have to create the *temp punched_mike variable much earlier in the story (perhaps even at the very start of the scene) and with a default value of false to begin with. That way it would exist regardless of the route / options the player-character chooses, and could simply be *set punched_mike true if or when that option is actually selected by the player.