diff --git a/public/game.html b/public/game.html
index e040f36..8a2e308 100644
--- a/public/game.html
+++ b/public/game.html
@@ -98,8 +98,17 @@
renderBoardFromState(data.boardState);
updateTurnBanner(data.boardState);
}
- // render hands: server now sends private hands as `handsOwn` and public counts as `handCounts`
- if(data.handsOwn || data.handCounts) renderHands(data.handsOwn || [], data.handCounts || {});
+ // render hands: prefer new private `handsOwn` + `handCounts`.
+ // If server (or older code) mistakenly sends a full `hands` object, only show the current player's own hand and public counts — never reveal other players' cards.
+ if(data.hands){
+ // legacy: full hands object mapping playerId -> array
+ const own = (data.hands && data.hands[myPlayerId]) ? data.hands[myPlayerId] : [];
+ const counts = {};
+ Object.entries(data.hands || {}).forEach(([pid, arr])=>{ counts[pid] = (arr && arr.length) || 0; });
+ renderHands(own, counts);
+ } else if(data.handsOwn || data.handCounts){
+ renderHands(data.handsOwn || [], data.handCounts || {});
+ }
});
socket.on('game:over', (data)=>{ log('game:over', data); if(data.boardState){ renderBoardFromState(data.boardState); updateTurnBanner(data.boardState); } });
socket.on('game:started', (data)=>{ log('game:started', data); if(data.boardState){ renderBoardFromState(data.boardState); updateTurnBanner(data.boardState); } });
@@ -457,19 +466,6 @@
});
wrap.appendChild(list);
handsEl.appendChild(wrap);
-
- // show counts for other players
- Object.entries(handCounts || {}).forEach(([pid, count]) => {
- if(pid === myPlayerId) return;
- const other = document.createElement('div');
- other.className = 'player-hand';
- const t = document.createElement('div');
- t.style.fontWeight = '700';
- t.style.marginBottom = '6px';
- t.textContent = `Main de ${pid} — ${count} carte(s)`;
- other.appendChild(t);
- handsEl.appendChild(other);
- });
}
function showCardDrawnNotification(evt){
diff --git a/server.js b/server.js
index cc93654..c54516c 100644
--- a/server.js
+++ b/server.js
@@ -99,7 +99,12 @@ function buildDefaultDeck(){
// ['doppelganger','Choisis une pièce. À partir de maintenant, devient chacune des pièces qu elle capture.'],
// ['kurby','Choisis une pièce. À sa prochaine capture, récupère les mouvements de la pièce capturée.']
];
- return cards.map(([title,desc])=>({ id: uuidv4().slice(0,8), cardId: title.replace(/[^a-z0-9]+/gi,'_').toLowerCase(), title: title, description: desc }));
+ function cap(s){ if(!s) return s; s = String(s).trim(); return s.charAt(0).toUpperCase() + s.slice(1); }
+ return cards.map(([title,desc])=>{
+ const normalized = (title||'').toString().trim();
+ const cardId = normalized.replace(/[^a-z0-9]+/gi,'_').toLowerCase();
+ return { id: uuidv4().slice(0,8), cardId, title: cap(normalized), description: desc };
+ });
}
// draw a random card from room.deck and assign to player hand (respect max hand size 5)
@@ -122,6 +127,11 @@ function drawCardForPlayer(room, playerId){
// pick random index
const idx = Math.floor(Math.random() * room.deck.length);
const card = room.deck.splice(idx,1)[0];
+ // normalize title capitalization just in case this deck was created earlier with inconsistent casing
+ if(card && card.title){
+ card.title = String(card.title).trim();
+ card.title = card.title.charAt(0).toUpperCase() + card.title.slice(1);
+ }
room.hands[playerId] = room.hands[playerId] || [];
room.hands[playerId].push(card);
if(boardVersion !== null) room._lastDrawForPlayer[playerId] = boardVersion;
@@ -356,11 +366,14 @@ io.on('connection', (socket) => {
sendRoomUpdate(room);
// If the game is already playing and it's this player's turn, attempt to draw (useful on reconnect)
+ // Only draw if the player's hand is currently empty to avoid double-drawing (e.g. initial granted cards)
try{
if(room.status === 'playing' && room.boardState && room.boardState.turn){
- const myShort = (room.players.find(p => p.id === assignedId).color || '')[0];
+ const myPlayer = room.players.find(p => p.id === assignedId);
+ const myShort = (myPlayer && myPlayer.color || '')[0];
if(myShort === room.boardState.turn){
- drawCardForPlayer(room, assignedId);
+ const hasHand = room.hands && room.hands[assignedId] && room.hands[assignedId].length > 0;
+ if(!hasHand) drawCardForPlayer(room, assignedId);
}
}
}catch(e){ console.error('post-join draw error', e); }
@@ -411,25 +424,26 @@ io.on('connection', (socket) => {
board.version = (board.version || 0) + 1;
board.turn = (board.turn === 'w') ? 'b' : 'w';
- // broadcast move and new board state
+ // at this point the board has been updated and the turn flipped
+ // determine next player and perform their draw BEFORE broadcasting the move, so the draw happens at the start of their turn
const moved = { playerId: senderId, from, to, boardState: board };
- io.to(roomId).emit('move:moved', moved);
-
- // after flipping turn, draw a card for the next player (beginning of their turn)
try{
const nextColor = board.turn; // 'w' or 'b'
const nextPlayer = room.players.find(p => (p.color && p.color[0]) === nextColor);
if(nextPlayer){
- // attempt to draw a card for them; drawCardForPlayer will emit updated room state if a card was drawn
+ // draw for next player (this will emit card:drawn privately and send personalized room:update)
drawCardForPlayer(room, nextPlayer.id);
} else {
- // still emit updated room state (no draw occurred)
+ // ensure room state is broadcast
sendRoomUpdate(room);
}
}catch(e){
- console.error('draw after move error', e);
+ console.error('draw-at-start-of-turn error', e);
}
+ // now broadcast the move to all clients (move event separate from room:update)
+ io.to(roomId).emit('move:moved', moved);
+
return cb && cb({ ok: true, moved });
}catch(err){
console.error('game:move error', err);
@@ -454,12 +468,14 @@ io.on('connection', (socket) => {
sendRoomUpdate(room);
// draw initial card for the player to move (beginning of their turn)
+ // If the player already has a card (for instance the special starter card), skip the automatic draw
try{
if(room.boardState && room.boardState.turn){
const firstColor = room.boardState.turn; // 'w' or 'b'
const firstPlayer = room.players.find(p => (p.color && p.color[0]) === firstColor);
if(firstPlayer){
- drawCardForPlayer(room, firstPlayer.id);
+ const hasHand = room.hands && room.hands[firstPlayer.id] && room.hands[firstPlayer.id].length > 0;
+ if(!hasHand) drawCardForPlayer(room, firstPlayer.id);
}
}
}catch(e){