some hotfixes

This commit is contained in:
2026-03-21 01:43:46 +01:00
parent edc065ca0c
commit 101820581e
9 changed files with 286 additions and 28 deletions
+7
View File
@@ -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;
+136
View File
@@ -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 -2
View File
@@ -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
View File
@@ -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'));
+12 -2
View File
@@ -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.");
+55
View File
@@ -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'];
+10 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}