Fix Grabej
This commit is contained in:
101
public/game.js
101
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 (!needTarget) {
|
||||||
if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
|
if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
|
||||||
socket.emit('playSpell', { handIndex: handIndex });
|
socket.emit('playSpell', { handIndex: handIndex });
|
||||||
@ -2238,14 +2246,25 @@
|
|||||||
const hintEl = $('steal-cards-hint');
|
const hintEl = $('steal-cards-hint');
|
||||||
const targetSelect = $('steal-target-select');
|
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) {
|
if (stealCardsMode.targetPlayerIndex !== null) {
|
||||||
// Обновляем колоду из актуального gameState
|
// Обновляем колоду из актуального gameState
|
||||||
const targetPlayer = state.players[stealCardsMode.targetPlayerIndex];
|
const targetPlayer = currentState.players[stealCardsMode.targetPlayerIndex];
|
||||||
if (targetPlayer && targetPlayer.deck) {
|
if (targetPlayer && targetPlayer.deck) {
|
||||||
stealCardsMode.targetDeck = [...targetPlayer.deck];
|
stealCardsMode.targetDeck = [...targetPlayer.deck];
|
||||||
|
} else {
|
||||||
|
console.warn('Target player not found or deck is empty:', stealCardsMode.targetPlayerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stealCardsMode.targetDeck.length === 0) {
|
if (stealCardsMode.targetDeck.length === 0) {
|
||||||
@ -2263,39 +2282,65 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
deckList.innerHTML = stealCardsMode.targetDeck.map((cardId, idx) => {
|
deckList.innerHTML = stealCardsMode.targetDeck.map((cardId, idx) => {
|
||||||
const meta = cardDb[cardId];
|
const cardDbToUse = currentState?.cardDb || cardDb;
|
||||||
if (!meta) return '';
|
const meta = cardDbToUse[cardId];
|
||||||
|
if (!meta) {
|
||||||
|
console.warn('Card not found in cardDb:', cardId, 'Available keys:', Object.keys(cardDbToUse).slice(0, 10));
|
||||||
|
return `<div class="card-wrap steal-deck-card" data-card-id="${cardId}" data-deck-index="${idx}" style="width: 100px; height: 140px; cursor: pointer; border: 2px solid red; position: relative; z-index: 10;">
|
||||||
|
<div style="padding: 0.5rem; text-align: center; font-size: 0.7rem; color: #ff6b6b;">Карта ${cardId}</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
const isSelected = stealCardsMode.selectedIndices.includes(idx);
|
const isSelected = stealCardsMode.selectedIndices.includes(idx);
|
||||||
const cost = meta.cost || 0;
|
const cost = meta.cost || 0;
|
||||||
const attack = meta.attack !== undefined ? meta.attack : '';
|
const attack = meta.attack !== undefined ? meta.attack : '';
|
||||||
const health = meta.health !== undefined ? meta.health : '';
|
const health = meta.health !== undefined ? meta.health : '';
|
||||||
const stats = meta.type === 'minion' ? `<div class="card-stats"><span class="atk">${attack}</span><span class="hp">${health}</span></div>` : '';
|
const stats = meta.type === 'minion' ? `<div class="card-stats"><span class="atk">${attack}</span><span class="hp">${health}</span></div>` : '';
|
||||||
const costDisplay = `<div class="card-cost-wrap"><span class="card-cost">${cost}</span></div>`;
|
const costDisplay = `<div class="card-cost-wrap"><span class="card-cost">${cost}</span></div>`;
|
||||||
const art = getCardArt ? getCardArt(meta) : '✦';
|
const art = typeof getCardArt === 'function' ? getCardArt(meta) : '✦';
|
||||||
|
|
||||||
return `<div class="card-wrap steal-deck-card ${isSelected ? 'selected' : ''}" data-card-id="${cardId}" data-deck-index="${idx}" style="width: 100px; height: 140px; cursor: pointer;">
|
return `<div class="card-wrap steal-deck-card ${isSelected ? 'selected' : ''}" data-card-id="${cardId}" data-deck-index="${idx}" style="width: 100px; height: 140px; cursor: pointer; position: relative; z-index: 10;">
|
||||||
<div class="card faction-${meta.faction || 'neutral'}">
|
<div class="card faction-${meta.faction || 'neutral'}">
|
||||||
<div class="card-art">${art}</div>
|
<div class="card-art">${art}</div>
|
||||||
<div class="card-info">
|
<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.7rem;">${escapeHtml(meta.name || cardId)}</div>
|
||||||
${stats}
|
${stats}
|
||||||
${costDisplay}
|
${costDisplay}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).filter(Boolean).join('');
|
}).join('');
|
||||||
|
|
||||||
$all('.steal-deck-card').forEach(card => {
|
$all('.steal-deck-card').forEach(card => {
|
||||||
card.onclick = function() {
|
const handleCardClick = function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
const idx = parseInt(card.dataset.deckIndex, 10);
|
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);
|
const selectedIdx = stealCardsMode.selectedIndices.indexOf(idx);
|
||||||
if (selectedIdx >= 0) {
|
if (selectedIdx >= 0) {
|
||||||
stealCardsMode.selectedIndices.splice(selectedIdx, 1);
|
stealCardsMode.selectedIndices.splice(selectedIdx, 1);
|
||||||
} else if (stealCardsMode.selectedIndices.length < 2) {
|
} else if (stealCardsMode.selectedIndices.length < 2) {
|
||||||
stealCardsMode.selectedIndices.push(idx);
|
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 => {
|
selectedEl.innerHTML = stealCardsMode.selectedIndices.length ? stealCardsMode.selectedIndices.map(idx => {
|
||||||
@ -2330,9 +2375,14 @@
|
|||||||
hintEl.textContent = 'Выберите противника для грабежа';
|
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) => {
|
targetSelect.innerHTML = enemies.map((enemy, idx) => {
|
||||||
const enemyIdx = state.players.indexOf(enemy);
|
const enemyIdx = currentState.players.indexOf(enemy);
|
||||||
return `<div class="steal-target-option" data-player-index="${enemyIdx}" style="padding: 1rem; margin: 0.5rem 0; background: rgba(0,0,0,0.3); border: 2px solid rgba(0,180,255,0.3); border-radius: 8px; cursor: pointer; transition: all 0.2s;">
|
return `<div class="steal-target-option" data-player-index="${enemyIdx}" style="padding: 1rem; margin: 0.5rem 0; background: rgba(0,0,0,0.3); border: 2px solid rgba(0,180,255,0.3); border-radius: 8px; cursor: pointer; transition: all 0.2s;">
|
||||||
<div style="font-weight: 700; color: var(--cyan);">${escapeHtml(enemy.name || `Игрок ${enemyIdx + 1}`)}</div>
|
<div style="font-weight: 700; color: var(--cyan);">${escapeHtml(enemy.name || `Игрок ${enemyIdx + 1}`)}</div>
|
||||||
<div style="font-size: 0.85rem; color: #94a3b8; margin-top: 0.25rem;">Колода: ${enemy.deck.length} карт</div>
|
<div style="font-size: 0.85rem; color: #94a3b8; margin-top: 0.25rem;">Колода: ${enemy.deck.length} карт</div>
|
||||||
@ -2340,21 +2390,40 @@
|
|||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
$all('.steal-target-option').forEach(option => {
|
$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 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) {
|
if (targetPlayer && targetPlayer.deck && targetPlayer.deck.length > 0) {
|
||||||
stealCardsMode.targetPlayerIndex = playerIdx;
|
stealCardsMode.targetPlayerIndex = playerIdx;
|
||||||
// Получаем актуальную колоду из gameState
|
|
||||||
stealCardsMode.targetDeck = targetPlayer.deck ? [...targetPlayer.deck] : [];
|
stealCardsMode.targetDeck = targetPlayer.deck ? [...targetPlayer.deck] : [];
|
||||||
showStealCardsModal(state, {
|
console.log('Selected target player:', playerIdx, 'Deck size:', stealCardsMode.targetDeck.length);
|
||||||
|
showStealCardsModal(currentState, {
|
||||||
targetPlayerIndex: playerIdx,
|
targetPlayerIndex: playerIdx,
|
||||||
targetPlayerName: targetPlayer.name || `Игрок ${playerIdx + 1}`,
|
targetPlayerName: targetPlayer.name || `Игрок ${playerIdx + 1}`,
|
||||||
targetDeckSize: targetPlayer.deck.length,
|
targetDeckSize: targetPlayer.deck.length,
|
||||||
maxCards: Math.min(2, 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1937,11 +1937,20 @@ html, body {
|
|||||||
.steal-target-select {
|
.steal-target-select {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
.steal-target-option {
|
||||||
|
pointer-events: auto !important;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
.steal-target-option:hover {
|
.steal-target-option:hover {
|
||||||
background: rgba(0,180,255,0.2) !important;
|
background: rgba(0,180,255,0.2) !important;
|
||||||
border-color: var(--cyan) !important;
|
border-color: var(--cyan) !important;
|
||||||
transform: scale(1.02);
|
transform: scale(1.02);
|
||||||
}
|
}
|
||||||
|
.steal-target-option:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
.steal-deck-list {
|
.steal-deck-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
|
||||||
@ -1957,14 +1966,24 @@ html, body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
pointer-events: auto !important;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
}
|
}
|
||||||
.steal-deck-card:hover {
|
.steal-deck-card:hover {
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
box-shadow: 0 0 15px rgba(0,180,255,0.5);
|
box-shadow: 0 0 15px rgba(0,180,255,0.5);
|
||||||
|
z-index: 15;
|
||||||
}
|
}
|
||||||
.steal-deck-card.selected {
|
.steal-deck-card.selected {
|
||||||
border-color: var(--cyan);
|
border-color: var(--cyan);
|
||||||
box-shadow: 0 0 20px rgba(0,180,255,0.7);
|
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 {
|
.steal-selected {
|
||||||
min-height: 80px;
|
min-height: 80px;
|
||||||
|
|||||||
Reference in New Issue
Block a user