diff --git a/clients/web/src/game/components/game_screen.rs b/clients/web/src/game/components/game_screen.rs index 3d8f047..525b7c5 100644 --- a/clients/web/src/game/components/game_screen.rs +++ b/clients/web/src/game/components/game_screen.rs @@ -152,13 +152,24 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView { // Values for MergedScorePanel — extracted before events are consumed. // Don't animate points when a hole was gained (points wrap around 12). - let my_pts_earned: u8 = my_scored_event.as_ref() - .map_or(0, |e| if e.holes_gained == 0 { e.points_earned } else { 0 }); - let opp_pts_earned: u8 = opp_scored_event.as_ref() - .map_or(0, |e| if e.holes_gained == 0 { e.points_earned } else { 0 }); + let my_pts_earned: u8 = my_scored_event.as_ref().map_or(0, |e| { + if e.holes_gained == 0 { + e.points_earned + } else { + 0 + } + }); + let opp_pts_earned: u8 = opp_scored_event.as_ref().map_or(0, |e| { + if e.holes_gained == 0 { + e.points_earned + } else { + 0 + } + }); let my_holes_gained_score: u8 = my_scored_event.as_ref().map_or(0, |e| e.holes_gained); let opp_holes_gained_score: u8 = opp_scored_event.as_ref().map_or(0, |e| e.holes_gained); - let my_bredouille_flash: bool = my_scored_event.as_ref() + let my_bredouille_flash: bool = my_scored_event + .as_ref() .map_or(false, |e| e.bredouille && e.holes_gained > 0); let is_double_dice = dice.0 == dice.1 && dice.0 != 0; @@ -414,6 +425,10 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView { guest_die: None, tie_count: 0, }); + if pgr.host_die != None { + crate::game::sound::play_dice_roll(); + } + let my_die = if player_id == 0 { pgr.host_die } else { pgr.guest_die }; let opp_die = if player_id == 0 { pgr.guest_die } else { pgr.host_die }; let can_roll = my_die.is_none() && !waiting_for_confirm; diff --git a/clients/web/src/game/components/score_panel.rs b/clients/web/src/game/components/score_panel.rs index 35dda0f..bd531f3 100644 --- a/clients/web/src/game/components/score_panel.rs +++ b/clients/web/src/game/components/score_panel.rs @@ -1,14 +1,17 @@ -use leptos::prelude::*; -use trictrac_store::Jan; #[cfg(target_arch = "wasm32")] use gloo_timers::future::TimeoutFuture; +use leptos::prelude::*; +#[cfg(target_arch = "wasm32")] +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; +use trictrac_store::Jan; #[cfg(target_arch = "wasm32")] use wasm_bindgen_futures::spawn_local; -#[cfg(target_arch = "wasm32")] -use std::sync::{Arc, atomic::{AtomicBool, Ordering}}; -use crate::i18n::*; use crate::game::trictrac::types::PlayerScore; +use crate::i18n::*; pub fn jan_label(jan: &Jan) -> String { let i18n = use_i18n(); @@ -42,13 +45,16 @@ pub fn MergedScorePanel( opp_score: PlayerScore, /// Points just earned this turn; 0 = no animation. Set to 0 when a hole /// was gained (points wrap around 12, counter stays at end value). - #[prop(default = 0)] my_points_earned: u8, + #[prop(default = 0)] + my_points_earned: u8, #[prop(default = 0)] opp_points_earned: u8, /// Non-zero when a new hole was just scored (triggers peg-pop animation). - #[prop(default = 0)] my_holes_gained: u8, + #[prop(default = 0)] + my_holes_gained: u8, #[prop(default = 0)] opp_holes_gained: u8, /// True when my hole was scored under bredouille (shows ×2 in the flash). - #[prop(default = false)] my_bredouille: bool, + #[prop(default = false)] + my_bredouille: bool, ) -> impl IntoView { let i18n = use_i18n(); @@ -89,8 +95,10 @@ pub fn MergedScorePanel( on_cleanup(move || alive_c.store(false, Ordering::Relaxed)); spawn_local(async move { for p in (my_pts_start + 1)..=my_pts_end { - TimeoutFuture::new(200).await; - if !is_alive.load(Ordering::Relaxed) { return; } + TimeoutFuture::new(100).await; + if !is_alive.load(Ordering::Relaxed) { + return; + } my_displayed_pts.set(p); crate::game::sound::play_points_tick(); } @@ -103,20 +111,23 @@ pub fn MergedScorePanel( on_cleanup(move || alive_c.store(false, Ordering::Relaxed)); spawn_local(async move { for p in (opp_pts_start + 1)..=opp_pts_end { - TimeoutFuture::new(200).await; - if !is_alive.load(Ordering::Relaxed) { return; } + TimeoutFuture::new(100).await; + if !is_alive.load(Ordering::Relaxed) { + return; + } opp_displayed_pts.set(p); + crate::game::sound::play_opp_points_tick(); } }); } } // ── Ghost bar widths (show the end value immediately — static reference) ─ - let my_bar_style = format!("width:{}%", (my_score.points as u32 * 100 / 12).min(100)); + let my_bar_style = format!("width:{}%", (my_score.points as u32 * 100 / 12).min(100)); let opp_bar_style = format!("width:{}%", (opp_score.points as u32 * 100 / 12).min(100)); // ── Hole peg tracks ───────────────────────────────────────────────────── - let my_holes = my_score.holes; + let my_holes = my_score.holes; let opp_holes = opp_score.holes; let my_pegs: Vec = (1u8..=12) @@ -128,7 +139,8 @@ pub fn MergedScorePanel( class:filled=filled class:peg-new=is_new> - }.into_any() + } + .into_any() }) .collect(); @@ -141,13 +153,14 @@ pub fn MergedScorePanel( class:filled=filled class:peg-new=is_new> - }.into_any() + } + .into_any() }) .collect(); - let my_name = my_score.name.clone(); + let my_name = my_score.name.clone(); let opp_name = opp_score.name.clone(); - let my_can_bredouille = my_score.can_bredouille; + let my_can_bredouille = my_score.can_bredouille; let opp_can_bredouille = opp_score.can_bredouille; view! { diff --git a/clients/web/src/game/sound.rs b/clients/web/src/game/sound.rs index 4fac6cc..8b99e50 100644 --- a/clients/web/src/game/sound.rs +++ b/clients/web/src/game/sound.rs @@ -154,6 +154,14 @@ mod inner { }); } + /// Brief low tick for the jackpot-style points counter (one call per increment). + pub fn play_opp_points_tick() { + with_ctx(|ctx| { + play_tone(ctx, 680.0, 0.18, 0.055, 0.000, OscillatorType::Sine); + play_tone(ctx, 1020.0, 0.07, 0.035, 0.000, OscillatorType::Sine); + }); + } + /// Triumphant four-note fanfare (C5 – E5 – G5 – C6). pub fn play_hole_scored() { with_ctx(|ctx| { @@ -175,7 +183,7 @@ mod inner { #[cfg(target_arch = "wasm32")] pub use inner::{ play_checker_move, play_dice_roll, play_dice_roll_cinematic, play_hole_scored, - play_points_scored, play_points_tick, + play_opp_points_tick, play_points_scored, play_points_tick, }; #[cfg(not(target_arch = "wasm32"))] @@ -189,4 +197,6 @@ pub fn play_points_scored() {} #[cfg(not(target_arch = "wasm32"))] pub fn play_points_tick() {} #[cfg(not(target_arch = "wasm32"))] +pub fn play_opp_points_tick() {} +#[cfg(not(target_arch = "wasm32"))] pub fn play_hole_scored() {}