diff options
| author | skylar <me@casper> | 2026-11-10 06:50:08 -0800 |
|---|---|---|
| committer | skylar <me@casper> | 2026-11-10 06:50:08 -0800 |
| commit | d36c54d996f3c14ae811312dbbe621e12a39edde (patch) | |
| tree | 1807134323479ac90bf69d28e410a7f70cb235a1 /src/term.rs | |
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 <noreply@anthropic.com>
Diffstat (limited to 'src/term.rs')
| -rw-r--r-- | src/term.rs | 50 |
1 files changed, 50 insertions, 0 deletions
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(); +} |