purification du code
This commit is contained in:
parent
5db522f7c2
commit
ebbeecbe75
3 changed files with 302 additions and 619 deletions
114
public/game.html
114
public/game.html
|
|
@ -44,7 +44,6 @@
|
||||||
<section class="card" style="margin-top:12px">
|
<section class="card" style="margin-top:12px">
|
||||||
<div><strong>Outils / Logs</strong></div>
|
<div><strong>Outils / Logs</strong></div>
|
||||||
<div style="margin-top:8px">
|
<div style="margin-top:8px">
|
||||||
<!-- movement controls removed as requested -->
|
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top:8px;display:flex;gap:8px;align-items:center">
|
<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>
|
<pre id="log" style="margin-top:0px;height:140px;overflow:auto;flex:1">logs...</pre>
|
||||||
|
|
@ -70,32 +69,24 @@
|
||||||
if(roomIdEl) roomIdEl.textContent = roomId || '-';
|
if(roomIdEl) roomIdEl.textContent = roomId || '-';
|
||||||
if(playerIdEl) playerIdEl.textContent = playerId || '-';
|
if(playerIdEl) playerIdEl.textContent = playerId || '-';
|
||||||
|
|
||||||
// optional UI elements: support removing the sidebar/sections without breaking JS
|
|
||||||
const logEl = document.getElementById('log');
|
const logEl = document.getElementById('log');
|
||||||
const playersEl = document.getElementById('players');
|
const playersEl = document.getElementById('players');
|
||||||
const boardEl = document.getElementById('board');
|
const boardEl = document.getElementById('board');
|
||||||
const myColorEl = document.getElementById('myColor');
|
const myColorEl = document.getElementById('myColor');
|
||||||
let socket = null;
|
let socket = null;
|
||||||
let myColor = null;
|
let myColor = null;
|
||||||
// map playerId -> color (kept up-to-date from room:update)
|
|
||||||
let playerColors = {};
|
let playerColors = {};
|
||||||
// selection state for this client
|
let selectedSquare = null;
|
||||||
let selectedSquare = null; // algebraic name like 'e2'
|
|
||||||
let selectedSquareEl = null;
|
let selectedSquareEl = null;
|
||||||
let myPlayerId = playerId || null;
|
let myPlayerId = playerId || null;
|
||||||
// track remote selections: { playerId: square }
|
|
||||||
const remoteSelections = {};
|
const remoteSelections = {};
|
||||||
// whether this client stayed to spectate after game over
|
|
||||||
let isSpectating = false;
|
let isSpectating = false;
|
||||||
// track remote moves: { playerId: [moves] }
|
|
||||||
const remoteMoves = {};
|
const remoteMoves = {};
|
||||||
// current boardState cached locally
|
|
||||||
let currentBoardState = null;
|
let currentBoardState = null;
|
||||||
let myMines = [];
|
let myMines = [];
|
||||||
let currentVeiledSquares = [];
|
let currentVeiledSquares = [];
|
||||||
let pendingCard = null; // when set, next square click is used as card target
|
let pendingCard = null;
|
||||||
|
|
||||||
// safe logger: prefer on-page log if present, otherwise console
|
|
||||||
function log(...args){
|
function log(...args){
|
||||||
if(logEl){
|
if(logEl){
|
||||||
try{
|
try{
|
||||||
|
|
@ -107,23 +98,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// append a user-facing activity message (visible to players). Keeps recent N entries.
|
|
||||||
function appendActivity(message){
|
function appendActivity(message){
|
||||||
try{
|
try{
|
||||||
const feed = document.getElementById('activityFeed');
|
const feed = document.getElementById('activityFeed');
|
||||||
if(!feed) return;
|
if(!feed) return;
|
||||||
const line = document.createElement('div');
|
const line = document.createElement('div');
|
||||||
// show only the message (no timestamp)
|
|
||||||
line.textContent = message;
|
line.textContent = message;
|
||||||
// prepend newest at top
|
|
||||||
if(feed.textContent && feed.textContent.indexOf("Aucune activité") !== -1){ feed.textContent = ''; }
|
if(feed.textContent && feed.textContent.indexOf("Aucune activité") !== -1){ feed.textContent = ''; }
|
||||||
feed.insertBefore(line, feed.firstChild);
|
feed.insertBefore(line, feed.firstChild);
|
||||||
// limit to 30 entries
|
|
||||||
while(feed.children.length > 30) feed.removeChild(feed.lastChild);
|
while(feed.children.length > 30) feed.removeChild(feed.lastChild);
|
||||||
}catch(_){ }
|
}catch(_){ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// small toast notification helper (non-blocking)
|
|
||||||
function showToast(message, opts){
|
function showToast(message, opts){
|
||||||
try{
|
try{
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
@ -147,9 +133,6 @@
|
||||||
}catch(_){ }
|
}catch(_){ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Robust card:play emitter with refresh fallback.
|
|
||||||
// Sometimes the client or network misses the room:update after playing a card —
|
|
||||||
// this helper emits card:play and requests a room refresh if no ack/update is received.
|
|
||||||
function emitCardPlay(payload, cb){
|
function emitCardPlay(payload, cb){
|
||||||
try{
|
try{
|
||||||
if(!socket) return cb && cb({ error: 'no_socket' });
|
if(!socket) return cb && cb({ error: 'no_socket' });
|
||||||
|
|
@ -161,66 +144,47 @@
|
||||||
}, 1500);
|
}, 1500);
|
||||||
socket.emit('card:play', payload, (resp)=>{
|
socket.emit('card:play', payload, (resp)=>{
|
||||||
acked = true; try{ clearTimeout(timer); }catch(_){ }
|
acked = true; try{ clearTimeout(timer); }catch(_){ }
|
||||||
// ask server to push a fresh room:update to ensure UIs are in sync
|
|
||||||
try{ socket.emit('room:refresh', { roomId }, ()=>{}); }catch(_){ }
|
try{ socket.emit('room:refresh', { roomId }, ()=>{}); }catch(_){ }
|
||||||
if(cb) cb(resp);
|
if(cb) cb(resp);
|
||||||
});
|
});
|
||||||
}catch(e){ if(cb) cb({ error: 'emit_failed' }); }
|
}catch(e){ if(cb) cb({ error: 'emit_failed' }); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// play a short shuffle animation (shake + fade) when pieces are mixed
|
|
||||||
function playShuffleAnimation(){
|
function playShuffleAnimation(){
|
||||||
if(!boardEl) return;
|
if(!boardEl) return;
|
||||||
try{
|
try{
|
||||||
boardEl.classList.add('shuffle-play');
|
boardEl.classList.add('shuffle-play');
|
||||||
// remove after animation duration
|
|
||||||
setTimeout(()=>{ try{ boardEl.classList.remove('shuffle-play'); }catch(_){ } }, 700);
|
setTimeout(()=>{ try{ boardEl.classList.remove('shuffle-play'); }catch(_){ } }, 700);
|
||||||
}catch(_){ }
|
}catch(_){ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper: decide if a card requires a target selected after clicking 'Jouer'
|
|
||||||
function cardRequiresTarget(cardId){
|
function cardRequiresTarget(cardId){
|
||||||
if(!cardId) return null;
|
if(!cardId) return null;
|
||||||
// normalize and strip diacritics so titles like "Téléportation" become "teleportation"
|
|
||||||
let id = String(cardId).toLowerCase();
|
let id = String(cardId).toLowerCase();
|
||||||
try{
|
try{
|
||||||
id = id.normalize('NFD').replace(/\p{Diacritic}/gu, '');
|
id = id.normalize('NFD').replace(/\p{Diacritic}/gu, '');
|
||||||
}catch(e){
|
}catch(e){
|
||||||
// fallback: remove non-ascii characters
|
|
||||||
id = id.replace(/[^\x00-\x7F]/g, '');
|
id = id.replace(/[^\x00-\x7F]/g, '');
|
||||||
}
|
}
|
||||||
if(id.indexOf('mine') !== -1) return 'empty';
|
if(id.indexOf('mine') !== -1) return 'empty';
|
||||||
// revolution is a global immediate effect: it should NOT require any piece selection
|
if(id.indexOf('revol') !== -1) return null;
|
||||||
if(id.indexOf('revol') !== -1) return null;
|
if(id.indexOf('sniper') !== -1) return 'owned';
|
||||||
// sniper: select one of your pieces to bind the sniper effect (capture later without moving)
|
if(id.indexOf('doppel') !== -1) return 'owned';
|
||||||
if(id.indexOf('sniper') !== -1) return 'owned';
|
if(id.indexOf('toucher') !== -1) return 'enemy';
|
||||||
// doppelganger: select one of your pieces after playing the card (minimal flow)
|
if(id.indexOf('parrure') !== -1) return 'enemy_queen';
|
||||||
if(id.indexOf('doppel') !== -1) return 'owned';
|
if(id.indexOf('tout') !== -1) return 'piece';
|
||||||
// 'toucher c'est jouer' : require selecting an enemy piece as the card target
|
if(id.indexOf('kamikaz') !== -1) return 'owned';
|
||||||
if(id.indexOf('toucher') !== -1) return 'enemy';
|
if(id.indexOf('invisible') !== -1) return 'owned';
|
||||||
// la parrure: select an enemy queen to downgrade to a pawn
|
if(id.indexOf('rebond') !== -1) return 'owned';
|
||||||
if(id.indexOf('parrure') !== -1) return 'enemy_queen';
|
if(id.indexOf('adoub') !== -1) return 'owned';
|
||||||
// tout ou rien: select a piece (any, except kings) to force it to only move when capturing
|
if(id.indexOf('folie') !== -1) return 'owned';
|
||||||
if(id.indexOf('tout') !== -1 && id.indexOf('rien') !== -1) return 'piece';
|
if(id.indexOf('fortification') !== -1) return 'owned';
|
||||||
// kamikaz targets one of your pieces (play card, then choose a piece)
|
if(id.indexOf('promotion') !== -1) return 'owned_pawn_then_enemy';
|
||||||
if(id.indexOf('kamikaz') !== -1) return 'owned';
|
if(id.indexOf('vol_carte') !== -1) return 'player';
|
||||||
if(id.indexOf('invis') !== -1 || id.indexOf('invisible') !== -1) return 'owned';
|
if(id.indexOf('vole_piece') !== -1) return 'enemy';
|
||||||
if(id.indexOf('rebond') !== -1) return 'owned';
|
if(id.indexOf('coincoin') !== -1) return 'owned';
|
||||||
if(id.indexOf('adoub') !== -1) return 'owned';
|
if(id.indexOf('teleportation') !== -1) return 'owned';
|
||||||
if(id.indexOf('folie') !== -1 || id.indexOf('fou') !== -1) return 'owned';
|
if(id.indexOf('inversion') !== -1) return 'own_then_enemy';
|
||||||
if(id.indexOf('fortif') !== -1 || id.indexOf('fortification') !== -1) return 'owned';
|
|
||||||
// promotion targets one of your pawns (special handling client-side to show promotion choice)
|
|
||||||
if(id.indexOf('promotion') !== -1 || id.indexOf('promot') !== -1 || id.indexOf('promouvoir') !== -1) return 'owned_pawn';
|
|
||||||
// steal a card (target a player) if the card mentions 'carte'/'card' — otherwise a 'vol' often targets a piece
|
|
||||||
if(id.indexOf('vol') !== -1 || id.indexOf('vole') !== -1 || id.indexOf('steal') !== -1){
|
|
||||||
if(id.indexOf('carte') !== -1 || id.indexOf('card') !== -1) return 'player';
|
|
||||||
return 'enemy';
|
|
||||||
}
|
|
||||||
if(id.indexOf('coin') !== -1 || id === 'coin_coin') return 'owned';
|
|
||||||
// teleportation: require selecting one of your pieces first (like promotion)
|
|
||||||
if(id.indexOf('teleport') !== -1 || id.indexOf('tele') !== -1 || id.indexOf('t_l_portation') !== -1) return 'owned';
|
|
||||||
// inversion: first choose one of your pieces, then choose an enemy piece to swap places
|
|
||||||
if(id.indexOf('inversion') !== -1) return 'own_then_enemy';
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,13 +196,10 @@
|
||||||
|
|
||||||
socket.on('room:update', (data)=>{
|
socket.on('room:update', (data)=>{
|
||||||
log('room:update', data);
|
log('room:update', data);
|
||||||
// server now sends `boardState` (JSON). renderBoardFromState will handle it.
|
|
||||||
if(playersEl){
|
if(playersEl){
|
||||||
playersEl.innerHTML = '';
|
playersEl.innerHTML = '';
|
||||||
(data.players||[]).forEach(p=>{
|
(data.players||[]).forEach(p=>{
|
||||||
// keep a mapping from playerId -> color for activity feed formatting
|
|
||||||
try{ playerColors[p.id] = p.color; }catch(_){ }
|
try{ playerColors[p.id] = p.color; }catch(_){ }
|
||||||
// if this is our player, store the color locally and update UI
|
|
||||||
try{ if(p.id === myPlayerId){ myColor = p.color; if(myColorEl) myColorEl.textContent = myColor; } }catch(_){ }
|
try{ if(p.id === myPlayerId){ myColor = p.color; if(myColorEl) myColorEl.textContent = myColor; } }catch(_){ }
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
li.textContent = (p.color || 'Joueur') + (p.id === myPlayerId ? ' (vous)' : '');
|
li.textContent = (p.color || 'Joueur') + (p.id === myPlayerId ? ' (vous)' : '');
|
||||||
|
|
@ -246,29 +207,20 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(data.size){
|
if(data.size){
|
||||||
// ensure grid layout matches requested size and build squares
|
|
||||||
buildGrid(data.size);
|
buildGrid(data.size);
|
||||||
// adjust board width/height responsively (keep squares roughly proportional)
|
|
||||||
const side = Math.min(800, Math.max(320, data.size * 80));
|
const side = Math.min(800, Math.max(320, data.size * 80));
|
||||||
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 = []; }
|
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);
|
||||||
}
|
}
|
||||||
// if the room is no longer finished, remove spectator quit button
|
|
||||||
try{ if(data && data.status && data.status !== 'finished'){ removeSpectatorQuitButton(); } }catch(_){ }
|
try{ if(data && data.status && data.status !== 'finished'){ removeSpectatorQuitButton(); } }catch(_){ }
|
||||||
// store mines owned by this client (private)
|
|
||||||
try{ myMines = data.minesOwn || []; }catch(e){ myMines = []; }
|
try{ myMines = data.minesOwn || []; }catch(e){ myMines = []; }
|
||||||
// after rendering the board, render mines for owner
|
|
||||||
try{ renderMines(); }catch(e){ }
|
try{ renderMines(); }catch(e){ }
|
||||||
// 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){
|
if(data.hands){
|
||||||
// legacy: full hands object mapping playerId -> array
|
|
||||||
const own = (data.hands && data.hands[myPlayerId]) ? data.hands[myPlayerId] : [];
|
const own = (data.hands && data.hands[myPlayerId]) ? data.hands[myPlayerId] : [];
|
||||||
const counts = {};
|
const counts = {};
|
||||||
Object.entries(data.hands || {}).forEach(([pid, arr])=>{ counts[pid] = (arr && arr.length) || 0; });
|
Object.entries(data.hands || {}).forEach(([pid, arr])=>{ counts[pid] = (arr && arr.length) || 0; });
|
||||||
|
|
@ -276,7 +228,6 @@
|
||||||
} else if(data.handsOwn || data.handCounts){
|
} else if(data.handsOwn || data.handCounts){
|
||||||
renderHands(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{
|
try{
|
||||||
const drawBtn = document.getElementById('drawBtn');
|
const drawBtn = document.getElementById('drawBtn');
|
||||||
if(drawBtn){
|
if(drawBtn){
|
||||||
|
|
@ -284,7 +235,6 @@
|
||||||
const board = data.boardState || null;
|
const board = data.boardState || null;
|
||||||
const myShort = myColor && myColor[0];
|
const myShort = myColor && myColor[0];
|
||||||
if(!auto && board && myShort && board.turn === myShort){
|
if(!auto && board && myShort && board.turn === myShort){
|
||||||
// enable draw if hand not full
|
|
||||||
const myHandLen = (data.handsOwn && data.handsOwn.length) || 0;
|
const myHandLen = (data.handsOwn && data.handsOwn.length) || 0;
|
||||||
drawBtn.style.display = 'inline-block';
|
drawBtn.style.display = 'inline-block';
|
||||||
drawBtn.disabled = myHandLen >= 5;
|
drawBtn.disabled = myHandLen >= 5;
|
||||||
|
|
@ -298,42 +248,31 @@
|
||||||
try{
|
try{
|
||||||
log('game:over', data);
|
log('game:over', data);
|
||||||
if(data.boardState){ renderBoardFromState(data.boardState); updateTurnBanner(data.boardState); }
|
if(data.boardState){ renderBoardFromState(data.boardState); updateTurnBanner(data.boardState); }
|
||||||
// show modal with friendly message
|
|
||||||
try{ showGameOver(data); }catch(_){ }
|
try{ showGameOver(data); }catch(_){ }
|
||||||
}catch(e){ console.warn('game:over handler error', e); }
|
}catch(e){ console.warn('game:over handler error', e); }
|
||||||
});
|
});
|
||||||
socket.on('game:started', (data)=>{ log('game:started', 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); } });
|
||||||
// card drawn notification from server
|
|
||||||
socket.on('card:drawn', (data) => {
|
socket.on('card:drawn', (data) => {
|
||||||
try{
|
try{
|
||||||
log('recv card:drawn', data);
|
log('recv card:drawn', data);
|
||||||
// show a small inline notification in the hands section
|
|
||||||
showCardDrawnNotification(data);
|
showCardDrawnNotification(data);
|
||||||
}catch(e){ console.warn('card:drawn handler error', e); }
|
}catch(e){ console.warn('card:drawn handler error', e); }
|
||||||
});
|
});
|
||||||
// public notice that a player drew a card when autoDraw is OFF (server emits this only in that case)
|
|
||||||
socket.on('player:drew', (data) => {
|
socket.on('player:drew', (data) => {
|
||||||
try{
|
try{
|
||||||
const pid = data && data.playerId;
|
const pid = data && data.playerId;
|
||||||
if(!pid) return;
|
if(!pid) return;
|
||||||
const actor = (pid === myPlayerId) ? 'Vous' : (playerColors[pid] ? playerColors[pid] : 'Adversaire');
|
const actor = (pid === myPlayerId) ? 'Vous' : (playerColors[pid] ? playerColors[pid] : 'Adversaire');
|
||||||
// show owner message as 'Vous : a pioché une carte' so the player sees the activity line too
|
|
||||||
appendActivity(`${actor} : a pioché une carte`);
|
appendActivity(`${actor} : a pioché une carte`);
|
||||||
}catch(_){ }
|
}catch(_){ }
|
||||||
});
|
});
|
||||||
// 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) => {
|
socket.on('card:played', (data) => {
|
||||||
try{
|
try{
|
||||||
log('recv card:played', data);
|
log('recv card:played', data);
|
||||||
// data.played or data depending on server shape
|
|
||||||
const played = data && data.played ? data.played : data;
|
const played = data && data.played ? data.played : data;
|
||||||
const cardObj = played && (played.card || played.cardObj || null);
|
const cardObj = played && (played.card || played.cardObj || null);
|
||||||
const owner = played && played.playerId;
|
const owner = played && played.playerId;
|
||||||
// if we have the card object and it's our card, remove its DOM element
|
|
||||||
if(owner === myPlayerId){
|
if(owner === myPlayerId){
|
||||||
// find the card element by uuid (data-card-uuid) or by cardId
|
|
||||||
const row = document.querySelector('.cards-row');
|
const row = document.querySelector('.cards-row');
|
||||||
if(row){
|
if(row){
|
||||||
const elems = Array.from(row.querySelectorAll('.pokemon-card'));
|
const elems = Array.from(row.querySelectorAll('.pokemon-card'));
|
||||||
|
|
@ -346,12 +285,9 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// show friendly activity: who played which card (use title if available)
|
|
||||||
try{
|
try{
|
||||||
const title = (cardObj && (cardObj.title || cardObj.cardId)) || (played && played.card && (played.card.title || played.card.cardId)) || 'Carte';
|
const title = (cardObj && (cardObj.title || cardObj.cardId)) || (played && played.card && (played.card.title || played.card.cardId)) || 'Carte';
|
||||||
// show player's color instead of their id; fallback to generic label
|
|
||||||
const actor = (owner === myPlayerId) ? 'Vous' : (playerColors[owner] ? playerColors[owner] : 'Adversaire');
|
const actor = (owner === myPlayerId) ? 'Vous' : (playerColors[owner] ? playerColors[owner] : 'Adversaire');
|
||||||
// If the played card is marked hidden, do not reveal the title to other players
|
|
||||||
const isHidden = (cardObj && cardObj.hidden) || (played && played.card && played.card.hidden);
|
const isHidden = (cardObj && cardObj.hidden) || (played && played.card && played.card.hidden);
|
||||||
if(isHidden && owner !== myPlayerId){
|
if(isHidden && owner !== myPlayerId){
|
||||||
appendActivity(`${actor} : a joué une carte`);
|
appendActivity(`${actor} : a joué une carte`);
|
||||||
|
|
@ -361,16 +297,13 @@
|
||||||
}catch(_){ }
|
}catch(_){ }
|
||||||
}catch(e){ console.warn('card:played handler error', e); }
|
}catch(e){ console.warn('card:played handler error', e); }
|
||||||
});
|
});
|
||||||
// show card effect notifications (both public and private) so owners get feedback on failed placements/promotions
|
|
||||||
socket.on('card:effect:applied', (data) => {
|
socket.on('card:effect:applied', (data) => {
|
||||||
try{
|
try{
|
||||||
const effect = data && data.effect ? data.effect : data;
|
const effect = data && data.effect ? data.effect : data;
|
||||||
if(!effect) return;
|
if(!effect) return;
|
||||||
// play shuffle animation for melange
|
if(effect.type === 'melange' || effect.type === 'melange'){
|
||||||
if(effect.type === 'melange' || effect.type === 'm\u00E9lange'){
|
|
||||||
try{ playShuffleAnimation(); }catch(_){ }
|
try{ playShuffleAnimation(); }catch(_){ }
|
||||||
}
|
}
|
||||||
// if this is a private or public effect relating to this player, show a small note
|
|
||||||
if(effect.playerId && effect.playerId === myPlayerId){
|
if(effect.playerId && effect.playerId === myPlayerId){
|
||||||
showEffectNotification(effect);
|
showEffectNotification(effect);
|
||||||
} else if(effect.type && (effect.type === 'promotion' || effect.type === 'steal' || effect.type === 'mine')){
|
} else if(effect.type && (effect.type === 'promotion' || effect.type === 'steal' || effect.type === 'mine')){
|
||||||
|
|
@ -1164,7 +1097,6 @@
|
||||||
const top = document.createElement('div'); top.className = 'pokemon-card-top';
|
const top = document.createElement('div'); top.className = 'pokemon-card-top';
|
||||||
const art = document.createElement('div'); art.className = 'pokemon-card-art';
|
const art = document.createElement('div'); art.className = 'pokemon-card-art';
|
||||||
art.textContent = '';
|
art.textContent = '';
|
||||||
// show card artwork if available in assets/img/cards matching the cardId or title
|
|
||||||
try{
|
try{
|
||||||
const cid = (c.cardId || c.id || '').toString().toLowerCase();
|
const cid = (c.cardId || c.id || '').toString().toLowerCase();
|
||||||
const title = (c.title || '').toString().toLowerCase();
|
const title = (c.title || '').toString().toLowerCase();
|
||||||
|
|
@ -1186,7 +1118,7 @@
|
||||||
if(cid === 'sniper' || title.indexOf('sniper') !== -1) imgSrc = '/assets/img/cards/sniper.png';
|
if(cid === 'sniper' || title.indexOf('sniper') !== -1) imgSrc = '/assets/img/cards/sniper.png';
|
||||||
if(cid === 'totem' || title.indexOf('totem') !== -1) imgSrc = '/assets/img/cards/totem.png';
|
if(cid === 'totem' || title.indexOf('totem') !== -1) imgSrc = '/assets/img/cards/totem.png';
|
||||||
if(cid === 'toucher' || title.indexOf('toucher') !== -1) imgSrc = '/assets/img/cards/toucher.png';
|
if(cid === 'toucher' || title.indexOf('toucher') !== -1) imgSrc = '/assets/img/cards/toucher.png';
|
||||||
if(cid === 'vole' || title.indexOf('vole') !== -1 || title.indexOf('vole') !== -1) imgSrc = '/assets/img/cards/vole_piece.png';
|
if(cid === 'vole_piece' || title.indexOf('vole_piece') !== -1) imgSrc = '/assets/img/cards/vole_piece.png';
|
||||||
if(imgSrc){
|
if(imgSrc){
|
||||||
const img = document.createElement('img');
|
const img = document.createElement('img');
|
||||||
img.src = imgSrc;
|
img.src = imgSrc;
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,19 @@
|
||||||
<li><strong>Fin de partie :</strong> si un roi est capturé, la partie s'arrête sur une victoire, une défaite ou peut-être même une égalité. Les joueurs peuvent choisir de rester en spectateur ou de quitter la partie.</li>
|
<li><strong>Fin de partie :</strong> si un roi est capturé, la partie s'arrête sur une victoire, une défaite ou peut-être même une égalité. Les joueurs peuvent choisir de rester en spectateur ou de quitter la partie.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p style="margin-top:8px;font-size:0.95em;color:#444">Remarque : ces règles couvrent uniquement les mécaniques des cartes — pour le jeu d'échecs standard, les mouvements habituels s'appliquent (pions, tours, cavaliers, fous, dames, rois).</p>
|
<p style="margin-top:8px;font-size:0.95em;color:#444">Remarque : ces règles couvrent uniquement les mécaniques des cartes — pour le jeu d'échecs standard, les mouvements habituels s'appliquent (pions, tours, cavaliers, fous, dames, rois).</p>
|
||||||
|
<h3>Modes de jeux</h3>
|
||||||
|
<p>Il existe plusieurs modes de jeux pour s'adapter à différents styles de jeu :</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Pioche automatique :</strong> Si activé, les cartes sont piochées automatiquement à chaque tour. Sinon, les joueurs doivent décider s'ils piochent ou s'ils jouent. Attention ! Il n'est pas possible de piocher deux fois de suite !</li>
|
||||||
|
<li><strong>Sans remise :</strong> Les cartes jouées ne sont pas remises dans la pioche, ce qui les rend uniques.</li>
|
||||||
|
<li><strong>Pioche personnalisée :</strong> Choisissez les cartes disponibles dans la pioche.</li>
|
||||||
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="card" id="availableCards" style="margin-top:16px">
|
<section class="card" id="availableCards" style="margin-top:16px">
|
||||||
<h3>Cartes disponibles</h3>
|
<h3>Cartes disponibles</h3>
|
||||||
<div id="cardsGrid" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-top:12px">
|
<div id="cardsGrid" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-top:12px">
|
||||||
<!-- cards will be injected here -->
|
<!-- Affichage des cartes disponibles -->
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue