From fcb77e936800b9ada1f83f625ce0e72b4b386ccd Mon Sep 17 00:00:00 2001 From: Bonchellon Date: Mon, 26 Jan 2026 16:19:58 +0300 Subject: [PATCH] 123 --- public/game.js | 286 ++++++++++++++++++++++++++++++++++++++++------ public/index.html | 21 ++-- public/styles.css | 201 ++++++++++++++++++++++++++------ 3 files changed, 434 insertions(+), 74 deletions(-) diff --git a/public/game.js b/public/game.js index 2e30b1d..36deab0 100644 --- a/public/game.js +++ b/public/game.js @@ -883,6 +883,8 @@ function bindGameEvents(state) { const you = state.players[state.yourIndex]; const isYourTurn = state.currentPlayerIndex === state.yourIndex; + const sidebar = $('forge-sidebar'); + const isForgeOpen = sidebar && !sidebar.classList.contains('hidden'); $all('.card-wrap.in-hand').forEach((wrap) => { wrap.classList.toggle('disabled', !isYourTurn); @@ -891,7 +893,18 @@ const isMinion = meta && meta.type === 'minion'; const canPlay = isYourTurn && !attackMode.active && !heroAbilityMode.active && meta && you.mana >= (meta.cost || 0); - if (isMinion && canPlay && (you.board?.length ?? 0) < 7) { + // Если кузница открыта и карта - миньон, делаем её перетаскиваемой для кузницы + if (isForgeOpen && isMinion) { + wrap.draggable = true; + wrap.ondragstart = function (e) { + e.dataTransfer.setData('text/plain', 'hand:' + handIndex); + e.dataTransfer.setData('source', 'hand'); + wrap.classList.add('dragging'); + }; + wrap.ondragend = function () { + wrap.classList.remove('dragging'); + }; + } else if (isMinion && canPlay && (you.board?.length ?? 0) < 7) { wrap.draggable = true; wrap.ondragstart = function (e) { if (!canPlay) return; @@ -1420,8 +1433,12 @@ forgeBtn.disabled = false; forgeBtn.onclick = function () { if (attackMode.active || spellMode.active || heroAbilityMode.active) return; - $('forge-overlay')?.classList.remove('hidden'); - renderForgeDeck(state); + const sidebar = $('forge-sidebar'); + if (sidebar) { + sidebar.classList.remove('hidden'); + renderForgeDeck(state); + setupForgeDragAndDrop(state); + } }; } else if (forgeBtn) { forgeBtn.disabled = true; @@ -1597,6 +1614,12 @@ yourBoardEl.ondragleave = null; yourBoardEl.ondrop = null; } + + // Настраиваем drag-and-drop для кузницы, если она открыта + const sidebar = $('forge-sidebar'); + if (sidebar && !sidebar.classList.contains('hidden')) { + setTimeout(() => setupForgeDragAndDrop(state), 100); + } } function initLobby() { @@ -1864,12 +1887,15 @@ }); $('btn-forge-close')?.addEventListener('click', () => { - $('forge-overlay')?.classList.add('hidden'); - }); - - $('forge-overlay')?.addEventListener('click', (e) => { - if (e.target.id === 'forge-overlay') { - $('forge-overlay')?.classList.add('hidden'); + const sidebar = $('forge-sidebar'); + if (sidebar) { + sidebar.classList.add('hidden'); + forgeSelected = []; + renderForgeSelected(); + // Обновляем отображение руки и колоды + if (gameState) { + renderHand(gameState); + } } }); @@ -2024,22 +2050,207 @@ } let forgeSelected = []; + + function renderForgeSelected() { + const selectedEl = $('forge-selected'); + if (!selectedEl) return; + + if (forgeSelected.length === 0) { + selectedEl.innerHTML = '
Перетащите карты сюда
'; + selectedEl.classList.remove('drag-over'); + } else { + selectedEl.innerHTML = forgeSelected.map((cardId, idx) => { + const meta = cardDb[cardId]; + if (!meta) return ''; + return `
+
+
${getCardArt(meta)}
+
+
${escapeHtml(meta.name)}
+ ${meta.type === 'minion' ? `
${meta.attack || 0}${meta.health || 0}
` : ''} +
+
+
`; + }).filter(Boolean).join(''); + + // Добавляем обработчики удаления + $all('.forge-selected-card').forEach(card => { + card.onclick = function(e) { + e.stopPropagation(); + const cardId = card.dataset.cardId; + const idx = forgeSelected.indexOf(cardId); + if (idx >= 0) { + forgeSelected.splice(idx, 1); + renderForgeSelected(); + updateForgeCraftButton(); + // Обновляем отображение в источнике + if (gameState) { + renderForgeDeck(gameState); + renderHand(gameState); + } + } + }; + }); + } + } + + function updateForgeCraftButton() { + const craftBtn = $('btn-forge-craft'); + const you = gameState?.players?.[gameState?.yourIndex]; + if (craftBtn && you) { + craftBtn.disabled = forgeSelected.length < 2 || forgeSelected.length > 3 || (you.mana || 0) < 2; + } + } + + function addCardToForge(cardId, source) { + if (forgeSelected.includes(cardId)) return; // Уже добавлена + if (forgeSelected.length >= 3) return; // Максимум 3 карты + + const meta = cardDb[cardId]; + if (!meta || meta.type !== 'minion') return; // Только миньоны + + forgeSelected.push(cardId); + renderForgeSelected(); + updateForgeCraftButton(); + + // Обновляем отображение в источнике (рука или колода) + if (gameState) { + if (source === 'hand') { + renderHand(gameState); + } else if (source === 'deck') { + renderForgeDeck(gameState); + } + } + } + + function setupForgeDragAndDrop(state) { + const selectedEl = $('forge-selected'); + const sidebar = $('forge-sidebar'); + if (!selectedEl || !sidebar || sidebar.classList.contains('hidden')) return; + + // Обработка drop в область выбранных карт + const handleDragOver = (e) => { + e.preventDefault(); + e.stopPropagation(); + selectedEl.classList.add('drag-over'); + }; + + const handleDragLeave = (e) => { + if (!selectedEl.contains(e.relatedTarget)) { + selectedEl.classList.remove('drag-over'); + } + }; + + const handleDrop = (e) => { + e.preventDefault(); + e.stopPropagation(); + selectedEl.classList.remove('drag-over'); + + let cardId = null; + let source = null; + + // Проверяем данные из dataTransfer + const data = e.dataTransfer.getData('text/plain'); + if (data) { + if (data.startsWith('hand:')) { + const handIndex = parseInt(data.split(':')[1], 10); + const you = state.players[state.yourIndex]; + if (you.hand && you.hand[handIndex]) { + cardId = you.hand[handIndex]; + source = 'hand'; + } + } else { + cardId = data; + source = e.dataTransfer.getData('source') || 'deck'; + } + } + + if (cardId) { + addCardToForge(cardId, source); + } + }; + + // Удаляем старые обработчики, если есть + selectedEl.removeEventListener('dragover', handleDragOver); + selectedEl.removeEventListener('dragleave', handleDragLeave); + selectedEl.removeEventListener('drop', handleDrop); + + // Добавляем новые обработчики + selectedEl.addEventListener('dragover', handleDragOver); + selectedEl.addEventListener('dragleave', handleDragLeave); + selectedEl.addEventListener('drop', handleDrop); + + // Делаем карты в руке перетаскиваемыми в кузницу + $all('#your-hand .card-wrap').forEach(cardWrap => { + const cardId = cardWrap.dataset.cardId; + const meta = cardDb[cardId]; + if (cardId && meta && meta.type === 'minion') { + // Сохраняем оригинальный draggable, если он был + const originalDraggable = cardWrap.draggable; + const originalOndragstart = cardWrap.ondragstart; + + // Добавляем дополнительный обработчик для кузницы + const forgeDragStart = (e) => { + // Проверяем, открыта ли кузница + if (sidebar && !sidebar.classList.contains('hidden')) { + e.dataTransfer.setData('text/plain', cardId); + e.dataTransfer.setData('source', 'hand'); + cardWrap.classList.add('dragging'); + } + }; + + cardWrap.addEventListener('dragstart', forgeDragStart); + + // Сохраняем ссылку для последующего удаления + cardWrap._forgeDragStart = forgeDragStart; + } + }); + + // Делаем карты в колоде перетаскиваемыми + $all('.forge-deck-card').forEach(cardWrap => { + const cardId = cardWrap.dataset.cardId; + if (cardId) { + cardWrap.draggable = true; + + const deckDragStart = (e) => { + e.dataTransfer.setData('text/plain', cardId); + e.dataTransfer.setData('source', 'deck'); + cardWrap.classList.add('dragging'); + }; + + const deckDragEnd = () => { + cardWrap.classList.remove('dragging'); + }; + + // Удаляем старые обработчики + cardWrap.removeEventListener('dragstart', cardWrap._deckDragStart); + cardWrap.removeEventListener('dragend', cardWrap._deckDragEnd); + + // Добавляем новые + cardWrap.addEventListener('dragstart', deckDragStart); + cardWrap.addEventListener('dragend', deckDragEnd); + + // Сохраняем ссылки + cardWrap._deckDragStart = deckDragStart; + cardWrap._deckDragEnd = deckDragEnd; + } + }); + } + function renderForgeDeck(state) { const you = state.players[state.yourIndex]; const deckList = $('forge-deck-list'); - const selectedEl = $('forge-selected'); - const craftBtn = $('btn-forge-craft'); - if (!deckList || !selectedEl) return; + if (!deckList) return; deckList.innerHTML = you.deck.map((cardId, idx) => { const meta = cardDb[cardId]; if (!meta || meta.type !== 'minion') return ''; const isSelected = forgeSelected.includes(cardId); - return `
+ return `
${getCardArt(meta)}
-
${escapeHtml(meta.name)}
+
${escapeHtml(meta.name)}
${meta.attack || 0} ${meta.health || 0} @@ -2049,33 +2260,40 @@
`; }).filter(Boolean).join(''); + // Клик по карте в колоде тоже добавляет её $all('.forge-deck-card').forEach(card => { card.onclick = function() { const cardId = card.dataset.cardId; - const idx = forgeSelected.indexOf(cardId); - if (idx >= 0) { - forgeSelected.splice(idx, 1); - } else if (forgeSelected.length < 3) { - forgeSelected.push(cardId); - } - renderForgeDeck(state); + addCardToForge(cardId, 'deck'); }; }); - selectedEl.innerHTML = forgeSelected.length ? forgeSelected.map(cardId => { - const meta = cardDb[cardId]; - return `
${getCardArt(meta)}
${escapeHtml(meta.name)}
`; - }).join('') : '
Выберите 2-3 карты
'; + renderForgeSelected(); + updateForgeCraftButton(); - if (craftBtn) { - craftBtn.disabled = forgeSelected.length < 2 || forgeSelected.length > 3 || (you.mana || 0) < 2; - craftBtn.onclick = function() { - if (craftBtn.disabled) return; - socket.emit('forgeCard', { cardIds: forgeSelected }); - forgeSelected = []; - $('forge-overlay')?.classList.add('hidden'); - }; - } + // Настраиваем drag-and-drop после рендеринга + setTimeout(() => setupForgeDragAndDrop(state), 100); + } + + // Обновляем drag-and-drop при каждом обновлении руки, если кузница открыта + // Это делается в bindGameEvents + + // Обработчик создания улучшенной карты + const craftBtn = $('btn-forge-craft'); + if (craftBtn) { + craftBtn.onclick = function() { + if (craftBtn.disabled) 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 }); + forgeSelected = []; + renderForgeSelected(); + const sidebar = $('forge-sidebar'); + if (sidebar) { + sidebar.classList.add('hidden'); + } + }; } $('music-toggle')?.addEventListener('click', () => { diff --git a/public/index.html b/public/index.html index ad5881b..66f4450 100644 --- a/public/index.html +++ b/public/index.html @@ -241,16 +241,21 @@

Выберите цель для геройской способности (1 урон)

-