brouillard de guerre
This commit is contained in:
parent
f0ec311155
commit
36dc3f8d20
3 changed files with 173 additions and 52 deletions
|
|
@ -4,6 +4,18 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>ChessNut - Partie</title>
|
<title>ChessNut - Partie</title>
|
||||||
<link rel="stylesheet" href="/styles/style.css">
|
<link rel="stylesheet" href="/styles/style.css">
|
||||||
|
<style>
|
||||||
|
/* veil overlay for brouillard effect */
|
||||||
|
.square { position: relative; }
|
||||||
|
.square .veil {
|
||||||
|
position: absolute;
|
||||||
|
left: 0; top: 0; right: 0; bottom: 0;
|
||||||
|
background: rgba(255,255,255,0.95);
|
||||||
|
pointer-events: auto; /* block interactions so veiled squares are not clickable */
|
||||||
|
z-index: 50;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Game over modal (hidden by default). Shown when server emits game:over -->
|
<!-- Game over modal (hidden by default). Shown when server emits game:over -->
|
||||||
|
|
@ -71,6 +83,7 @@
|
||||||
// current boardState cached locally
|
// current boardState cached locally
|
||||||
let currentBoardState = null;
|
let currentBoardState = null;
|
||||||
let myMines = [];
|
let myMines = [];
|
||||||
|
let currentVeiledSquares = [];
|
||||||
let pendingCard = null; // when set, next square click is used as card target
|
let pendingCard = null; // when set, next square click is used as card target
|
||||||
|
|
||||||
// safe logger: prefer on-page log if present, otherwise console
|
// safe logger: prefer on-page log if present, otherwise console
|
||||||
|
|
@ -166,6 +179,8 @@
|
||||||
boardEl.style.width = side + 'px';
|
boardEl.style.width = side + 'px';
|
||||||
boardEl.style.height = side + 'px';
|
boardEl.style.height = side + 'px';
|
||||||
}
|
}
|
||||||
|
// store veiled squares list for brouillard effect (if provided by server)
|
||||||
|
try{ currentVeiledSquares = Array.isArray(data.veiledSquares) ? data.veiledSquares : (data.boardState && data.boardState.veiledSquares) || []; }catch(_){ currentVeiledSquares = []; }
|
||||||
if(data.boardState) {
|
if(data.boardState) {
|
||||||
renderBoardFromState(data.boardState);
|
renderBoardFromState(data.boardState);
|
||||||
updateTurnBanner(data.boardState);
|
updateTurnBanner(data.boardState);
|
||||||
|
|
@ -529,6 +544,11 @@
|
||||||
if(!to) return;
|
if(!to) return;
|
||||||
const target = boardEl.querySelector(`.square[data-square="${to}"]`);
|
const target = boardEl.querySelector(`.square[data-square="${to}"]`);
|
||||||
if(!target) return;
|
if(!target) return;
|
||||||
|
// do not show legal-move markers on squares that are veiled/hidden
|
||||||
|
try{
|
||||||
|
if(Array.isArray(currentVeiledSquares) && currentVeiledSquares.indexOf(to) !== -1) return;
|
||||||
|
if(target.classList && target.classList.contains('veiled')) return;
|
||||||
|
}catch(_){ }
|
||||||
const marker = document.createElement('div');
|
const marker = document.createElement('div');
|
||||||
marker.className = 'move-marker';
|
marker.className = 'move-marker';
|
||||||
// store metadata if needed later
|
// store metadata if needed later
|
||||||
|
|
@ -546,6 +566,11 @@
|
||||||
if(!to) return;
|
if(!to) return;
|
||||||
const target = boardEl.querySelector(`.square[data-square="${to}"]`);
|
const target = boardEl.querySelector(`.square[data-square="${to}"]`);
|
||||||
if(!target) return;
|
if(!target) return;
|
||||||
|
// do not show remote move markers on veiled/hidden squares
|
||||||
|
try{
|
||||||
|
if(Array.isArray(currentVeiledSquares) && currentVeiledSquares.indexOf(to) !== -1) return;
|
||||||
|
if(target.classList && target.classList.contains('veiled')) return;
|
||||||
|
}catch(_){ }
|
||||||
const marker = document.createElement('div');
|
const marker = document.createElement('div');
|
||||||
marker.className = 'move-marker';
|
marker.className = 'move-marker';
|
||||||
marker.dataset.from = m.from || '';
|
marker.dataset.from = m.from || '';
|
||||||
|
|
@ -591,10 +616,21 @@
|
||||||
|
|
||||||
if(boardEl){
|
if(boardEl){
|
||||||
boardEl.addEventListener('click', (ev)=>{
|
boardEl.addEventListener('click', (ev)=>{
|
||||||
const sqEl = ev.target.closest && ev.target.closest('.square');
|
const sqEl = ev.target.closest && ev.target.closest('.square');
|
||||||
if(!sqEl) return;
|
if(!sqEl) return;
|
||||||
const square = sqEl.getAttribute('data-square');
|
const square = sqEl.getAttribute('data-square');
|
||||||
if(!square) return;
|
if(!square) return;
|
||||||
|
|
||||||
|
// Do not allow interacting with veiled/hidden squares.
|
||||||
|
// `currentVeiledSquares` is populated from server `room:update` and
|
||||||
|
// we also add a `.veiled` class during rendering as a fallback.
|
||||||
|
try{
|
||||||
|
if(Array.isArray(currentVeiledSquares) && currentVeiledSquares.indexOf(square) !== -1){
|
||||||
|
log('clicked veiled square, ignoring');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(sqEl.classList && sqEl.classList.contains('veiled')){ log('clicked veiled square (DOM class), ignoring'); return; }
|
||||||
|
}catch(_){ }
|
||||||
|
|
||||||
// If we're in a pending card-targeting mode, handle target selection and do NOT attempt moves
|
// If we're in a pending card-targeting mode, handle target selection and do NOT attempt moves
|
||||||
if(pendingCard){
|
if(pendingCard){
|
||||||
|
|
@ -783,6 +819,31 @@
|
||||||
});
|
});
|
||||||
// render any mines owned by this player
|
// render any mines owned by this player
|
||||||
try{ renderMines(); }catch(e){ }
|
try{ renderMines(); }catch(e){ }
|
||||||
|
// render veils for brouillard effect (if any)
|
||||||
|
try{
|
||||||
|
// remove existing veils
|
||||||
|
const allSq = boardEl.querySelectorAll('.square');
|
||||||
|
allSq.forEach(sqEl => {
|
||||||
|
const v = sqEl.querySelector('.veil'); if(v) v.remove();
|
||||||
|
// also remove prior veiled marker class
|
||||||
|
try{ sqEl.classList.remove('veiled'); }catch(_){ }
|
||||||
|
});
|
||||||
|
if(Array.isArray(currentVeiledSquares) && currentVeiledSquares.length){
|
||||||
|
currentVeiledSquares.forEach(sq => {
|
||||||
|
const el = boardEl.querySelector(`.square[data-square="${sq}"]`);
|
||||||
|
if(!el) return;
|
||||||
|
const veil = document.createElement('div'); veil.className = 'veil';
|
||||||
|
el.appendChild(veil);
|
||||||
|
// add a class to hide piece images as a fallback in case z-index/stacking causes overlay issues
|
||||||
|
try{
|
||||||
|
el.classList.add('veiled');
|
||||||
|
// remove any move markers that may have been added previously on this square
|
||||||
|
const prevMarkers = el.querySelectorAll('.move-marker');
|
||||||
|
prevMarkers.forEach(m => m.remove());
|
||||||
|
}catch(_){ }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}catch(_){ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw mine icons on squares for mines owned by this client
|
// draw mine icons on squares for mines owned by this client
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,11 @@ a:hover{text-decoration:underline}
|
||||||
pointer-events:none; z-index:2; image-rendering: -webkit-optimize-contrast;
|
pointer-events:none; z-index:2; image-rendering: -webkit-optimize-contrast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When a square is veiled by brouillard, hide its piece images to ensure full concealment
|
||||||
|
This is a robust fallback in case stacking context / transform interactions make an overlay
|
||||||
|
not fully cover the image. Hiding the image guarantees the piece is not visible. */
|
||||||
|
.square.veiled img, .square.veiled .piece{ visibility: hidden !important; opacity: 0 !important; }
|
||||||
|
|
||||||
/* highlighted/selected square when a player selects a piece */
|
/* highlighted/selected square when a player selects a piece */
|
||||||
.square.selected{
|
.square.selected{
|
||||||
outline: 3px solid rgba(245,158,11,0.95); /* amber */
|
outline: 3px solid rgba(245,158,11,0.95); /* amber */
|
||||||
|
|
|
||||||
151
server.js
151
server.js
|
|
@ -77,9 +77,36 @@ function sendRoomUpdate(room){
|
||||||
payload.boardState = base.boardState || null;
|
payload.boardState = base.boardState || null;
|
||||||
}
|
}
|
||||||
}catch(_){ payload.boardState = base.boardState || null; }
|
}catch(_){ payload.boardState = base.boardState || null; }
|
||||||
// attach visible squares for this recipient (fog of war)
|
// attach visible squares for this recipient (fog of war)
|
||||||
try{
|
try{
|
||||||
payload.visibleSquares = Array.from(visibleSquaresForPlayer(room, p.id) || []);
|
payload.visibleSquares = Array.from(visibleSquaresForPlayer(room, p.id) || []);
|
||||||
|
// attach veiled squares if a brouillard effect targets this recipient
|
||||||
|
try{
|
||||||
|
const brouillards = (room.activeCardEffects || []).filter(e => e && e.type === 'brouillard');
|
||||||
|
if(brouillards && brouillards.length){
|
||||||
|
// If any brouillard is active in the room, veil the board for ALL players,
|
||||||
|
// but exclude the recipient's visible squares (their pieces + adjacent squares).
|
||||||
|
const state = room.boardState || {};
|
||||||
|
const width = state.width || 8;
|
||||||
|
const height = state.height || 8;
|
||||||
|
const all = [];
|
||||||
|
for(let yy = 0; yy < height; yy++){
|
||||||
|
for(let xx = 0; xx < width; xx++){
|
||||||
|
all.push(String.fromCharCode('a'.charCodeAt(0) + xx) + (yy+1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// compute the set of squares that the recipient can see (their pieces + adjacent squares)
|
||||||
|
let visibleSet = new Set();
|
||||||
|
try{
|
||||||
|
const vs = visibleSquaresForPlayer(room, p.id) || new Set();
|
||||||
|
visibleSet = new Set(Array.from(vs));
|
||||||
|
}catch(_){ visibleSet = new Set(); }
|
||||||
|
// veiled squares are all minus visibleSet (so own pieces and their neighbors remain visible)
|
||||||
|
payload.veiledSquares = all.filter(sq => !visibleSet.has(sq));
|
||||||
|
} else {
|
||||||
|
payload.veiledSquares = [];
|
||||||
|
}
|
||||||
|
}catch(_){ payload.veiledSquares = []; }
|
||||||
// attach any mines owned by this recipient (mines are hidden from other players)
|
// attach any mines owned by this recipient (mines are hidden from other players)
|
||||||
try{
|
try{
|
||||||
const mines = (room.activeCardEffects || []).filter(e => e.type === 'mine' && e.playerId === p.id).map(e => e.square);
|
const mines = (room.activeCardEffects || []).filter(e => e.type === 'mine' && e.playerId === p.id).map(e => e.square);
|
||||||
|
|
@ -225,7 +252,7 @@ function buildDefaultDeck(){
|
||||||
['folie','La pièce sélectionnée peut maintenant faire les déplacements du fou en plus'],
|
['folie','La pièce sélectionnée peut maintenant faire les déplacements du fou en plus'],
|
||||||
['fortification','La pièce sélectionnée peut maintenant faire les déplacements de la tour en plus'],
|
['fortification','La pièce sélectionnée peut maintenant faire les déplacements de la tour en plus'],
|
||||||
["l'anneau","Le plateau devient un anneau pendant un tour"],
|
["l'anneau","Le plateau devient un anneau pendant un tour"],
|
||||||
// ['brouillard de guerre','Les joueur ne peuvent voir que au alentour de leurs pièces pendant 4 tours'],
|
['brouillard de guerre','Les joueur ne peuvent voir que au alentour de leurs pièces pendant 4 tours'],
|
||||||
// ['changer la pièce à capturer','Le joueur choisie la nouvelle pièce jouant le rôle de roi sans la révéler'],
|
// ['changer la pièce à capturer','Le joueur choisie la nouvelle pièce jouant le rôle de roi sans la révéler'],
|
||||||
// ['trou de ver','Deux cases du plateau deviennent maintenant la même'],
|
// ['trou de ver','Deux cases du plateau deviennent maintenant la même'],
|
||||||
['jouer deux fois','Le joueur peut déplacer deux pièces'],
|
['jouer deux fois','Le joueur peut déplacer deux pièces'],
|
||||||
|
|
@ -471,17 +498,7 @@ function computeLegalMoves(room, square){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter moves according to brouillard (fog of war) if it is active for the owner of this piece
|
// brouillard (fog of war) removed — moves are not filtered by fog
|
||||||
function filterMovesByFog(moves){
|
|
||||||
try{
|
|
||||||
const owner = ownerPlayer;
|
|
||||||
if(!owner) return moves;
|
|
||||||
const hasBrouillard = (room.activeCardEffects || []).some(e => e.type === 'brouillard' && e.playerId === owner.id);
|
|
||||||
if(!hasBrouillard) return moves;
|
|
||||||
const vis = visibleSquaresForPlayer(room, owner.id);
|
|
||||||
return (moves || []).filter(m => vis.has(m.to));
|
|
||||||
}catch(e){ return moves; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper to add diagonal sliding moves when a piece has been "folié"
|
// helper to add diagonal sliding moves when a piece has been "folié"
|
||||||
function addFolieMoves(){
|
function addFolieMoves(){
|
||||||
|
|
@ -571,7 +588,7 @@ function computeLegalMoves(room, square){
|
||||||
if(occ && occ.color !== color) moves.push({ from: square, to: tsq });
|
if(occ && occ.color !== color) moves.push({ from: square, to: tsq });
|
||||||
});
|
});
|
||||||
addAdoubementMoves(); addFolieMoves(); addFortificationMoves();
|
addAdoubementMoves(); addFolieMoves(); addFortificationMoves();
|
||||||
return filterMovesByFog(moves);
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type === 'N'){
|
if(type === 'N'){
|
||||||
|
|
@ -584,7 +601,7 @@ function computeLegalMoves(room, square){
|
||||||
if(!occ || occ.color !== color) moves.push({ from: square, to: tsq });
|
if(!occ || occ.color !== color) moves.push({ from: square, to: tsq });
|
||||||
});
|
});
|
||||||
addAdoubementMoves(); addFolieMoves(); addFortificationMoves();
|
addAdoubementMoves(); addFolieMoves(); addFortificationMoves();
|
||||||
return filterMovesByFog(moves);
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type === 'B' || type === 'Q' || type === 'R'){
|
if(type === 'B' || type === 'Q' || type === 'R'){
|
||||||
|
|
@ -658,7 +675,7 @@ function computeLegalMoves(room, square){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
addAdoubementMoves(); addFolieMoves(); addFortificationMoves();
|
addAdoubementMoves(); addFolieMoves(); addFortificationMoves();
|
||||||
return filterMovesByFog(moves);
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type === 'K'){
|
if(type === 'K'){
|
||||||
|
|
@ -671,11 +688,11 @@ function computeLegalMoves(room, square){
|
||||||
if(!occ || occ.color !== color) moves.push({ from: square, to: tsq });
|
if(!occ || occ.color !== color) moves.push({ from: square, to: tsq });
|
||||||
}
|
}
|
||||||
addAdoubementMoves(); addFolieMoves();
|
addAdoubementMoves(); addFolieMoves();
|
||||||
return filterMovesByFog(moves);
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
addAdoubementMoves(); addFolieMoves(); addFortificationMoves();
|
addAdoubementMoves(); addFolieMoves(); addFortificationMoves();
|
||||||
return filterMovesByFog(moves);
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startingBoardState8(){
|
function startingBoardState8(){
|
||||||
|
|
@ -894,14 +911,16 @@ io.on('connection', (socket) => {
|
||||||
const legal = computeLegalMoves(room, from) || [];
|
const legal = computeLegalMoves(room, from) || [];
|
||||||
const ok = legal.some(m => m.to === to);
|
const ok = legal.some(m => m.to === to);
|
||||||
if(!ok) return cb && cb({ error: 'illegal move' });
|
if(!ok) return cb && cb({ error: 'illegal move' });
|
||||||
// additionally, do not allow moving into a fogged square if brouillard is active for this player
|
// If any brouillard is active in the room, disallow moving onto squares that the player cannot see
|
||||||
try{
|
try{
|
||||||
const hasBrouillardForPlayer = (room.activeCardEffects || []).some(e => e.type === 'brouillard' && e.playerId === senderId);
|
const hasBrouillard = (room.activeCardEffects || []).some(e => e && e.type === 'brouillard');
|
||||||
if(hasBrouillardForPlayer){
|
if(hasBrouillard){
|
||||||
const vis = visibleSquaresForPlayer(room, senderId);
|
const visible = visibleSquaresForPlayer(room, senderId) || new Set();
|
||||||
if(!vis.has(to)) return cb && cb({ error: 'destination not visible (fog of war)' });
|
if(!visible.has(to)){
|
||||||
|
return cb && cb({ error: 'destination_not_visible' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}catch(e){ /* ignore */ }
|
}catch(_){ }
|
||||||
|
|
||||||
// apply move: remove any piece on target (capture)
|
// apply move: remove any piece on target (capture)
|
||||||
const targetIndex = pieces.findIndex(p => p.square === to);
|
const targetIndex = pieces.findIndex(p => p.square === to);
|
||||||
|
|
@ -1047,6 +1066,31 @@ io.on('connection', (socket) => {
|
||||||
// advance board version
|
// advance board version
|
||||||
board.version = (board.version || 0) + 1;
|
board.version = (board.version || 0) + 1;
|
||||||
|
|
||||||
|
// Update brouillard play counters: if any brouillard is active, increment the move count for the moving player.
|
||||||
|
try{
|
||||||
|
room.activeCardEffects = room.activeCardEffects || [];
|
||||||
|
for(let ei = room.activeCardEffects.length - 1; ei >= 0; ei--){
|
||||||
|
const ev = room.activeCardEffects[ei];
|
||||||
|
if(!ev || ev.type !== 'brouillard') continue;
|
||||||
|
try{
|
||||||
|
ev.playCounts = ev.playCounts || {};
|
||||||
|
ev.playCounts[senderId] = (ev.playCounts[senderId] || 0) + 1;
|
||||||
|
try{ io.to(room.id).emit('card:effect:updated', { roomId: room.id, effect: ev }); }catch(_){ }
|
||||||
|
// expire the brouillard when ALL players have reached the threshold of plays
|
||||||
|
const threshold = 2;
|
||||||
|
const players = room.players || [];
|
||||||
|
let allReached = true;
|
||||||
|
for(const pl of players){ if(!pl || !pl.id) continue; if((ev.playCounts[pl.id] || 0) < threshold){ allReached = false; break; } }
|
||||||
|
if(allReached){
|
||||||
|
try{ room.activeCardEffects.splice(ei,1); }catch(_){ }
|
||||||
|
try{ io.to(room.id).emit('card:effect:removed', { roomId: room.id, effectId: ev.id, type: ev.type, playerId: ev.playerId }); }catch(_){ }
|
||||||
|
// broadcast updated room state so clients remove veils
|
||||||
|
try{ sendRoomUpdate(room); }catch(_){ }
|
||||||
|
}
|
||||||
|
}catch(_){ }
|
||||||
|
}
|
||||||
|
}catch(e){ console.error('brouillard playcount update error', e); }
|
||||||
|
|
||||||
// Check victory (king capture) before further turn bookkeeping. If game ended, broadcast move and game:over and return.
|
// Check victory (king capture) before further turn bookkeeping. If game ended, broadcast move and game:over and return.
|
||||||
try{
|
try{
|
||||||
const end = checkAndHandleVictory(room);
|
const end = checkAndHandleVictory(room);
|
||||||
|
|
@ -2166,29 +2210,40 @@ io.on('connection', (socket) => {
|
||||||
played.payload = Object.assign({}, payload, { applied: 'invisible', appliedTo: target });
|
played.payload = Object.assign({}, payload, { applied: 'invisible', appliedTo: target });
|
||||||
}catch(e){ console.error('invisible effect error', e); }
|
}catch(e){ console.error('invisible effect error', e); }
|
||||||
}
|
}
|
||||||
// brouillard de guerre: target a player so their board is fogged (they only see adjacent squares)
|
else if(cardId === 'brouillard_de_guerre' || (typeof cardId === 'string' && cardId.indexOf('brouillard') !== -1)){
|
||||||
else if(cardId === 'brouillard_de_guerre' || (typeof cardId === 'string' && cardId.indexOf('brouillard') !== -1)){
|
try{
|
||||||
try{
|
const board = room.boardState;
|
||||||
const board = room.boardState;
|
// determine target player id: payload.targetPlayerId or the opponent
|
||||||
// determine target player id: payload.targetPlayerId or the opponent
|
let targetPlayerId = payload && payload.targetPlayerId;
|
||||||
let targetPlayerId = payload && payload.targetPlayerId;
|
if(!targetPlayerId){
|
||||||
if(!targetPlayerId){
|
const opp = (room.players || []).find(p => p.id !== senderId);
|
||||||
const opp = (room.players || []).find(p => p.id !== senderId);
|
targetPlayerId = opp && opp.id;
|
||||||
targetPlayerId = opp && opp.id;
|
}
|
||||||
}
|
const targetPlayer = (room.players || []).find(p => p.id === targetPlayerId);
|
||||||
const targetPlayer = (room.players || []).find(p => p.id === targetPlayerId);
|
if(!board || !targetPlayer || targetPlayer.id === senderId){
|
||||||
if(!board || !targetPlayer || targetPlayer.id === senderId){
|
// restore removed card to hand and abort
|
||||||
// restore removed card to hand and abort
|
try{ room.hands = room.hands || {}; room.hands[senderId] = room.hands[senderId] || []; if(removed) room.hands[senderId].push(removed); room.discard = room.discard || []; for(let i = room.discard.length-1;i>=0;i--){ if(room.discard[i] && room.discard[i].id === (removed && removed.id)){ room.discard.splice(i,1); break; } } }catch(e){}
|
||||||
try{ room.hands = room.hands || {}; room.hands[senderId] = room.hands[senderId] || []; if(removed) room.hands[senderId].push(removed); room.discard = room.discard || []; for(let i = room.discard.length-1;i>=0;i--){ if(room.discard[i] && room.discard[i].id === (removed && removed.id)){ room.discard.splice(i,1); break; } } }catch(e){}
|
return cb && cb({ error: 'no valid target player' });
|
||||||
return cb && cb({ error: 'no valid target player' });
|
}
|
||||||
}
|
// compute list of all squares (each square veiled individually)
|
||||||
// record brouillard effect for target player
|
const width = board.width || 8;
|
||||||
room.activeCardEffects = room.activeCardEffects || [];
|
const height = board.height || 8;
|
||||||
const effect = { id: played.id, type: 'brouillard', playerId: targetPlayer.id, ts: Date.now(), remainingTurns: (payload && payload.turns) || 4 };
|
const all = [];
|
||||||
room.activeCardEffects.push(effect);
|
for(let yy = 0; yy < height; yy++){
|
||||||
try{ io.to(room.id).emit('card:effect:applied', { roomId: room.id, effect }); }catch(_){}
|
for(let xx = 0; xx < width; xx++){
|
||||||
played.payload = Object.assign({}, payload, { applied: 'brouillard', appliedToPlayer: targetPlayer.id });
|
all.push(String.fromCharCode('a'.charCodeAt(0) + xx) + (yy+1));
|
||||||
}catch(e){ console.error('brouillard effect error', e); }
|
}
|
||||||
|
}
|
||||||
|
// record brouillard effect for target player with veiledSquares
|
||||||
|
room.activeCardEffects = room.activeCardEffects || [];
|
||||||
|
// initialize playCounts so we can expire brouillard after each player played N times
|
||||||
|
const playCounts = {};
|
||||||
|
try{ (room.players || []).forEach(pl => { if(pl && pl.id) playCounts[pl.id] = 0; }); }catch(_){ }
|
||||||
|
const effect = { id: played.id, type: 'brouillard', playerId: targetPlayer.id, ts: Date.now(), remainingTurns: (payload && payload.turns) || 4, veiledSquares: all, playCounts };
|
||||||
|
room.activeCardEffects.push(effect);
|
||||||
|
try{ io.to(room.id).emit('card:effect:applied', { roomId: room.id, effect }); }catch(_){ }
|
||||||
|
played.payload = Object.assign({}, payload, { applied: 'brouillard', appliedToPlayer: targetPlayer.id });
|
||||||
|
}catch(e){ console.error('brouillard effect error', e); }
|
||||||
}
|
}
|
||||||
// anneau: make the board horizontally wrap for the playing player's pieces for this turn
|
// anneau: make the board horizontally wrap for the playing player's pieces for this turn
|
||||||
else if(cardId === 'anneau' || (typeof cardId === 'string' && cardId.indexOf('anneau') !== -1)){
|
else if(cardId === 'anneau' || (typeof cardId === 'string' && cardId.indexOf('anneau') !== -1)){
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue