// Modèle de domaine partagé entre client et serveur. // Le serveur est la source de vérité ; le client n'affiche qu'un état reçu. /** Statut courant d'une room (machine à états du jeu). */ export type RoomStatus = "lobby" | "in_round" | "reveal" | "scores" | "ended" /** Types d'épreuves disponibles. Étendre = ajouter une valeur + un module GameRound. */ export type RoundType = "blindtest" | "quiz" /** Type de partie choisi au lobby : mélange par défaut, ou un seul mode. */ export type GameType = "mixed" | "quiz" | "image" | "blindtest" /** Sous-modes activables quand la partie est "mixed". */ export type MixMode = "quiz" | "image" | "blindtest" /** Modes de blindtest, déterminent la forme du vote et le barème. */ export type BlindtestMode = "title_artist" | "who_added" | "mixed" /** Formats de question quiz. */ export type QuizFormat = "mcq" | "truefalse" | "free" | "image_reveal" /** Joueur connecté à une room. */ export interface Player { id: string name: string connected: boolean } /** Configuration d'une épreuve planifiée dans la séquence de la partie. */ export interface RoundConfig { type: RoundType /** Pour une manche quiz : dans quel sous-pool piocher (quiz "classique" ou images). */ pool?: "quiz" | "image" } /** Réglages de la room, modifiables dans le lobby par l'hôte. */ export interface RoomSettings { /** Type de partie choisi dans le lobby (pilote l'UI partagée). */ gameType: GameType /** Sous-modes actifs quand gameType === "mixed". */ mixedModes: MixMode[] blindtestMode: BlindtestMode /** Durée d'une manche en secondes (def. 60). */ roundDuration: number /** Nombre de titres que chaque joueur soumet (blindtest). */ tracksPerPlayer: number /** Catégories de quiz autorisées (vide = toutes). */ categories: string[] /** Séquence d'épreuves de la partie. */ rounds: RoundConfig[] } /** Réglages par défaut d'une nouvelle room. */ export const DEFAULT_ROOM_SETTINGS: RoomSettings = { gameType: "mixed", mixedModes: ["quiz", "image"], blindtestMode: "title_artist", roundDuration: 60, tracksPerPlayer: 2, categories: [], rounds: [], } // --- Votes --------------------------------------------------------------- /** Vote blindtest, forme selon RoomSettings.blindtestMode. */ export type BlindtestAnswer = | { title: string; artist: string } | { guessedPlayerId: string } | { title: string; artist: string; guessedPlayerId: string } /** Vote quiz, forme selon le format de la question. */ export type QuizAnswer = { choiceIndex: number } | { text: string } /** Réponse soumise par un joueur pour la manche en cours. */ export type Answer = BlindtestAnswer | QuizAnswer // --- Scores -------------------------------------------------------------- /** Score d'un joueur. */ export interface PlayerScore { playerId: string score: number } /** Variation de score appliquée à l'issue d'une manche. */ export interface ScoreDelta { playerId: string delta: number } /** Joueur ayant marqué sur une manche (récap de fin de partie). */ export interface RoundRecapScorer { playerId: string points: number } /** Réponse d'un joueur sur une manche (récap). */ export interface RoundPlayerAnswer { playerId: string answer: string correct: boolean } /** Récapitulatif d'une manche jouée (affiché en fin de partie). */ export interface RoundRecap { index: number type: RoundType /** Intitulé (question quiz) ou libellé du mode. */ label: string /** Bonne réponse révélée. */ answer: string category?: string imageUrl?: string youtubeId?: string url?: string /** Blindtest : qui avait ajouté le titre. */ addedBy?: string /** Joueurs ayant marqué sur cette manche. */ scorers: RoundRecapScorer[] /** Réponse de chaque joueur ayant répondu. */ answers: RoundPlayerAnswer[] } // --- Snapshot diffusé au client (room:state) ----------------------------- /** * Vue publique de la room poussée à tous les clients. * Ne contient JAMAIS de réponse non révélée ni d'info secrète (ex: submittedBy). */ export interface RoomSnapshot { code: string status: RoomStatus hostId: string players: Player[] settings: RoomSettings scores: PlayerScore[] /** Index de la manche en cours, -1 dans le lobby. */ currentRound: number /** Nombre total de manches planifiées. */ totalRounds: number /** Blindtest : nombre de titres soumis par joueur (comptes seulement, jamais les titres). */ submissions: { playerId: string; count: number }[] }