From 0e68f6d188016b3a817454859eb12c543ac32066 Mon Sep 17 00:00:00 2001 From: Jonas Tranberg Date: Tue, 28 May 2024 16:47:00 +0200 Subject: [PATCH] add DNF dialog --- public/skull.svg | 32 ++++++++++++++ src/stores/game.mapper.ts | 10 ++--- src/stores/game.ts | 56 ++++++++++++++++++++++++ src/views/Game/components/DNFDialog.tsx | 23 ++++++++-- src/views/Game/components/Header.tsx | 30 ++++++++----- src/views/Game/components/PlayerItem.tsx | 26 +++++++++++ 6 files changed, 157 insertions(+), 20 deletions(-) create mode 100644 public/skull.svg diff --git a/public/skull.svg b/public/skull.svg new file mode 100644 index 0000000..3ef5aba --- /dev/null +++ b/public/skull.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/src/stores/game.mapper.ts b/src/stores/game.mapper.ts index 9a97a1e..b585095 100644 --- a/src/stores/game.mapper.ts +++ b/src/stores/game.mapper.ts @@ -19,10 +19,8 @@ const mapToRemote = (state: GameState): Game => { cards: state.draws, - // TODO: Implement - - dnf_player_ids: [], - dnf: false, + dnf_player_ids: state.dnf_player_ids, + dnf: false, // TODO: Implement }; }; @@ -38,7 +36,7 @@ const mapToLocal = (game: Game): GameState => { gameStartDateString: game.start_datetime, gameStartTimestamp: Date.parse(game.start_datetime), turnStartTimestamp: 0, // TODO: Implement - gameEndTimestamp: 0, + gameEndTimestamp: 0, // TODO: Implement players: game.player_names.map((name, index) => ({ id: game.player_ids[index], @@ -48,6 +46,8 @@ const mapToLocal = (game: Game): GameState => { shuffleIndices: game.shuffle_indices, draws: game.cards, + + dnf_player_ids: game.dnf_player_ids, }; }; diff --git a/src/stores/game.ts b/src/stores/game.ts index ad0691c..f6f94d3 100644 --- a/src/stores/game.ts +++ b/src/stores/game.ts @@ -30,6 +30,8 @@ interface GameState { players: Player[]; + dnf_player_ids: number[]; + draws: Card[]; } @@ -43,6 +45,8 @@ interface GameActions { }, ) => Promise; + SetPlayerDNF: (playerId: number, dnf: boolean) => void; + StartChug: () => number; StopChug: () => number; @@ -71,6 +75,8 @@ const initialState: GameState = { players: [], + dnf_player_ids: [], + draws: [], }; @@ -146,6 +152,56 @@ const useGame = create()( useGamesPlayed.getState().incrementStarted(); }, + SetPlayerDNF: (playerId: number, dnf: boolean) => { + const state = useGame.getState(); + + if (state.offline) { + throw new Error("Cannot set DNF in offline mode"); + } + + const player = state.players.find((player) => player.id === playerId); + if (!player) { + throw new Error("Player id not found"); + } + + if (dnf && state.dnf_player_ids.includes(playerId)) { + return; + } + + let new_dnfs = [...state.dnf_player_ids]; + if (dnf) { + if (state.dnf_player_ids.includes(playerId)) { + return; + } + + new_dnfs.push(playerId); + } + + if (!dnf) { + if (!state.dnf_player_ids.includes(playerId)) { + return; + } + + new_dnfs = state.dnf_player_ids.filter((id) => id !== playerId); + } + + set({ + dnf_player_ids: new_dnfs, + }); + + try { + GameAPI.postUpdate( + state.token as string, + mapToRemote({ + ...state, + dnf_player_ids: new_dnfs, + }), + ); + } catch (error) { + console.error("[Game]", "Failed to update game state", error); + } + }, + DrawCard: () => { console.debug("[Game]", "Drawing card"); diff --git a/src/views/Game/components/DNFDialog.tsx b/src/views/Game/components/DNFDialog.tsx index 5b15e28..f4586f9 100644 --- a/src/views/Game/components/DNFDialog.tsx +++ b/src/views/Game/components/DNFDialog.tsx @@ -19,11 +19,28 @@ import useGame from "../../../stores/game"; interface DNFDialogProps extends DialogProps {} const DNFDialog: FunctionComponent = (props) => { - const players = useGame((state) => state.players); + const { players, dnf_player_ids, SetPlayerDNF } = useGame((state) => ({ + players: state.players, + dnf_player_ids: state.dnf_player_ids, + SetPlayerDNF: state.SetPlayerDNF, + })); + const sound = useSounds(); const toggle = (index: number) => { - sound.play("moops"); + sound.play("click"); + + const player = players[index]; + + if (player.id === undefined) { + return; + } + + const isDNF = dnf_player_ids.includes(player.id); + + console.log("Setting DNF for player", player.id, !isDNF); + + SetPlayerDNF(player.id, !isDNF); }; return ( @@ -84,7 +101,7 @@ const DNFDialog: FunctionComponent = (props) => { {player.username} - + {dnf_player_ids.includes(player.id || 0) && } ); })} diff --git a/src/views/Game/components/Header.tsx b/src/views/Game/components/Header.tsx index 6fe03c1..3956a4a 100644 --- a/src/views/Game/components/Header.tsx +++ b/src/views/Game/components/Header.tsx @@ -45,6 +45,7 @@ const Header: FunctionComponent = () => { turnStartTimestamp: state.turnStartTimestamp, numberOfRounds: state.numberOfRounds, ExitGame: state.Exit, + offline: state.offline, })); const gameMetrics = useGameMetrics(); @@ -213,19 +214,24 @@ const Header: FunctionComponent = () => { }, }} > - {/* - setDNFDialogOpen(true)} + {!game.offline && ( + - DNF - - */} + setDNFDialogOpen(true)} + > + DNF + + + )} = (props) => { const playerMetrics = usePlayerMetricsByIndex(props.index); const gameMetrics = useGameMetrics(); + const game = useGame((state) => ({ + dnf_player_ids: state.dnf_player_ids, + })); + const isFirstRound = gameMetrics.currentRound === 1; + const isDNF = game.dnf_player_ids.includes(props.player.id || -1); + const settings = useSettings((state) => ({ simpleCardsMode: state.simpleCardsMode, SetSimpleCardsMode: state.SetSimpleCardsMode, @@ -88,6 +95,9 @@ const PlayerItem: FunctionComponent = (props) => { transform: props.active ? "translateY(-32px)" : "none", transitionProperty: "transform", transitionDuration: "200ms", + + filter: isDNF ? "grayscale(100%)" : "none", + opacity: isDNF ? 0.75 : 1, }} > = (props) => { }} onClick={() => settings.SetSimpleCardsMode(!settings.simpleCardsMode)} > + + + +