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 /// 
13 Blue,
14 /// 
15 Cyan,
16 /// 
17 Green,
18 /// 
19 Purple,
20 /// 
21 Red,
22 /// <span style="border: 1px solid black;"></span>
23 White,
24 /// 
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}