diff options
Diffstat (limited to 'src/bin/client/repl.rs')
| -rw-r--r-- | src/bin/client/repl.rs | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/bin/client/repl.rs b/src/bin/client/repl.rs index 1ed3073..e028cc2 100644 --- a/src/bin/client/repl.rs +++ b/src/bin/client/repl.rs | |||
| @@ -20,6 +20,7 @@ use zagan_bet::client::ui::{ | |||
| 20 | visual_line_count, | 20 | visual_line_count, |
| 21 | }; | 21 | }; |
| 22 | use zagan_bet::protocol::io_failure_message; | 22 | use zagan_bet::protocol::io_failure_message; |
| 23 | use zagan_bet::roulette::WHEEL; | ||
| 23 | 24 | ||
| 24 | use crate::connection::TlsStream; | 25 | use crate::connection::TlsStream; |
| 25 | 26 | ||
| @@ -150,6 +151,16 @@ impl ClientState { | |||
| 150 | } | 151 | } |
| 151 | } | 152 | } |
| 152 | Effect::ReplaceRegion(lines) => self.draw_region(&lines), | 153 | Effect::ReplaceRegion(lines) => self.draw_region(&lines), |
| 154 | Effect::AnimateRoulette { | ||
| 155 | winning, | ||
| 156 | final_lines, | ||
| 157 | } => { | ||
| 158 | self.animate_wheel(winning); | ||
| 159 | self.draw_region(&final_lines); | ||
| 160 | while crossterm::event::poll(std::time::Duration::ZERO).unwrap_or(false) { | ||
| 161 | let _ = crossterm::event::read(); | ||
| 162 | } | ||
| 163 | } | ||
| 153 | Effect::ClearRegion => self.clear_region(), | 164 | Effect::ClearRegion => self.clear_region(), |
| 154 | Effect::SetPrompt { text, cursor_col } => self.draw_prompt(&text, cursor_col), | 165 | Effect::SetPrompt { text, cursor_col } => self.draw_prompt(&text, cursor_col), |
| 155 | Effect::SendLine(line) => { | 166 | Effect::SendLine(line) => { |
| @@ -276,6 +287,49 @@ impl ClientState { | |||
| 276 | self.game_lines = 0; | 287 | self.game_lines = 0; |
| 277 | } | 288 | } |
| 278 | 289 | ||
| 290 | /// CS:GO-style wheel strip: the ball marker is fixed and the numbers move | ||
| 291 | /// left-to-right under it, ending with the winning number in the center. | ||
| 292 | fn animate_wheel(&mut self, winning: u8) { | ||
| 293 | use std::thread; | ||
| 294 | use std::time::Duration; | ||
| 295 | |||
| 296 | let target = WHEEL | ||
| 297 | .iter() | ||
| 298 | .position(|number| *number == winning) | ||
| 299 | .unwrap_or(0) as f64; | ||
| 300 | let wheel_len = WHEEL.len() as f64; | ||
| 301 | let start = target - 4.0 * wheel_len - 7.0; | ||
| 302 | let frames = 32; | ||
| 303 | |||
| 304 | for frame in 0..frames { | ||
| 305 | let t = frame as f64 / (frames - 1) as f64; | ||
| 306 | let ease = 1.0 - (1.0 - t).powi(3); | ||
| 307 | let center = (start + (target - start) * ease).round() as isize; | ||
| 308 | |||
| 309 | let strip = (0..9) | ||
| 310 | .map(|offset| { | ||
| 311 | let index = (center - 4 + offset).rem_euclid(WHEEL.len() as isize) as usize; | ||
| 312 | format!("[ {:>2} ]", WHEEL[index]) | ||
| 313 | }) | ||
| 314 | .collect::<Vec<_>>() | ||
| 315 | .join(" "); | ||
| 316 | let marker = format!("{}▼", " ".repeat(4 * 7 + 3)); | ||
| 317 | let lines = vec![ | ||
| 318 | "=== ROULETTE ===".to_string(), | ||
| 319 | strip, | ||
| 320 | marker, | ||
| 321 | "Spinning...".to_string(), | ||
| 322 | ]; | ||
| 323 | |||
| 324 | self.draw_region(&lines); | ||
| 325 | thread::sleep(Duration::from_millis(35)); | ||
| 326 | } | ||
| 327 | |||
| 328 | // Let the winning number sit under the static ball before the result | ||
| 329 | // board replaces the wheel. | ||
| 330 | thread::sleep(Duration::from_millis(450)); | ||
| 331 | } | ||
| 332 | |||
| 279 | fn draw_prompt(&mut self, text: &str, cursor_col: u16) { | 333 | fn draw_prompt(&mut self, text: &str, cursor_col: u16) { |
| 280 | execute!(stdout(), MoveToColumn(0), Clear(ClearType::CurrentLine)).unwrap(); | 334 | execute!(stdout(), MoveToColumn(0), Clear(ClearType::CurrentLine)).unwrap(); |
| 281 | print!("{}", "> ".cyan()); | 335 | print!("{}", "> ".cyan()); |
