diff --git a/reikhelm-viz/src/main.rs b/reikhelm-viz/src/main.rs index 38cbcd5..cf11749 100644 --- a/reikhelm-viz/src/main.rs +++ b/reikhelm-viz/src/main.rs @@ -201,7 +201,10 @@ fn draw_edges(snapshot: &Snapshot, layout: &Layout) { } /// Draws the on-screen HUD: seed, current stage, and the controls hint. -fn draw_hud(dungeon: &Dungeon) { +/// +/// When `seed_input` is `Some`, the user is typing a seed: the top line becomes +/// an entry prompt showing the buffer, and the hint switches to the entry keys. +fn draw_hud(dungeon: &Dungeon, seed_input: Option<&str>) { let stage_count = dungeon.snapshots.len(); let stage_label = dungeon .current() @@ -209,7 +212,17 @@ fn draw_hud(dungeon: &Dungeon) { .unwrap_or("(empty)"); let is_final = dungeon.stage + 1 == stage_count; - let seed_line = format!("seed: {}", dungeon.seed); + // The top line doubles as the seed-entry prompt while typing. + let (top_line, hint) = match seed_input { + Some(buf) => ( + format!("set seed: {buf}_"), + "Enter: apply Esc: cancel (digits only)", + ), + None => ( + format!("seed: {}", dungeon.seed), + "Space: reroll Left/Right: scrub stages S: set seed", + ), + }; let stage_line = format!( "stage {}/{}: {}{}", dungeon.stage + 1, @@ -217,11 +230,11 @@ fn draw_hud(dungeon: &Dungeon) { stage_label, if is_final { " (final)" } else { "" }, ); - let hint = "Space: reroll Left/Right: scrub stages"; // A dark plate behind the text so it stays readable over light floor tiles. draw_rectangle(0.0, 0.0, screen_width(), 64.0, Color::new(0.0, 0.0, 0.0, 0.55)); - draw_text(&seed_line, 12.0, 22.0, 24.0, WHITE); + let top_color = if seed_input.is_some() { GOLD } else { WHITE }; + draw_text(&top_line, 12.0, 22.0, 24.0, top_color); draw_text(&stage_line, 12.0, 44.0, 22.0, SKYBLUE); draw_text(hint, 12.0, 60.0, 18.0, LIGHTGRAY); } @@ -234,18 +247,57 @@ async fn main() { // determinism is unaffected — same seed always rebuilds the same dungeon. let mut seed: u64 = 0; let mut dungeon = Dungeon::generate(seed); + // `Some(buffer)` while the user is typing a seed; `None` in normal mode. + let mut seed_input: Option = None; loop { // --- input --- - if is_key_pressed(KeyCode::Space) { - seed = seed.wrapping_add(1); - dungeon = Dungeon::generate(seed); - } - if is_key_pressed(KeyCode::Left) { - dungeon.scrub(-1); - } - if is_key_pressed(KeyCode::Right) { - dungeon.scrub(1); + if seed_input.is_none() { + // Normal mode: reroll, scrub, or begin seed entry. + if is_key_pressed(KeyCode::Space) { + seed = seed.wrapping_add(1); + dungeon = Dungeon::generate(seed); + } + if is_key_pressed(KeyCode::Left) { + dungeon.scrub(-1); + } + if is_key_pressed(KeyCode::Right) { + dungeon.scrub(1); + } + if is_key_pressed(KeyCode::S) { + // Begin seed entry; digits are collected on the following frames. + seed_input = Some(String::new()); + } + } else { + // Seed-entry mode: collect digits, apply on Enter, cancel on Esc. + let mut exit = false; + { + let buf = seed_input.as_mut().expect("in seed-entry mode"); + // Drain this frame's typed chars; keep digits only (so the `S` + // that opened the mode and any other keys are ignored). Cap the + // length well under u64's 20 digits so it always parses. + while let Some(c) = get_char_pressed() { + if c.is_ascii_digit() && buf.len() < 19 { + buf.push(c); + } + } + if is_key_pressed(KeyCode::Backspace) { + buf.pop(); + } + if is_key_pressed(KeyCode::Enter) { + // Empty or unparseable buffer simply cancels (no change). + if let Ok(parsed) = buf.parse::() { + seed = parsed; + dungeon = Dungeon::generate(seed); + } + exit = true; + } else if is_key_pressed(KeyCode::Escape) { + exit = true; + } + } + if exit { + seed_input = None; + } } // --- draw --- @@ -271,7 +323,7 @@ async fn main() { ); } - draw_hud(&dungeon); + draw_hud(&dungeon, seed_input.as_deref()); next_frame().await; }