Choice menus
Choices
Input is offered to the player via text choices. A text choice is indicated by an *
character.
If no other flow instructions are given, once made, the choice will flow into the next line of text.
Hello world!
* Hello back!
Nice to hear from you!
This produces the following game:
Hello world!
1: Hello back!
> 1
Hello back!
Nice to hear from you!
By default, the text of a choice appears again, in the output.
Suppressing choice text
Some games separate the text of a choice from its outcome. In ink, if the choice text is given in square brackets, the text of the choice will not be printed into response.
Hello world!
* [Hello back!]
Nice to hear from you!
produces
Hello world!
1: Hello back!
> 1
Nice to hear from you!
Advanced: mixing choice and output text
The square brackets in fact divide up the option content. What's before is printed in both choice and output; what's inside only in choice; and what's after, only in output. Effectively, they provide alternative ways for a line to end.
Hello world!
* Hello [back!] right back to you!
Nice to hear from you!
produces:
Hello world!
1: Hello back!
> 1
Hello right back to you!
Nice to hear from you!
This is most useful when writing dialogue choices:
"What's that?" my master asked.
* "I am somewhat tired[."]," I repeated.
"Really," he responded. "How deleterious."
produces:
"What's that?" my master asked.
1: "I am somewhat tired."
> 1
"I am somewhat tired," I repeated.
"Really," he responded. "How deleterious."
Multiple Choices
To make choices really choices, we need to provide alternatives. We can do this simply by listing them:
"What's that?" my master asked.
* "I am somewhat tired[."]," I repeated.
"Really," he responded. "How deleterious."
* "Nothing, Monsieur!"[] I replied.
"Very good, then."
* "I said, this journey is appalling[."] and I want no more of it."
"Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve."
This produces the following game:
"What's that?" my master asked.
1: "I am somewhat tired."
2: "Nothing, Monsieur!"
3: "I said, this journey is appalling."
> 3
"I said, this journey is appalling and I want no more of it."
"Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve."
The above syntax is enough to write a single set of choices. In a real game, we'll want to move the flow from one point to another based on what the player chooses. To do that, we need to introduce a bit more structure.
Varying Choices
Choices can only be used once
By default, every choice in the game can only be chosen once. If you don't have loops in your story, you'll never notice this behaviour. But if you do use loops, you'll quickly notice your options disappearing...
=== find_help ===
You search desperately for a friendly face in the crowd.
* The woman in the hat[?] pushes you roughly aside. -> find_help
* The man with the briefcase[?] looks disgusted as you stumble past him. -> find_help
produces:
You search desperately for a friendly face in the crowd.
1: The woman in the hat?
2: The man with the briefcase?
> 1
The woman in the hat pushes you roughly aside.
You search desperately for a friendly face in the crowd.
1: The man with the briefcase?
>
... and on the next loop you'll have no options left.
Fallback choices
The above example stops where it does, because the next choice ends up in an "out of content" run-time error.
> 1
The man with the briefcase looks disgusted as you stumble past him.
You search desperately for a friendly face in the crowd.
Runtime error in tests/test.ink line 6: ran out of content. Do you need a '-> DONE' or '-> END'?
We can resolve this with a 'fallback choice'. Fallback choices are never displayed to the player, but are 'chosen' by the game if no other options exist.
A fallback choice is simply a "choice without choice text":
* -> out_of_options
Example of a fallback choice
Adding this into the previous example gives us:
=== find_help ===
You search desperately for a friendly face in the crowd.
* The woman in the hat[?] pushes you roughly aside. -> find_help
* The man with the briefcase[?] looks disgusted as you stumble past him. -> find_help
* ->
But it is too late: you collapse onto the station platform. This is the end.
-> END
and produces:
You search desperately for a friendly face in the crowd.
1: The woman in the hat?
2: The man with the briefcase?
> 1
The woman in the hat pushes you roughly aside.
You search desperately for a friendly face in the crowd.
1: The man with the briefcase?
> 1
The man with the briefcase looks disgusted as you stumble past him.
You search desperately for a friendly face in the crowd.
But it is too late: you collapse onto the station platform. This is the end.
Sticky choices
The 'once-only' behaviour is not always what we want, of course, so we have a second kind of choice: the "sticky" choice. A sticky choice is simply one that doesn't get used up, and is marked by a +
bullet.
=== homers_couch ===
+ [Eat another donut]
You eat another donut. -> homers_couch
* [Get off the couch]
You struggle up off the couch to go and compose epic poetry.
-> END
Fallback choices can be sticky too.
=== conversation_loop
* [Talk about the weather] -> chat_weather
* [Talk about the children] -> chat_children
+ -> sit_in_silence_again
Conditional Choices
You can also turn choices on and off by hand. ink has quite a lot of logic available, but the simplest tests is "has the player seen a particular piece of content".
Every knot/stitch in the game has a unique address (so it can be diverted to), and we use the same address to test if that piece of content has been seen.
* { not visit_paris } [Go to Paris] -> visit_paris
+ { visit_paris } [Return to Paris] -> visit_paris
* { visit_paris.met_estelle } [ Telephone Mme Estelle ] -> phone_estelle
Note that the test knot_name
is true if any stitch inside that knot has been seen.
Note also that conditionals don't override the once-only behaviour of options, so you'll still need sticky options for repeatable choices.
Advanced: multiple conditions
You can use several logical tests on an option; if you do, all the tests must all be passed for the option to appear.
* { not visit_paris } [Go to Paris] -> visit_paris
+ { visit_paris } { not bored_of_paris }
[Return to Paris] -> visit_paris