Conditional content
Ink
provides many methods for varying the text content of a line or the choices
presented to a user.
Choice conditions
The easiest way to gate which choices are presented to the user is to check if they have
visited a knot in the story. This is done by preceding the choice with the knot name
enclosed by curly braces, for example {knot}
.
In the following example, the first choice is only presented if the player has previously
visited the knot with name tea_house
.
#![allow(unused)] fn main() { extern crate inkling; use inkling::{read_story_from_string, Location, Prompt}; let content = r#" -> choice === choice === + {tea_house} "Yes, I saw them at 'Au thé à la menthe.'" + "No, I have not met them." === tea_house === -> choice "#; let mut story = read_story_from_string(content).unwrap(); let mut buffer = Vec::new(); match story.resume(&mut buffer).unwrap() { Prompt::Choice(choices) => { assert_eq!(choices.len(), 1); assert_eq!(choices[0].text, r#""No, I have not met them.""#); } _ => unreachable!() } story.move_to(&Location::from("tea_house")).unwrap(); match story.resume(&mut buffer).unwrap() { Prompt::Choice(choices) => { assert_eq!(choices.len(), 2); assert_eq!(choices[0].text, r#""Yes, I saw them at 'Au thé à la menthe.'""#); } _ => unreachable!() } }
Under the hood, inkling
resolves this by translating {tea_house}
as a variable
whose value is the number of times the knot has been visited. It then asserts
whether that value is “true”, which in Ink
is whether it is non-zero. Thus, {tea_house}
is an implicit form of writing the explicit condition {tea_house != 0}
.
#![allow(unused)] fn main() { extern crate inkling; use inkling::{read_story_from_string, Location, Prompt}; let content = r#" -> choice === choice === + {tea_house != 0} "Yes, I saw them at 'Au thé à la menthe.'" + "No, I have not met them." === tea_house === -> choice "#; let mut story = read_story_from_string(content).unwrap(); let mut buffer = Vec::new(); match story.resume(&mut buffer).unwrap() { Prompt::Choice(choices) => { assert_eq!(choices.len(), 1); assert_eq!(choices[0].text, r#""No, I have not met them.""#); } _ => unreachable!() } story.move_to(&Location::from("tea_house")).unwrap(); match story.resume(&mut buffer).unwrap() { Prompt::Choice(choices) => { assert_eq!(choices.len(), 2); assert_eq!(choices[0].text, r#""Yes, I saw them at 'Au thé à la menthe.'""#); } _ => unreachable!() } }
Knowing this, we can of course also test these conditions using other types of variables.
#![allow(unused)] fn main() { extern crate inkling; use inkling::{read_story_from_string, Prompt}; let content = r" VAR visited_château = true VAR coins = 3 + {visited_château} You recognize the bellboy. + {coins > 2} [Tip the bellboy] + {coins <= 2} [You cannot afford entry] "; let mut story = read_story_from_string(content).unwrap(); let mut buffer = Vec::new(); match story.resume(&mut buffer).unwrap() { Prompt::Choice(choices) => { assert_eq!(choices.len(), 2); assert_eq!(choices[0].text, "You recognize the bellboy."); assert_eq!(choices[1].text, "Tip the bellboy"); } _ => unreachable!() } }
Multiple conditions
Multiple conditions can be tested at once by supplying them one after another. All must be true for the choice to be presented. In this example, the first and third choices will be presented.
#![allow(unused)] fn main() { extern crate inkling; use inkling::{read_story_from_string, Prompt}; let content = r" VAR visited_château = true VAR coins = 6 + {visited_château} {coins > 5} Purchase the painting + {not visited_château} {coins > 5} Your wallet itches but you see nothing of interest. + Leave the exhibit "; let mut story = read_story_from_string(content).unwrap(); let mut buffer = Vec::new(); match story.resume(&mut buffer).unwrap() { Prompt::Choice(choices) => { assert_eq!(choices.len(), 2); assert_eq!(choices[0].text, "Purchase the painting"); assert_eq!(choices[1].text, "Leave the exhibit"); } _ => unreachable!() } }
Beginning choices with variables instead of conditions
Finally, in case you want the choice text to begin with a variable, “escape” the first
curly brace by prepending it with a \
character. This is so that inkling
will know
to write the variable as text, not evaluate it as a condition. This is an unfortunate
quirk of the very compact Ink
scripting language, where curly braces play many roles.
#![allow(unused)] fn main() { extern crate inkling; use inkling::{read_story_from_string, Prompt}; let content = r#" VAR mentor = "Evan" + \{mentor}, your mentor, greets you "#; let mut story = read_story_from_string(content).unwrap(); let mut buffer = Vec::new(); match story.resume(&mut buffer).unwrap() { Prompt::Choice(choices) => { assert_eq!(choices[0].text, "Evan, your mentor, greets you"); } _ => unreachable!() } }
For more information about which types of comparisons are supported, see the section on variable comparisons.
Text conditions
Conditions for displaying text are very similar to how conditions work for choices,
but work on this format: {condition: process this if true | otherwise process this}
.
A colon :
follows the condition, the content is inside the braces and an optional
|
marker marks content to show if the condition is not true.
#![allow(unused)] fn main() { extern crate inkling; use inkling::{read_story_from_string, Prompt}; let content = r" VAR visited_château = false VAR coins = 3 You {visited_château: recognize a painting | see nothing of interest}. {coins < 5: You cannot afford anything.} "; let mut story = read_story_from_string(content).unwrap(); let mut buffer = Vec::new(); story.resume(&mut buffer).unwrap(); assert_eq!(&buffer[0].text, "You see nothing of interest.\n"); assert_eq!(&buffer[1].text, "You cannot afford anything.\n"); }
You see nothing of interest.
You cannot afford anything.
Again, see the section on variable comparisons for more information about how conditions can be tested.
Nesting conditions
Conditions can naturally be nested inside of conditional content:
#![allow(unused)] fn main() { extern crate inkling; use inkling::{read_story_from_string, Prompt}; let content = r" VAR met_evan = true VAR met_austin = false {met_evan: Yes, I met with Evan {met_austin: and | but not} Austin}. "; let mut story = read_story_from_string(content).unwrap(); let mut buffer = Vec::new(); story.resume(&mut buffer).unwrap(); assert_eq!(&buffer[0].text, "Yes, I met with Evan but not Austin.\n"); }
Yes, I met with Evan but not Austin.
Diverts inside conditions
Content inside of conditions can divert to other knots.
#![allow(unused)] fn main() { extern crate inkling; use inkling::{read_story_from_string, Prompt}; let content = r" VAR met_evan = true {met_evan: Evan takes you to his home. -> château | -> END } === château === The car ride takes a few hours. "; let mut story = read_story_from_string(content).unwrap(); let mut buffer = Vec::new(); story.resume(&mut buffer).unwrap(); assert_eq!(&buffer[0].text, "Evan takes you to his home.\n"); assert_eq!(&buffer[1].text, "The car ride takes a few hours.\n"); }
Evan takes you to his home.
The car ride takes a few hours.