1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Partial implementation of the *Ink* markup language for game dialogue.
//!
//! Ink is a creation of [Inkle](https://www.inklestudios.com/). For more information
//! about the language, [see their website](https://www.inklestudios.com/ink/).
//!
//! # 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, probably `rand` 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
//! ```
//! # use inkling::read_story_from_string;
//! # let story_content = "Hello, World!\n*Hello[ back!] right back at you!";
//! # let mut story = read_story_from_string(story_content).unwrap();
//! // We will supply a buffer for the story to read content into
//! let mut line_buffer = Vec::new();
//!
//! // Start the story processing: it will return once it encounters the branching choice
//! let result = story.start(&mut line_buffer).unwrap();
//!
//! assert_eq!(&line_buffer[0].text, "Hello, World!\n");
//! ```
//!
//!
//! ### Accessing the content of a presented choice
//! ```
//! # use inkling::read_story_from_string;
//! # let story_content = "Hello, World!\n*Hello[ back!] right back at you!";
//! # let mut story = read_story_from_string(story_content).unwrap();
//! # let mut line_buffer = Vec::new();
//! # let result = story.start(&mut line_buffer).unwrap();
//! 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
//! ```
//! # use inkling::{read_story_from_string, Prompt};
//! # let story_content = "Hello, World!\n*Hello[ back!] right back at you!";
//! # let mut story = read_story_from_string(story_content).unwrap();
//! # let mut line_buffer = Vec::new();
//! # let result = story.start(&mut line_buffer).unwrap();
//! # let choice = match result {
//! #     Prompt::Choice(choices) => choices[0].clone(),
//! #     _ => unreachable!(),
//! # };
//! // Resume by supplying the selected choice
//!
//! match story.resume_with_choice(&choice, &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:
//!
//! ```ignore
//! while let Ok(Prompt::Choice(choices)) = story.resume_with_choice(..) {
//!     // 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
//! *   Choices:    Non-sticky, sticky, fallback, line variations, simple conditions
//! *   Lines:      Plain text, diverts, tags, alternative sequences (all except shuffle)
//!
//! Hopefully coming:
//!
//! *   Lines:      Conditions
//! *   Variables:  Use in lines, ability to modify from the calling program
//! *   Reading:    Include statements in files, verifying addresses and content
//! *   Logic:      Nested conditions with brackets, `and`/`or` statements
//!
//! Unlikely features:
//!
//! *   Structure:  Threads and tunnels (maybe?)
//! *   Program:    Defining functions in the `Ink` story file, "advanced state tracking",
//!                 calling Rust functions from the script to get variables
//! *   Mathematics: I'm not yet sure that I want to write a calculator
//!
//! # De/serializing stories
//! Enable the `serde_support` feature to derive `Deserialize` and `Serialize` for all
//! required objects.
//!
//! # 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](https://github.com/pjohansson/inkling) to discuss improvements
//! or submit a pull request.
mod consts;
pub mod error;
mod follow;
mod knot;
mod line;
mod node;
mod story;
mod utils;

pub use error::InklingError;
pub use story::{
    copy_lines_into_string, read_story_from_string, Choice, Line, LineBuffer, Prompt, Story,
};