Nuevas funcionalidades: - Pantallas de victoria diferenciadas (NAZIS_WIN / ALLIED_WIN) * Diseño visual diferenciado (rojo para Nazis, azul para Aliados) * Timer de 30 segundos con auto-finalización * Estadísticas de misiones (exitosas vs fracasadas) * Opciones para el host: NUEVA PARTIDA o TERMINAR * Mensaje de espera para jugadores no-host - Sistema de reinicio de partida * Método restartGame() que resetea todas las variables * Reasigna roles y líder aleatorios * Vuelve a fase REVEAL_ROLE manteniendo jugadores - Sistema de finalización y expulsión * Método finalizeGame() que expulsa a todos después de 5s * Auto-expulsión si el host no decide en 30s * Limpieza de partida del servidor Mejoras en MISSION_RESULT: - Eliminado oscurecimiento de fondo (bg-transparent) - Tiempo de visualización aumentado de 5 a 7 segundos - Ahora se puede ver claramente el tablero con las fichas Lógica de transiciones: - 3 misiones fracasadas → NAZIS_WIN - 3 misiones exitosas → ASSASSIN_PHASE * Asesino acierta (mata a Marlene) → NAZIS_WIN * Asesino falla → ALLIED_WIN Archivos modificados: - shared/types.ts: Nuevas fases NAZIS_WIN y ALLIED_WIN - server/src/models/Game.ts: Métodos restartGame() y finalizeGame() - server/src/index.ts: Eventos restart_game y finalize_game - client/src/hooks/useSocket.ts: Acciones restartGame() y finalizeGame() - client/src/components/GameBoard.tsx: Renderizado de VictoryScreen - client/src/components/MissionResult.tsx: Sin oscurecimiento, 7s - client/src/components/VictoryScreen.tsx: NUEVO componente
130 lines
4.2 KiB
TypeScript
130 lines
4.2 KiB
TypeScript
export enum Role {
|
|
// Bando Aliado (Resistencia Francesa)
|
|
MARLENE = 'marlene', // Agente de inteligencia (antes Merlin)
|
|
CAPITAN_PHILIPPE = 'capitan_philippe', // Oficial que conoce a Marlene (antes Percival)
|
|
PARTISANO = 'partisano', // Miembro leal de la resistencia (antes Loyal Servant)
|
|
|
|
// Bando Alemán (Ocupación Nazi)
|
|
COMANDANTE_SCHMIDT = 'comandante_schmidt', // Oficial nazi oculto (antes Mordred)
|
|
FRANCOTIRADOR = 'francotirador', // Puede eliminar a Marlene (antes Assassin)
|
|
AGENTE_DOBLE = 'agente_doble', // Se hace pasar por Marlene (antes Morgana)
|
|
INFILTRADO = 'infiltrado', // Espía solitario (antes Oberon)
|
|
COLABORACIONISTA = 'colaboracionista', // Espía genérico (antes Minion/Spy)
|
|
}
|
|
|
|
export enum Faction {
|
|
ALIADOS = 'aliados', // Antes RESISTANCE
|
|
ALEMANES = 'alemanes', // Antes SPIES
|
|
}
|
|
|
|
export enum GamePhase {
|
|
LOBBY = 'lobby',
|
|
INTRO = 'intro',
|
|
REVEAL_ROLE = 'reveal_role',
|
|
ROLL_CALL = 'roll_call',
|
|
VOTE_LEADER = 'vote_leader', // Votar si se acepta al líder
|
|
TEAM_BUILDING = 'team_building', // Líder propone equipo
|
|
VOTING_TEAM = 'voting_team', // Todos votan si aprueban el equipo
|
|
MISSION = 'mission', // Los elegidos votan éxito/fracaso
|
|
MISSION_REVEAL = 'mission_reveal', // Mostrar cartas una a una
|
|
MISSION_RESULT = 'mission_result', // Pantalla de resumen
|
|
ASSASSIN_PHASE = 'assassin_phase', // Si gana el bien, el asesino intenta matar a Marlene
|
|
NAZIS_WIN = 'nazis_win', // Pantalla de victoria de los Nazis
|
|
ALLIED_WIN = 'allied_win', // Pantalla de victoria de los Aliados
|
|
GAME_OVER = 'game_over',
|
|
}
|
|
|
|
export interface Player {
|
|
id: string;
|
|
name: string;
|
|
avatar: string; // Avatar persistente
|
|
role?: Role;
|
|
faction?: Faction;
|
|
isLeader: boolean;
|
|
}
|
|
|
|
export interface MissionResult {
|
|
successes: number;
|
|
fails: number;
|
|
isSuccess: boolean;
|
|
}
|
|
|
|
// Registro de una misión completada
|
|
export interface MissionRecord {
|
|
round: number;
|
|
team: string[]; // IDs de los participantes
|
|
votes: boolean[]; // Votos (barajados)
|
|
successes: number;
|
|
fails: number;
|
|
isSuccess: boolean;
|
|
leaderId: string;
|
|
}
|
|
|
|
export interface GameState {
|
|
roomId: string;
|
|
phase: GamePhase;
|
|
players: Player[];
|
|
hostId: string;
|
|
|
|
currentRound: number;
|
|
failedVotesCount: number;
|
|
questResults: (boolean | null)[];
|
|
|
|
currentLeaderId: string;
|
|
|
|
// Votación de Líder
|
|
leaderVotes: Record<string, boolean | null>;
|
|
|
|
// Selección de Equipo (Misión)
|
|
proposedTeam: string[];
|
|
teamVotes: Record<string, boolean>; // Votos de aprobación del equipo (idJugador -> aprueba/rechaza)
|
|
missionVotes: boolean[]; // Votos anónimos de la misión (éxito/fracaso)
|
|
|
|
// Histórico de misiones
|
|
missionHistory: MissionRecord[];
|
|
|
|
// Para la animación de revelación de cartas
|
|
revealedVotes: boolean[]; // Votos que se van mostrando uno a uno
|
|
|
|
winner?: Faction;
|
|
history: string[]; // Log de acciones para mostrar en pantalla
|
|
}
|
|
|
|
// Configuración de jugadores por partida (según tus reglas)
|
|
export const GAME_CONFIG = {
|
|
5: { good: 3, evil: 2, quests: [2, 3, 2, 3, 3] },
|
|
6: { good: 4, evil: 2, quests: [2, 3, 4, 3, 4] },
|
|
7: { good: 4, evil: 3, quests: [2, 3, 3, 4, 4] }, // Nota: 4ta misión requiere 2 fallos
|
|
8: { good: 5, evil: 3, quests: [3, 4, 4, 5, 5] },
|
|
9: { good: 6, evil: 3, quests: [3, 4, 4, 5, 5] },
|
|
10: { good: 6, evil: 4, quests: [3, 4, 4, 5, 5] },
|
|
};
|
|
|
|
// --- NUEVOS TIPOS PARA EL LOBBY ---
|
|
|
|
export interface GameRoom {
|
|
id: string; // ID interno único (uuid)
|
|
name: string; // Nombre de misión (ej: Operación Overlord)
|
|
hostId: string; // ID del creador
|
|
currentPlayers: number;
|
|
maxPlayers: number;
|
|
isPrivate: boolean; // Si tiene contraseña
|
|
status: 'waiting' | 'playing' | 'finished';
|
|
}
|
|
|
|
export interface CreateGamePayload {
|
|
hostName: string;
|
|
maxPlayers: number;
|
|
password?: string;
|
|
}
|
|
|
|
export interface JoinGamePayload {
|
|
roomId: string; // Puede ser el ID numérico interno o lo que usemos
|
|
playerName: string;
|
|
password?: string;
|
|
}
|
|
|
|
export interface LobbyLists {
|
|
rooms: GameRoom[];
|
|
}
|