diff --git a/public/waiting.html b/public/waiting.html index 998a2c7..272667f 100644 --- a/public/waiting.html +++ b/public/waiting.html @@ -28,6 +28,13 @@ +
+ +
+
@@ -54,6 +61,8 @@ const youAreHostEl = document.getElementById('youAreHost'); const autoDrawLabelEl = document.getElementById('autoDrawLabel'); const autoDrawToggleEl = document.getElementById('autoDrawToggle'); + const noRemiseLabelEl = document.getElementById('no-remise'); + const noRemiseToggleEl = document.getElementById('no-remiseToggle'); function log(...args){ console.log(...args); } @@ -114,6 +123,20 @@ } } }catch(_){ } + // update no-remise UI if server provides it + try{ + if(typeof data.noRemise !== 'undefined' && noRemiseLabelEl && noRemiseToggleEl){ + // show the control only to the host + if(myPlayerId && roomHostId && myPlayerId === roomHostId){ + noRemiseLabelEl.style.display = 'inline-flex'; + noRemiseToggleEl.checked = !!data.noRemise; + noRemiseToggleEl.disabled = false; + } else { + // hide control for non-hosts + noRemiseLabelEl.style.display = 'none'; + } + } + }catch(_){ } }); // register game started handler early so we don't miss the broadcast @@ -162,6 +185,16 @@ if(autoDrawLabelEl) autoDrawLabelEl.style.display = 'none'; } } + // set no-remise independently so host sees it even if autoDraw is undefined + try{ + if(roomInfo && typeof roomInfo.noRemise !== 'undefined'){ + if(myPlayerId && roomHostId && myPlayerId === roomHostId){ + if(noRemiseLabelEl && noRemiseToggleEl){ noRemiseLabelEl.style.display = 'inline-flex'; noRemiseToggleEl.checked = !!roomInfo.noRemise; noRemiseToggleEl.disabled = false; } + } else { + if(noRemiseLabelEl) noRemiseLabelEl.style.display = 'none'; + } + } + }catch(_){ } }catch(_){ } if(roomInfo && roomInfo.status === 'playing'){ // server already marked room as playing; redirect immediately diff --git a/server.js b/server.js index c0da89e..dca6f11 100644 --- a/server.js +++ b/server.js @@ -38,6 +38,7 @@ function sendRoomUpdate(room){ size: (room.boardState && room.boardState.width) || room.size, cards: Object.keys(room.cards || {}), autoDraw: !!room.autoDraw, + noRemise: !!room.noRemise, deckCount: (room.deck && room.deck.length) || 0, discardCount: (room.discard && room.discard.length) || 0 }; @@ -296,8 +297,8 @@ function drawCardForPlayer(room, playerId){ } if(hand.length >= 5) return null; // hand full if(room.deck.length === 0){ - // if deck empty, try to refill from discard and shuffle - if(room.discard && room.discard.length > 0){ + // if deck empty, try to refill from discard and shuffle — unless 'noRemise' is enabled + if(!room.noRemise && room.discard && room.discard.length > 0){ // move all discard into deck room.deck = room.discard.splice(0).concat(room.deck || []); // simple Fisher-Yates shuffle @@ -717,7 +718,7 @@ app.post('/rooms', (req, res) => { // hostId will be set when the first player joins // initialize a deck for this room const deck = buildDefaultDeck(); - rooms.set(id, { id, boardState, players: [], status: 'waiting', hostId: null, size, cards: {}, playedCards: [], removalTimers: new Map(), deck, hands: {}, autoDraw: false }); + rooms.set(id, { id, boardState, players: [], status: 'waiting', hostId: null, size, cards: {}, playedCards: [], removalTimers: new Map(), deck, hands: {}, autoDraw: false, noRemise: false }); res.json({ roomId: id, size }); }); @@ -726,7 +727,7 @@ app.get('/rooms/:id', (req, res) => { if (!room) return res.status(404).json({ error: 'room not found' }); const boardState = room.boardState || null; const size = (room.boardState && room.boardState.width) || room.size; - res.json({ id: room.id, boardState, size: size, players: room.players.map(p => ({ id: p.id, color: p.color })), status: room.status, hostId: room.hostId, cards: Object.keys(room.cards || {}), autoDraw: !!room.autoDraw }); + res.json({ id: room.id, boardState, size: size, players: room.players.map(p => ({ id: p.id, color: p.color })), status: room.status, hostId: room.hostId, cards: Object.keys(room.cards || {}), autoDraw: !!room.autoDraw, noRemise: !!room.noRemise }); }); io.on('connection', (socket) => { @@ -824,6 +825,20 @@ io.on('connection', (socket) => { return cb && cb({ ok: true, autoDraw: room.autoDraw }); }); + // Host can toggle the 'no remise' flag (prevent reshuffling discard into deck). Only the host may change this setting. + socket.on('room:no_remise:set', ({ roomId, enabled }, cb) => { + const room = rooms.get(roomId); + if(!room) return cb && cb({ error: 'room not found' }); + const sender = socket.data.playerId; + if(!sender) return cb && cb({ error: 'not joined' }); + if(room.hostId !== sender) return cb && cb({ error: 'only the host can change no-remise' }); + room.noRemise = !!enabled; + // Broadcast updated room state to all participants + try{ sendRoomUpdate(room); }catch(_){ } + try{ io.to(room.id).emit('room:no_remise:changed', { roomId: room.id, enabled: room.noRemise }); }catch(_){ } + return cb && cb({ ok: true, noRemise: room.noRemise }); + }); + socket.on('game:move', ({ roomId, from, to, promotion }, cb) => { const room = rooms.get(roomId); if (!room) return cb && cb({ error: 'room not found' });