80 lines
3.0 KiB
Rust
80 lines
3.0 KiB
Rust
//! Play-mode status sidebar widget for kiln-tui.
|
|
//!
|
|
//! [`StatusSidebarWidget`] draws the player's persistent stats (health + gems)
|
|
//! in a bordered block on the left of the screen during play. It is purely
|
|
//! presentational: it reads `health`/`gems` values handed in at construction and
|
|
//! never mutates game state.
|
|
|
|
use crate::utils::rgba8_to_color;
|
|
use kiln_core::Archetype;
|
|
use kiln_core::cp437::tile_to_char;
|
|
use ratatui::buffer::Buffer;
|
|
use ratatui::layout::Rect;
|
|
use ratatui::style::{Color, Style};
|
|
use ratatui::symbols::merge::MergeStrategy;
|
|
use ratatui::text::{Line, Span};
|
|
use ratatui::widgets::{Block, Paragraph, Widget};
|
|
|
|
/// How many hearts the health row always shows (the player's max health).
|
|
const MAX_HEARTS: u32 = 5;
|
|
/// A filled heart: bright red.
|
|
const HEART_FULL: Color = Color::Rgb(255, 0, 0);
|
|
/// A depleted heart: dark red.
|
|
const HEART_EMPTY: Color = Color::Rgb(90, 0, 0);
|
|
|
|
/// A ratatui widget that renders the play-mode status sidebar.
|
|
///
|
|
/// Shows a `Health:` label above a row of [`MAX_HEARTS`] heart glyphs (the first
|
|
/// `health` filled bright red, the rest dark red) and a `Gems: ♦ N` line.
|
|
pub struct StatusSidebarWidget {
|
|
/// The player's current health, clamped to [`MAX_HEARTS`] when drawn.
|
|
health: u32,
|
|
/// The number of gems collected, shown as a count.
|
|
gems: u32,
|
|
}
|
|
|
|
impl StatusSidebarWidget {
|
|
/// Builds a sidebar widget for the given player stats.
|
|
pub fn new(health: u32, gems: u32) -> Self {
|
|
Self { health, gems }
|
|
}
|
|
}
|
|
|
|
impl Widget for StatusSidebarWidget {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
// One bright-red span per filled heart, dark-red for the rest, so a
|
|
// partly-depleted bar reads at a glance.
|
|
let filled = self.health.min(MAX_HEARTS);
|
|
let hearts: Vec<Span> = (0..MAX_HEARTS)
|
|
.map(|i| {
|
|
let color = if i < filled { HEART_FULL } else { HEART_EMPTY };
|
|
Span::styled("♥", Style::default().fg(color))
|
|
})
|
|
.collect();
|
|
|
|
// Draw the gem indicator from the gem archetype's default glyph, so the
|
|
// sidebar matches what gems look like on the board (no hardcoded ♦/color).
|
|
let gem_glyph = Archetype::Gem.default_glyph();
|
|
let gem_char = tile_to_char(gem_glyph.tile).to_string();
|
|
let gem_style = Style::default().fg(rgba8_to_color(gem_glyph.fg));
|
|
|
|
let lines = vec![
|
|
Line::from("Health:"),
|
|
Line::from(hearts),
|
|
Line::from(""),
|
|
Line::from(vec![
|
|
Span::raw("Gems: "),
|
|
Span::styled(gem_char, gem_style),
|
|
Span::raw(format!(" {}", self.gems)),
|
|
]),
|
|
];
|
|
|
|
// A bordered block; `merge_borders` joins its right edge with the board
|
|
// block's left edge where the layout overlaps them by one column.
|
|
let block = Block::bordered()
|
|
.title(" Status (tab) ")
|
|
.merge_borders(MergeStrategy::Exact);
|
|
Paragraph::new(lines).block(block).render(area, buf);
|
|
}
|
|
}
|