feat: Sistema completo de fin de juego y pantallas de victoria
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
This commit is contained in:
@@ -274,7 +274,32 @@ io.on('connection', (socket) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 7. DESCONEXIÓN
|
||||
// 7. REINICIAR PARTIDA
|
||||
socket.on('restart_game', ({ roomId }) => {
|
||||
const game = games[roomId];
|
||||
if (game && game.hostId === socket.id) {
|
||||
game.restartGame();
|
||||
io.to(roomId).emit('game_state', game.state);
|
||||
}
|
||||
});
|
||||
|
||||
// 8. FINALIZAR Y EXPULSAR JUGADORES
|
||||
socket.on('finalize_game', ({ roomId }) => {
|
||||
const game = games[roomId];
|
||||
if (game && game.hostId === socket.id) {
|
||||
game.finalizeGame();
|
||||
io.to(roomId).emit('game_state', game.state);
|
||||
|
||||
// Esperar 5 segundos y luego eliminar la partida
|
||||
setTimeout(() => {
|
||||
delete games[roomId];
|
||||
// Desconectar a todos los jugadores de la sala
|
||||
io.in(roomId).socketsLeave(roomId);
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
// 9. DESCONEXIÓN
|
||||
socket.on('disconnect', () => {
|
||||
// Buscar en qué partida estaba y sacarlo (opcional, por ahora solo notificamos)
|
||||
console.log('Desconectado:', socket.id);
|
||||
|
||||
@@ -312,10 +312,14 @@ export class Game {
|
||||
const failures = this.state.questResults.filter(r => r === false).length;
|
||||
|
||||
if (failures >= 3) {
|
||||
this.endGame(Faction.ALEMANES, 'Tres misiones han fracasado.'); // Updated Faction
|
||||
// Los Nazis ganan directamente
|
||||
this.state.winner = Faction.ALEMANES;
|
||||
this.state.phase = GamePhase.NAZIS_WIN;
|
||||
this.log('¡Los Nazis han ganado! Tres misiones han fracasado.');
|
||||
} else if (successes >= 3) {
|
||||
// Los Aliados han completado 3 misiones, pero el Asesino tiene una oportunidad
|
||||
this.state.phase = GamePhase.ASSASSIN_PHASE;
|
||||
this.log('¡La Resistencia ha triunfado! Pero el Asesino tiene una última oportunidad...');
|
||||
this.log('¡La Resistencia ha triunfado! Pero el Francotirador tiene una última oportunidad...');
|
||||
} else {
|
||||
// Siguiente ronda
|
||||
this.state.currentRound++;
|
||||
@@ -328,10 +332,16 @@ export class Game {
|
||||
|
||||
assassinKill(targetId: string) {
|
||||
const target = this.state.players.find(p => p.id === targetId);
|
||||
if (target && target.role === Role.MARLENE) { // Updated Role
|
||||
this.endGame(Faction.ALEMANES, '¡El Asesino ha eliminado a Marlene!'); // Updated Faction and message
|
||||
if (target && target.role === Role.MARLENE) {
|
||||
// El Francotirador acierta: Nazis ganan
|
||||
this.state.winner = Faction.ALEMANES;
|
||||
this.state.phase = GamePhase.NAZIS_WIN;
|
||||
this.log('¡El Francotirador ha eliminado a Marlene! Los Nazis ganan.');
|
||||
} else {
|
||||
this.endGame(Faction.ALIADOS, 'El Asesino ha fallado. ¡La Resistencia gana!'); // Updated Faction
|
||||
// El Francotirador falla: Aliados ganan
|
||||
this.state.winner = Faction.ALIADOS;
|
||||
this.state.phase = GamePhase.ALLIED_WIN;
|
||||
this.log('El Francotirador ha fallado. ¡La Resistencia gana!');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,6 +364,43 @@ export class Game {
|
||||
this.log(`FIN DEL JUEGO. Victoria para ${winner}. Razón: ${reason}`);
|
||||
}
|
||||
|
||||
// Método para reiniciar la partida (volver a REVEAL_ROLE)
|
||||
restartGame() {
|
||||
this.log('=== REINICIANDO PARTIDA ===');
|
||||
|
||||
// Resetear variables de juego
|
||||
this.state.currentRound = 1;
|
||||
this.state.failedVotesCount = 0;
|
||||
this.state.questResults = [null, null, null, null, null];
|
||||
this.state.leaderVotes = {};
|
||||
this.state.proposedTeam = [];
|
||||
this.state.teamVotes = {};
|
||||
this.state.missionVotes = [];
|
||||
this.state.revealedVotes = [];
|
||||
this.state.missionHistory = [];
|
||||
this.state.winner = undefined;
|
||||
|
||||
// Reasignar roles
|
||||
const count = this.state.players.length;
|
||||
const config = GAME_CONFIG[count as keyof typeof GAME_CONFIG];
|
||||
this.assignRoles(config.good, config.evil);
|
||||
|
||||
// Asignar nuevo líder aleatorio
|
||||
const leaderIndex = Math.floor(Math.random() * count);
|
||||
this.state.players.forEach((p, i) => p.isLeader = i === leaderIndex);
|
||||
this.state.currentLeaderId = this.state.players[leaderIndex].id;
|
||||
|
||||
// Volver a REVEAL_ROLE
|
||||
this.state.phase = GamePhase.REVEAL_ROLE;
|
||||
this.log('Nueva partida iniciada. Revelando roles...');
|
||||
}
|
||||
|
||||
// Método para finalizar definitivamente y preparar expulsión
|
||||
finalizeGame() {
|
||||
this.state.phase = GamePhase.GAME_OVER;
|
||||
this.log('Partida finalizada. Los jugadores serán expulsados.');
|
||||
}
|
||||
|
||||
private log(message: string) {
|
||||
this.state.history.push(message);
|
||||
// Mantener solo los últimos 50 mensajes
|
||||
|
||||
Reference in New Issue
Block a user