diff --git a/public/game.js b/public/game.js index 87b2a1a..7d35e48 100644 --- a/public/game.js +++ b/public/game.js @@ -10,6 +10,8 @@ let gameState = null; let cardDb = {}; let yourIndex = -1; + let forgePreviewRequestId = 0; + let forgePreviewPendingIds = null; let attackMode = { active: false, attackerPlayer: -1, attackerBoard: -1 }; let spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' }; let heroAbilityMode = { active: false }; @@ -179,6 +181,39 @@ if (data.warn && typeof window.Sounds !== 'undefined') window.Sounds.timerWarning(); if (data.ended && typeof window.Sounds !== 'undefined') window.Sounds.timerEnd(); }); + socket.on('forgePreviewResult', (data) => { + if (!data) return; + if (data.requestId != null && data.requestId !== forgePreviewRequestId) return; + const preview = $('forge-preview'); + const wrap = $('forge-preview-card-wrap'); + const confirmBtn = $('btn-forge-confirm'); + if (!preview) return; + if (data.error || !data.resultCardId) { + preview.classList.add('hidden'); + if (wrap) wrap.innerHTML = ''; + if (confirmBtn) confirmBtn.disabled = true; + forgePreviewPendingIds = null; + return; + } + const meta = (gameState?.cardDb || cardDb)[data.resultCardId]; + if (!meta) { + preview.classList.add('hidden'); + forgePreviewPendingIds = null; + return; + } + const you = gameState?.players?.[gameState?.yourIndex]; + const canCraft = you && (you.mana || 0) >= 2; + if (wrap) { + const art = typeof getCardArt === 'function' ? getCardArt(meta) : ''; + wrap.innerHTML = '
' + + '
' + art + '
' + + '
' + escapeHtml(meta.name || '') + '
' + + '
' + (meta.attack || 0) + '' + (meta.health || 0) + '
'; + } + if (confirmBtn) confirmBtn.disabled = !canCraft; + preview.classList.remove('hidden'); + }); + socket.on('chatMessage', (data) => { const chatMessagesEl = $('chat-messages'); if (chatMessagesEl && data) { @@ -399,7 +434,7 @@ document.body.appendChild(damageEl); setTimeout(() => { damageEl.style.animation = 'damageFloat 1.5s ease-out forwards'; - setTimeout(() => damageEl.remove(), 1000); // Сократил с 1500 до 1000 мс + setTimeout(() => damageEl.remove(), 1000); }, 10); } @@ -1658,9 +1693,8 @@ sidebar.classList.remove('hidden'); forgeSelected = []; // Сбрасываем выбор при открытии renderForgeHand(state); - renderForgeDeck(state); renderForgeSelected(); - updateForgeCraftButton(); + updateForgePreview(); } }; } else if (forgeBtn) { @@ -1841,9 +1875,8 @@ // Обновляем кузницу, если она открыта if (isForgeOpen) { renderForgeHand(state); - renderForgeDeck(state); renderForgeSelected(); - updateForgeCraftButton(); + updateForgePreview(); } } @@ -2162,18 +2195,20 @@ if (sidebar) { sidebar.classList.add('hidden'); forgeSelected = []; + forgePreviewPendingIds = null; + const preview = $('forge-preview'); + if (preview) preview.classList.add('hidden'); renderForgeSelected(); + updateForgePreview(); } }); $('btn-forge-clear')?.addEventListener('click', () => { forgeSelected = []; + forgePreviewPendingIds = null; renderForgeSelected(); - updateForgeCraftButton(); - if (gameState) { - renderForgeHand(gameState); - renderForgeDeck(gameState); - } + updateForgePreview(); + if (gameState) renderForgeHand(gameState); }); $('btn-steal-close')?.addEventListener('click', () => { @@ -2338,7 +2373,7 @@ } if (forgeSelected.length === 0) { - selectedEl.innerHTML = '
Кликните на карты чтобы выбрать
'; + selectedEl.innerHTML = '
Кликните на карты из руки
'; } else { selectedEl.innerHTML = forgeSelected.map((cardId, idx) => { const meta = cardDb[cardId]; @@ -2365,19 +2400,30 @@ } } - function updateForgeCraftButton() { - const craftBtn = $('btn-forge-craft'); - const you = gameState?.players?.[gameState?.yourIndex]; - if (craftBtn && you) { - const canCraft = forgeSelected.length >= 2 && forgeSelected.length <= 3 && (you.mana || 0) >= 2; - craftBtn.disabled = !canCraft; + function updateForgePreview() { + const preview = $('forge-preview'); + const wrap = $('forge-preview-card-wrap'); + const confirmBtn = $('btn-forge-confirm'); + if (!preview) return; + if (forgeSelected.length < 2 || forgeSelected.length > 3) { + preview.classList.add('hidden'); + if (wrap) wrap.innerHTML = ''; + if (confirmBtn) confirmBtn.disabled = true; + forgePreviewPendingIds = null; + return; } + forgePreviewRequestId = Date.now(); + forgePreviewPendingIds = [...forgeSelected]; + if (wrap) wrap.innerHTML = '

