bouton de pioche

This commit is contained in:
Didictateur 2025-11-23 02:01:08 +01:00
parent a73e07f510
commit 18403495eb
3 changed files with 147 additions and 10 deletions

View file

@ -20,9 +20,13 @@
<div style="margin-top:8px">
<!-- movement controls removed as requested -->
</div>
<pre id="log" style="margin-top:8px;height:160px;overflow:auto">logs...</pre>
<div style="margin-top:8px;display:flex;gap:8px;align-items:center">
<pre id="log" style="margin-top:0px;height:140px;overflow:auto;flex:1">logs...</pre>
</div>
</section>
<div id="hands" style="margin-top:8px;display:flex;flex-direction:column;gap:8px"></div>
<div style="margin-top:10px;display:flex;align-items:center;gap:12px">
<div id="hands" style="display:flex;flex-direction:column;gap:8px;flex:1;margin-left:6px"></div>
</div>
</aside>
</div>
@ -154,6 +158,23 @@
} else if(data.handsOwn || data.handCounts){
renderHands(data.handsOwn || [], data.handCounts || {});
}
// show/hide draw button: only when autoDraw is OFF and it's this player's turn
try{
const drawBtn = document.getElementById('drawBtn');
if(drawBtn){
const auto = !!data.autoDraw;
const board = data.boardState || null;
const myShort = myColor && myColor[0];
if(!auto && board && myShort && board.turn === myShort){
// enable draw if hand not full
const myHandLen = (data.handsOwn && data.handsOwn.length) || 0;
drawBtn.style.display = 'inline-block';
drawBtn.disabled = myHandLen >= 5;
} else {
drawBtn.style.display = 'none';
}
}
}catch(_){ }
});
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); } });
@ -165,6 +186,8 @@
showCardDrawnNotification(data);
}catch(e){ console.warn('card:drawn handler error', e); }
});
// when server broadcasts generic room updates, it includes autoDraw flag
// ensure draw button visibility is updated inside the room:update handler below
// when a card is played by any player, ensure the UI removes it from the owner's hand
socket.on('card:played', (data) => {
try{
@ -848,6 +871,28 @@
row.appendChild(cardEl);
});
// draw button inside the 'Vos cartes' header (visible only when autoDraw is off and it's your turn)
try{
const drawBtn = document.createElement('button');
drawBtn.id = 'drawBtn';
drawBtn.type = 'button';
drawBtn.className = 'btn-draw';
drawBtn.style.display = 'none';
drawBtn.textContent = 'Piocher';
// attach handler that emits player:draw and temporarily disables the button
drawBtn.addEventListener('click', (ev)=>{
ev.stopPropagation();
if(!socket) return;
drawBtn.disabled = true;
socket.emit('player:draw', { roomId }, (resp)=>{
if(resp && resp.error){ log('player:draw error', resp); alert(resp.error); drawBtn.disabled = false; return; }
log('player:draw ok', resp);
// server will send room:update which will hide/disable the button as needed
});
});
header.appendChild(drawBtn);
}catch(_){ }
wrap.appendChild(row);
handsEl.appendChild(wrap);
}

View file

