This commit is contained in:
2026-01-27 02:17:57 +03:00
parent a4479916f9
commit 814abb60f3
5 changed files with 312 additions and 144 deletions

View File

@ -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 = '<div class="card-wrap forge-preview-card" style="width:110px;height:154px;"><div class="card faction-' + (meta.faction || 'neutral') + '">' +
'<div class="card-art">' + art + '</div>' +
'<div class="card-info"><div class="card-name" style="font-size:0.75rem">' + escapeHtml(meta.name || '') + '</div>' +
'<div class="card-stats"><span class="atk">' + (meta.attack || 0) + '</span><span class="hp">' + (meta.health || 0) + '</span></div></div></div></div>';
}
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 = '<div class="forge-selected-empty">Кликните на карты чтобы выбрать</div>';
selectedEl.innerHTML = '<div class="forge-selected-empty">Кликните на карты из руки</div>';
} 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 = '<p class="forge-preview-loading">Загрузка…</p>';
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 = '<div style="color: #94a3b8; text-align: center; padding: 2rem; font-size: 0.9rem;">Колода пуста</div>';
return;
}
// Фильтруем только миньонов
const minionCards = deck.filter(cardId => {
const meta = cardDb[cardId];
return meta && meta.type === 'minion';
});
if (minionCards.length === 0) {
deckList.innerHTML = '<div style="color: #94a3b8; text-align: center; padding: 2rem; font-size: 0.9rem;">Нет миньонов в колоде</div>';
return;
}
deckList.innerHTML = minionCards.map((cardId) => {
const meta = cardDb[cardId];
if (!meta) return '';
const isSelected = forgeSelected.includes(cardId);
return `<div class="card-wrap ${isSelected ? 'selected' : ''}" data-card-id="${cardId}" style="width: 100px; height: 140px; cursor: pointer;">
<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-stats">
<span class="atk">${meta.attack || 0}</span>
<span class="hp">${meta.health || 0}</span>
</div>
</div>
</div>
</div>`;
}).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;
};
}