v16 — игры дают звёзды в рейтинг (викторина, крестики-нолики, реакция, угадай число)

This commit is contained in:
Dauren777 2026-06-01 11:17:23 +00:00
parent 6e31752125
commit b67252633a

View File

@ -589,7 +589,12 @@ function ticMove(i){
const lines = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];
for(const [a,b,c] of lines){
if(gameState.board[a]&&gameState.board[a]===gameState.board[b]&&gameState.board[a]===gameState.board[c]){
gameState.over = true; gameState.winner = gameState.board[a]; break;
gameState.over = true; gameState.winner = gameState.board[a];
// Award star for winning
const users = LS('users') || [];
const uidx = users.findIndex(u => u.id === uid());
if (uidx >= 0 && !gameState.starGiven) { users[uidx].stars = (users[uidx].stars || 0) + 1; users[uidx].gamesWon = (users[uidx].gamesWon || 0) + 1; SS('users', users); currentUser = users[uidx]; gameState.starGiven = true; }
break;
}
}
if(!gameState.over && gameState.board.every(c=>c)){ gameState.over = true; gameState.winner = 'draw'; }
@ -606,7 +611,7 @@ function renderGuessNumber(){
let h = `<div class="card" style="text-align:center"><h3>&#x1F522; Угадай число (1-100)</h3>
<p class="muted">Осталось попыток: <strong>${g.max - g.attempts}</strong></p>`;
if(g.won){
h += `<p style="color:var(--green);font-size:20px;font-weight:800">&#x1F389; Угадал! Это ${g.number}!</p><p class="muted">За ${g.attempts} попыток</p>`;
h += `<p style="color:var(--green);font-size:20px;font-weight:800">&#x1F389; Угадал! Это ${g.number}!</p><p class="muted">За ${g.attempts} попыток</p>${g.attempts<=5?'<p style=\'color:var(--cyan);font-weight:700\'>+2 &#x2B50; в рейтинг!</p>':''}`;
h += '<button class="btn small outline" onclick="startGuessNumber()">Играть ещё</button>';
} else if(g.attempts >= g.max){
h += `<p style="color:var(--red);font-size:18px;font-weight:800">Не угадал! Это было ${g.number}</p>`;
@ -622,7 +627,13 @@ function doGuess(){
const n = +document.getElementById('guessInput').value;
if(!n||n<1||n>100)return;
gameState.attempts++;
if(n === gameState.number){ gameState.won = true; renderGuessNumber(); return }
if(n === gameState.number){ gameState.won = true;
if(gameState.attempts <= 5) {
const users = LS('users') || [];
const idx = users.findIndex(u => u.id === uid());
if(idx >= 0) { users[idx].stars = (users[idx].stars || 0) + 2; SS('users', users); currentUser = users[idx]; }
}
renderGuessNumber(); return }
const hint = n < gameState.number ? '&#x1F4C8; Больше!' : '&#x1F4C9; Меньше!';
const tempDiv = document.createElement('div'); tempDiv.innerHTML = `<div class="card" style="text-align:center;padding:12px;margin-bottom:8px"><p>${n} &mdash; ${hint}</p></div>`;
document.getElementById('gameArea').insertBefore(tempDiv, document.getElementById('gameArea').firstChild);
@ -640,7 +651,7 @@ function renderReaction(){
if(g.state === 'waiting'){ bg = '#FF6B6B'; txt = '&#x1F534; Жди зелёный!'; }
else if(g.state === 'ready'){ bg = '#4CAF50'; txt = '&#x1F7E2; ЖМИ СЕЙЧАС!'; }
else if(g.state === 'early'){ bg = '#FFD700'; txt = '&#x26A0; Слишком рано! Жми "Начать"'; }
else if(g.state === 'done'){ txt = `&#x23F1; Твоё время: <strong>${g.reaction} мс</strong><br>Рекорд: ${g.best !== 9999 ? g.best+' мс' : '—'}`; }
else if(g.state === 'done'){ txt = `&#x23F1; Твоё время: <strong>${g.reaction} мс</strong>${g.reactStar?'<br><span style=\'color:var(--cyan);font-weight:700\'>+1 &#x2B50; быстрее 300 мс!</span>':''}<br>Рекорд: ${g.best !== 9999 ? g.best+' мс' : '—'}`; }
let h = `<div class="card" style="text-align:center">
<h3>&#x26A1; Реакция</h3>
<div style="width:200px;height:200px;border-radius:50%;background:${bg};display:flex;align-items:center;justify-content:center;margin:16px auto;cursor:${g.state==='ready'?'pointer':'default'};font-size:18px;font-weight:800;transition:background .1s" onclick="reactClick()">${txt||'&#x1F3AF; Нажми "Начать"'}</div>`;
@ -665,6 +676,11 @@ function reactClick(){
if(!gameState)return;
if(gameState.state === 'waiting'){ gameState.state = 'early'; renderReaction(); return; }
if(gameState.state === 'ready'){ gameState.reaction = Date.now() - gameState.startTime; gameState.state = 'done';
if(gameState.reaction < 300) {
const users = LS('users') || [];
const idx = users.findIndex(u => u.id === uid());
if(idx >= 0) { users[idx].stars = (users[idx].stars || 0) + 1; SS('users', users); currentUser = users[idx]; gameState.reactStar = true; }
}
if(gameState.reaction < gameState.best){ gameState.best = gameState.reaction; setMy('reactionBest', gameState.reaction); }
renderReaction(); }
}
@ -686,9 +702,17 @@ function startQuiz(){
function renderQuiz(){
const g = gameState;
if(g.current >= g.questions.length){
document.getElementById('gameArea').innerHTML = `<div class="card" style="text-align:center"><h3>&#x1F3C6; Викторина завершена!</h3><p style="font-size:24px;font-weight:800;color:var(--cyan)">${g.score} / ${g.questions.length}</p><p class="muted">${g.score>=6?'&#x1F451; Ты знаток спорта!':g.score>=4?'&#x1F44D; Неплохо!':'&#x1F4DA; Учи матчасть!'}</p><button class="btn" onclick="startQuiz()">Ещё раз</button></div>`;
// Award stars for quiz
const earned = g.score >= 7 ? 5 : g.score >= 5 ? 3 : g.score >= 3 ? 1 : 0;
if (earned > 0) {
const users = LS('users') || [];
const idx = users.findIndex(u => u.id === uid());
if (idx >= 0) { users[idx].stars = (users[idx].stars || 0) + earned; users[idx].quizScore = g.score; SS('users', users); currentUser = users[idx]; }
}
document.getElementById('gameArea').innerHTML = `<div class="card" style="text-align:center"><h3>&#x1F3C6; Викторина завершена!</h3><p style="font-size:24px;font-weight:800;color:var(--cyan)">${g.score} / ${g.questions.length}</p>${earned>0?`<p style='color:var(--cyan);font-weight:700'>+${earned} &#x2B50; в рейтинг!</p>`:''}<p class="muted">${g.score>=6?'&#x1F451; Ты знаток спорта!':g.score>=4?'&#x1F44D; Неплохо!':'&#x1F4DA; Учи матчасть!'}</p><button class="btn" onclick="startQuiz()">Ещё раз</button></div>`;
return;
}
if(g.current >= g.questions.length) return;
const q = g.questions[g.current];
let h = `<div class="card"><h3>&#x2753; Вопрос ${g.current+1}/${g.questions.length}</h3><p style="font-size:17px;font-weight:600;margin:12px 0">${q.q}</p>`;
q.a.forEach((ans,i)=>{
@ -796,7 +820,7 @@ function renderRanking(){
const users=LS('users')||[];
const sorted=[...users].filter(u=>u.stars>0).sort((a,b)=>b.stars-a.stars).slice(0,5);
if(!sorted.length){el.innerHTML='<p class="muted">Пока никто не проголосовал</p>';return}
el.innerHTML=sorted.map((u,i)=>`<div style="display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid #2a3342"><span style="color:${i===0?'#FFD700':i===1?'#C0C0C0':i===2?'#CD7F32':'var(--gray-500)'}">${i+1}.</span><span>${u.name}</span><span style="margin-left:auto;color:var(--cyan);font-size:13px">&#x2B50; ${u.stars}</span></div>`).join('');
el.innerHTML=sorted.map((u,i)=>`<div style="display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid #2a3342"><span style="color:${i===0?'#FFD700':i===1?'#C0C0C0':i===2?'#CD7F32':'var(--gray-500)'}">${i+1}.</span><span>${u.name}</span><span style="margin-left:auto;color:var(--cyan);font-size:13px">&#x2B50; ${u.stars||0}${u.quizScore?` | &#x1F3C6; ${u.quizScore}/8`:''}${u.gamesWon?` | &#x1F3AE; ${u.gamesWon}`:''}</span></div>`).join('');
}
function voteRandom(){
const users=LS('users')||[];