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
//! Narrative text with light composition.
//!
//! Every player-facing string in the data layer is a [`Text`] value. Resolving
//! a `Text` into a final `String` requires `RuntimeState` context and happens
//! in [`crate::interactive_fiction::engine::resolve`].
use crate::interactive_fiction::data::condition::Condition;
use crate::interactive_fiction::data::ids::{FlagKey, StatKey, TextId};
use serde::{Deserialize, Serialize};
/// A composable piece of narrative text.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Text {
/// A literal string, written as-is.
Literal(String),
/// Look up another `Text` by ID from `World.texts`.
Ref(TextId),
/// Inline the current textual representation of a flag's value.
Flag(FlagKey),
/// Inline the current value of a stat.
Stat(StatKey),
/// Pick one of two texts based on a condition.
Conditional {
when: Condition,
then: Box<Text>,
otherwise: Box<Text>,
},
/// Pick one of several variants using the runtime RNG.
OneOf(Vec<Text>),
/// Concatenate several texts in order.
Sequence(Vec<Text>),
}
impl Text {
/// Convenience constructor for literal strings.
pub fn lit(value: impl Into<String>) -> Self {
Text::Literal(value.into())
}
/// Empty literal text, useful as a default.
pub fn empty() -> Self {
Text::Literal(String::new())
}
}
impl Default for Text {
fn default() -> Self {
Text::empty()
}
}
impl From<&str> for Text {
fn from(value: &str) -> Self {
Text::Literal(value.to_string())
}
}
impl From<String> for Text {
fn from(value: String) -> Self {
Text::Literal(value)
}
}