Use player names in two-player briscola
Classic briscola has no partnerships: its "teams" are just the two players, but the UI labelled them Team A/Team B. - add is_individual_game() and GameView::player_name_for_team() to the model; - the briscola table HUD reads "Alice 0 — 0 Bob (target 61)" and the seat panels drop the Team badge for two-player games; - the deal summary and game-over screen name the sides and the winner; - the waiting room and join preview hide the Team badge. briscola a quattro and scopone keep their team labels, and the match history table is unchanged.
This commit is contained in:
@@ -7,7 +7,9 @@ use sycamore::prelude::*;
|
||||
|
||||
use crate::components::card::{card_back, card_img};
|
||||
use crate::components::copy::CopyButton;
|
||||
use crate::model::{hand_sort_key, suit_name, GameView, PlayerView, Scores};
|
||||
use crate::model::{
|
||||
hand_sort_key, is_individual_game, suit_name, GameView, PlayerView, Scores,
|
||||
};
|
||||
use crate::pages::game::watch_link;
|
||||
|
||||
fn player_for_seat(game: &GameView, seat: usize) -> Option<PlayerView> {
|
||||
@@ -25,7 +27,10 @@ fn seat_panel(game: GameView, seat: usize, position: &'static str) -> View {
|
||||
if active { " active" } else { "" }
|
||||
);
|
||||
let name = player.name.clone();
|
||||
let team = player.team.clone();
|
||||
let team_badge = (!is_individual_game(&game.game_type)).then(|| {
|
||||
let team = player.team.clone();
|
||||
view! { span(class="team-badge") { "Team " (team) } }
|
||||
});
|
||||
let points = player.points;
|
||||
let captured = player.captured_count;
|
||||
let backs = (0..player.cards_left)
|
||||
@@ -35,7 +40,7 @@ fn seat_panel(game: GameView, seat: usize, position: &'static str) -> View {
|
||||
div(class=cls) {
|
||||
div(class="seat-name") {
|
||||
(name)
|
||||
span(class="team-badge") { "Team " (team) }
|
||||
(team_badge)
|
||||
}
|
||||
div(class="seat-cards") { (backs) }
|
||||
div(class="seat-stats") {
|
||||
@@ -160,6 +165,19 @@ pub fn briscola_table(
|
||||
let scores = game.scores.unwrap_or(Scores { a: 0, b: 0 });
|
||||
let target = game.target_score;
|
||||
let deal = game.hand_number;
|
||||
// Two-player briscola has no partnerships: show the players' names.
|
||||
let score_line = if is_individual_game(&game.game_type) {
|
||||
format!(
|
||||
"{} {} — {} {} (target {})",
|
||||
game.player_name_for_team("A"),
|
||||
scores.a,
|
||||
scores.b,
|
||||
game.player_name_for_team("B"),
|
||||
target
|
||||
)
|
||||
} else {
|
||||
format!("Team A {} — {} Team B (target {})", scores.a, scores.b, target)
|
||||
};
|
||||
|
||||
let (grid_cls, top, left, right) = if player_count == 2 {
|
||||
(
|
||||
@@ -234,10 +252,7 @@ pub fn briscola_table(
|
||||
span { "Deal " (deal) }
|
||||
(trump_badge)
|
||||
(spectator_badge)
|
||||
span(class="hud-scores") {
|
||||
"Team A " (scores.a) " — " (scores.b) " Team B (target "
|
||||
(target) ")"
|
||||
}
|
||||
span(class="hud-scores") { (score_line) }
|
||||
span(class=turn_cls) { (turn_note) }
|
||||
(countdown)
|
||||
CopyButton(text=watch_link, label="Copy watch link".to_string())
|
||||
|
||||
+21
-7
@@ -12,8 +12,8 @@ use crate::components::copy::CopyButton;
|
||||
use crate::components::summary::{hand_summary_modal, summary_rows};
|
||||
use crate::components::toast::toast;
|
||||
use crate::model::{
|
||||
card_label, hand_sort_key, is_briscola, GameView, MoveView, PlayerView, Scores,
|
||||
ServerMessage,
|
||||
card_label, hand_sort_key, is_briscola, is_individual_game, GameView, MoveView,
|
||||
PlayerView, Scores, ServerMessage,
|
||||
};
|
||||
use crate::pages::briscola::briscola_table;
|
||||
use crate::ws::{self, GameSocket};
|
||||
@@ -433,19 +433,23 @@ fn LobbyView(game: GameView) -> View {
|
||||
let join_code = game.join_code.clone();
|
||||
let watch_link = watch_link(&game.id);
|
||||
|
||||
let show_teams = !is_individual_game(&game.game_type);
|
||||
let players = game
|
||||
.players
|
||||
.iter()
|
||||
.map(|p| {
|
||||
let name = p.name.clone();
|
||||
let seat = p.seat;
|
||||
let team = p.team.clone();
|
||||
let team_badge = show_teams.then(|| {
|
||||
let team = p.team.clone();
|
||||
view! { span(class="badge text-bg-info") { "Team " (team) } }
|
||||
});
|
||||
view! {
|
||||
li(class="list-group-item d-flex justify-content-between align-items-center") {
|
||||
strong { (name) }
|
||||
span {
|
||||
span(class="badge text-bg-secondary me-2") { "Seat " (seat) }
|
||||
span(class="badge text-bg-info") { "Team " (team) }
|
||||
(team_badge)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -744,14 +748,24 @@ fn game_over_view(over: Option<(Scores, Option<String>)>, game: Option<GameView>
|
||||
None => view! {},
|
||||
Some((scores, winner)) => {
|
||||
let winner = winner.unwrap_or_else(|| "?".to_string());
|
||||
let line = format!("Team {winner} wins {} – {}", scores.a, scores.b);
|
||||
// Two-player briscola has no teams: name the winner instead.
|
||||
let winner_label = match game.as_ref() {
|
||||
Some(g) if is_individual_game(&g.game_type) => {
|
||||
g.player_name_for_team(&winner)
|
||||
}
|
||||
_ => format!("Team {winner}"),
|
||||
};
|
||||
let line = format!("{winner_label} wins {} – {}", scores.a, scores.b);
|
||||
// Spectators have no match history to look at.
|
||||
let spectator = game.as_ref().is_some_and(|g| g.spectator);
|
||||
// Explain the final hand's (scopone) or deal's (briscola)
|
||||
// scoring before the result.
|
||||
let final_summary: View = if briscola {
|
||||
match game.as_ref().and_then(|g| g.last_deal.clone()) {
|
||||
Some(deal) => deal_rows(&deal),
|
||||
match game.as_ref() {
|
||||
Some(g) => match g.last_deal.clone() {
|
||||
Some(deal) => deal_rows(g, &deal),
|
||||
None => view! {},
|
||||
},
|
||||
None => view! {},
|
||||
}
|
||||
} else {
|
||||
|
||||
+11
-6
@@ -15,8 +15,8 @@ use crate::api;
|
||||
use crate::components::card::card_back;
|
||||
use crate::components::toast::toast;
|
||||
use crate::model::{
|
||||
fallback_game_types, AuthProvider, GameTypeInfo, JoinPreview, OptionField, OptionKind,
|
||||
PlayerRating, User,
|
||||
fallback_game_types, is_individual_game, AuthProvider, GameTypeInfo, JoinPreview,
|
||||
OptionField, OptionKind, PlayerRating, User,
|
||||
};
|
||||
|
||||
/// Human-readable label for a provider name ("google" -> "Google").
|
||||
@@ -237,15 +237,20 @@ fn join_preview_panel(
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let seated = p.players.len();
|
||||
let show_teams = !is_individual_game(&p.game_type);
|
||||
let players = p
|
||||
.players
|
||||
.iter()
|
||||
.map(|player| {
|
||||
let name = player.name.clone();
|
||||
let team = player.team.as_ref().map(|t| {
|
||||
let label = t.clone();
|
||||
view! { span(class="badge text-bg-info ms-2") { "Team " (label) } }
|
||||
});
|
||||
let team = if show_teams {
|
||||
player.team.as_ref().map(|t| {
|
||||
let label = t.clone();
|
||||
view! { span(class="badge text-bg-info ms-2") { "Team " (label) } }
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
view! {
|
||||
li(
|
||||
class="list-group-item d-flex justify-content-between \
|
||||
|
||||
Reference in New Issue
Block a user