summaryrefslogtreecommitdiffstats
path: root/src/client/core.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/client/core.rs109
1 files changed, 60 insertions, 49 deletions
diff --git a/src/client/core.rs b/src/client/core.rs
index 0b2e683..7e43fb7 100644
--- a/src/client/core.rs
+++ b/src/client/core.rs
@@ -4,13 +4,14 @@ use crate::client::games::response::{
4 parse_roulette_response, parse_spin_response, 4 parse_roulette_response, parse_spin_response,
5}; 5};
6use crate::client::games::roulette::Direction; 6use crate::client::games::roulette::Direction;
7use crate::client::view::{Command, RouletteView, View};
7use crate::client::ui::{ 8use crate::client::ui::{
8 command_names, completion_lines, display_width, help_lines, history_lines, 9 command_names, completion_lines, display_width, help_lines, history_lines,
9 input_cursor_column, parse_bet_arg, record_history, 10 input_cursor_column, parse_bet_arg, record_history,
10}; 11};
11use crate::crash::{CrashState, multiplier_at}; 12use crate::crash::{CrashState, multiplier_at};
12use crate::history::MAX_HISTORY; 13use crate::history::MAX_HISTORY;
13use crate::roulette::Bets; 14use crate::roulette::{BetTarget, Bets};
14use std::time::{Duration, Instant}; 15use std::time::{Duration, Instant};
15 16
16#[derive(Debug, Clone, Copy, PartialEq, Eq)] 17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -41,13 +42,10 @@ pub enum InteractiveCommand {
41pub enum Effect { 42pub enum Effect {
42 /// Append lines to the scrolling transcript. 43 /// Append lines to the scrolling transcript.
43 Print(Vec<String>), 44 Print(Vec<String>),
44 /// Replace the game board region in place. 45 /// Draw the current view in the board region.
45 ReplaceRegion(Vec<String>), 46 Render(View),
46 /// Run the roulette wheel animation, then draw the final board lines. 47 /// Run the roulette wheel animation, then draw the final view.
47 AnimateRoulette { 48 AnimateRoulette { winning: u8, view: View },
48 winning: u8,
49 final_lines: Vec<String>,
50 },
51 /// Remove the game board region. 49 /// Remove the game board region.
52 ClearRegion, 50 ClearRegion,
53 /// Redraw the command prompt. `text` is the input without the `> ` prefix. 51 /// Redraw the command prompt. `text` is the input without the `> ` prefix.
@@ -215,11 +213,8 @@ impl ClientCore {
215 self.balance = Some(result.balance); 213 self.balance = Some(result.balance);
216 let winning = result.number; 214 let winning = result.number;
217 self.game.apply_roulette_result(result); 215 self.game.apply_roulette_result(result);
218 let final_lines = self.board_lines().unwrap_or_default(); 216 let view = self.view();
219 vec![Effect::AnimateRoulette { 217 vec![Effect::AnimateRoulette { winning, view }]
220 winning,
221 final_lines,
222 }]
223 } 218 }
224 Err(message) => { 219 Err(message) => {
225 self.game.set_error(message); 220 self.game.set_error(message);
@@ -380,53 +375,62 @@ impl ClientCore {
380 } 375 }
381 376
382 fn handle_roulette_key(&mut self, key: Key) -> Vec<Effect> { 377 fn handle_roulette_key(&mut self, key: Key) -> Vec<Effect> {
383 let direction = match key {
384 Key::Up => Some(Direction::Up),
385 Key::Down => Some(Direction::Down),
386 Key::Left => Some(Direction::Left),
387 Key::Right => Some(Direction::Right),
388 _ => None,
389 };
390 if let Some(direction) = direction {
391 let cursor = self.game.roulette_cursor().moved(direction);
392 self.game.set_roulette_cursor(&cursor);
393 return self.board_effects();
394 }
395
396 match key { 378 match key {
397 Key::CtrlC => vec![Effect::Quit], 379 Key::CtrlC => vec![Effect::Quit],
398 Key::Char('q') => { 380 Key::Up => self.command(Command::MoveCursor(Direction::Up)),
399 self.game.end_game(); 381 Key::Down => self.command(Command::MoveCursor(Direction::Down)),
400 vec![ 382 Key::Left => self.command(Command::MoveCursor(Direction::Left)),
401 Effect::ClearRegion, 383 Key::Right => self.command(Command::MoveCursor(Direction::Right)),
402 Effect::Print(vec!["Game exited.".to_string()]), 384 Key::Enter => self.command(Command::PlaceBet),
403 ] 385 Key::Char(' ') => self.command(Command::Spin),
386 Key::Char('c') => self.command(Command::ClearBets),
387 Key::Char('+') | Key::Char('=') => self.command(Command::AdjustChip(10)),
388 Key::Char('-') => self.command(Command::AdjustChip(-10)),
389 Key::Char('q') => self.command(Command::Leave),
390 _ => Vec::new(),
391 }
392 }
393
394 /// Apply a semantic command. Both frontends drive the core through this.
395 pub fn command(&mut self, command: Command) -> Vec<Effect> {
396 match command {
397 Command::MoveCursor(direction) => {
398 let cursor = self.game.roulette_cursor().moved(direction);
399 self.game.set_roulette_cursor(&cursor);
400 self.board_effects()
404 } 401 }
405 Key::Char(' ') => self.spin_roulette(), 402 Command::PlaceBet => match self.game.roulette_cursor().target() {
406 Key::Char('c') => { 403 Some(target) => self.place_roulette_chip_on(target),
404 None => Vec::new(),
405 },
406 Command::PlaceBetAt(target) => self.place_roulette_chip_on(target),
407 Command::ClearBets => {
407 self.game.set_roulette_bets(&Bets::default()); 408 self.game.set_roulette_bets(&Bets::default());
408 self.game.set_roulette_status("place"); 409 self.game.set_roulette_status("place");
409 self.board_effects() 410 self.board_effects()
410 } 411 }
411 Key::Char('+') | Key::Char('=') => { 412 Command::SetChip(chip) => {
412 let chip = self.game.roulette_chip().saturating_add(10); 413 self.game.set_roulette_chip(chip.max(10));
413 self.game.set_roulette_chip(chip);
414 self.board_effects() 414 self.board_effects()
415 } 415 }
416 Key::Char('-') => { 416 Command::AdjustChip(delta) => {
417 let chip = self.game.roulette_chip().saturating_sub(10).max(10); 417 let chip = (self.game.roulette_chip() as i64 + delta).max(10) as u64;
418 self.game.set_roulette_chip(chip); 418 self.game.set_roulette_chip(chip);
419 self.board_effects() 419 self.board_effects()
420 } 420 }
421 Key::Enter => self.place_roulette_chip(), 421 Command::Spin => self.spin_roulette(),
422 _ => Vec::new(), 422 Command::Leave => {
423 self.crash_started = None;
424 self.game.end_game();
425 vec![
426 Effect::ClearRegion,
427 Effect::Print(vec!["Game exited.".to_string()]),
428 ]
429 }
423 } 430 }
424 } 431 }
425 432
426 fn place_roulette_chip(&mut self) -> Vec<Effect> { 433 fn place_roulette_chip_on(&mut self, target: BetTarget) -> Vec<Effect> {
427 let Some(target) = self.game.roulette_cursor().target() else {
428 return Vec::new();
429 };
430 let mut bets = self.game.roulette_bets(); 434 let mut bets = self.game.roulette_bets();
431 bets.add(target, self.game.roulette_chip()); 435 bets.add(target, self.game.roulette_chip());
432 self.place_roulette_bets(bets) 436 self.place_roulette_bets(bets)
@@ -950,11 +954,18 @@ impl ClientCore {
950 Some(game.render(state).lines().map(str::to_string).collect()) 954 Some(game.render(state).lines().map(str::to_string).collect())
951 } 955 }
952 956
957 /// Snapshot of the current screen for a frontend to draw.
958 pub fn view(&self) -> View {
959 if let Some(state) = self.game.get_current_state() {
960 if state.game_type == "roulette" {
961 return View::Roulette(RouletteView::from_state(state));
962 }
963 }
964 View::Text(self.board_lines().unwrap_or_default())
965 }
966
953 fn board_effects(&self) -> Vec<Effect> { 967 fn board_effects(&self) -> Vec<Effect> {
954 self.board_lines() 968 vec![Effect::Render(self.view())]
955 .map(Effect::ReplaceRegion)
956 .into_iter()
957 .collect()
958 } 969 }
959 970
960 fn prompt_effects(&self) -> Vec<Effect> { 971 fn prompt_effects(&self) -> Vec<Effect> {