some hotfixes
This commit is contained in:
@@ -242,6 +242,13 @@ body {
|
||||
}
|
||||
.btn-call:hover { background: var(--green); color: #000; }
|
||||
|
||||
.btn-stay {
|
||||
background: transparent;
|
||||
color: rgba(77, 166, 255, 1);
|
||||
border: 2px solid rgba(77, 166, 255, 1);
|
||||
}
|
||||
.btn-stay:hover { background: rgba(77, 166, 255, 0.4); color: #fff; }
|
||||
|
||||
.btn-allin {
|
||||
background: linear-gradient(45deg, #8b0000, #e60000);
|
||||
color: white;
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/* Importation d'une police élégante */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&family=Playfair+Display:wght@700&display=swap');
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: radial-gradient(circle at center, #1a2a23 0%, #0a0f0d 100%);
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
color: #e0e0e0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Background décoratif (Optionnel : petits motifs de cartes) */
|
||||
body::before {
|
||||
content: "♠ ♥ ♣ ♦";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 20rem;
|
||||
opacity: 0.03;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Conteneur principal */
|
||||
.login-container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
backdrop-filter: blur(15px);
|
||||
border: 1px solid rgba(255, 215, 0, 0.2);
|
||||
padding: 40px;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Playfair Display', serif;
|
||||
font-size: 2.5rem;
|
||||
color: #f1c40f; /* Or */
|
||||
margin-bottom: 30px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 3px;
|
||||
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
/* Formulaire */
|
||||
#admin-login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 0.9rem;
|
||||
color: #bdc3c7;
|
||||
margin-bottom: -10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Input password style premium */
|
||||
input[type="password"] {
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
border: 2px solid #2c3e50;
|
||||
border-radius: 10px;
|
||||
padding: 15px;
|
||||
color: #fff;
|
||||
font-size: 1.1rem;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type="password"]:focus {
|
||||
border-color: #f1c40f;
|
||||
box-shadow: 0 0 15px rgba(241, 196, 15, 0.2);
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* Bouton Login */
|
||||
button {
|
||||
background: linear-gradient(135deg, #f1c40f 0%, #d4ac0d 100%);
|
||||
color: #1a1a1a;
|
||||
border: none;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(241, 196, 15, 0.3);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(241, 196, 15, 0.4);
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Animation d'entrée */
|
||||
.login-container {
|
||||
animation: fadeInContainer 0.8s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeInContainer {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.btn-back-home {
|
||||
display: inline-block;
|
||||
margin-top: 15px;
|
||||
color: #4da6ff;
|
||||
opacity: 0.6;
|
||||
text-decoration: none;
|
||||
font-size: 0.8rem;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.btn-back-home:hover {
|
||||
opacity: 1;
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
// Fonction et variables essentiel
|
||||
|
||||
async function SqlRequest(action, params = {}) {
|
||||
@@ -96,6 +94,7 @@ loginForm.addEventListener('submit', async function(event) {
|
||||
await SqlRequest('addPlayer', {game_id: gameId, name: player.value, money: start_money});
|
||||
}
|
||||
const result = await SqlRequest('setFirstPlayer', {game_id: gameId})
|
||||
console.log(result)
|
||||
if (result.success) {
|
||||
window.location.href = 'admin-login.html?game_id=' + gameId;
|
||||
} else {
|
||||
|
||||
+45
-7
@@ -81,24 +81,26 @@ async function updateClientInterface() {
|
||||
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
|
||||
// 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();
|
||||
closeVictoryScreen();
|
||||
}
|
||||
|
||||
// --- 2. GESTION DU HASH POUR L'INTERFACE DE TABLE ---
|
||||
@@ -106,10 +108,10 @@ async function updateClientInterface() {
|
||||
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;
|
||||
@@ -118,8 +120,10 @@ async function updateClientInterface() {
|
||||
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');
|
||||
}
|
||||
@@ -127,15 +131,45 @@ async function updateClientInterface() {
|
||||
if (isLocked) {
|
||||
if (turnInfo) turnInfo.innerHTML = `<span style="color: #f1c40f; font-weight: bold;">🔒 Jeu verrouillé. En attente de l'Admin...</span>`;
|
||||
inputs.forEach(el => el.disabled = true);
|
||||
|
||||
} else if (!isMyTurn) {
|
||||
if (turnInfo && currentPlayer) {
|
||||
turnInfo.innerHTML = `Attente de <strong style="color: #e74c3c;">${currentPlayer.name}</strong>...`;
|
||||
}
|
||||
|
||||
inputs.forEach(el => el.disabled = true);
|
||||
} else {
|
||||
if (turnInfo) turnInfo.innerHTML = `<span style="color: #2ecc71; font-weight: bold;">✅ C'est à vous de jouer !</span>`;
|
||||
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) {
|
||||
@@ -414,6 +448,10 @@ async function playerFollow() {
|
||||
}
|
||||
}
|
||||
|
||||
async function playerCall() {
|
||||
changePlayer();
|
||||
}
|
||||
|
||||
async function playerAllIn() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const viewerId = Number(urlParams.get('player_id'));
|
||||
|
||||
@@ -394,8 +394,18 @@ async function declareWinner(playerId) {
|
||||
if (resStatus && resStatus.success) {
|
||||
console.log("✅ Statut passé à 'finished'");
|
||||
|
||||
// Mise à jour de l'interface Admin
|
||||
showAdminWinPanel(playerId);
|
||||
// On met a jour les valeurs dans BDD
|
||||
const result = await SqlRequest('declare_winner', {
|
||||
game_id: gameData.id,
|
||||
player_id: playerId
|
||||
});
|
||||
|
||||
if (result && result.success){
|
||||
// Mise à jour de l'interface Admin
|
||||
showAdminWinPanel(playerId);
|
||||
} else {
|
||||
console.log("Dommage tu y étais presque")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alert("Erreur lors de la mise à jour du gagnant.");
|
||||
|
||||
@@ -61,6 +61,61 @@ switch ($action) {
|
||||
$stmt->execute([$params['name'], (int)$params['game_id'], (int)$params['money']]);
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
|
||||
case 'setFirstPlayer':
|
||||
$game_id = (int)$params['game_id'];
|
||||
|
||||
// 1. Récupérer le premier joueur (id le plus petit)
|
||||
$stmt = $pdo->prepare("SELECT id FROM players WHERE game_id = ? ORDER BY id ASC LIMIT 1");
|
||||
$stmt->execute([$game_id]);
|
||||
$player = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($player) {
|
||||
$firstPlayerId = $player['id'];
|
||||
|
||||
// 2. Définir ce joueur comme dealer
|
||||
$stmt = $pdo->prepare("UPDATE players SET is_dealer = 1 WHERE id = ?");
|
||||
$stmt->execute([$firstPlayerId]);
|
||||
|
||||
// 3. IMPORTANT : Définir aussi ce joueur comme "joueur actuel" dans la table games
|
||||
// pour que le jeu sache qui doit commencer à parler
|
||||
$stmt = $pdo->prepare("UPDATE games SET current_player_id = ? WHERE id = ?");
|
||||
$stmt->execute([$firstPlayerId, $game_id]);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'player_id' => $firstPlayerId
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Aucun joueur trouvé pour cette partie.'
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
|
||||
case 'call':
|
||||
$game_id = $params['game_id'];
|
||||
$player_id = $params['player_id'];
|
||||
|
||||
// 1. Récupérer la mise actuelle de la table
|
||||
$stmt = $pdo->prepare("SELECT last_bet FROM games WHERE id = ?");
|
||||
$stmt->execute([$game_id]);
|
||||
$last_bet = $stmt->fetchColumn();
|
||||
|
||||
// 2. Mettre à jour la mise du joueur (si c'est un call, il paye, si c'est un check, last_bet est 0)
|
||||
$stmt = $pdo->prepare("UPDATE players SET current_bet = ?, money = money - ? WHERE id = ?");
|
||||
$stmt->execute([$last_bet, $last_bet, $player_id]);
|
||||
|
||||
// 3. Ajouter la mise au pot global
|
||||
$stmt = $pdo->prepare("UPDATE games SET pot = pot + ? WHERE id = ?");
|
||||
$stmt->execute([$last_bet, $game_id]);
|
||||
|
||||
// 4. Passer au joueur suivant (ta fonction habituelle)
|
||||
moveToNextPlayer($game_id, $pdo);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
|
||||
case 'next_player':
|
||||
$game_id = (int)$params['game_id'];
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
<title>Connexion Administrateur - PokerPaf</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/admin-login.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
|
||||
<meta charset='utf-8'>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Admin Login</h1>
|
||||
<form id="admin-login-form">
|
||||
<label for="adminPassword">Mot de passe administrateur :</label>
|
||||
<input type="password" id="adminPassword" name="adminPassword" required>
|
||||
<br><br>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<div class="login-container">
|
||||
<a href="index.html" class="btn-back-home">◀️ Retourner à l'accueil</a>
|
||||
<h1>Admin Login</h1>
|
||||
<form id="admin-login-form">
|
||||
<label for="adminPassword">Mot de passe administrateur :</label>
|
||||
<input type="password" id="adminPassword" name="adminPassword" required="" placeholder="••••••••">
|
||||
<button type="submit">Accéder au Panneau</button>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
const hashedAdminPassword = "7215d31f702fe2faf2a7df114c6427007bd254740c6b9cbaa2a5505060088929";
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@
|
||||
<p class="turn-info">Au tour de : <strong id="active-player-name"></strong></p>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-fold" onclick="playerFold()">Se coucher</button>
|
||||
<button class="btn btn-call" onclick="playerFollow()">Suivre</button>
|
||||
<button class="btn btn-fold" id="btn-fold" onclick="playerFold()">Se coucher</button>
|
||||
<button class="btn btn-call" id="btn-call" onclick="playerFollow()">Suivre</button>
|
||||
<div class="raise-group">
|
||||
<input type="number" id="raise-amount" placeholder="Mise" min="0">
|
||||
<button class="btn-validate" onclick="playerRaise()">OK</button>
|
||||
|
||||
+18
-8
@@ -7,20 +7,20 @@ $host = 'localhost'; $db = 'poker_paf'; $user = 'root'; $pass = '';
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass);
|
||||
|
||||
$game_id = $_GET['game_id'] ?? 0;
|
||||
// On stocke l'état précédent pour ne pas envoyer de doublons
|
||||
$last_state_hash = "";
|
||||
|
||||
while (true) {
|
||||
// On récupère l'état global de la partie et des joueurs
|
||||
// 1. Récupérer les données de la partie
|
||||
$stmt = $pdo->prepare("SELECT g.*, (SELECT COUNT(*) FROM players WHERE game_id = g.id AND is_folded=0) as active_count FROM games g WHERE g.id = ?");
|
||||
$stmt->execute([$game_id]);
|
||||
$game = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// 2. Récupérer les données des joueurs
|
||||
$stmt = $pdo->prepare("SELECT * FROM players WHERE game_id = ?");
|
||||
$stmt->execute([$game_id]);
|
||||
$players = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$full_state = ['game' => $game, 'players' => $players];
|
||||
// 3. Typage propre AVANT de mettre dans le full_state
|
||||
foreach ($players as &$player) {
|
||||
$player['id'] = (int)$player['id'];
|
||||
$player['money'] = (int)$player['money'];
|
||||
@@ -28,16 +28,26 @@ while (true) {
|
||||
$player['is_dealer'] = (int)$player['is_dealer'];
|
||||
$player['is_folded'] = (int)$player['is_folded'];
|
||||
}
|
||||
unset($player); // Nettoyage de la référence
|
||||
unset($player);
|
||||
|
||||
// 4. Construction de l'objet final
|
||||
$full_state = [
|
||||
'game' => $game,
|
||||
'players' => $players
|
||||
];
|
||||
|
||||
// 5. Calcul du hash sur l'objet finalisé
|
||||
$current_hash = md5(json_encode($full_state));
|
||||
|
||||
// Si le hash a changé, c'est qu'une action a eu lieu (mise, tour suivant, fold...)
|
||||
if ($current_hash !== $last_state_hash) {
|
||||
echo "data: " . json_encode($full_state) . "\n\n";
|
||||
$last_state_hash = $current_hash;
|
||||
|
||||
// On force l'envoi
|
||||
ob_flush();
|
||||
flush();
|
||||
}
|
||||
|
||||
ob_flush();
|
||||
flush();
|
||||
sleep(0.01); // On vérifie toutes les secondes
|
||||
// 6. Pause raisonnable (500ms) pour ne pas tuer le CPU/Base de données
|
||||
sleep(0.01);
|
||||
}
|
||||
Reference in New Issue
Block a user