This commit is contained in:
2026-01-26 16:19:58 +03:00
parent 11d88bd53f
commit fcb77e9368
3 changed files with 434 additions and 74 deletions

View File

@ -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 = '<div class="forge-selected-empty">Перетащите карты сюда</div>';
selectedEl.classList.remove('drag-over');
} else {
selectedEl.innerHTML = forgeSelected.map((cardId, idx) => {
const meta = cardDb[cardId];
if (!meta) return '';
return `<div class="card-wrap forge-selected-card" data-card-id="${cardId}" data-forge-index="${idx}" style="width: 80px; height: 112px; position: relative;">
<div class="card faction-${meta.faction || 'neutral'}">
<div class="card-art">${getCardArt(meta)}</div>
<div class="card-info">
<div class="card-name" style="font-size: 0.6rem;">${escapeHtml(meta.name)}</div>
${meta.type === 'minion' ? `<div class="card-stats"><span class="atk">${meta.attack || 0}</span><span class="hp">${meta.health || 0}</span></div>` : ''}
</div>
</div>
</div>`;
}).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 `<div class="card-wrap forge-deck-card ${isSelected ? 'selected' : ''}" data-card-id="${cardId}" data-deck-index="${idx}" style="width: 100px; height: 140px; cursor: pointer;">
return `<div class="card-wrap forge-deck-card ${isSelected ? 'selected' : ''}" data-card-id="${cardId}" data-deck-index="${idx}" draggable="true" style="width: 90px; height: 126px; cursor: grab;">
<div class="card faction-${meta.faction || 'neutral'}">
<div class="card-art">${getCardArt(meta)}</div>
<div class="card-info">
<div class="card-name" style="font-size: 0.7rem;">${escapeHtml(meta.name)}</div>
<div class="card-name" style="font-size: 0.65rem;">${escapeHtml(meta.name)}</div>
<div class="card-stats">
<span class="atk">${meta.attack || 0}</span>
<span class="hp">${meta.health || 0}</span>
@ -2049,33 +2260,40 @@
</div>`;
}).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 `<div class="card-wrap" style="width: 80px; height: 112px;"><div class="card faction-${meta.faction || 'neutral'}"><div class="card-art">${getCardArt(meta)}</div><div class="card-info"><div class="card-name" style="font-size: 0.6rem;">${escapeHtml(meta.name)}</div></div></div></div>`;
}).join('') : '<div class="forge-selected-empty">Выберите 2-3 карты</div>';
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', () => {