🎮 Fix question selection, add score editing, media host-only playback

- Fix: select questions by questionIndex instead of points (fixes same-points categories)
- Fix: persist questionIndex in MongoDB schema for game state recovery
- Fix: update scores in UI on wrong answer
- Add: host can manually adjust team scores
- Add: audio/video plays only on host device
- Add: replay button for host after media ends
- Fix: answer media modal shown only to host
This commit is contained in:
Cosmo
2026-03-22 10:21:51 +00:00
parent c5e1344610
commit ddad7f2126
9 changed files with 166 additions and 50 deletions

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -332,9 +332,10 @@
"questions": [
{
"points": 100,
"type": "text",
"question": "",
"answer": ""
"type": "image",
"question": "/images/professii_1.jpg",
"questionText": "Что зашифровано в этой картинке?",
"answer": "Третий закон Ньютона"
},
{
"points": 200,

View File

@@ -30,7 +30,8 @@ const gameSchema = new mongoose.Schema({
},
usedQuestions: [{
category: String,
points: Number
points: Number,
questionIndex: Number
}],
status: {
type: String,

View File

@@ -202,7 +202,7 @@ export const setupSocketHandlers = (io, activeGames) => {
});
// Выбор вопроса
socket.on('select-question', ({ gameCode, category, points }) => {
socket.on('select-question', ({ gameCode, category, points, questionIndex: requestedIndex }) => {
const game = activeGames.get(gameCode);
if (!game) return;
@@ -210,20 +210,21 @@ export const setupSocketHandlers = (io, activeGames) => {
// Находим категорию
const categoryData = game.selectedCategories.find(cat => cat.name === category);
// Подсчитываем, сколько вопросов с такими баллами уже использовано в этой категории
const usedCount = game.usedQuestions.filter(
q => q.category === category && q.points === points
).length;
// Используем переданный индекс вопроса напрямую
const questionIndex = requestedIndex;
// Находим следующий неиспользованный вопрос с такими баллами (по порядку)
const questionsWithPoints = categoryData?.questions
.map((q, idx) => ({ ...q, originalIndex: idx }))
.filter(q => q.points === points);
// Проверяем, не использован ли уже этот вопрос
const alreadyUsed = game.usedQuestions.some(
q => q.category === category && q.questionIndex === questionIndex
);
const questionIndex = questionsWithPoints[usedCount]?.originalIndex;
if (alreadyUsed) {
console.log('❌ Question already used:', { category, questionIndex });
socket.emit('error', { message: 'Этот вопрос уже был использован' });
return;
}
console.log(`📊 Select question: category="${category}", points=${points}, usedCount=${usedCount}, questionIndex=${questionIndex}`);
console.log(`📊 Questions with these points:`, questionsWithPoints.map(q => q.originalIndex));
console.log(`📊 Select question: category="${category}", points=${points}, questionIndex=${questionIndex}`);
if (questionIndex === undefined) {
console.log('❌ No available question found');
@@ -730,6 +731,27 @@ export const setupSocketHandlers = (io, activeGames) => {
});
// Отключение
// Manual score adjustment by host
socket.on('adjust-score', async ({ gameCode, teamId, amount }) => {
const game = activeGames.get(gameCode);
if (!game || socket.id !== game.hostId) return;
const team = game.teams.find(t => t.id === teamId);
if (!team) return;
team.score += amount;
console.log(`Score adjusted: ${team.name} ${amount > 0 ? '+' : ''}${amount} = ${team.score}`);
try {
await Game.findOneAndUpdate({ gameCode }, { teams: game.teams });
} catch (error) {
console.log('Error updating DB:', error.message);
}
io.to(gameCode).emit('score-updated', { teams: game.teams });
});
socket.on('disconnect', () => {
console.log('👤 Client disconnected:', socket.id);