team04_server/lobby/game/
completion.rs

1use rand::seq::IndexedRandom;
2
3use crate::{
4    lobby::state::{LobbyPhase, SharedLobbyState},
5    log,
6    messages::{MessageTx, game_end::GameEnd},
7};
8
9#[must_use = "if true, the game should end"]
10pub async fn completion(lobby: &SharedLobbyState) -> bool {
11    let mut pfx = log::pfx();
12    pfx.lobby(lobby.id());
13    let mut lock = lobby.lock().await;
14    let mut alive_players = lock.clients.players.iter_alive();
15    let mut winner = None;
16    if let Some(potential_winner) = alive_players.next() {
17        if alive_players.next().is_none() {
18            // this is the last player who is still alive
19            winner = Some(*potential_winner.0);
20        } else {
21            // multiple players still alive, do nothing
22        }
23    } else {
24        // all players have died
25        let max_lives = lock
26            .clients
27            .players
28            .players_all()
29            .map(|p| p.lives)
30            .max()
31            .unwrap();
32        let mut potential_winners = lock
33            .clients
34            .players
35            .iter_all()
36            .filter(|(_id, p)| p.lives == max_lives)
37            .collect::<Vec<_>>();
38        if potential_winners.len() == 1 {
39            winner = Some(*potential_winners[0].0);
40        } else {
41            let max_fights_won = potential_winners
42                .iter()
43                .map(|(_id, p)| p.fights_won)
44                .max()
45                .unwrap();
46            potential_winners.retain(|(_id, p)| p.fights_won == max_fights_won);
47            // choose at random (if more than 1 left, otherwise choose that one)
48            winner = Some(*potential_winners.choose(&mut rand::rng()).unwrap().0);
49        }
50    }
51    drop(alive_players);
52    lock.phase = LobbyPhase::CompletionPhase;
53    lock.broadcast_gamestate().await;
54    if let Some(winner) = winner {
55        log::info!("player {winner} has won this game!"; log::pfx().lobby(lock.id()));
56        // TODO! add fun stats
57        lock.clients
58            .broadcast_message(
59                &GameEnd {
60                    winner,
61                    global_stats: vec![],
62                    player_stats: vec![],
63                }
64                .serialize(),
65            )
66            .await;
67        true
68    } else {
69        false
70    }
71}