From 08269639606c0481037cbde7ebaf2e0455460883 Mon Sep 17 00:00:00 2001 From: salmonik Date: Thu, 29 Oct 2026 18:43:09 +0100 Subject: v2.2.1: forfeit blackjack bets when leaving or disconnecting --- src/client/core.rs | 18 ++++++++++------ src/client/games/blackjack.rs | 9 ++++---- src/server/core.rs | 50 ++++++++++++++++++++++++++++++++++++++----- src/server/games/blackjack.rs | 4 ++-- 4 files changed, 63 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/client/core.rs b/src/client/core.rs index 6e9c28b..77761b4 100644 --- a/src/client/core.rs +++ b/src/client/core.rs @@ -65,7 +65,7 @@ enum Pending { RouletteSpin, BlackjackStart, BlackjackAction, - BlackjackCancel, + BlackjackForfeit, Ping, Echo, Info, @@ -209,12 +209,16 @@ impl ClientCore { } } } - Some(Pending::BlackjackCancel) => match parse_blackjack_response(reply) { - Ok(_) => { + Some(Pending::BlackjackForfeit) => match parse_blackjack_response(reply) { + Ok(state) => { self.game.end_game(); + let message = format!( + "Game exited. Active hand forfeited ({} PLN lost).", + state.bet + ); vec![ Effect::ClearRegion, - Effect::Print(vec!["Game exited.".to_string()]), + Effect::Print(vec![message]), ] } Err(message) => { @@ -457,10 +461,10 @@ impl ClientCore { Key::CtrlC => vec![Effect::Quit], Key::Char('q') => { if let Some(hand) = hand.filter(|hand| hand.phase == "player") { - self.game.set_blackjack_status("cancelling"); - self.pending = Some(Pending::BlackjackCancel); + self.game.set_blackjack_status("forfeiting"); + self.pending = Some(Pending::BlackjackForfeit); vec![Effect::SendLine(format!( - "BLACKJACK_ACTION {} cancel", + "BLACKJACK_ACTION {} forfeit", hand.session_id ))] } else { diff --git a/src/client/games/blackjack.rs b/src/client/games/blackjack.rs index a34eb63..bad1781 100644 --- a/src/client/games/blackjack.rs +++ b/src/client/games/blackjack.rs @@ -38,6 +38,7 @@ impl BlackjackGame { "push" => "Push. Bet returned.".to_string(), "lose" => "Dealer wins.".to_string(), "bust" => "Bust.".to_string(), + "forfeit" => "Forfeited. Bet lost.".to_string(), "cancelled" => "Cancelled.".to_string(), _ => "Hand complete.".to_string(), } @@ -85,15 +86,15 @@ impl Game for BlackjackGame { } } "dealing" => "Dealing...".to_string(), - "cancelling" => "Cancelling...".to_string(), + "forfeiting" => "Forfeiting...".to_string(), "done" => Self::result_text(&hand.result, hand.winnings), _ => "Press [SPACE] to deal.".to_string(), }; let controls = if status == "player" { if hand.actions.iter().any(|action| action == "double") { - "[H]it [S]tand [D]ouble [Q]uit".to_string() + "[H]it [S]tand [D]ouble [Q] Forfeit".to_string() } else { - "[H]it [S]tand [Q]uit".to_string() + "[H]it [S]tand [Q] Forfeit".to_string() } } else { "[SPACE] New hand [+/-] Bet [Q] Quit".to_string() @@ -142,7 +143,7 @@ impl Game for BlackjackGame { D - double (when available)\n\ SPACE - deal a new hand\n\ +/- - change the next hand's bet\n\ - Q - leave the table" + Q - forfeit an active hand (bet is lost), or leave when no hand is active" .to_string() } } diff --git a/src/server/core.rs b/src/server/core.rs index cf8c4b9..259f936 100644 --- a/src/server/core.rs +++ b/src/server/core.rs @@ -297,11 +297,27 @@ impl ServerCore { return format!("ERROR {error}"); } } - "cancel" => { - let refund = session.bet_amount as i64; - let balance = database::credit(&mut self.conn, user, refund).unwrap_or(balance); + "forfeit" | "cancel" => { + hand.forfeit(); + let state = hand.state(session_id, balance); + let details = serde_json::to_string(&state).unwrap_or_else(|_| "{}".to_string()); + let balance = match database::settle_play( + &mut self.conn, + session_id, + user, + "blackjack", + hand.bet as i64, + 0, + &details, + ) { + Ok(balance) => balance, + Err(error) => { + eprintln!("Blackjack forfeit settlement failed for {user}: {error}"); + let _ = self.sessions.remove_session(session_id); + return "ERROR Failed to update balance".to_string(); + } + }; let _ = self.sessions.remove_session(session_id); - hand.cancel(); let state = hand.state(session_id, balance); return blackjack_wire(&state); } @@ -485,7 +501,31 @@ impl ServerCore { if let Some(user) = state.user.as_deref() { for session in self.sessions.get_user_sessions(user) { if session.game_type == "blackjack" { - let _ = database::credit(&mut self.conn, user, session.bet_amount as i64); + if let Some(raw) = session.state.data.get("hand") { + if let Ok(mut hand) = BlackjackHand::from_json(raw) { + if !hand.is_done() { + hand.forfeit(); + let balance = + database::get_balance(&self.conn, user).unwrap_or(0); + let final_state = hand.state(&session.session_id, balance); + let details = serde_json::to_string(&final_state) + .unwrap_or_else(|_| "{}".to_string()); + if let Err(error) = database::settle_play( + &mut self.conn, + &session.session_id, + user, + "blackjack", + hand.bet as i64, + 0, + &details, + ) { + eprintln!( + "Blackjack disconnect forfeit failed for {user}: {error}" + ); + } + } + } + } } let _ = self.sessions.remove_session(&session.session_id); } diff --git a/src/server/games/blackjack.rs b/src/server/games/blackjack.rs index 9505fed..df5a6ac 100644 --- a/src/server/games/blackjack.rs +++ b/src/server/games/blackjack.rs @@ -133,9 +133,9 @@ impl BlackjackHand { Ok(()) } - pub fn cancel(&mut self) { + pub fn forfeit(&mut self) { self.phase = "done".to_string(); - self.result = "cancelled".to_string(); + self.result = "forfeit".to_string(); self.winnings = 0; } -- cgit v1.2.3