summaryrefslogtreecommitdiff
path: root/dungeon/src/msg.rs
blob: 68a6cbde637f17649b9e7efb67d01a748c285e66 (plain)
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
//! The `msg` crate contains the core functionality for
//! the on screen message.

use std::time::{Duration, Instant};

use crate::player_input::PlayerInput;

/// Duration between each character printed
const DURATION_PER: Duration = Duration::from_millis(100);

#[derive(Debug, Clone)]
pub struct Message {
	text: Option<Vec<u8>>,
	end: usize,
	waiting: bool,
	last: Instant,
}
impl Message {
	/// Returns the default empty message
	pub fn empty() -> Self {
		Self {
			text: None,
			end: 0,
			waiting: false,
			last: Instant::now(),
		}
	}

	/// Sets string as the current onscreen message
	pub fn set_message(&mut self, msg: &str) {
		let bytes = msg.bytes().collect();
		self.text = Some(bytes);
		self.end = 0;
	}

	/// Attempts to update the message on screen.
	/// Returns true if a character was printed
	pub fn update(&mut self, input: PlayerInput) -> bool {
		let Some(text) = &self.text else { return false };

		if self.end >= text.len() {
			if input.interact {
				self.text = None;
			}
			return false;
		}

		if self.waiting && !input.interact {
			return false;
		}

		if self.last.elapsed() < DURATION_PER {
			return false;
		}
		self.last = Instant::now();

		if text[self.end] == b'.' {
			self.waiting = true;
		}

		self.end += 1;
		true
	}

	/// Returns the current ascii message (if exists)
	pub fn current(&self) -> Option<&[u8]> {
		self.text.as_ref().map(|text| &text[..self.end])
	}

	/// Returns if the message box is visible
	pub const fn visible(&self) -> bool {
		self.text.is_some()
	}
}