From d9f1fe513e6f7696809d3a9b4d44ca485fe99c97 Mon Sep 17 00:00:00 2001 From: salmonik Date: Thu, 29 Oct 2026 17:18:34 +0100 Subject: v2.1.0: add European roulette with split bets and wheel animation --- src/client/games/manager.rs | 131 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) (limited to 'src/client/games/manager.rs') diff --git a/src/client/games/manager.rs b/src/client/games/manager.rs index 168c49d..02e9451 100644 --- a/src/client/games/manager.rs +++ b/src/client/games/manager.rs @@ -1,6 +1,8 @@ -use super::response::SpinResult; +use super::response::{RouletteResult, SpinResult}; +use super::roulette::RouletteGame; use super::slots::SlotsGame; use super::traits::{Game, GameError, GamePhase, GameState}; +use crate::roulette::Bets; use std::collections::HashMap; pub struct GameManager { @@ -12,6 +14,7 @@ impl GameManager { pub fn new() -> Self { let mut games: HashMap> = HashMap::new(); games.insert("slots".to_string(), Box::new(SlotsGame::new())); + games.insert("roulette".to_string(), Box::new(RouletteGame::new())); Self { current_session: None, @@ -38,11 +41,25 @@ impl GameManager { return Err(GameError::InvalidAction); } + let mut data = HashMap::new(); + let bet_amount = if game_type == "roulette" { + data.insert( + "bets".to_string(), + serde_json::to_string(&Bets::default()).unwrap_or_else(|_| "{}".to_string()), + ); + data.insert("chip".to_string(), "10".to_string()); + data.insert("status".to_string(), "place".to_string()); + data.insert("number_input".to_string(), String::new()); + 0 + } else { + 10 + }; + self.current_session = Some(GameState { game_type: game_type.to_string(), - bet_amount: 10, + bet_amount, phase: GamePhase::WaitingToStart, - data: HashMap::new(), + data, }); Ok(()) @@ -54,6 +71,17 @@ impl GameManager { if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { return None; } + if session.game_type == "roulette" { + let bets = session + .data + .get("bets") + .cloned() + .unwrap_or_else(|| "{}".to_string()); + return Some(format!( + "PLAY_START roulette {} {}", + session.bet_amount, bets + )); + } Some(format!( "PLAY_START {} {}", session.game_type, session.bet_amount @@ -78,6 +106,13 @@ impl GameManager { session.data.remove("win_lines"); session.data.remove("win_cells"); session.data.remove("winnings"); + session.data.remove("number"); + session.data.remove("color"); + if session.game_type == "roulette" { + session + .data + .insert("status".to_string(), "spinning".to_string()); + } Ok(()) } @@ -130,6 +165,13 @@ impl GameManager { session.data.remove("win_lines"); session.data.remove("win_cells"); session.data.remove("winnings"); + session.data.remove("number"); + session.data.remove("color"); + if session.game_type == "roulette" { + session + .data + .insert("status".to_string(), "place".to_string()); + } session.data.insert("error".to_string(), message.into()); } @@ -141,6 +183,83 @@ impl GameManager { } } + pub fn roulette_bets(&self) -> Bets { + self.current_session + .as_ref() + .and_then(|session| session.data.get("bets")) + .and_then(|raw| serde_json::from_str(raw).ok()) + .unwrap_or_default() + } + + pub fn set_roulette_bets(&mut self, bets: &Bets) { + if let Some(session) = self.current_session.as_mut() { + session.data.insert( + "bets".to_string(), + serde_json::to_string(bets).unwrap_or_else(|_| "{}".to_string()), + ); + session.bet_amount = bets.total(); + } + } + + pub fn roulette_chip(&self) -> u64 { + self.current_session + .as_ref() + .and_then(|session| session.data.get("chip")) + .and_then(|value| value.parse().ok()) + .unwrap_or(10) + } + + pub fn set_roulette_chip(&mut self, chip: u64) { + if let Some(session) = self.current_session.as_mut() { + session.data.insert("chip".to_string(), chip.to_string()); + } + } + + pub fn set_roulette_number_input(&mut self, value: &str) { + if let Some(session) = self.current_session.as_mut() { + session + .data + .insert("number_input".to_string(), value.to_string()); + } + } + + pub fn set_roulette_status(&mut self, status: &str) { + if let Some(session) = self.current_session.as_mut() { + session + .data + .insert("status".to_string(), status.to_string()); + if status != "error" { + session.data.remove("error"); + } + } + } + + pub fn apply_roulette_result(&mut self, result: RouletteResult) { + 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("bets".to_string(), result.bets); + session + .data + .insert("number".to_string(), result.number.to_string()); + session.data.insert("color".to_string(), result.color); + session + .data + .insert("winnings".to_string(), result.winnings.to_string()); + session + .data + .insert("balance".to_string(), result.balance.to_string()); + session + .data + .insert("status".to_string(), "result".to_string()); + session + .data + .insert("number_input".to_string(), String::new()); + } + pub fn get_current_game(&self) -> Option<&dyn Game> { self.current_session .as_ref() @@ -167,6 +286,12 @@ impl GameManager { if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { return Err(GameError::InvalidAction); } + if session.game_type == "roulette" { + session + .data + .insert("chip".to_string(), bet.max(10).to_string()); + return Ok(bet.max(10)); + } session.bet_amount = bet.max(10); Ok(session.bet_amount) } -- cgit v1.2.3