diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-29 17:18:34 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-29 17:18:34 +0100 |
| commit | d9f1fe513e6f7696809d3a9b4d44ca485fe99c97 (patch) | |
| tree | 9da99200fdfe004a47056d10340b3f59c7ccc52e /src/client/games/manager.rs | |
| parent | v2.0.0: reset plays audit to a generic per-game schema (diff) | |
| download | zagan-bet-d9f1fe513e6f7696809d3a9b4d44ca485fe99c97.tar.gz zagan-bet-d9f1fe513e6f7696809d3a9b4d44ca485fe99c97.zip | |
v2.1.0: add European roulette with split bets and wheel animation
Diffstat (limited to '')
| -rw-r--r-- | src/client/games/manager.rs | 131 |
1 files changed, 128 insertions, 3 deletions
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 @@ | |||
| 1 | use super::response::SpinResult; | 1 | use super::response::{RouletteResult, SpinResult}; |
| 2 | use super::roulette::RouletteGame; | ||
| 2 | use super::slots::SlotsGame; | 3 | use super::slots::SlotsGame; |
| 3 | use super::traits::{Game, GameError, GamePhase, GameState}; | 4 | use super::traits::{Game, GameError, GamePhase, GameState}; |
| 5 | use crate::roulette::Bets; | ||
| 4 | use std::collections::HashMap; | 6 | use std::collections::HashMap; |
| 5 | 7 | ||
| 6 | pub struct GameManager { | 8 | pub struct GameManager { |
| @@ -12,6 +14,7 @@ impl GameManager { | |||
| 12 | pub fn new() -> Self { | 14 | pub fn new() -> Self { |
| 13 | let mut games: HashMap<String, Box<dyn Game>> = HashMap::new(); | 15 | let mut games: HashMap<String, Box<dyn Game>> = HashMap::new(); |
| 14 | games.insert("slots".to_string(), Box::new(SlotsGame::new())); | 16 | games.insert("slots".to_string(), Box::new(SlotsGame::new())); |
| 17 | games.insert("roulette".to_string(), Box::new(RouletteGame::new())); | ||
| 15 | 18 | ||
| 16 | Self { | 19 | Self { |
| 17 | current_session: None, | 20 | current_session: None, |
| @@ -38,11 +41,25 @@ impl GameManager { | |||
| 38 | return Err(GameError::InvalidAction); | 41 | return Err(GameError::InvalidAction); |
| 39 | } | 42 | } |
| 40 | 43 | ||
| 44 | let mut data = HashMap::new(); | ||
| 45 | let bet_amount = if game_type == "roulette" { | ||
| 46 | data.insert( | ||
| 47 | "bets".to_string(), | ||
| 48 | serde_json::to_string(&Bets::default()).unwrap_or_else(|_| "{}".to_string()), | ||
| 49 | ); | ||
| 50 | data.insert("chip".to_string(), "10".to_string()); | ||
| 51 | data.insert("status".to_string(), "place".to_string()); | ||
| 52 | data.insert("number_input".to_string(), String::new()); | ||
| 53 | 0 | ||
| 54 | } else { | ||
| 55 | 10 | ||
| 56 | }; | ||
| 57 | |||
| 41 | self.current_session = Some(GameState { | 58 | self.current_session = Some(GameState { |
| 42 | game_type: game_type.to_string(), | 59 | game_type: game_type.to_string(), |
| 43 | bet_amount: 10, | 60 | bet_amount, |
| 44 | phase: GamePhase::WaitingToStart, | 61 | phase: GamePhase::WaitingToStart, |
| 45 | data: HashMap::new(), | 62 | data, |
| 46 | }); | 63 | }); |
| 47 | 64 | ||
| 48 | Ok(()) | 65 | Ok(()) |
| @@ -54,6 +71,17 @@ impl GameManager { | |||
| 54 | if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { | 71 | if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { |
| 55 | return None; | 72 | return None; |
| 56 | } | 73 | } |
| 74 | if session.game_type == "roulette" { | ||
| 75 | let bets = session | ||
| 76 | .data | ||
| 77 | .get("bets") | ||
| 78 | .cloned() | ||
| 79 | .unwrap_or_else(|| "{}".to_string()); | ||
| 80 | return Some(format!( | ||
| 81 | "PLAY_START roulette {} {}", | ||
| 82 | session.bet_amount, bets | ||
| 83 | )); | ||
| 84 | } | ||
| 57 | Some(format!( | 85 | Some(format!( |
| 58 | "PLAY_START {} {}", | 86 | "PLAY_START {} {}", |
| 59 | session.game_type, session.bet_amount | 87 | session.game_type, session.bet_amount |
| @@ -78,6 +106,13 @@ impl GameManager { | |||
| 78 | session.data.remove("win_lines"); | 106 | session.data.remove("win_lines"); |
| 79 | session.data.remove("win_cells"); | 107 | session.data.remove("win_cells"); |
| 80 | session.data.remove("winnings"); | 108 | session.data.remove("winnings"); |
| 109 | session.data.remove("number"); | ||
| 110 | session.data.remove("color"); | ||
| 111 | if session.game_type == "roulette" { | ||
| 112 | session | ||
| 113 | .data | ||
| 114 | .insert("status".to_string(), "spinning".to_string()); | ||
| 115 | } | ||
| 81 | Ok(()) | 116 | Ok(()) |
| 82 | } | 117 | } |
| 83 | 118 | ||
| @@ -130,6 +165,13 @@ impl GameManager { | |||
| 130 | session.data.remove("win_lines"); | 165 | session.data.remove("win_lines"); |
| 131 | session.data.remove("win_cells"); | 166 | session.data.remove("win_cells"); |
| 132 | session.data.remove("winnings"); | 167 | session.data.remove("winnings"); |
| 168 | session.data.remove("number"); | ||
| 169 | session.data.remove("color"); | ||
| 170 | if session.game_type == "roulette" { | ||
| 171 | session | ||
| 172 | .data | ||
| 173 | .insert("status".to_string(), "place".to_string()); | ||
| 174 | } | ||
| 133 | session.data.insert("error".to_string(), message.into()); | 175 | session.data.insert("error".to_string(), message.into()); |
| 134 | } | 176 | } |
| 135 | 177 | ||
| @@ -141,6 +183,83 @@ impl GameManager { | |||
| 141 | } | 183 | } |
| 142 | } | 184 | } |
| 143 | 185 | ||
| 186 | pub fn roulette_bets(&self) -> Bets { | ||
| 187 | self.current_session | ||
| 188 | .as_ref() | ||
| 189 | .and_then(|session| session.data.get("bets")) | ||
| 190 | .and_then(|raw| serde_json::from_str(raw).ok()) | ||
| 191 | .unwrap_or_default() | ||
| 192 | } | ||
| 193 | |||
| 194 | pub fn set_roulette_bets(&mut self, bets: &Bets) { | ||
| 195 | if let Some(session) = self.current_session.as_mut() { | ||
| 196 | session.data.insert( | ||
| 197 | "bets".to_string(), | ||
| 198 | serde_json::to_string(bets).unwrap_or_else(|_| "{}".to_string()), | ||
| 199 | ); | ||
| 200 | session.bet_amount = bets.total(); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | pub fn roulette_chip(&self) -> u64 { | ||
| 205 | self.current_session | ||
| 206 | .as_ref() | ||
| 207 | .and_then(|session| session.data.get("chip")) | ||
| 208 | .and_then(|value| value.parse().ok()) | ||
| 209 | .unwrap_or(10) | ||
| 210 | } | ||
| 211 | |||
| 212 | pub fn set_roulette_chip(&mut self, chip: u64) { | ||
| 213 | if let Some(session) = self.current_session.as_mut() { | ||
| 214 | session.data.insert("chip".to_string(), chip.to_string()); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | pub fn set_roulette_number_input(&mut self, value: &str) { | ||
| 219 | if let Some(session) = self.current_session.as_mut() { | ||
| 220 | session | ||
| 221 | .data | ||
| 222 | .insert("number_input".to_string(), value.to_string()); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | pub fn set_roulette_status(&mut self, status: &str) { | ||
| 227 | if let Some(session) = self.current_session.as_mut() { | ||
| 228 | session | ||
| 229 | .data | ||
| 230 | .insert("status".to_string(), status.to_string()); | ||
| 231 | if status != "error" { | ||
| 232 | session.data.remove("error"); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | pub fn apply_roulette_result(&mut self, result: RouletteResult) { | ||
| 238 | let Some(session) = self.current_session.as_mut() else { | ||
| 239 | return; | ||
| 240 | }; | ||
| 241 | session.phase = GamePhase::Finished; | ||
| 242 | session.bet_amount = result.bet_amount; | ||
| 243 | session.data.remove("error"); | ||
| 244 | session.data.insert("bets".to_string(), result.bets); | ||
| 245 | session | ||
| 246 | .data | ||
| 247 | .insert("number".to_string(), result.number.to_string()); | ||
| 248 | session.data.insert("color".to_string(), result.color); | ||
| 249 | session | ||
| 250 | .data | ||
| 251 | .insert("winnings".to_string(), result.winnings.to_string()); | ||
| 252 | session | ||
| 253 | .data | ||
| 254 | .insert("balance".to_string(), result.balance.to_string()); | ||
| 255 | session | ||
| 256 | .data | ||
| 257 | .insert("status".to_string(), "result".to_string()); | ||
| 258 | session | ||
| 259 | .data | ||
| 260 | .insert("number_input".to_string(), String::new()); | ||
| 261 | } | ||
| 262 | |||
| 144 | pub fn get_current_game(&self) -> Option<&dyn Game> { | 263 | pub fn get_current_game(&self) -> Option<&dyn Game> { |
| 145 | self.current_session | 264 | self.current_session |
| 146 | .as_ref() | 265 | .as_ref() |
| @@ -167,6 +286,12 @@ impl GameManager { | |||
| 167 | if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { | 286 | if session.phase != GamePhase::WaitingToStart && session.phase != GamePhase::Finished { |
| 168 | return Err(GameError::InvalidAction); | 287 | return Err(GameError::InvalidAction); |
| 169 | } | 288 | } |
| 289 | if session.game_type == "roulette" { | ||
| 290 | session | ||
| 291 | .data | ||
| 292 | .insert("chip".to_string(), bet.max(10).to_string()); | ||
| 293 | return Ok(bet.max(10)); | ||
| 294 | } | ||
| 170 | session.bet_amount = bet.max(10); | 295 | session.bet_amount = bet.max(10); |
| 171 | Ok(session.bet_amount) | 296 | Ok(session.bet_amount) |
| 172 | } | 297 | } |
