diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-01 21:24:48 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-01 21:24:48 +0100 |
| commit | a5ea79739783682c46983d5b67b2b4b7b5338ccb (patch) | |
| tree | d7e06cacfffdb173e8b27bcca426d6bbdd152ee3 | |
| parent | v4.2.0: wire the GUI to the core, transport and all four games (diff) | |
| download | zagan-bet-a5ea79739783682c46983d5b67b2b4b7b5338ccb.tar.gz zagan-bet-a5ea79739783682c46983d5b67b2b4b7b5338ccb.zip | |
v4.2.1: plain-language game copy and a balance fetch on login
The lobby and every game screen now speak to a player, not an operator: each game has one how-to sentence, and the table headers, limits, RTP, paytable and server-timing notes are gone. The account and balance are fetched whenever a session signs in, including stored-credential auto-login, so the header is filled before the lobby appears.
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | docs/GUI-PLAN.md | 7 | ||||
| -rw-r--r-- | docs/TESTING.md | 5 | ||||
| -rw-r--r-- | docs/screenshots/gui-blackjack-1080p.png | bin | 60075 -> 47190 bytes | |||
| -rw-r--r-- | docs/screenshots/gui-crash-1080p.png | bin | 64377 -> 44892 bytes | |||
| -rw-r--r-- | docs/screenshots/gui-lobby-1080p.png | bin | 64944 -> 67881 bytes | |||
| -rw-r--r-- | docs/screenshots/gui-roulette-1080p.png | bin | 118143 -> 105976 bytes | |||
| -rw-r--r-- | docs/screenshots/gui-roulette-result-1080p.png | bin | 113253 -> 109944 bytes | |||
| -rw-r--r-- | docs/screenshots/gui-slots-1080p.png | bin | 78173 -> 56798 bytes | |||
| -rw-r--r-- | gui/Cargo.toml | 2 | ||||
| -rw-r--r-- | gui/src/app.rs | 79 | ||||
| -rw-r--r-- | gui/src/blackjack.rs | 36 | ||||
| -rw-r--r-- | gui/src/crash.rs | 47 | ||||
| -rw-r--r-- | gui/src/net.rs | 2 | ||||
| -rw-r--r-- | gui/src/roulette.rs | 38 | ||||
| -rw-r--r-- | gui/src/slots.rs | 56 |
16 files changed, 51 insertions, 223 deletions
| @@ -3,7 +3,7 @@ members = ["gui"] | |||
| 3 | 3 | ||
| 4 | [package] | 4 | [package] |
| 5 | name = "zagan-bet" | 5 | name = "zagan-bet" |
| 6 | version = "4.2.0" | 6 | version = "4.2.1" |
| 7 | edition = "2024" | 7 | edition = "2024" |
| 8 | license = "GPL-3.0-or-later" | 8 | license = "GPL-3.0-or-later" |
| 9 | 9 | ||
diff --git a/docs/GUI-PLAN.md b/docs/GUI-PLAN.md index 4279626..89cf495 100644 --- a/docs/GUI-PLAN.md +++ b/docs/GUI-PLAN.md | |||
| @@ -130,6 +130,9 @@ they show the same layout with the real session and the pinned action bars. | |||
| 130 | - Sidebars pin their action block below the content, so SPIN, CLEAR, DEAL and | 130 | - Sidebars pin their action block below the content, so SPIN, CLEAR, DEAL and |
| 131 | START never move as the bet slip or a hand grows. The embedded fonts have no | 131 | START never move as the bet slip or a hand grows. The embedded fonts have no |
| 132 | suit or arrow glyphs, so suits are shapes and navigation uses plain words. | 132 | suit or arrow glyphs, so suits are shapes and navigation uses plain words. |
| 133 | - The lobby and the game screens speak plain language: one how-to sentence per | ||
| 134 | game, no RTP, table limits, deck rules or server-timing jargon. The account | ||
| 135 | and balance are fetched as soon as a session signs in. | ||
| 133 | - The header balance is held at the staked amount while the reels or wheel | 136 | - The header balance is held at the staked amount while the reels or wheel |
| 134 | turn, then jumps to the settled value: the GUI never reveals a payout before | 137 | turn, then jumps to the settled value: the GUI never reveals a payout before |
| 135 | the animation does. Refused spins cancel the animation and show the error. | 138 | the animation does. Refused spins cancel the animation and show the error. |
| @@ -152,8 +155,8 @@ Measured on Linux at 1080p with llvmpipe software GL: | |||
| 152 | | --- | --- | | 155 | | --- | --- | |
| 153 | | Linux binary | 8.3 MB | | 156 | | Linux binary | 8.3 MB | |
| 154 | | Windows x86_64 binary | 6.8 MB | | 157 | | Windows x86_64 binary | 6.8 MB | |
| 155 | | Cold start to window | 61 ms | | 158 | | Cold start to window | 72 ms | |
| 156 | | Idle RSS | 131 MB | | 159 | | Idle RSS | 130 MB | |
| 157 | | Idle CPU | 0% | | 160 | | Idle CPU | 0% | |
| 158 | 161 | ||
| 159 | **Gate:** the screenshot set is ready for review. Remaining for the gate: | 162 | **Gate:** the screenshot set is ready for review. Remaining for the gate: |
diff --git a/docs/TESTING.md b/docs/TESTING.md index 817cb3d..613cd08 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md | |||
| @@ -126,8 +126,9 @@ terminal client; a saved login from one signs in the other. | |||
| 126 | 2. First contact: the fingerprint modal appears before any credentials. Cancel | 126 | 2. First contact: the fingerprint modal appears before any credentials. Cancel |
| 127 | leaves the connect screen; Trust continues to the login screen. | 127 | leaves the connect screen; Trust continues to the login screen. |
| 128 | 3. Register, then log in with "Remember this login". The lobby shows the host, | 128 | 3. Register, then log in with "Remember this login". The lobby shows the host, |
| 129 | ping, account, balance and the four games; quit and reconnect: the stored | 129 | ping, account, balance and the four games; the balance fills in immediately |
| 130 | login signs in without asking. | 130 | without entering a game. Quit and reconnect: the stored login signs in |
| 131 | without asking. | ||
| 131 | 4. Each game: place a bet or deal, play a round, and confirm the balance and the | 132 | 4. Each game: place a bet or deal, play a round, and confirm the balance and the |
| 132 | header update. Slots shows reels and win lines; roulette spins the wheel and | 133 | header update. Slots shows reels and win lines; roulette spins the wheel and |
| 133 | reports the payout; blackjack draws suits and settles; crash draws a smooth | 134 | reports the payout; blackjack draws suits and settles; crash draws a smooth |
diff --git a/docs/screenshots/gui-blackjack-1080p.png b/docs/screenshots/gui-blackjack-1080p.png index b0fcc19..361f987 100644 --- a/docs/screenshots/gui-blackjack-1080p.png +++ b/docs/screenshots/gui-blackjack-1080p.png | |||
| Binary files differ | |||
diff --git a/docs/screenshots/gui-crash-1080p.png b/docs/screenshots/gui-crash-1080p.png index 245a3a1..da72f1f 100644 --- a/docs/screenshots/gui-crash-1080p.png +++ b/docs/screenshots/gui-crash-1080p.png | |||
| Binary files differ | |||
diff --git a/docs/screenshots/gui-lobby-1080p.png b/docs/screenshots/gui-lobby-1080p.png index a258967..8bfe8c8 100644 --- a/docs/screenshots/gui-lobby-1080p.png +++ b/docs/screenshots/gui-lobby-1080p.png | |||
| Binary files differ | |||
diff --git a/docs/screenshots/gui-roulette-1080p.png b/docs/screenshots/gui-roulette-1080p.png index 1d7af3d..703ea57 100644 --- a/docs/screenshots/gui-roulette-1080p.png +++ b/docs/screenshots/gui-roulette-1080p.png | |||
| Binary files differ | |||
diff --git a/docs/screenshots/gui-roulette-result-1080p.png b/docs/screenshots/gui-roulette-result-1080p.png index fe4c9cd..c1ffa63 100644 --- a/docs/screenshots/gui-roulette-result-1080p.png +++ b/docs/screenshots/gui-roulette-result-1080p.png | |||
| Binary files differ | |||
diff --git a/docs/screenshots/gui-slots-1080p.png b/docs/screenshots/gui-slots-1080p.png index 9d79321..0982114 100644 --- a/docs/screenshots/gui-slots-1080p.png +++ b/docs/screenshots/gui-slots-1080p.png | |||
| Binary files differ | |||
diff --git a/gui/Cargo.toml b/gui/Cargo.toml index d3d9c36..5418794 100644 --- a/gui/Cargo.toml +++ b/gui/Cargo.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "zagan-bet-gui" | 2 | name = "zagan-bet-gui" |
| 3 | version = "4.2.0" | 3 | version = "4.2.1" |
| 4 | edition = "2024" | 4 | edition = "2024" |
| 5 | license = "GPL-3.0-or-later" | 5 | license = "GPL-3.0-or-later" |
| 6 | description = "Desktop frontend for zagan-bet" | 6 | description = "Desktop frontend for zagan-bet" |
diff --git a/gui/src/app.rs b/gui/src/app.rs index f0efd3e..af64e5e 100644 --- a/gui/src/app.rs +++ b/gui/src/app.rs | |||
| @@ -49,6 +49,7 @@ pub struct ZaganApp { | |||
| 49 | notices: VecDeque<Notice>, | 49 | notices: VecDeque<Notice>, |
| 50 | awaiting: Option<Instant>, | 50 | awaiting: Option<Instant>, |
| 51 | need_info: bool, | 51 | need_info: bool, |
| 52 | was_logged_in: bool, | ||
| 52 | pending_login: Option<(String, String)>, | 53 | pending_login: Option<(String, String)>, |
| 53 | /// Displayed balance while a result animation runs: stake deducted, no | 54 | /// Displayed balance while a result animation runs: stake deducted, no |
| 54 | /// winnings yet. The view already knows the outcome; the player must not. | 55 | /// winnings yet. The view already knows the outcome; the player must not. |
| @@ -62,7 +63,6 @@ struct Session { | |||
| 62 | host: String, | 63 | host: String, |
| 63 | fingerprint: Option<String>, | 64 | fingerprint: Option<String>, |
| 64 | ping_ms: f32, | 65 | ping_ms: f32, |
| 65 | server_version: String, | ||
| 66 | latest: String, | 66 | latest: String, |
| 67 | url: String, | 67 | url: String, |
| 68 | user: Option<String>, | 68 | user: Option<String>, |
| @@ -186,6 +186,7 @@ impl ZaganApp { | |||
| 186 | notices: VecDeque::new(), | 186 | notices: VecDeque::new(), |
| 187 | awaiting: None, | 187 | awaiting: None, |
| 188 | need_info: false, | 188 | need_info: false, |
| 189 | was_logged_in: false, | ||
| 189 | pending_login: None, | 190 | pending_login: None, |
| 190 | balance_hold: None, | 191 | balance_hold: None, |
| 191 | balance: None, | 192 | balance: None, |
| @@ -348,7 +349,7 @@ impl ZaganApp { | |||
| 348 | reply, | 349 | reply, |
| 349 | }); | 350 | }); |
| 350 | } | 351 | } |
| 351 | Event::Connected(connected) => self.connected(ctx, connected), | 352 | Event::Connected(connected) => self.connected(connected), |
| 352 | Event::Failed { | 353 | Event::Failed { |
| 353 | addr, | 354 | addr, |
| 354 | failure, | 355 | failure, |
| @@ -376,7 +377,7 @@ impl ZaganApp { | |||
| 376 | } | 377 | } |
| 377 | } | 378 | } |
| 378 | 379 | ||
| 379 | fn connected(&mut self, ctx: &Context, connected: Connected) { | 380 | fn connected(&mut self, connected: Connected) { |
| 380 | self.connect.pending = false; | 381 | self.connect.pending = false; |
| 381 | self.connect.error = None; | 382 | self.connect.error = None; |
| 382 | self.core.set_connected(true); | 383 | self.core.set_connected(true); |
| @@ -393,19 +394,14 @@ impl ZaganApp { | |||
| 393 | host: connected.addr, | 394 | host: connected.addr, |
| 394 | fingerprint: connected.fingerprint, | 395 | fingerprint: connected.fingerprint, |
| 395 | ping_ms: connected.elapsed_ms, | 396 | ping_ms: connected.elapsed_ms, |
| 396 | server_version: connected.server_version, | ||
| 397 | latest: connected.latest, | 397 | latest: connected.latest, |
| 398 | url: connected.url, | 398 | url: connected.url, |
| 399 | user: connected.user, | 399 | user: connected.user, |
| 400 | }); | 400 | }); |
| 401 | 401 | ||
| 402 | self.need_info = self.session.as_ref().is_some_and(|s| s.user.is_some()); | 402 | self.need_info = false; |
| 403 | self.was_logged_in = false; | ||
| 403 | self.account = None; | 404 | self.account = None; |
| 404 | if self.need_info { | ||
| 405 | let effects = self.core.command(Command::Info); | ||
| 406 | self.apply(ctx, effects); | ||
| 407 | self.need_info = false; | ||
| 408 | } | ||
| 409 | } | 405 | } |
| 410 | 406 | ||
| 411 | fn failed(&mut self, addr: String, failure: Failure, message: String) { | 407 | fn failed(&mut self, addr: String, failure: Failure, message: String) { |
| @@ -511,7 +507,6 @@ impl ZaganApp { | |||
| 511 | let command = if registering { | 507 | let command = if registering { |
| 512 | Command::Register { user, credential } | 508 | Command::Register { user, credential } |
| 513 | } else { | 509 | } else { |
| 514 | self.need_info = true; | ||
| 515 | if self.login.remember { | 510 | if self.login.remember { |
| 516 | self.pending_login = Some((user.clone(), credential.clone())); | 511 | self.pending_login = Some((user.clone(), credential.clone())); |
| 517 | } | 512 | } |
| @@ -522,19 +517,26 @@ impl ZaganApp { | |||
| 522 | } | 517 | } |
| 523 | 518 | ||
| 524 | fn tick(&mut self, ctx: &Context) { | 519 | fn tick(&mut self, ctx: &Context) { |
| 525 | // Request deadline, mirroring the terminal's socket timeout. | 520 | // Fetch the account and balance once each time a session signs in. |
| 526 | if self.need_info | 521 | let signed_in = self |
| 527 | && self | 522 | .core |
| 528 | .session | 523 | .view() |
| 529 | .as_ref() | 524 | .as_ref() |
| 530 | .is_some_and(|session| session.user.is_some()) | 525 | .is_some_and(|view| matches!(view, View::Lobby(lobby) if lobby.user.is_some())); |
| 531 | && self.account.is_none() | 526 | if signed_in != self.was_logged_in { |
| 532 | { | 527 | self.was_logged_in = signed_in; |
| 528 | if signed_in { | ||
| 529 | self.need_info = true; | ||
| 530 | } | ||
| 531 | } | ||
| 532 | if self.need_info && signed_in { | ||
| 533 | let effects = self.core.command(Command::Info); | 533 | let effects = self.core.command(Command::Info); |
| 534 | self.apply(ctx, effects); | 534 | self.apply(ctx, effects); |
| 535 | self.need_info = false; | 535 | self.need_info = false; |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | // Request deadline, mirroring the terminal's socket timeout. | ||
| 539 | |||
| 538 | if let Some(sent) = self.awaiting { | 540 | if let Some(sent) = self.awaiting { |
| 539 | if sent.elapsed() > REQUEST_TIMEOUT { | 541 | if sent.elapsed() > REQUEST_TIMEOUT { |
| 540 | self.awaiting = None; | 542 | self.awaiting = None; |
| @@ -1351,13 +1353,7 @@ fn lobby_screen(ui: &mut Ui, app: &mut ZaganApp, lobby: &LobbyView) { | |||
| 1351 | ui.add_space(theme::SPACE_2); | 1353 | ui.add_space(theme::SPACE_2); |
| 1352 | ui.horizontal(|ui| { | 1354 | ui.horizontal(|ui| { |
| 1353 | if let Some(session) = &app.session { | 1355 | if let Some(session) = &app.session { |
| 1354 | widgets::note( | 1356 | widgets::note(ui, &format!("Signed in to {}", session.host)); |
| 1355 | ui, | ||
| 1356 | &format!( | ||
| 1357 | "Signed in to {} · server v{}", | ||
| 1358 | session.host, session.server_version | ||
| 1359 | ), | ||
| 1360 | ); | ||
| 1361 | } | 1357 | } |
| 1362 | ui.with_layout(Layout::right_to_left(Align::Center), |ui| { | 1358 | ui.with_layout(Layout::right_to_left(Align::Center), |ui| { |
| 1363 | if widgets::ghost(ui, "Forget saved login") { | 1359 | if widgets::ghost(ui, "Forget saved login") { |
| @@ -1396,15 +1392,9 @@ fn game_card(ui: &mut Ui, app: &mut ZaganApp, key: &str, name: &str) { | |||
| 1396 | .font(theme::sans(22.0)) | 1392 | .font(theme::sans(22.0)) |
| 1397 | .color(theme::TEXT), | 1393 | .color(theme::TEXT), |
| 1398 | ); | 1394 | ); |
| 1399 | ui.add_space(2.0); | ||
| 1400 | widgets::note(ui, tagline(key)); | ||
| 1401 | ui.add_space(theme::SPACE_1); | 1395 | ui.add_space(theme::SPACE_1); |
| 1402 | ui.label( | 1396 | widgets::note(ui, how_to(key)); |
| 1403 | RichText::new(meta(key)) | 1397 | ui.add_space(theme::SPACE_4); |
| 1404 | .font(theme::mono(10.0)) | ||
| 1405 | .color(theme::TEXT_FAINT), | ||
| 1406 | ); | ||
| 1407 | ui.add_space(theme::SPACE_3); | ||
| 1408 | if widgets::primary(ui, "PLAY", true, 110.0, 36.0) { | 1398 | if widgets::primary(ui, "PLAY", true, 110.0, 36.0) { |
| 1409 | let effects = app.core.command(Command::Play { | 1399 | let effects = app.core.command(Command::Play { |
| 1410 | game: key.to_string(), | 1400 | game: key.to_string(), |
| @@ -1415,22 +1405,13 @@ fn game_card(ui: &mut Ui, app: &mut ZaganApp, key: &str, name: &str) { | |||
| 1415 | }); | 1405 | }); |
| 1416 | } | 1406 | } |
| 1417 | 1407 | ||
| 1418 | fn tagline(game: &str) -> &'static str { | 1408 | /// One plain sentence: how to play, not the house's rules sheet. |
| 1419 | match game { | 1409 | fn how_to(game: &str) -> &'static str { |
| 1420 | "slots" => "Five reels, five paylines, one lever.", | ||
| 1421 | "roulette" => "The European wheel, thirty-seven pockets.", | ||
| 1422 | "blackjack" => "Six decks, dealer stands on seventeen. Pays 3:2.", | ||
| 1423 | "crash" => "The multiplier rises. Cash out before it busts.", | ||
| 1424 | _ => "", | ||
| 1425 | } | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | fn meta(game: &str) -> &'static str { | ||
| 1429 | match game { | 1410 | match game { |
| 1430 | "slots" => "MIN 10 KR · RTP 96%", | 1411 | "slots" => "Spin the reels. Three or more matching symbols from the left win.", |
| 1431 | "roulette" => "MIN 10 KR · SINGLE ZERO", | 1412 | "roulette" => "Put chips on the table, then spin. Straight numbers pay the most.", |
| 1432 | "blackjack" => "MIN 10 KR · S17 · 3:2", | 1413 | "blackjack" => "Get closer to 21 than the dealer without going over.", |
| 1433 | "crash" => "MIN 10 KR · 1% EDGE", | 1414 | "crash" => "Start the round, then cash out before the multiplier crashes.", |
| 1434 | _ => "", | 1415 | _ => "", |
| 1435 | } | 1416 | } |
| 1436 | } | 1417 | } |
diff --git a/gui/src/blackjack.rs b/gui/src/blackjack.rs index d42f000..bbe96fa 100644 --- a/gui/src/blackjack.rs +++ b/gui/src/blackjack.rs | |||
| @@ -70,11 +70,7 @@ fn sidebar(ui: &mut Ui, view: &BlackjackView) -> Option<Command> { | |||
| 70 | .font(theme::sans(22.0)) | 70 | .font(theme::sans(22.0)) |
| 71 | .color(theme::TEXT), | 71 | .color(theme::TEXT), |
| 72 | ); | 72 | ); |
| 73 | ui.label( | 73 | widgets::note(ui, "Get close to 21 without going over."); |
| 74 | eframe::egui::RichText::new("6 decks · dealer stands on 17 · 3:2") | ||
| 75 | .font(theme::sans(12.0)) | ||
| 76 | .color(theme::TEXT_DIM), | ||
| 77 | ); | ||
| 78 | 74 | ||
| 79 | ui.add_space(theme::SPACE_5); | 75 | ui.add_space(theme::SPACE_5); |
| 80 | ui.label(theme::label("Bet")); | 76 | ui.label(theme::label("Bet")); |
| @@ -104,12 +100,6 @@ fn sidebar(ui: &mut Ui, view: &BlackjackView) -> Option<Command> { | |||
| 104 | ui.add_space(theme::SPACE_3); | 100 | ui.add_space(theme::SPACE_3); |
| 105 | widgets::error(ui, error); | 101 | widgets::error(ui, error); |
| 106 | } | 102 | } |
| 107 | |||
| 108 | ui.add_space(theme::SPACE_4); | ||
| 109 | ui.separator(); | ||
| 110 | ui.add_space(theme::SPACE_2); | ||
| 111 | widgets::note(ui, "Blackjack pays 3:2. The dealer stands on soft 17."); | ||
| 112 | widgets::note(ui, "Double only on the first two cards."); | ||
| 113 | }); | 103 | }); |
| 114 | }, | 104 | }, |
| 115 | ); | 105 | ); |
| @@ -189,29 +179,7 @@ fn result_text(result: &str, winnings: u64) -> (String, Color32) { | |||
| 189 | } | 179 | } |
| 190 | 180 | ||
| 191 | fn board(ui: &mut Ui, view: &BlackjackView) { | 181 | fn board(ui: &mut Ui, view: &BlackjackView) { |
| 192 | ui.horizontal(|ui| { | 182 | ui.add_space(theme::SPACE_2); |
| 193 | ui.label( | ||
| 194 | eframe::egui::RichText::new("Table 01") | ||
| 195 | .font(theme::sans(15.0)) | ||
| 196 | .color(theme::TEXT), | ||
| 197 | ); | ||
| 198 | ui.label( | ||
| 199 | eframe::egui::RichText::new("Blackjack · six decks") | ||
| 200 | .font(theme::sans(12.0)) | ||
| 201 | .color(theme::TEXT_DIM), | ||
| 202 | ); | ||
| 203 | ui.with_layout( | ||
| 204 | eframe::egui::Layout::right_to_left(eframe::egui::Align::Center), | ||
| 205 | |ui| { | ||
| 206 | ui.label( | ||
| 207 | eframe::egui::RichText::new("3:2 · S17") | ||
| 208 | .font(theme::mono(12.0)) | ||
| 209 | .color(theme::TEXT_FAINT), | ||
| 210 | ); | ||
| 211 | }, | ||
| 212 | ); | ||
| 213 | }); | ||
| 214 | ui.add_space(theme::SPACE_5); | ||
| 215 | 183 | ||
| 216 | let Some(hand) = &view.hand else { | 184 | let Some(hand) = &view.hand else { |
| 217 | centered_note(ui, "Place a bet and deal a hand."); | 185 | centered_note(ui, "Place a bet and deal a hand."); |
diff --git a/gui/src/crash.rs b/gui/src/crash.rs index 14197ae..08113a8 100644 --- a/gui/src/crash.rs +++ b/gui/src/crash.rs | |||
| @@ -119,11 +119,7 @@ fn sidebar(ui: &mut Ui, view: &CrashView, fx: &mut Fx) -> Option<Command> { | |||
| 119 | .font(theme::sans(22.0)) | 119 | .font(theme::sans(22.0)) |
| 120 | .color(theme::TEXT), | 120 | .color(theme::TEXT), |
| 121 | ); | 121 | ); |
| 122 | ui.label( | 122 | widgets::note(ui, "Cash out before the multiplier crashes."); |
| 123 | eframe::egui::RichText::new("Rise · cash out · don't bust") | ||
| 124 | .font(theme::sans(12.0)) | ||
| 125 | .color(theme::TEXT_DIM), | ||
| 126 | ); | ||
| 127 | 123 | ||
| 128 | ui.add_space(theme::SPACE_5); | 124 | ui.add_space(theme::SPACE_5); |
| 129 | ui.label(theme::label("Bet")); | 125 | ui.label(theme::label("Bet")); |
| @@ -152,14 +148,6 @@ fn sidebar(ui: &mut Ui, view: &CrashView, fx: &mut Fx) -> Option<Command> { | |||
| 152 | ui.add_space(theme::SPACE_3); | 148 | ui.add_space(theme::SPACE_3); |
| 153 | widgets::error(ui, error); | 149 | widgets::error(ui, error); |
| 154 | } | 150 | } |
| 155 | |||
| 156 | ui.add_space(theme::SPACE_4); | ||
| 157 | ui.separator(); | ||
| 158 | ui.add_space(theme::SPACE_2); | ||
| 159 | widgets::note( | ||
| 160 | ui, | ||
| 161 | "The crash point is server-timed. The curve here is display only.", | ||
| 162 | ); | ||
| 163 | }); | 151 | }); |
| 164 | }, | 152 | }, |
| 165 | ); | 153 | ); |
| @@ -231,29 +219,7 @@ fn status(ui: &mut Ui, view: &CrashView) { | |||
| 231 | } | 219 | } |
| 232 | 220 | ||
| 233 | fn chart(ui: &mut Ui, view: &CrashView, fx: &Fx) { | 221 | fn chart(ui: &mut Ui, view: &CrashView, fx: &Fx) { |
| 234 | ui.horizontal(|ui| { | 222 | ui.add_space(theme::SPACE_2); |
| 235 | ui.label( | ||
| 236 | eframe::egui::RichText::new("Table 01") | ||
| 237 | .font(theme::sans(15.0)) | ||
| 238 | .color(theme::TEXT), | ||
| 239 | ); | ||
| 240 | ui.label( | ||
| 241 | eframe::egui::RichText::new("Crash · server-timed") | ||
| 242 | .font(theme::sans(12.0)) | ||
| 243 | .color(theme::TEXT_DIM), | ||
| 244 | ); | ||
| 245 | ui.with_layout( | ||
| 246 | eframe::egui::Layout::right_to_left(eframe::egui::Align::Center), | ||
| 247 | |ui| { | ||
| 248 | ui.label( | ||
| 249 | eframe::egui::RichText::new("Cash out any time before the crash") | ||
| 250 | .font(theme::mono(11.0)) | ||
| 251 | .color(theme::TEXT_FAINT), | ||
| 252 | ); | ||
| 253 | }, | ||
| 254 | ); | ||
| 255 | }); | ||
| 256 | ui.add_space(theme::SPACE_4); | ||
| 257 | 223 | ||
| 258 | let available = ui.available_size(); | 224 | let available = ui.available_size(); |
| 259 | let size = vec2(available.x, (available.y - 70.0).max(260.0)); | 225 | let size = vec2(available.x, (available.y - 70.0).max(260.0)); |
| @@ -379,15 +345,6 @@ fn chart(ui: &mut Ui, view: &CrashView, fx: &Fx) { | |||
| 379 | } | 345 | } |
| 380 | } | 346 | } |
| 381 | } | 347 | } |
| 382 | |||
| 383 | ui.add_space(theme::SPACE_4); | ||
| 384 | ui.label( | ||
| 385 | eframe::egui::RichText::new( | ||
| 386 | "The crash point is drawn from the server; the multiplier here is display only.", | ||
| 387 | ) | ||
| 388 | .font(theme::sans(11.0)) | ||
| 389 | .color(theme::TEXT_FAINT), | ||
| 390 | ); | ||
| 391 | } | 348 | } |
| 392 | 349 | ||
| 393 | fn map_y(plot: Rect, multiplier: f64, max_multiplier: f64) -> f32 { | 350 | fn map_y(plot: Rect, multiplier: f64, max_multiplier: f64) -> f32 { |
diff --git a/gui/src/net.rs b/gui/src/net.rs index d2bc7e4..7cba604 100644 --- a/gui/src/net.rs +++ b/gui/src/net.rs | |||
| @@ -46,7 +46,6 @@ pub struct Connected { | |||
| 46 | pub user: Option<String>, | 46 | pub user: Option<String>, |
| 47 | pub auth_error: Option<String>, | 47 | pub auth_error: Option<String>, |
| 48 | pub fingerprint: Option<String>, | 48 | pub fingerprint: Option<String>, |
| 49 | pub server_version: String, | ||
| 50 | pub latest: String, | 49 | pub latest: String, |
| 51 | pub url: String, | 50 | pub url: String, |
| 52 | pub elapsed_ms: f32, | 51 | pub elapsed_ms: f32, |
| @@ -162,7 +161,6 @@ fn worker( | |||
| 162 | user: connected.user, | 161 | user: connected.user, |
| 163 | auth_error: connected.auth_error, | 162 | auth_error: connected.auth_error, |
| 164 | fingerprint, | 163 | fingerprint, |
| 165 | server_version: connected.server_version, | ||
| 166 | latest: connected.latest, | 164 | latest: connected.latest, |
| 167 | url: connected.url, | 165 | url: connected.url, |
| 168 | elapsed_ms: connected.elapsed.as_secs_f64() as f32 * 1000.0, | 166 | elapsed_ms: connected.elapsed.as_secs_f64() as f32 * 1000.0, |
diff --git a/gui/src/roulette.rs b/gui/src/roulette.rs index c791693..0100d1e 100644 --- a/gui/src/roulette.rs +++ b/gui/src/roulette.rs | |||
| @@ -730,11 +730,7 @@ fn sidebar( | |||
| 730 | .font(theme::sans(22.0)) | 730 | .font(theme::sans(22.0)) |
| 731 | .color(theme::TEXT), | 731 | .color(theme::TEXT), |
| 732 | ); | 732 | ); |
| 733 | ui.label( | 733 | super::widgets::note(ui, "Pick numbers or colours, then spin."); |
| 734 | eframe::egui::RichText::new("European · single zero") | ||
| 735 | .font(theme::sans(12.0)) | ||
| 736 | .color(theme::TEXT_DIM), | ||
| 737 | ); | ||
| 738 | 734 | ||
| 739 | ui.add_space(theme::SPACE_4); | 735 | ui.add_space(theme::SPACE_4); |
| 740 | let wheel_size = ui.available_width().min(210.0); | 736 | let wheel_size = ui.available_width().min(210.0); |
| @@ -906,29 +902,7 @@ fn sidebar( | |||
| 906 | fn board(ui: &mut Ui, view: &RouletteView, fx: &Fx) -> Option<zagan_bet::client::view::Command> { | 902 | fn board(ui: &mut Ui, view: &RouletteView, fx: &Fx) -> Option<zagan_bet::client::view::Command> { |
| 907 | use zagan_bet::client::view::Command; | 903 | use zagan_bet::client::view::Command; |
| 908 | 904 | ||
| 909 | ui.horizontal(|ui| { | 905 | ui.add_space(theme::SPACE_2); |
| 910 | ui.label( | ||
| 911 | eframe::egui::RichText::new("Table 01") | ||
| 912 | .font(theme::sans(15.0)) | ||
| 913 | .color(theme::TEXT), | ||
| 914 | ); | ||
| 915 | ui.label( | ||
| 916 | eframe::egui::RichText::new("European · single zero") | ||
| 917 | .font(theme::sans(12.0)) | ||
| 918 | .color(theme::TEXT_DIM), | ||
| 919 | ); | ||
| 920 | ui.with_layout( | ||
| 921 | eframe::egui::Layout::right_to_left(eframe::egui::Align::Center), | ||
| 922 | |ui| { | ||
| 923 | ui.label( | ||
| 924 | eframe::egui::RichText::new("Limits 10 – 500 Kr") | ||
| 925 | .font(theme::mono(12.0)) | ||
| 926 | .color(theme::TEXT_FAINT), | ||
| 927 | ); | ||
| 928 | }, | ||
| 929 | ); | ||
| 930 | }); | ||
| 931 | ui.add_space(theme::SPACE_4); | ||
| 932 | 906 | ||
| 933 | let strip_height = 104.0; | 907 | let strip_height = 104.0; |
| 934 | let available = ui.available_size(); | 908 | let available = ui.available_size(); |
| @@ -968,11 +942,9 @@ fn board(ui: &mut Ui, view: &RouletteView, fx: &Fx) -> Option<zagan_bet::client: | |||
| 968 | }); | 942 | }); |
| 969 | ui.add_space(theme::SPACE_2); | 943 | ui.add_space(theme::SPACE_2); |
| 970 | ui.label( | 944 | ui.label( |
| 971 | eframe::egui::RichText::new( | 945 | eframe::egui::RichText::new("Click to place a chip · right-click to take one back") |
| 972 | "Click to place · right or middle click takes back · C clears · space spins", | 946 | .font(theme::sans(12.0)) |
| 973 | ) | 947 | .color(theme::TEXT_FAINT), |
| 974 | .font(theme::sans(12.0)) | ||
| 975 | .color(theme::TEXT_FAINT), | ||
| 976 | ); | 948 | ); |
| 977 | command | 949 | command |
| 978 | } | 950 | } |
diff --git a/gui/src/slots.rs b/gui/src/slots.rs index 6574626..d2a288a 100644 --- a/gui/src/slots.rs +++ b/gui/src/slots.rs | |||
| @@ -109,11 +109,7 @@ fn sidebar(ui: &mut Ui, view: &SlotsView, fx: &mut Fx) -> Option<Command> { | |||
| 109 | .font(theme::sans(22.0)) | 109 | .font(theme::sans(22.0)) |
| 110 | .color(theme::TEXT), | 110 | .color(theme::TEXT), |
| 111 | ); | 111 | ); |
| 112 | ui.label( | 112 | widgets::note(ui, "Match three or more symbols from the left."); |
| 113 | eframe::egui::RichText::new("5 reels · 5 paylines") | ||
| 114 | .font(theme::sans(12.0)) | ||
| 115 | .color(theme::TEXT_DIM), | ||
| 116 | ); | ||
| 117 | 113 | ||
| 118 | ui.add_space(theme::SPACE_5); | 114 | ui.add_space(theme::SPACE_5); |
| 119 | ui.label(theme::label("Bet")); | 115 | ui.label(theme::label("Bet")); |
| @@ -128,32 +124,6 @@ fn sidebar(ui: &mut Ui, view: &SlotsView, fx: &mut Fx) -> Option<Command> { | |||
| 128 | ui.add_space(theme::SPACE_3); | 124 | ui.add_space(theme::SPACE_3); |
| 129 | widgets::error(ui, error); | 125 | widgets::error(ui, error); |
| 130 | } | 126 | } |
| 131 | |||
| 132 | ui.add_space(theme::SPACE_4); | ||
| 133 | ui.separator(); | ||
| 134 | ui.add_space(theme::SPACE_3); | ||
| 135 | ui.label(theme::label("Paytable")); | ||
| 136 | ui.add_space(theme::SPACE_2); | ||
| 137 | ui.label( | ||
| 138 | eframe::egui::RichText::new("Pays bet × symbol × shape") | ||
| 139 | .font(theme::sans(11.0)) | ||
| 140 | .color(theme::TEXT_FAINT), | ||
| 141 | ); | ||
| 142 | ui.horizontal(|ui| { | ||
| 143 | ui.spacing_mut().item_spacing.x = theme::SPACE_2; | ||
| 144 | for (symbol, multiplier) in zagan_bet::slots::SYMBOL_MULTIPLIERS { | ||
| 145 | ui.label( | ||
| 146 | eframe::egui::RichText::new(format!("{symbol}{multiplier}")) | ||
| 147 | .font(theme::mono(12.0)) | ||
| 148 | .color(symbol_color(symbol)), | ||
| 149 | ); | ||
| 150 | } | ||
| 151 | }); | ||
| 152 | ui.label( | ||
| 153 | eframe::egui::RichText::new("3×1 4×3 5×14") | ||
| 154 | .font(theme::mono(12.0)) | ||
| 155 | .color(theme::TEXT_DIM), | ||
| 156 | ); | ||
| 157 | }); | 127 | }); |
| 158 | }, | 128 | }, |
| 159 | ); | 129 | ); |
| @@ -240,29 +210,7 @@ fn status(ui: &mut Ui, view: &SlotsView, spinning: bool) { | |||
| 240 | } | 210 | } |
| 241 | 211 | ||
| 242 | fn board(ui: &mut Ui, view: &SlotsView, fx: &Fx) { | 212 | fn board(ui: &mut Ui, view: &SlotsView, fx: &Fx) { |
| 243 | ui.horizontal(|ui| { | 213 | ui.add_space(theme::SPACE_2); |
| 244 | ui.label( | ||
| 245 | eframe::egui::RichText::new("Machine 01") | ||
| 246 | .font(theme::sans(15.0)) | ||
| 247 | .color(theme::TEXT), | ||
| 248 | ); | ||
| 249 | ui.label( | ||
| 250 | eframe::egui::RichText::new("5 reels · 5 paylines") | ||
| 251 | .font(theme::sans(12.0)) | ||
| 252 | .color(theme::TEXT_DIM), | ||
| 253 | ); | ||
| 254 | ui.with_layout( | ||
| 255 | eframe::egui::Layout::right_to_left(eframe::egui::Align::Center), | ||
| 256 | |ui| { | ||
| 257 | ui.label( | ||
| 258 | eframe::egui::RichText::new("Bet 10 – 500 Kr") | ||
| 259 | .font(theme::mono(12.0)) | ||
| 260 | .color(theme::TEXT_FAINT), | ||
| 261 | ); | ||
| 262 | }, | ||
| 263 | ); | ||
| 264 | }); | ||
| 265 | ui.add_space(theme::SPACE_5); | ||
| 266 | 214 | ||
| 267 | let now = ui.input(|input| input.time); | 215 | let now = ui.input(|input| input.time); |
| 268 | let spinning = fx.spinning(view, now); | 216 | let spinning = fx.spinning(view, now); |
