Expand description
Partial implementation of the Ink markup language for game dialogue.
Ink is a creation of Inkle. For more information about the language, see their website.
§Why inkling
?
- Simple interface for walking through branching stories or dialog trees
- Designed to slot into an external framework: like Inkle’s implementation this is not a stand alone game engine, just a processor that will feed the story text and choices to the user
- Rust native, no wrestling with Unity or C# integration
- Support for non-latin alphabets in identifiers
- Few dependencies: currently only
serde
as an optional dependency to de/serialize stories, probablyrand
as maybe-optional in the future.
§Why not inkling
?
- Fewer features than Inkle’s implementation of the language
- Untested in serious work loads and large scripts
- Not even alpha status, what is this???
§Usage example
§A short story
This example shows the basics of using inkling
.
§Parsing the story
use inkling::read_story_from_string;
// Imagine that this is a complete `Ink` story!
let story_content = "\
Hello, World!
* Hello[ back!] right back at you!
";
let mut story = read_story_from_string(story_content).unwrap();
§Starting the story processor
// We will supply a buffer for the story to read content into
let mut line_buffer = Vec::new();
// Mark the story as being prepared by calling `start`
story.start().unwrap();
// Begin the story processing: it will return once it encounters the branching choice
let result = story.resume(&mut line_buffer).unwrap();
assert_eq!(&line_buffer[0].text, "Hello, World!\n");
§Accessing the content of a presented choice
use inkling::Prompt;
// The story provided us with the choice in the result
let choice = match result {
Prompt::Choice(choices) => choices[0].clone(),
_ => unreachable!(),
};
assert_eq!(&choice.text, "Hello back!");
§Resuming with a selected choice
// Resume by supplying a selected choice index and calling `resume`
story.make_choice(0).unwrap();
match story.resume(&mut line_buffer).unwrap() {
Prompt::Done => (),
_ => unreachable!(),
}
// The choice text has now been added to the buffer
assert_eq!(&line_buffer[1].text, "Hello right back at you!\n");
§Story loop
The idea is that story processing should be as simple as this loop:
while let Ok(Prompt::Choice(choices)) = story.resume(&mut line_buffer) {
// Present story text to user, then have them select a choice
}
An example of a simple command line story player is provided in the examples.
Run cargo run --example player
to try it out and browse the source code to see the
implementation.
§Features
A complete recreation of all features in the Ink language is beyond the scope of this project (and my capabilities as a programmer).
Currently the processor supports:
- Structure: Knots, stitches, nested branching choices, gathers, diverts, tags for knots and story
- Choices: Non-sticky, sticky, fallback, line variations, conditions
- Lines: Plain text, diverts, tags, conditions, alternative sequences (all except shuffle)
- Conditions: Nested,
and
/or
linking, can check against variables - Reading: Address validation for diverts and conditions. Conditions and expressions are validated after parsing the story.
- Variables: Used as text in sentences and in conditions, can modify from calling program
- Mathematics: In line text, using numbers, parenthesis and variables for all numerical
calculations. Strings can be concatenated using the
+
operator.
Hopefully coming:
- Structure: Multi-line blocks, labels
- Variables: Modify in the Ink script
- Reading: Include statements in files
Unlikely features:
- Structure: Threads (maybe?) and tunnels
- Program: Defining functions in the Ink story file, “advanced state tracking,” calling Rust functions from the script to get variables
§De/serializing stories
Enable the serde_support
feature to derive Deserialize
and Serialize
for all
required objects. If you are unfamiliar with serde
, this corresponds to reading
and writing finished story files in their current state. In game terms: saving
and loading.
For more information about serde
see their website.
§Contributions
I am a complete novice at designing frameworks which will fit into larger schemes. As such I have no real idea of best practices for interacting with an engine like this. If you have a suggestion for how to make it easier for a user to run the processor I would be very glad to hear it!
Likewise, contributions are welcome. Please open an issue on Github to discuss improvements or submit a pull request.
Re-exports§
pub use error::InklingError;
Modules§
- error
- Errors from creating or walking through stories.
Structs§
- Choice
- Choice presented to the user.
- Line
- Single line of text in a story, ready to display.
- Story
- Story with knots, diverts, choices and possibly lots of text.
Enums§
Functions§
- copy_
lines_ into_ string - Read all text from lines in a buffer into a single string and return it.
- read_
story_ from_ string - Read a
Story
by parsing an input string.
Type Aliases§
- Line
Buffer - Convenience type to indicate when a buffer of
Line
objects is being manipulated.