fix: Sistema de votación de líder completamente refactorizado

- Timer de 10 segundos que se reinicia correctamente al cambiar de líder
- Votación por mayoría calculada sobre votos emitidos, no total de jugadores
- Si nadie vota, líder rechazado automáticamente
- Alemanes pueden ver carta de sabotaje en misiones
- Reset correcto de selectedTeam al cambiar de fase
- Contador de votos fallidos incrementa correctamente
- Logs mejorados para debugging

Fixes:
- Timer visual se reinicia con key basada en currentLeaderId
- Facción verificada correctamente (Faction.ALEMANES vs 'spies')
- forceResolveLeaderVote llama a resolución con votos actuales
- selectedTeam se limpia al salir de TEAM_BUILDING
This commit is contained in:
Resistencia Dev
2025-12-08 00:05:08 +01:00
parent 9e0e343868
commit 06d2171871
21 changed files with 67 additions and 35 deletions

View File

@@ -41,22 +41,22 @@ const MISSION_NAMES = [
"Operación Eiche", "Operación León Marino", "Operación Urano"
];
// Helper para iniciar timer de votación de líder
// Helper para iniciar timer de votación de líder (10 segundos)
function startLeaderVoteTimer(roomId: string) {
if (voteTimers[roomId]) clearTimeout(voteTimers[roomId]);
voteTimers[roomId] = setTimeout(() => {
const g = games[roomId];
if (g && g.state.phase === 'vote_leader') {
// Pasar al siguiente líder sin resolver (rechazar implícitamente)
g.nextLeader();
// Forzar resolución de votos cuando se acaba el tiempo
g.forceResolveLeaderVote();
io.to(roomId).emit('game_state', g.state);
// Si sigue en vote_leader (nuevo líder), reiniciar timer
// Si sigue en vote_leader (líder rechazado, nuevo líder), reiniciar timer
if (g.state.phase === 'vote_leader') {
startLeaderVoteTimer(roomId);
}
}
}, 11000); // 11 segundos
}, 10000); // 10 segundos
}
const generateRoomName = () => {

View File

@@ -128,7 +128,11 @@ export class Game {
}
// --- LOGICA DE VOTACIÓN DE LÍDER ---
voteLeader(playerId: string, approve: boolean | null) {
voteLeader(playerId: string, approve: boolean) {
// Solo registrar el voto si el jugador existe y aún no ha votado
const player = this.state.players.find(p => p.id === playerId);
if (!player) return;
this.state.leaderVotes[playerId] = approve;
// Comprobar si todos han votado
@@ -137,33 +141,55 @@ export class Game {
}
}
// Método para forzar la resolución de votos (llamado por timeout)
// Método para forzar la resolución de votos cuando se acaba el tiempo
forceResolveLeaderVote() {
// Registrar votos null para los que no votaron
this.state.players.forEach(player => {
if (!(player.id in this.state.leaderVotes)) {
this.state.leaderVotes[player.id] = null;
}
});
// Si nadie votó o no todos votaron, se considera fracaso
this.resolveLeaderVote();
}
private resolveLeaderVote() {
const votes = Object.values(this.state.leaderVotes);
const approves = votes.filter(v => v === true).length;
const rejects = votes.filter(v => v === false || v === null).length; // null cuenta como rechazo
const totalPlayers = this.state.players.length;
const votesCount = Object.keys(this.state.leaderVotes).length;
this.log(`Votación de Líder: ${approves} A favor - ${rejects} En contra.`);
// Si nadie votó, rechazar automáticamente
if (votesCount === 0) {
this.log(`Votación de Líder: nadie votó. Líder rechazado.`);
this.state.failedVotesCount++;
if (approves > rejects) {
if (this.state.failedVotesCount >= 5) {
this.endGame(Faction.ALEMANES, 'Se han rechazado 5 líderes consecutivos.');
} else {
this.nextLeader();
}
return;
}
// Contar votos de aprobación y rechazo
const approves = Object.values(this.state.leaderVotes).filter(v => v === true).length;
const rejects = Object.values(this.state.leaderVotes).filter(v => v === false).length;
// La mayoría se calcula sobre los que votaron, no sobre el total
const isSuccess = approves > rejects;
this.log(`Votación de Líder: ${approves} a favor, ${rejects} en contra (${votesCount}/${totalPlayers} votaron)`);
if (isSuccess) {
// Líder Aprobado -> Fase de Construcción de Equipo
this.state.phase = GamePhase.TEAM_BUILDING;
this.state.proposedTeam = []; // Reset team selection
this.log('Líder confirmado. Ahora debe proponer un equipo.');
this.state.failedVotesCount = 0; // Reset contador al aprobar líder
this.log(`Líder ${this.state.players.find(p => p.id === this.state.currentLeaderId)?.name} confirmado con ${approves} votos a favor.`);
} else {
// Líder Rechazado -> Siguiente líder
this.log('Líder rechazado. Pasando turno al siguiente jugador.');
this.nextLeader(); // Esto pondrá phase en VOTE_LEADER de nuevo
// Líder Rechazado -> Incrementar contador y pasar al siguiente líder
this.state.failedVotesCount++;
this.log(`Líder rechazado: ${rejects} votos en contra superan a ${approves} a favor. Pasando turno al siguiente jugador.`);
// Verificar si se alcanzó el límite de rechazos (5 votos fallidos = alemanes ganan)
if (this.state.failedVotesCount >= 5) {
this.endGame(Faction.ALEMANES, 'Se han rechazado 5 líderes consecutivos.');
} else {
this.nextLeader(); // Esto pondrá phase en VOTE_LEADER de nuevo
}
}
}