import { useEffect, useState } from "react"; import { dispatch, useGameId, useIsMuted, usePlayerName, } from "../../../domain/gameStore"; import { usePlayers } from "../../../hooks/useGameInfo"; import styles from "./KillFeed.module.css"; import hitmarker from "../../../assets/hitmarker.svg"; import hitsound from "../../../assets/hitsound.wav"; // okay, in an ideal world this would be part of the game store or something // and it would get properly managed by reactive state // but also, this totally works as is, and the only downside is it might potentially grow too big // but that only happens if someone plays that many gun games without ever leaving the window const shownItems = new Set(); const KillFeed = () => { const muted = useIsMuted(); const playerName = usePlayerName(); const gameId = useGameId(); const players = usePlayers(); useEffect(() => { if (players?.find(({ currentRound }) => currentRound === null)) { dispatch.goToSummary(); } }, [players]); const [shownItemsState, setShownItemsState] = useState(shownItems); const [display, setDisplay] = useState([]); useEffect(() => { const toDisplay = players ?.filter(({ name }) => name !== playerName) ?.flatMap(({ name, guesses }) => Object.entries(guesses).map(([round, { score }]) => ({ name, round, score, })) ) ?.filter( ({ name, round }) => !shownItemsState.has(`${gameId}-${name}-${round}`) ) ?? []; setDisplay(toDisplay); const timeout = setTimeout(() => { toDisplay.forEach(({ name, round }) => { shownItems.add(`${gameId}-${name}-${round}`); }); setShownItemsState(new Set(shownItems)); }, 5000); return () => { clearTimeout(timeout); }; }, [shownItemsState, gameId, players, playerName]); useEffect(() => { if (!muted) { display.forEach(() => { const audio = new Audio(hitsound); audio.volume = 0.5; // delay up to half a second so overlapping sounds better const delayedPlay = () => setTimeout(() => audio.play(), Math.random() * 500); audio.addEventListener("canplaythrough", delayedPlay); // clean up after ourselves in the hopes that the browser actually deletes this audio element audio.addEventListener("ended", () => audio.removeEventListener("canplaythrough", delayedPlay) ); }); } }, [display, muted]); return ( <> {display.map(() => ( hitmarker ))}
{display.map(({ name, round, score }) => ( {name}{" "} {score >= 4950 ? "🎯" : "🖱️"} 🗺️ {round} ))}
); }; export default KillFeed;