Skip to main content

intfic/
write_out.rs

1use colored::*;
2use rand::prelude::*;
3use std::io::{self, Write};
4use std::thread;
5use std::time::Duration;
6
7use crate::{FASTMODE, LINETIME, TYPETIME};
8
9/// Represents the available text colors we can output.
10#[derive(Debug)]
11pub enum Color {
12    /// ![Blue](https://via.placeholder.com/16/0000ff/000000?text=+)
13    Blue,
14    /// ![Cyan](https://via.placeholder.com/16/00ffff/000000?text=+)
15    Cyan,
16    /// ![Green](https://via.placeholder.com/16/008000/000000?text=+)
17    Green,
18    /// ![Purple](https://via.placeholder.com/16/800080/000000?text=+)
19    Purple,
20    /// ![Red](https://via.placeholder.com/16/ff0000/000000?text=+)
21    Red,
22    /// <span style="border: 1px solid black;">![White](https://via.placeholder.com/16/ffffff/000000?text=+)</span>
23    White,
24    /// ![Yellow](https://via.placeholder.com/16/ffff00/000000?text=+)
25    Yellow,
26}
27
28/// Prints out a line one character at a time with a specified color
29/// 
30/// The last parameter determines how long to sleep after the line is finished typing.
31/// One use of this is to make options type out faster so the player doesnt have to wait as long to choose one.
32/// 
33/// If the line contains one or more quotes (some text within two quotation marks), the color will only be used inside those quotes.
34/// This allows the author to associate certain colors with specific characters talking.
35/// 
36/// ```no_run
37/// # use intfic::write_out::{type_text, Color};
38/// type_text(
39///     "\"You better show up on time tomorrow!\" He shouted as I left. \"No more excuses!\"",
40///     Color::Blue,
41///     false
42/// );
43/// ```
44/// Output:
45/// <pre class="example-wrap"
46/// <span style="color:blue;">"You better show up on time tomorrow!" </span>
47/// <span style="color:black;">He shouted as I left. </span>
48/// <span style="color:blue;">"No more excuses!"</span>
49/// </pre>
50pub fn type_text(line: &str, color: Color, fast: bool) {
51    if contains_quote(line) {
52        type_quote(line, color, fast);
53    } else {
54        type_normal(line, color, fast);
55    }
56}
57
58// Types out a given line all in the same given color.
59//
60// After each character, wait a slightly random amount of time based on TYPETIME.
61// After each line, wait a shorter or longer amount of time based on the given "fast" parameter and LINETIME.
62fn type_normal(line: &str, color: Color, fast: bool) {
63    if line.is_empty() {
64        return;
65    }
66
67    let mut rng = rand::thread_rng();
68    for c in line.chars() {
69        write_char(c, &color);
70        naptime(TYPETIME.mul_f64(rng.gen::<f64>() + 0.25));
71    }
72
73    naptime(if fast { LINETIME / 2 } else { LINETIME });
74    println!();
75}
76
77// Types out a given line, only using the given color to accentuate quotes in the line.
78//
79// After each character, wait a slightly random amount of time based on TYPETIME.
80// After each line, wait a shorter or longer amount of time based on the given "fast" parameter and LINETIME.
81fn type_quote(line: &str, color: Color, fast: bool) {
82    if line.is_empty() {
83        return;
84    }
85
86    let mut in_quote: bool = false;
87
88    let mut rng = rand::thread_rng();
89    for c in line.chars() {
90        if c == '"' {
91            write_char(c, &color);
92            in_quote = !in_quote;
93        } else if in_quote {
94            write_char(c, &color);
95        } else {
96            write_char(c, &Color::White);
97        }
98
99        naptime(TYPETIME.mul_f64(rng.gen::<f64>() + 0.25));
100    }
101
102    naptime(if fast { LINETIME / 2 } else { LINETIME });
103    println!();
104}
105
106// Returns true if the line contains two quotation marks.
107fn contains_quote(line: &str) -> bool {
108    let mut seen_quote: bool = false;
109
110    for c in line.chars() {
111        if c == '"' && seen_quote {
112            return true;
113        } else {
114            seen_quote = true;
115        }
116    }
117
118    false
119}
120
121// Type a single character with the given color, then flush stdout to display it.
122fn write_char(c: char, color: &Color) {
123    let mut s = String::default();
124    s.push(c);
125
126    match color {
127        Color::White  => print!("{}", s),
128        Color::Blue   => print!("{}", s.blue()),
129        Color::Cyan   => print!("{}", s.cyan()),
130        Color::Green  => print!("{}", s.green()),
131        Color::Purple => print!("{}", s.purple()),
132        Color::Red    => print!("{}", s.red()),
133        Color::Yellow => print!("{}", s.yellow()),
134    }
135
136    io::stdout().flush().unwrap();
137}
138
139// Wait the given duration, unless FASTMODE is enabled.
140fn naptime(time: Duration) {
141    if !FASTMODE {
142        thread::sleep(time);
143    }
144}