// Fonction et variables essentiel const activePlayerLabel = document.getElementById('active-player-name'); let gameData = null; let currentPlayer = null; let playersData = []; async function SqlRequest(action, params = {}) { try { const response = await fetch('RequestsHandler.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: action, params: params }) }); const resultat = await response.json(); if (resultat.success) { return resultat; } else { console.error("Erreur :", resultat.error); } } catch (erreur) { console.error("Erreur de communication :", erreur); } } // Fonctions pour démarrer la page // Remplace ton window.onload par ceci : window.onload = async function() { const urlParams = new URLSearchParams(window.location.search); const gId = urlParams.get('game_id'); // On récupère les données initiales gameData = await getGame(gId); playersData = await getPlayers(); document.getElementById('title_page').textContent = gameData.name + " - Poker PAF"; updateClientInterface(); // --- LANCEMENT DU TEMPS RÉEL (SSE) --- startRealTimeSync(gId); } function startRealTimeSync(gameId) { const evtSource = new EventSource(`stream.php?game_id=${gameId}`); evtSource.onmessage = function(event) { const data = JSON.parse(event.data); // On met à jour nos variables globales avec les données fraîches du serveur gameData = data.game; playersData = data.players; console.log("🔄 Table synchronisée"); // On rafraîchit l'affichage sans recharger la page updateClientInterface(); }; evtSource.onerror = function() { console.log("⚠️ Connexion perdue, tentative de reconnexion..."); }; } // Dans game.js let lastDataHash = ""; async function updateClientInterface() { if (!gameData) return; const urlParams = new URLSearchParams(window.location.search); const viewerId = Number(urlParams.get('player_id')); const actionPanel = document.querySelector('.action-panel'); // --- 1. GESTION DES PANNEAUX DE VICTOIRE (SYNCHRO SSE) --- console.log("DEBUG STATUS SSE:", gameData.status); if (gameData.status === 'deciding') { // L'admin est en train de choisir : on affiche "Attente" showWaitingForWinner(); } else if (gameData.status === 'finished' && gameData.winner_id) { // Un gagnant a été validé en BDD const winner = playersData.find(p => Number(p.id) === Number(gameData.winner_id)); const winnerName = winner ? winner.name : "Un joueur"; // showVictoryScreen s'occupe maintenant de supprimer l'ancien panneau // avant d'afficher le nouveau avec les confettis. showVictoryScreen(winnerName, gameData.pot); } else if (gameData.status === 'playing') { // Si l'admin a relancé la partie (StartNewGame), on nettoie les panneaux // pour ceux qui n'auraient pas cliqué sur "OK" closeVictoryScreen(); } // --- 2. GESTION DU HASH POUR L'INTERFACE DE TABLE --- const currentHash = `${gameData.pot}-${gameData.current_player_id}-${gameData.last_bet}-${gameData.is_locked}-${gameData.status}`; if (currentHash === lastDataHash) return; lastDataHash = currentHash; setupPlayers(); getCurrentPlayer(); // --- 3. GESTION DES BOUTONS ET DU TOUR --- const isLocked = Number(gameData.is_locked) === 1; const isMyTurn = Number(gameData.current_player_id) === viewerId; const turnInfo = document.querySelector('.turn-info'); const inputs = document.querySelectorAll('.action-buttons button, .raise-group input, .raise-group button'); // Bordure de tour if (!isLocked && isMyTurn && gameData.status === 'playing') { actionPanel.classList.add('my-turn-border'); } else { actionPanel.classList.remove('my-turn-border'); } if (isLocked) { if (turnInfo) turnInfo.innerHTML = `🔒 Jeu verrouillé. En attente de l'Admin...`; inputs.forEach(el => el.disabled = true); } else if (!isMyTurn) { if (turnInfo && currentPlayer) { turnInfo.innerHTML = `Attente de ${currentPlayer.name}...`; } inputs.forEach(el => el.disabled = true); } else { if (turnInfo) turnInfo.innerHTML = `✅ C'est à vous de jouer !`; inputs.forEach(el => el.disabled = false); } // --- 3.bis BOUTON INTELLIGENT (Seulement si c'est mon tour) --- const currentMiseTable = Number(gameData.last_bet); const btnFollow = document.getElementById('btn-call'); const btnFold = document.getElementById('btn-fold'); if (currentMiseTable === 0) { // PERSONNE N'A MISÉ : "Rester" if (btnFollow) { btnFollow.textContent = `Rester (Passer son tour)`; btnFollow.onclick = () => playerCall(); btnFollow.className = "btn btn-stay"; } if (btnFold) { btnFold.disabled = true; // Désactivé car inutile de se coucher btnFold.style.opacity = "0.5"; } } else { // UNE MISE EXISTE : "Suivre" if (btnFollow) { btnFollow.textContent = `Suivre (${currentMiseTable} 🪙)`; btnFollow.onclick = () => playerFollow(); btnFollow.className = "btn btn-call"; } if (btnFold) { btnFold.disabled = false; btnFold.style.opacity = "1"; } } // Mise à jour du label du haut if (currentPlayer && activePlayerLabel) { activePlayerLabel.textContent = `${currentPlayer.name} (${currentPlayer.money} 🪙)`; } } // Fonction pour envoyer l'ordre au serveur async function toggleGameLock(checkbox) { const status = checkbox.checked ? 0 : 1; // 1. On change d'abord le statut de verrouillage const response = await SqlRequest('toggle_lock', { game_id: gameData.id, status: status }); if (response && response.success) { // 2. Si on vient de DÉVERROUILLER (status 0), on reset le joueur actif if (status === 0) { console.log("🔓 Déverrouillage : Réinitialisation au joueur après le Dealer..."); await resetToPostDealerPlayer(); } } else { alert("Erreur lors du changement de statut"); checkbox.checked = !checkbox.checked; } } async function resetToPostDealerPlayer() { // On cherche l'index du dealer dans playersData const dealerIndex = playersData.findIndex(p => Number(p.is_dealer) === 1); // Le premier joueur à parler est (dealer + 1), mais on doit gérer la boucle du tableau // et sauter les joueurs qui se sont couchés (is_folded) let nextIndex = (dealerIndex + 1) % playersData.length; // Sécurité : on cherche le prochain qui n'est pas couché let attempts = 0; while (playersData[nextIndex].is_folded && attempts < playersData.length) { nextIndex = (nextIndex + 1) % playersData.length; attempts++; } const firstPlayerId = playersData[nextIndex].id; // On envoie l'ordre au serveur de mettre ce joueur en actif await SqlRequest('set_current_player', { game_id: gameData.id, player_id: firstPlayerId }); } async function setupPlayers() { const urlParams = new URLSearchParams(window.location.search); const viewerId = Number(urlParams.get('player_id')); // On récupère qui regarde la page const PokerTable = document.getElementById('table'); PokerTable.innerHTML = ''; let newHtml = `
${gameData.pot}
Mise: ${gameData.last_bet}
`; playersData.forEach((player, index) => { const isDealer = Number(player.is_dealer) === 1; const isMe = Number(player.id) === viewerId; // Est-ce moi ? const isActive = Number(gameData.current_player_id) === Number(player.id); newHtml += `
${isDealer ? '
D
' : ''} ${isMe ? 'VOUS' : 'J' + (index + 1)} : ${player.name} ${player.money} 🪙
Mise: ${player.current_bet} 🪙
`; }); PokerTable.innerHTML = newHtml; } async function getGame(id = null) { let gameId; if (id === null) { const urlParams = new URLSearchParams(window.location.search); gameId = urlParams.get('game_id'); } else { gameId = id; } const response = await SqlRequest('getGame', { game_id: gameId }); if (response.success) { return response.game; } else { console.error("Erreur lors de la récupération du jeu :", response.error); return null; } } async function getPlayers() { const response = await SqlRequest('getPlayers', { game_id: gameData.id }); if (response.success) { return response.players; } else { console.error("Erreur lors de la récupération des joueurs :", response.error); return []; } } function getCurrentPlayer() { if (!playersData || !gameData) return null; // On cherche le joueur dans le tableau par son ID currentPlayer = playersData.find(player => Number(player.id) === Number(gameData.current_player_id)); return currentPlayer; } // ----------------------------------------------------- // Fonctions pour les actions async function changePlayer(id = null) { if (id === null) { const response = await SqlRequest('next_player', { game_id: gameData.id, current_player_id: gameData.current_player_id }); if (response.success) { gameData.current_player_id = response.next_player_id; } else { console.error("Erreur lors du passage au joueur suivant :", response.error); } } else { const response = await SqlRequest('set_current_player', { game_id: gameData.id, player_id: id }); if (response.success) { gameData.current_player_id = id; } else { console.error("Erreur lors du changement de joueur :", response.error); } } updateClientInterface(); } async function playerFold() { const urlParams = new URLSearchParams(window.location.search); const viewerId = Number(urlParams.get('player_id')); // Sécurité : si l'ID de l'URL n'est pas celui du joueur actif, on stoppe tout if (Number(gameData.current_player_id) !== viewerId) { alert("Ce n'est pas votre tour !"); return; } const response = await SqlRequest('fold', { player_id: gameData.current_player_id }); if (response.success) { playersData = await getPlayers(); changePlayer(); } else { console.error("Erreur lors du fold :", response.error); } } async function playerRaise() { const urlParams = new URLSearchParams(window.location.search); const viewerId = Number(urlParams.get('player_id')); // Sécurité : si l'ID de l'URL n'est pas celui du joueur actif, on stoppe tout if (Number(gameData.current_player_id) !== viewerId) { alert("Ce n'est pas votre tour !"); return; } const betInput = document.getElementById('raise-amount'); const betValue = parseInt(betInput.value); // Validation basique du champ de saisie if (isNaN(betValue) || betValue <= 0) { alert("Veuillez saisir un montant valide."); return; } // Envoi de la requête de relance au serveur const response = await SqlRequest('raise', { game_id: gameData.id, player_id: gameData.current_player_id, bet_input: betValue }); if (response && response.success) { betInput.value = ''; // Réinitialisation du champ await changePlayer(); // Passage au joueur suivant } else { // Affichage de l'erreur retournée par le PHP (ex: "Fonds insuffisants") alert("Erreur : " + (response ? response.error : "Serveur injoignable")); } } async function playerFollow() { const urlParams = new URLSearchParams(window.location.search); const viewerId = Number(urlParams.get('player_id')); // Sécurité : si l'ID de l'URL n'est pas celui du joueur actif, on stoppe tout if (Number(gameData.current_player_id) !== viewerId) { alert("Ce n'est pas votre tour !"); return; } // Si le joueur a déjà mis la somme requise if (Number(currentPlayer.current_bet) >= Number(gameData.last_bet)) { // AU LIEU DE changePlayer(), on vérifie si le tour est fini const activePlayers = playersData.filter(p => Number(p.is_folded) === 0); const allMatched = activePlayers.every(p => Number(p.current_bet) === Number(gameData.last_bet)); if (allMatched) { await SqlRequest('toggle_lock', { game_id: gameData.id, status: 1 }); return; // On s'arrête là, le SSE fera le reste } await changePlayer(); return; } // 1. On force la récupération du joueur actuel s'il est manquant if (!currentPlayer) { await getCurrentPlayer(); } // 2. Si après ça il est toujours introuvable, on arrête pour éviter l'erreur if (!currentPlayer) { console.error("Erreur : Impossible de trouver les données du joueur actif."); return; } // 3. Logique de suivi if (Number(currentPlayer.current_bet) >= Number(gameData.last_bet)) { changePlayer(); return; } // Calcul du montant à ajouter let delta_amount = Math.max(0, Number(gameData.last_bet) - Number(currentPlayer.current_bet)); if (Number(currentPlayer.money) < delta_amount) { delta_amount = Number(currentPlayer.money); } const response = await SqlRequest('follow', { game_id: gameData.id, player_id: gameData.current_player_id, amount: delta_amount }); if (response && response.success) { // --- LOGIQUE DE VÉRIFICATION DU TOUR --- // On récupère les données fraîches pour savoir si c'était le dernier à suivre const refreshedPlayers = await getPlayers(); // On vérifie si tout le monde a mis la même somme (et n'est pas couché) const activePlayers = refreshedPlayers.filter(p => Number(p.is_folded) === 0); const allMatched = activePlayers.every(p => Number(p.current_bet) === Number(gameData.last_bet)); if (allMatched) { // On demande au serveur de verrouiller la partie (si tu as l'action prévue) await SqlRequest('toggle_lock', { game_id: gameData.id, status: 1 }); console.log("Tour terminé, table verrouillée."); } else { // Sinon on passe juste au suivant await changePlayer(); } } } async function playerCall() { changePlayer(); } async function playerAllIn() { const urlParams = new URLSearchParams(window.location.search); const viewerId = Number(urlParams.get('player_id')); // Sécurité : si l'ID de l'URL n'est pas celui du joueur actif, on stoppe tout if (Number(gameData.current_player_id) !== viewerId) { alert("Ce n'est pas votre tour !"); return; } const response = await SqlRequest('all_in', { game_id: gameData.id, player_id: gameData.current_player_id }); if (response.success) { gameData = await getGame(gameData.id); playersData = await getPlayers(); changePlayer(); } else { console.error("Erreur lors du all-in :", response.error); } } // Étape 1 : Afficher l'attente quand l'admin termine la partie function showWaitingForWinner() { if (document.getElementById('player-modal')) return; const overlay = document.createElement('div'); overlay.id = 'player-modal'; overlay.className = 'player-win-overlay'; overlay.innerHTML = `

FIN DE PARTIE

Détermination du gagnant en cours...

`; document.body.appendChild(overlay); } let victoryDisplayedFor = null; // Variable globale function showVictoryScreen(winnerName, amount) { // 1. On cherche s'il y a déjà un panneau ouvert (celui d'attente par exemple) const existingModal = document.getElementById('player-modal'); if (existingModal) { existingModal.remove(); // On le supprime proprement } // 2. On crée le nouveau panneau de victoire const modal = document.createElement('div'); modal.id = 'player-modal'; modal.className = 'player-win-overlay'; modal.innerHTML = `

VICTOIRE DE ${winnerName}

Il remporte ${amount} 🪙
`; document.body.appendChild(modal); // On lance les confettis if (typeof startConfetti === "function") startConfetti(); } // Et dans ton closeVictoryScreen function closeVictoryScreen() { const modal = document.getElementById('player-modal'); if (modal) modal.remove(); victoryDisplayedFor = null; // Reset pour la prochaine partie } function startConfetti() { for (let i = 0; i < 50; i++) { const confetti = document.createElement('div'); confetti.style.cssText = ` position: fixed; width: 10px; height: 10px; background: ${['#d4af37','#ffffff','#2ecc71'][Math.floor(Math.random()*3)]}; top: -10px; left: ${Math.random() * 100}vw; z-index: 10001; pointer-events: none; border-radius: 50%; animation: fall ${2 + Math.random() * 3}s linear forwards; `; document.body.appendChild(confetti); setTimeout(() => confetti.remove(), 5000); } } function toPornoJaponnaisOrNotToPornoJaponnais(){ // let a = Math.random() let a = 1 if (a <= 0.25){ return ' porno-japonnais' } else { return ' blur-effect' } }