@ -142,6 +142,14 @@ a:hover{text-decoration:underline}
.btn-ghost{background:transparent;border:1px solid rgba(11,18,32,0.06);padding:8px 10px;border-radius:8px;color:inherit}
.btn-cta{background:linear-gradient(90deg,#3b82f6,#60a5fa);box-shadow:0 8px 20px rgba(59,130,246,0.18)}
/* draw button: compact rectangular CTA used in the cards area */
.btn-draw{
background:linear-gradient(90deg,#10b981,#059669); /* green gradient */
color:white;padding:10px 14px;border-radius:8px;border:none;cursor:pointer;font-weight:800;font-size:14px;
min-width:140px;height:44px;display:inline-flex;align-items:center;justify-content:center;box-shadow:0 8px 18px rgba(6,95,70,0.12);
}
.btn-draw[disabled]{opacity:0.6;cursor:not-allowed}
/* cancel button shown during pending card selection: white background, red text for clear contrast */
.btn-cancel{
background: #ffffff;

View file

@ -86,6 +86,21 @@ function sendRoomUpdate(room){
});
}
// Helper: at the start of a player's turn, either perform an automatic draw
// if room.autoDraw is enabled, or simply broadcast the room state so clients
// can update UI. This centralizes the auto-draw toggle behavior.
function maybeDrawAtTurnStart(room, playerId){
try{
if(!room) return;
if(room.autoDraw){
drawCardForPlayer(room, playerId);
} else {
// ensure clients get the updated room state even if no draw happens
sendRoomUpdate(room);
}
}catch(e){ console.error('maybeDrawAtTurnStart error', e); sendRoomUpdate(room); }
}
// Compute the set of squares visible to a given player (adjacent to any of their pieces).
// Returns a Set of square strings (e.g., 'e4').
function visibleSquaresForPlayer(room, playerId){
@ -686,7 +701,7 @@ io.on('connection', (socket) => {
const myShort = (myPlayer && myPlayer.color || '')[0];
if(myShort === room.boardState.turn){
const hasHand = room.hands && room.hands[assignedId] && room.hands[assignedId].length > 0;
if(!hasHand) drawCardForPlayer(room, assignedId);
if(!hasHand) maybeDrawAtTurnStart(room, assignedId);
}
}
}catch(e){ console.error('post-join draw error', e); }
@ -906,8 +921,8 @@ io.on('connection', (socket) => {
const nextColor = board.turn; // 'w' or 'b'
const nextPlayer = room.players.find(p => (p.color && p.color[0]) === nextColor);
if(nextPlayer){
// draw for next player (this will emit card:drawn privately and send personalized room:update)
drawCardForPlayer(room, nextPlayer.id);
// draw for next player (respect room.autoDraw)
maybeDrawAtTurnStart(room, nextPlayer.id);
} else {
// ensure room state is broadcast
sendRoomUpdate(room);
@ -955,7 +970,7 @@ io.on('connection', (socket) => {
const firstPlayer = room.players.find(p => (p.color && p.color[0]) === firstColor);
if(firstPlayer){
const hasHand = room.hands && room.hands[firstPlayer.id] && room.hands[firstPlayer.id].length > 0;
if(!hasHand) drawCardForPlayer(room, firstPlayer.id);
if(!hasHand) maybeDrawAtTurnStart(room, firstPlayer.id);
}
}
}catch(e){
@ -1039,6 +1054,75 @@ io.on('connection', (socket) => {
cb && cb({ ok: true });
});
// Manual draw by player (consumes the player's turn). Only valid when autoDraw is disabled.
socket.on('player:draw', ({ roomId }, cb) => {
const room = rooms.get(roomId);
if(!room) return cb && cb({ error: 'room not found' });
const senderId = socket.data.playerId;
if(!senderId) return cb && cb({ error: 'not joined' });
const board = room.boardState;
if(!board) return cb && cb({ error: 'no board state' });
const roomPlayer = room.players.find(p => p.id === senderId);
if(!roomPlayer) return cb && cb({ error: 'player not in room' });
const playerColorShort = (roomPlayer.color && roomPlayer.color[0]) || null;
// must be player's turn
if(board.turn !== playerColorShort) return cb && cb({ error: 'not your turn' });
// manual draw only allowed when autoDraw is disabled
if(room.autoDraw) return cb && cb({ error: 'auto_draw_enabled' });
// do not allow drawing if player already played a card this turn
room._cardPlayedThisTurn = room._cardPlayedThisTurn || {};
if(room._cardPlayedThisTurn[senderId]) return cb && cb({ error: 'card_already_played_this_turn' });
try{
// perform the draw (this will emit card:drawn privately and send personalized room:update)
const drawn = drawCardForPlayer(room, senderId);
if(!drawn){
// nothing drawn (hand full or deck empty)
return cb && cb({ error: 'no_card_drawn' });
}
// drawing consumes the player's turn: flip turn and decrement per-turn effects
// advance board version
board.version = (board.version || 0) + 1;
// flip turn
board.turn = (board.turn === 'w') ? 'b' : 'w';
// decrement remainingTurns for time-limited effects that belong to the player who just finished their turn
try{
room.activeCardEffects = room.activeCardEffects || [];
for(let i = room.activeCardEffects.length - 1; i >= 0; i--){
const e = room.activeCardEffects[i];
if(typeof e.remainingTurns === 'number'){
let shouldDecrement = false;
if(e.decrementOn === 'opponent'){
shouldDecrement = (e.playerId !== senderId);
} else if(e.decrementOn === 'owner'){
shouldDecrement = (e.playerId === senderId);
} else {
shouldDecrement = (e.playerId === senderId);
}
if(shouldDecrement){
e.remainingTurns = e.remainingTurns - 1;
try{ io.to(room.id).emit('card:effect:updated', { roomId: room.id, effect: e }); }catch(_){ }
if(e.remainingTurns <= 0){ room.activeCardEffects.splice(i,1); try{ io.to(room.id).emit('card:effect:removed', { roomId: room.id, effectId: e.id, type: e.type, playerId: e.playerId }); }catch(_){ } }
}
}
}
}catch(e){ console.error('decrement-after-draw error', e); }
// reset per-turn card-play flags
try{ room._cardPlayedThisTurn = {}; }catch(_){ }
// at this point it's the next player's turn; perform start-of-turn draw if autoDraw enabled
const nextColor = board.turn;
const nextPlayer = (room.players || []).find(p => (p.color && p.color[0]) === nextColor);
if(nextPlayer){ try{ maybeDrawAtTurnStart(room, nextPlayer.id); }catch(_){ sendRoomUpdate(room); } }
else { sendRoomUpdate(room); }
// notify room that the player drew and ended their turn
try{ io.to(room.id).emit('player:drew', { roomId: room.id, playerId: senderId, card: drawn }); }catch(_){ }
return cb && cb({ ok: true, card: drawn });
}catch(err){ console.error('player:draw error', err); return cb && cb({ error: 'server_error' }); }
});
// Simple cards API via sockets: list/play
socket.on('card:list', ({ roomId }, cb) => {
const room = rooms.get(roomId);
@ -1440,7 +1524,7 @@ io.on('connection', (socket) => {
// draw for the next player at the start of their turn
const nextColor = board.turn;
const nextPlayer = (room.players || []).find(p => (p.color && p.color[0]) === nextColor);
if(nextPlayer){ try{ drawCardForPlayer(room, nextPlayer.id); }catch(_){ } }
if(nextPlayer){ try{ maybeDrawAtTurnStart(room, nextPlayer.id); }catch(_){ } }
}
}catch(_){ }
}catch(e){ console.error('kamikaz effect error', e); }
@ -1713,7 +1797,7 @@ io.on('connection', (socket) => {
// draw for the next player at the start of their turn
const nextColor = board.turn;
const nextPlayer = (room.players || []).find(p => (p.color && p.color[0]) === nextColor);
if(nextPlayer){ try{ drawCardForPlayer(room, nextPlayer.id); }catch(_){ } }
if(nextPlayer){ try{ maybeDrawAtTurnStart(room, nextPlayer.id); }catch(_){ } }
}
}catch(_){ }
}