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, };