summaryrefslogtreecommitdiff
path: root/dungeon
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-11-14 23:30:05 -0500
committerFreya Murphy <freya@freyacat.org>2025-11-14 23:30:05 -0500
commit65f5143d3e01e111afb960451e0741ddb37be240 (patch)
treed59bc1e885aa31743fd87ebadab8e1728e2cd683 /dungeon
parentgraphics: use 32bit color for atlas (diff)
downloadDungeonCrawl-65f5143d3e01e111afb960451e0741ddb37be240.tar.gz
DungeonCrawl-65f5143d3e01e111afb960451e0741ddb37be240.tar.bz2
DungeonCrawl-65f5143d3e01e111afb960451e0741ddb37be240.zip
graphics: add text message rendering (and sans ig)
Diffstat (limited to 'dungeon')
-rw-r--r--dungeon/src/lib.rs29
-rw-r--r--dungeon/src/msg.rs74
-rw-r--r--dungeon/src/player_input.rs3
3 files changed, 103 insertions, 3 deletions
diff --git a/dungeon/src/lib.rs b/dungeon/src/lib.rs
index a475f95..0c9e055 100644
--- a/dungeon/src/lib.rs
+++ b/dungeon/src/lib.rs
@@ -5,6 +5,7 @@ pub mod astar;
pub mod bsp;
pub mod entity;
pub mod map;
+pub mod msg;
pub mod player_input;
pub mod pos;
@@ -16,10 +17,23 @@ use rand::{
use crate::{
entity::{Entity, Player},
map::Floor,
+ msg::Message,
player_input::PlayerInput,
pos::FPos,
};
+/// Lets the caller know what has
+/// changed in the game state this
+/// tick
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum UpdateResult {
+ /// Default, entities have moved
+ EntityMovement,
+ /// Message on screen updated.
+ /// Contains if a char was added.
+ MessageUpdated(bool),
+}
+
/// The `Dungeon` type represents the game state of the
/// dungeon crawler.
#[derive(Debug, Clone)]
@@ -27,6 +41,7 @@ pub struct Dungeon {
pub floor: Floor,
pub player: Player,
pub enemies: Vec<Entity>,
+ pub msg: Message,
seed: u64,
rng: SmallRng,
}
@@ -48,11 +63,13 @@ impl Dungeon {
let player = Player::new(floor.player_start());
// TODO: Randomize enemy positions/types
let enemies = vec![Entity::zombie(floor.random_walkable_pos(&mut rng))];
+ let msg = Message::empty();
Self {
floor,
player,
enemies,
+ msg,
seed,
rng,
}
@@ -91,9 +108,15 @@ impl Dungeon {
&mut self.rng
}
- pub fn update(&mut self, player_input: PlayerInput, delta_time: f32) {
- self.act_player(player_input, delta_time);
- self.act_non_players(delta_time);
+ pub fn update(&mut self, player_input: PlayerInput, delta_time: f32) -> UpdateResult {
+ if self.msg.visible() {
+ let changed = self.msg.update(player_input);
+ UpdateResult::MessageUpdated(changed)
+ } else {
+ self.act_player(player_input, delta_time);
+ self.act_non_players(delta_time);
+ UpdateResult::EntityMovement
+ }
}
fn act_player(&mut self, player_input: PlayerInput, delta_time: f32) {
diff --git a/dungeon/src/msg.rs b/dungeon/src/msg.rs
new file mode 100644
index 0000000..68a6cbd
--- /dev/null
+++ b/dungeon/src/msg.rs
@@ -0,0 +1,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()
+ }
+}
diff --git a/dungeon/src/player_input.rs b/dungeon/src/player_input.rs
index aa0ef14..ddaad9f 100644
--- a/dungeon/src/player_input.rs
+++ b/dungeon/src/player_input.rs
@@ -12,5 +12,8 @@ pub struct PlayerInput {
/// (eg if the player is holding multiple keys at once,
/// or a joystick)
pub direction: Option<Direction>,
+ /// If the player is currently attempting to interact
+ /// with some object, entity, etc.
+ pub interact: bool,
// other player actions are to be added later
}