From d36c54d996f3c14ae811312dbbe621e12a39edde Mon Sep 17 00:00:00 2001 From: skylar Date: Tue, 10 Nov 2026 06:50:08 -0800 Subject: Orrery: game loop, name generator and derelict dungeons An ASCII sci-fi-fantasy game for the terminal, built on ratatui. - Game loop with a fixed 30 Hz tick and a stack of scenes; the kitty keyboard protocol is turned on where the terminal supports it, so later real-time scenes can tell when a key is held. - Stable hierarchical seeds: the whole universe derives from one u64, with tests pinning the exact outputs so old seeds keep working. - Name generator with four cultures, each with its own syllables and templates, plus unidentified/true names for artifacts. - Title screen with an animated orrery, and a name forge for browsing generated names. - Derelict ships to board: ship-shaped maps with an engine room, spine corridor, side rooms and bridge; symmetric shadowcasting sight; monsters that wake on sight and hunt; loot carried out through the airlock goes into the hold. - `orrery names` and `orrery ship` print the generators' output without the TUI, for tuning. Co-Authored-By: Claude Opus 5.5 --- src/term.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/term.rs (limited to 'src/term.rs') diff --git a/src/term.rs b/src/term.rs new file mode 100644 index 0000000..b11bbdc --- /dev/null +++ b/src/term.rs @@ -0,0 +1,50 @@ +//! Terminal setup and teardown. + +use std::io::{self, stdout}; + +use ratatui::DefaultTerminal; +use ratatui::crossterm::event::{ + KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags, +}; +use ratatui::crossterm::{execute, terminal}; + +/// What this terminal can tell us about the keyboard. +#[derive(Clone, Copy, Debug)] +pub struct KeyboardCaps { + /// The terminal reports key releases (the kitty keyboard protocol), so a + /// scene can know a key is being held. Without it, holding a key looks + /// like one press, a ~0.5 s pause, then auto-repeats, and real-time + /// controls need a fallback such as a throttle you step up and down. + pub key_release: bool, +} + +/// Raw mode, alternate screen, and the kitty keyboard protocol where available. +pub fn init() -> io::Result<(DefaultTerminal, KeyboardCaps)> { + let terminal = ratatui::try_init()?; + let key_release = terminal::supports_keyboard_enhancement().unwrap_or(false); + if key_release { + execute!( + stdout(), + PushKeyboardEnhancementFlags( + KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES + | KeyboardEnhancementFlags::REPORT_EVENT_TYPES + ) + )?; + // ratatui's panic hook restores raw mode and the alternate screen but + // not these flags, which would leave the shell receiving kitty-encoded + // keys. Pop them first, then hand over to ratatui's hook. + let previous = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |info| { + let _ = execute!(stdout(), PopKeyboardEnhancementFlags); + previous(info); + })); + } + Ok((terminal, KeyboardCaps { key_release })) +} + +pub fn restore(caps: KeyboardCaps) { + if caps.key_release { + let _ = execute!(stdout(), PopKeyboardEnhancementFlags); + } + ratatui::restore(); +} -- cgit v1.2.3