false, 'error' => 'Missing data']); break; } $stmt = $pdo->prepare("INSERT INTO players (nickname, session_id, last_seen) VALUES (?, ?, NOW()) ON DUPLICATE KEY UPDATE nickname = ?, last_seen = NOW()"); $stmt->execute([$nickname, $session_id, $nickname]); echo json_encode(['success' => true]); break; case 'heartbeat': $session_id = $input['player_id'] ?? ''; if ($session_id) { $stmt = $pdo->prepare("UPDATE players SET last_seen = NOW() WHERE session_id = ?"); $stmt->execute([$session_id]); } echo json_encode(['success' => true]); break; case 'get_online': $session_id = $_GET['player_id'] ?? ''; $stmt = $pdo->prepare("SELECT id, nickname, session_id FROM players WHERE last_seen > DATE_SUB(NOW(), INTERVAL 30 SECOND) AND session_id != ? LIMIT 20"); $stmt->execute([$session_id]); $players = $stmt->fetchAll(); echo json_encode(['success' => true, 'players' => $players]); break; case 'invite': $from_session = $input['from_player_id'] ?? ''; $to_session = $input['to_player_id'] ?? ''; $room_code = strtoupper(substr(md5(uniqid()), 0, 6)); $stmt = $pdo->prepare("SELECT id FROM players WHERE session_id = ?"); $stmt->execute([$from_session]); $from = $stmt->fetch(); $stmt = $pdo->prepare("SELECT id FROM players WHERE session_id = ?"); $stmt->execute([$to_session]); $to = $stmt->fetch(); if ($from && $to) { $stmt = $pdo->prepare("INSERT INTO invitations (from_player_id, to_player_id, room_code) VALUES (?, ?, ?)"); $stmt->execute([$from['id'], $to['id'], $room_code]); // Pre-create the room $stmt = $pdo->prepare("INSERT INTO rooms (room_code, player1_id, status) VALUES (?, ?, 'waiting')"); $stmt->execute([$room_code, $from_session]); echo json_encode(['success' => true, 'room_code' => $room_code]); } else { echo json_encode(['success' => false, 'error' => 'Player not found']); } break; case 'check_invites': $session_id = $_GET['player_id'] ?? ''; $stmt = $pdo->prepare(" SELECT i.id, p.nickname as from_nickname, i.room_code FROM invitations i JOIN players p ON i.from_player_id = p.id JOIN players target ON i.to_player_id = target.id WHERE target.session_id = ? AND i.status = 'pending' AND i.created_at > DATE_SUB(NOW(), INTERVAL 1 MINUTE) "); $stmt->execute([$session_id]); $invites = $stmt->fetchAll(); echo json_encode(['success' => true, 'invites' => $invites]); break; case 'respond_invite': $invite_id = $input['invite_id'] ?? 0; $status = $input['status'] ?? 'rejected'; $stmt = $pdo->prepare("UPDATE invitations SET status = ? WHERE id = ?"); $stmt->execute([$status, $invite_id]); echo json_encode(['success' => true]); break; case 'create': $player_id = $input['player_id'] ?? ''; $room_code = $input['room_code'] ?? strtoupper(substr(md5(uniqid()), 0, 6)); $stmt = $pdo->prepare("INSERT INTO rooms (room_code, player1_id, status) VALUES (?, ?, 'waiting') ON DUPLICATE KEY UPDATE player1_id = VALUES(player1_id)"); $stmt->execute([$room_code, $player_id]); $room_id = $pdo->lastInsertId(); if (!$room_id) { $stmt = $pdo->prepare("SELECT id FROM rooms WHERE room_code = ?"); $stmt->execute([$room_code]); $room_id = $stmt->fetchColumn(); } echo json_encode(['success' => true, 'room_code' => $room_code, 'room_id' => $room_id]); break; case 'join': $player_id = $input['player_id'] ?? ''; $room_code = strtoupper($input['room_code'] ?? ''); $stmt = $pdo->prepare("SELECT id, player1_id, player2_id FROM rooms WHERE room_code = ? AND (status = 'waiting' OR status = 'playing')"); $stmt->execute([$room_code]); $room = $stmt->fetch(); if ($room) { if ($room['player1_id'] === $player_id) { echo json_encode(['success' => true, 'room_id' => $room['id']]); } else { $stmt = $pdo->prepare("UPDATE rooms SET player2_id = ?, status = 'playing' WHERE id = ?"); $stmt->execute([$player_id, $room['id']]); echo json_encode(['success' => true, 'room_id' => $room['id']]); } } else { echo json_encode(['success' => false, 'error' => 'Room not found or full']); } break; case 'update': $room_id = $input['room_id'] ?? 0; $player_id = $input['player_id'] ?? ''; $board = json_encode($input['board'] ?? []); $score = $input['score'] ?? 0; $is_game_over = $input['is_game_over'] ? 1 : 0; $stmt = $pdo->prepare("INSERT INTO game_states (room_id, player_id, board, score, is_game_over) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE board = VALUES(board), score = VALUES(score), is_game_over = VALUES(is_game_over)"); $stmt->execute([$room_id, $player_id, $board, $score, $is_game_over]); echo json_encode(['success' => true]); break; case 'poll': $room_id = $_GET['room_id'] ?? 0; $player_id = $_GET['player_id'] ?? ''; $stmt = $pdo->prepare("SELECT player_id, board, score, is_game_over FROM game_states WHERE room_id = ? AND player_id != ?"); $stmt->execute([$room_id, $player_id]); $opponent = $stmt->fetch(); $stmt = $pdo->prepare("SELECT pending_debuffs FROM game_states WHERE room_id = ? AND player_id = ?"); $stmt->execute([$room_id, $player_id]); $self = $stmt->fetch(); $debuffs = []; if ($self && $self['pending_debuffs']) { $debuffs = explode(',', $self['pending_debuffs']); $stmt = $pdo->prepare("UPDATE game_states SET pending_debuffs = NULL WHERE room_id = ? AND player_id = ?"); $stmt->execute([$room_id, $player_id]); } $stmt = $pdo->prepare("SELECT status FROM rooms WHERE id = ?"); $stmt->execute([$room_id]); $room = $stmt->fetch(); echo json_encode([ 'success' => true, 'opponent' => $opponent ? [ 'board' => json_decode($opponent['board']), 'score' => $opponent['score'], 'is_game_over' => (bool)$opponent['is_game_over'] ] : null, 'status' => $room['status'] ?? 'unknown', 'debuffs' => $debuffs ]); break; case 'send_debuff': $room_id = $input['room_id'] ?? 0; $player_id = $input['player_id'] ?? ''; $debuff = $input['debuff'] ?? ''; $stmt = $pdo->prepare("SELECT player_id FROM game_states WHERE room_id = ? AND player_id != ?"); $stmt->execute([$room_id, $player_id]); $opponent = $stmt->fetch(); if ($opponent) { $stmt = $pdo->prepare("UPDATE game_states SET pending_debuffs = IF(pending_debuffs IS NULL, ?, CONCAT(pending_debuffs, ',', ?)) WHERE room_id = ? AND player_id = ?"); $stmt->execute([$debuff, $debuff, $room_id, $opponent['player_id']]); echo json_encode(['success' => true]); } else { echo json_encode(['success' => false, 'error' => 'Opponent not found']); } break; default: echo json_encode(['success' => false, 'error' => 'Invalid action']); } } catch (Exception $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); }