From 09acbecdf1da852a20d3f69ca1f6b0af59bc8d87 Mon Sep 17 00:00:00 2001 From: Bonchellon Date: Tue, 27 Jan 2026 20:28:18 +0300 Subject: [PATCH] Fix Grabej --- public/game.js | 101 ++++++++++++++++++++++++++++++++++++++-------- public/styles.css | 19 +++++++++ 2 files changed, 104 insertions(+), 16 deletions(-) diff --git a/public/game.js b/public/game.js index 7d35e48..c87b28f 100644 --- a/public/game.js +++ b/public/game.js @@ -1187,6 +1187,14 @@ } } + // Если это Грабеж, но spellTarget не enemy_player, все равно активируем режим выбора цели + if (meta.spellEffect === 'steal_cards' && !meta.spellTarget) { + spellMode = { active: true, handIndex: handIndex, cardId: wrap.dataset.cardId, spellTarget: 'enemy_player' }; + $('spell-mode')?.classList.remove('hidden'); + renderGame(state); + return; + } + if (!needTarget) { if (typeof window.Sounds !== 'undefined') window.Sounds.playCard(); socket.emit('playSpell', { handIndex: handIndex }); @@ -2238,14 +2246,25 @@ const hintEl = $('steal-cards-hint'); const targetSelect = $('steal-target-select'); - if (!deckList || !selectedEl || !confirmBtn) return; + if (!deckList || !selectedEl || !confirmBtn) { + console.error('Steal cards modal elements not found'); + return; + } + + const currentState = gameState || state; + if (!currentState || !currentState.players) { + console.error('Invalid game state for steal cards modal'); + return; + } // Если противник уже выбран, показываем его колоду if (stealCardsMode.targetPlayerIndex !== null) { // Обновляем колоду из актуального gameState - const targetPlayer = state.players[stealCardsMode.targetPlayerIndex]; + const targetPlayer = currentState.players[stealCardsMode.targetPlayerIndex]; if (targetPlayer && targetPlayer.deck) { stealCardsMode.targetDeck = [...targetPlayer.deck]; + } else { + console.warn('Target player not found or deck is empty:', stealCardsMode.targetPlayerIndex); } if (stealCardsMode.targetDeck.length === 0) { @@ -2263,39 +2282,65 @@ } deckList.innerHTML = stealCardsMode.targetDeck.map((cardId, idx) => { - const meta = cardDb[cardId]; - if (!meta) return ''; + const cardDbToUse = currentState?.cardDb || cardDb; + const meta = cardDbToUse[cardId]; + if (!meta) { + console.warn('Card not found in cardDb:', cardId, 'Available keys:', Object.keys(cardDbToUse).slice(0, 10)); + return `
+
Карта ${cardId}
+
`; + } const isSelected = stealCardsMode.selectedIndices.includes(idx); const cost = meta.cost || 0; const attack = meta.attack !== undefined ? meta.attack : ''; const health = meta.health !== undefined ? meta.health : ''; const stats = meta.type === 'minion' ? `
${attack}${health}
` : ''; const costDisplay = `
${cost}
`; - const art = getCardArt ? getCardArt(meta) : '✦'; + const art = typeof getCardArt === 'function' ? getCardArt(meta) : '✦'; - return `
+ return `
${art}
-
${escapeHtml(meta.name)}
+
${escapeHtml(meta.name || cardId)}
${stats} ${costDisplay}
`; - }).filter(Boolean).join(''); + }).join(''); $all('.steal-deck-card').forEach(card => { - card.onclick = function() { + const handleCardClick = function(e) { + e.preventDefault(); + e.stopPropagation(); const idx = parseInt(card.dataset.deckIndex, 10); + if (isNaN(idx)) { + console.warn('Invalid deck index:', card.dataset.deckIndex); + return; + } const selectedIdx = stealCardsMode.selectedIndices.indexOf(idx); if (selectedIdx >= 0) { stealCardsMode.selectedIndices.splice(selectedIdx, 1); } else if (stealCardsMode.selectedIndices.length < 2) { stealCardsMode.selectedIndices.push(idx); } - showStealCardsModal(state, data); + const currentState = gameState || state; + showStealCardsModal(currentState, data || { + targetPlayerIndex: stealCardsMode.targetPlayerIndex, + targetPlayerName: currentState?.players?.[stealCardsMode.targetPlayerIndex]?.name || `Игрок ${stealCardsMode.targetPlayerIndex + 1}`, + targetDeckSize: stealCardsMode.targetDeck.length, + maxCards: Math.min(2, stealCardsMode.targetDeck.length) + }); }; + card.onclick = handleCardClick; + card.style.pointerEvents = 'auto'; + if (isTouchDevice()) { + card.ontouchstart = function(e) { + e.preventDefault(); + handleCardClick(e); + }; + } }); selectedEl.innerHTML = stealCardsMode.selectedIndices.length ? stealCardsMode.selectedIndices.map(idx => { @@ -2330,9 +2375,14 @@ hintEl.textContent = 'Выберите противника для грабежа'; } - const enemies = state.players.filter((p, i) => i !== state.yourIndex && p.health > 0 && p.deck && p.deck.length > 0); + const enemies = currentState.players.filter((p, i) => i !== currentState.yourIndex && p.health > 0 && p.deck && p.deck.length > 0); + if (enemies.length === 0) { + if (hintEl) hintEl.textContent = 'Нет доступных противников для грабежа'; + targetSelect.innerHTML = ''; + return; + } targetSelect.innerHTML = enemies.map((enemy, idx) => { - const enemyIdx = state.players.indexOf(enemy); + const enemyIdx = currentState.players.indexOf(enemy); return `
${escapeHtml(enemy.name || `Игрок ${enemyIdx + 1}`)}
Колода: ${enemy.deck.length} карт
@@ -2340,21 +2390,40 @@ }).join(''); $all('.steal-target-option').forEach(option => { - option.onclick = function() { + const handleOptionClick = function(e) { + e.preventDefault(); + e.stopPropagation(); const playerIdx = parseInt(option.dataset.playerIndex, 10); - const targetPlayer = state.players[playerIdx]; + if (isNaN(playerIdx)) return; + const currentState = gameState || state; + if (!currentState || !currentState.players) { + console.error('Invalid state when selecting target player'); + return; + } + const targetPlayer = currentState.players[playerIdx]; if (targetPlayer && targetPlayer.deck && targetPlayer.deck.length > 0) { stealCardsMode.targetPlayerIndex = playerIdx; - // Получаем актуальную колоду из gameState stealCardsMode.targetDeck = targetPlayer.deck ? [...targetPlayer.deck] : []; - showStealCardsModal(state, { + console.log('Selected target player:', playerIdx, 'Deck size:', stealCardsMode.targetDeck.length); + showStealCardsModal(currentState, { targetPlayerIndex: playerIdx, targetPlayerName: targetPlayer.name || `Игрок ${playerIdx + 1}`, targetDeckSize: targetPlayer.deck.length, maxCards: Math.min(2, targetPlayer.deck.length) }); + } else { + console.warn('Target player has no deck or is invalid:', playerIdx, targetPlayer); } }; + option.onclick = handleOptionClick; + option.style.pointerEvents = 'auto'; + option.style.cursor = 'pointer'; + if (isTouchDevice()) { + option.ontouchstart = function(e) { + e.preventDefault(); + handleOptionClick(e); + }; + } }); } diff --git a/public/styles.css b/public/styles.css index 5746a22..30452ef 100644 --- a/public/styles.css +++ b/public/styles.css @@ -1937,11 +1937,20 @@ html, body { .steal-target-select { margin-bottom: 1rem; } +.steal-target-option { + pointer-events: auto !important; + cursor: pointer; + user-select: none; + -webkit-user-select: none; +} .steal-target-option:hover { background: rgba(0,180,255,0.2) !important; border-color: var(--cyan) !important; transform: scale(1.02); } +.steal-target-option:active { + transform: scale(0.98); +} .steal-deck-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); @@ -1957,14 +1966,24 @@ html, body { cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; border: 2px solid transparent; + position: relative; + z-index: 10; + pointer-events: auto !important; + user-select: none; + -webkit-user-select: none; } .steal-deck-card:hover { transform: scale(1.1); box-shadow: 0 0 15px rgba(0,180,255,0.5); + z-index: 15; } .steal-deck-card.selected { border-color: var(--cyan); box-shadow: 0 0 20px rgba(0,180,255,0.7); + transform: scale(1.05); +} +.steal-deck-card:active { + transform: scale(0.95); } .steal-selected { min-height: 80px;