From 86d5f832c8452aad2313489b82eb8fd514215b95 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 28 Oct 2026 22:28:20 +0100 Subject: v0.2.3: add ClientCore and fix the game board rendering --- src/client/games/manager.rs | 140 +++++++++++++++++++++++++++----------------- 1 file changed, 87 insertions(+), 53 deletions(-) (limited to 'src/client/games/manager.rs') diff --git a/src/client/games/manager.rs b/src/client/games/manager.rs index be96b1a..71cd28c 100644 --- a/src/client/games/manager.rs +++ b/src/client/games/manager.rs @@ -1,11 +1,10 @@ +use super::response::SpinResult; use super::slots::SlotsGame; use super::traits::{Game, GameError, GamePhase, GameState}; use std::collections::HashMap; -use std::io::Write; pub struct GameManager { current_session: Option, - pending_game_type: Option, games: HashMap>, } @@ -16,16 +15,18 @@ impl GameManager { Self { current_session: None, - pending_game_type: None, games, } } pub fn get_available_games(&self) -> Vec<(&str, &str)> { - self.games + let mut games: Vec<(&str, &str)> = self + .games .iter() - .map(|(k, v)| (k.as_str(), v.get_name())) - .collect() + .map(|(key, game)| (key.as_str(), game.get_name())) + .collect(); + games.sort_unstable_by_key(|(key, _)| *key); + games } pub fn enter_game(&mut self, game_type: &str) -> Result<(), GameError> { @@ -37,8 +38,6 @@ impl GameManager { return Err(GameError::InvalidAction); } - self.pending_game_type = Some(game_type.to_string()); - self.current_session = Some(GameState { game_type: game_type.to_string(), bet_amount: 10, @@ -49,28 +48,75 @@ impl GameManager { Ok(()) } - pub fn start_game(&mut self, stream: &mut W) -> Result<(), GameError> { - let game_type = self - .pending_game_type - .as_ref() - .ok_or(GameError::InvalidAction)?; + /// The wire request for a spin, if the current phase allows one. + pub fn spin_request(&self) -> Option { + let session = self.current_session.as_ref()?; + if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { + return None; + } + Some(format!( + "PLAY_START {} {}", + session.game_type, session.bet_amount + )) + } - let state = self + /// Move the board into its spinning state and drop the previous result + /// so stale reels/winnings cannot leak into the new spin. + pub fn begin_spin(&mut self) -> Result<(), GameError> { + let session = self .current_session .as_mut() .ok_or(GameError::InvalidAction)?; - - if state.phase != GamePhase::WaitingToStart && state.phase != GamePhase::Finished { + if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { return Err(GameError::InvalidAction); } - let bet_amount = state.bet_amount; + session.phase = GamePhase::Playing; + session.data.remove("error"); + session.data.remove("reels"); + session.data.remove("win_type"); + session.data.remove("winnings"); + Ok(()) + } - let writer = stream; - writeln!(writer, "PLAY_START {} {}", game_type, bet_amount) - .map_err(|_| GameError::NetworkError)?; + /// Store the settled spin so `render()` can draw it in place. + pub fn apply_result(&mut self, result: SpinResult) { + let Some(session) = self.current_session.as_mut() else { + return; + }; + session.phase = GamePhase::Finished; + session.bet_amount = result.bet_amount; + session.data.remove("error"); + session.data.insert("reels".to_string(), result.reels); + session + .data + .insert("win_type".to_string(), result.win_type); + session + .data + .insert("winnings".to_string(), result.winnings.to_string()); + session + .data + .insert("balance".to_string(), result.balance.to_string()); + } - Ok(()) + /// Show a failed spin without leaving the player stuck in `Playing`. + pub fn set_error(&mut self, message: impl Into) { + let Some(session) = self.current_session.as_mut() else { + return; + }; + session.phase = GamePhase::WaitingToStart; + session.data.remove("reels"); + session.data.remove("win_type"); + session.data.remove("winnings"); + session.data.insert("error".to_string(), message.into()); + } + + pub fn set_balance(&mut self, balance: i64) { + if let Some(session) = self.current_session.as_mut() { + session + .data + .insert("balance".to_string(), balance.to_string()); + } } pub fn get_current_game(&self) -> Option<&dyn Game> { @@ -83,49 +129,37 @@ impl GameManager { self.current_session.as_ref() } - pub fn get_current_render_lines(&self) -> Option { - let session = self.current_session.as_ref()?; - let game = self.games.get(&session.game_type)?; - Some(game.render_lines(session)) - } - pub fn is_in_game(&self) -> bool { self.current_session.is_some() } - pub fn is_game_started(&self) -> bool { - self.current_session - .as_ref() - .map(|s| s.phase != GamePhase::WaitingToStart) - .unwrap_or(false) + pub fn end_game(&mut self) { + self.current_session = None; } - pub fn reset_phase_to_waiting(&mut self) { - if let Some(ref mut session) = self.current_session { - session.phase = GamePhase::WaitingToStart; - session.data.clear(); + pub fn set_bet(&mut self, bet: u64) -> Result { + let session = self + .current_session + .as_mut() + .ok_or(GameError::InvalidAction)?; + if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { + return Err(GameError::InvalidAction); } - } - - pub fn end_game(&mut self) { - self.current_session = None; - self.pending_game_type = None; + session.bet_amount = bet.max(10); + Ok(session.bet_amount) } pub fn adjust_bet(&mut self, delta: i64) -> Result { - if let Some(ref session) = self.current_session { - if session.phase != GamePhase::WaitingToStart { - return Err(GameError::InvalidAction); - } + let session = self + .current_session + .as_mut() + .ok_or(GameError::InvalidAction)?; + if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { + return Err(GameError::InvalidAction); } - if let Some(ref mut session) = self.current_session { - let current_bet = session.bet_amount as i64; - let new_bet = (current_bet + delta).max(10) as u64; - session.bet_amount = new_bet; - Ok(new_bet) - } else { - Err(GameError::InvalidAction) - } + let current_bet = session.bet_amount as i64; + session.bet_amount = (current_bet + delta).max(10) as u64; + Ok(session.bet_amount) } } -- cgit v1.2.3