Загрузка…

'; + if (confirmBtn) confirmBtn.disabled = true; + preview.classList.remove('hidden'); + socket.emit('forgePreview', { cardIds: forgePreviewPendingIds, requestId: forgePreviewRequestId }); } - + function addCardToForge(cardId, source) { if (!cardId) return; + if (source !== 'hand') return; // только из руки if (forgeSelected.includes(cardId)) { - // Если карта уже выбрана, убираем её removeCardFromForge(cardId); return; } @@ -2396,26 +2442,17 @@ forgeSelected.push(cardId); renderForgeSelected(); - updateForgeCraftButton(); - - // Обновляем отображение в источниках - if (gameState) { - renderForgeHand(gameState); - renderForgeDeck(gameState); - } + updateForgePreview(); + if (gameState) renderForgeHand(gameState); } - + function removeCardFromForge(cardId) { const idx = forgeSelected.indexOf(cardId); if (idx >= 0) { forgeSelected.splice(idx, 1); renderForgeSelected(); - updateForgeCraftButton(); - // Обновляем отображение в источниках - if (gameState) { - renderForgeHand(gameState); - renderForgeDeck(gameState); - } + updateForgePreview(); + if (gameState) renderForgeHand(gameState); } } @@ -2472,76 +2509,35 @@ }); } - function renderForgeDeck(state) { - const deck = state.yourDeck || []; - const deckList = $('forge-deck-list'); - if (!deckList) return; - - if (!deck || deck.length === 0) { - deckList.innerHTML = '
Колода пуста
'; - return; - } - - // Фильтруем только миньонов - const minionCards = deck.filter(cardId => { - const meta = cardDb[cardId]; - return meta && meta.type === 'minion'; - }); - - if (minionCards.length === 0) { - deckList.innerHTML = '
Нет миньонов в колоде
'; - return; - } - - deckList.innerHTML = minionCards.map((cardId) => { - const meta = cardDb[cardId]; - if (!meta) return ''; - const isSelected = forgeSelected.includes(cardId); - return `
-
-
${getCardArt(meta)}
-
-
${escapeHtml(meta.name)}
-
- ${meta.attack || 0} - ${meta.health || 0} -
-
-
-
`; - }).filter(Boolean).join(''); - - // Обработчики клика для карт из колоды - $all('#forge-deck-list .card-wrap').forEach(card => { - card.onclick = function(e) { - e.stopPropagation(); - const cardId = card.dataset.cardId; - if (cardId) { - addCardToForge(cardId, 'deck'); - } - }; - }); - } - - // Обновляем drag-and-drop при каждом обновлении руки, если кузница открыта - // Это делается в bindGameEvents - - // Обработчик создания улучшенной карты - const craftBtn = $('btn-forge-craft'); - if (craftBtn) { - craftBtn.onclick = function() { - if (craftBtn.disabled) return; + const confirmBtn = $('btn-forge-confirm'); + if (confirmBtn) { + confirmBtn.onclick = function() { + if (confirmBtn.disabled || !forgePreviewPendingIds || forgePreviewPendingIds.length < 2) return; const you = gameState?.players?.[gameState?.yourIndex]; - if (!you || forgeSelected.length < 2 || forgeSelected.length > 3 || (you.mana || 0) < 2) return; - - socket.emit('forgeCard', { cardIds: forgeSelected }); + if (!you || (you.mana || 0) < 2) return; + socket.emit('forgeCard', { cardIds: forgePreviewPendingIds }); + if (typeof window.Sounds !== 'undefined' && window.Sounds.forge) window.Sounds.forge(); forgeSelected = []; + forgePreviewPendingIds = null; + const preview = $('forge-preview'); + if (preview) preview.classList.add('hidden'); renderForgeSelected(); - updateForgeCraftButton(); + updateForgePreview(); + if (gameState) renderForgeHand(gameState); const sidebar = $('forge-sidebar'); - if (sidebar) { - sidebar.classList.add('hidden'); - } + if (sidebar) sidebar.classList.add('hidden'); + }; + } + const cancelPreviewBtn = $('btn-forge-cancel-preview'); + if (cancelPreviewBtn) { + cancelPreviewBtn.onclick = function() { + const preview = $('forge-preview'); + if (preview) preview.classList.add('hidden'); + forgePreviewPendingIds = null; + const wrap = $('forge-preview-card-wrap'); + if (wrap) wrap.innerHTML = ''; + const cb = $('btn-forge-confirm'); + if (cb) cb.disabled = true; }; } diff --git a/public/index.html b/public/index.html index 660f480..8f0d1ed 100644 --- a/public/index.html +++ b/public/index.html @@ -271,10 +271,11 @@
-
+

📋 Из руки

+

Только миньоны из руки. Выберите 2–3 карты.

@@ -282,21 +283,22 @@

✨ Выбрано (0/3)

-
Кликните на карты чтобы выбрать
+
Кликните на карты из руки
- - -
-

📚 Из колоды

-
-
+
-