New update

This commit is contained in:
2026-01-27 22:45:36 +03:00
parent 7d5769ac8b
commit dedc2635f2
3 changed files with 125 additions and 66 deletions

View File

@ -23,11 +23,12 @@ module.exports = {
health: 8, health: 8,
type: 'minion', type: 'minion',
faction: 'empire', faction: 'empire',
text: 'Sith Lord. Fear is his weapon. Даёт +1/+1 штурмовикам и клонам.', text: 'Sith Lord. Fear is his weapon. Даёт +1/+1 штурмовикам и клонам. Пока на поле, все джедаи противника получают -1/-1.',
art: 'vader', art: 'vader',
legendary: true, legendary: true,
deathrattle: 'Нанеси 2 урона всем врагам.', deathrattle: 'Нанеси 2 урона всем врагам.',
deathrattleId: 'deal_2_all_enemies', deathrattleId: 'deal_2_all_enemies',
aura: 'jedi_debuff_enemy',
bio: 'Дарт Вейдер — бывший Энакин Скайуокер, Избранный, самый сильный в Силе. Рыцарь-джедай, павший на тёмную сторону из-за страха потерять Падме. Ученик Палпатина, ставший тёмным лордом ситхов. Правой рукой Императора, командовал армией Империи. В битве на Мустафаре потерял конечности и был сожжён лавой, выжил благодаря кибернетическим имплантам и костюму. В конце жизни вернулся к свету, убив Палпатина и спася сына, но погиб от полученных ран.', bio: 'Дарт Вейдер — бывший Энакин Скайуокер, Избранный, самый сильный в Силе. Рыцарь-джедай, павший на тёмную сторону из-за страха потерять Падме. Ученик Палпатина, ставший тёмным лордом ситхов. Правой рукой Императора, командовал армией Империи. В битве на Мустафаре потерял конечности и был сожжён лавой, выжил благодаря кибернетическим имплантам и костюму. В конце жизни вернулся к свету, убив Палпатина и спася сына, но погиб от полученных ран.',
}, },
yoda: { yoda: {
@ -1034,11 +1035,11 @@ module.exports = {
cost: 3, cost: 3,
type: 'spell', type: 'spell',
faction: 'pirates', faction: 'pirates',
text: 'Укради 2 карты из колоды противника.', text: 'Укради 2 карты с доски противника (они перейдут в твою руку).',
art: 'plunder', art: 'plunder',
spellEffect: 'steal_cards', spellEffect: 'steal_cards',
spellTarget: 'enemy_player', spellTarget: 'enemy_board',
bio: 'Пираты грабят и крадут карты у противников.', bio: 'Пираты грабят и крадут карты у противников с поля боя.',
}, },
mandalorian_rage: { mandalorian_rage: {
name: 'Ярость мандалорца', name: 'Ярость мандалорца',
@ -1308,12 +1309,13 @@ module.exports = {
health: 6, health: 6,
type: 'minion', type: 'minion',
faction: 'rebellion', faction: 'rebellion',
text: 'Избранный. Может пасть на тёмную сторону. Даёт +1/+1 Оби-Вану и Падме.', text: 'Избранный. Может пасть на тёмную сторону. Даёт +1/+1 Оби-Вану, Падме и Асоке. Пока на поле, все джедаи получают +1/+1.',
art: 'anakin', art: 'anakin',
legendary: true, legendary: true,
battlecry: 'Уничтожь вражеского миньона с атакой 4 или меньше.', battlecry: 'Уничтожь вражеского миньона с атакой 4 или меньше.',
battlecryId: 'destroy_medium_minion', battlecryId: 'destroy_medium_minion',
transformOnDeath: 'vader', transformOnDeath: 'vader',
aura: 'jedi_buff_all',
bio: 'Избранный, самый сильный в Силе. Ученик Оби-Вана, муж Падме. Пад на тёмную сторону и стал Дартом Вейдером.', bio: 'Избранный, самый сильный в Силе. Ученик Оби-Вана, муж Падме. Пад на тёмную сторону и стал Дартом Вейдером.',
}, },
kanan: { kanan: {

View File

@ -325,10 +325,10 @@
stealCardsMode.targetDeck = []; stealCardsMode.targetDeck = [];
stealCardsMode.selectedIndices = []; stealCardsMode.selectedIndices = [];
// Получаем колоду противника из gameState // Получаем доску противника из gameState
const targetPlayer = gameState.players[data.targetPlayerIndex]; const targetPlayer = gameState.players[data.targetPlayerIndex];
if (targetPlayer && targetPlayer.deck) { if (targetPlayer && targetPlayer.board) {
stealCardsMode.targetDeck = [...targetPlayer.deck]; stealCardsMode.targetDeck = targetPlayer.board.map(m => m.cardId);
} }
showStealCardsModal(gameState, data); showStealCardsModal(gameState, data);
@ -1571,22 +1571,22 @@
// Специальная обработка для Грабежа - открываем модальное окно // Специальная обработка для Грабежа - открываем модальное окно
const spellCard = cardDb[spellMode.cardId]; const spellCard = cardDb[spellMode.cardId];
if (spellCard && spellCard.spellEffect === 'steal_cards' && spellCard.spellTarget === 'enemy_player') { if (spellCard && spellCard.spellEffect === 'steal_cards' && (spellCard.spellTarget === 'enemy_player' || spellCard.spellTarget === 'enemy_board')) {
// Выбираем противника (tp должен быть индексом противника, tb игнорируем для enemy_player) // Выбираем противника (tp должен быть индексом противника, tb игнорируем для enemy_player)
if (tp !== state.yourIndex && tp >= 0) { if (tp !== state.yourIndex && tp >= 0) {
const targetPlayer = state.players[tp]; const targetPlayer = state.players[tp];
if (targetPlayer && targetPlayer.deck && targetPlayer.deck.length > 0) { if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
stealCardsMode.active = true; stealCardsMode.active = true;
stealCardsMode.handIndex = spellMode.handIndex; stealCardsMode.handIndex = spellMode.handIndex;
stealCardsMode.targetPlayerIndex = tp; stealCardsMode.targetPlayerIndex = tp;
// Получаем актуальную колоду из gameState // Получаем актуальную доску из gameState
stealCardsMode.targetDeck = targetPlayer.deck ? [...targetPlayer.deck] : []; stealCardsMode.targetDeck = targetPlayer.board ? targetPlayer.board.map(m => m.cardId) : [];
stealCardsMode.selectedIndices = []; stealCardsMode.selectedIndices = [];
showStealCardsModal(state, { showStealCardsModal(state, {
targetPlayerIndex: tp, targetPlayerIndex: tp,
targetPlayerName: targetPlayer.name || `Игрок ${tp + 1}`, targetPlayerName: targetPlayer.name || `Игрок ${tp + 1}`,
targetDeckSize: targetPlayer.deck.length, targetBoardSize: targetPlayer.board.length,
maxCards: Math.min(2, targetPlayer.deck.length) maxCards: Math.min(2, targetPlayer.board.length)
}); });
spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' }; spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
$('spell-mode')?.classList.add('hidden'); $('spell-mode')?.classList.add('hidden');
@ -1614,21 +1614,21 @@
// Специальная обработка для Грабежа // Специальная обработка для Грабежа
const spellCard = cardDb[spellMode.cardId]; const spellCard = cardDb[spellMode.cardId];
if (spellCard && spellCard.spellEffect === 'steal_cards' && spellCard.spellTarget === 'enemy_player') { if (spellCard && spellCard.spellEffect === 'steal_cards' && (spellCard.spellTarget === 'enemy_player' || spellCard.spellTarget === 'enemy_board')) {
if (tp !== state.yourIndex && tp >= 0) { if (tp !== state.yourIndex && tp >= 0) {
const targetPlayer = state.players[tp]; const targetPlayer = state.players[tp];
if (targetPlayer && targetPlayer.deck && targetPlayer.deck.length > 0) { if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
stealCardsMode.active = true; stealCardsMode.active = true;
stealCardsMode.handIndex = spellMode.handIndex; stealCardsMode.handIndex = spellMode.handIndex;
stealCardsMode.targetPlayerIndex = tp; stealCardsMode.targetPlayerIndex = tp;
// Получаем актуальную колоду из gameState // Получаем актуальную доску из gameState
stealCardsMode.targetDeck = targetPlayer.deck ? [...targetPlayer.deck] : []; stealCardsMode.targetDeck = targetPlayer.board ? targetPlayer.board.map(m => m.cardId) : [];
stealCardsMode.selectedIndices = []; stealCardsMode.selectedIndices = [];
showStealCardsModal(state, { showStealCardsModal(state, {
targetPlayerIndex: tp, targetPlayerIndex: tp,
targetPlayerName: targetPlayer.name || `Игрок ${tp + 1}`, targetPlayerName: targetPlayer.name || `Игрок ${tp + 1}`,
targetDeckSize: targetPlayer.deck.length, targetBoardSize: targetPlayer.board.length,
maxCards: Math.min(2, targetPlayer.deck.length) maxCards: Math.min(2, targetPlayer.board.length)
}); });
spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' }; spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
$('spell-mode')?.classList.add('hidden'); $('spell-mode')?.classList.add('hidden');
@ -1682,23 +1682,23 @@
el.onclick = function (e) { el.onclick = function (e) {
if (!spellMode.active) return; if (!spellMode.active) return;
const spellCard = cardDb[spellMode.cardId]; const spellCard = cardDb[spellMode.cardId];
if (!spellCard || spellCard.spellEffect !== 'steal_cards' || spellCard.spellTarget !== 'enemy_player') return; if (!spellCard || spellCard.spellEffect !== 'steal_cards' || (spellCard.spellTarget !== 'enemy_player' && spellCard.spellTarget !== 'enemy_board')) return;
e.stopPropagation(); e.stopPropagation();
var tp = parseInt(el.dataset.playerIndex ?? el.dataset.opponentIndex, 10); var tp = parseInt(el.dataset.playerIndex ?? el.dataset.opponentIndex, 10);
if (tp === state.yourIndex || tp < 0) return; if (tp === state.yourIndex || tp < 0) return;
const targetPlayer = state.players[tp]; const targetPlayer = state.players[tp];
if (targetPlayer && targetPlayer.deck && targetPlayer.deck.length > 0) { if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
stealCardsMode.active = true; stealCardsMode.active = true;
stealCardsMode.handIndex = spellMode.handIndex; stealCardsMode.handIndex = spellMode.handIndex;
stealCardsMode.targetPlayerIndex = tp; stealCardsMode.targetPlayerIndex = tp;
// Получаем актуальную колоду из gameState // Получаем актуальную доску из gameState
stealCardsMode.targetDeck = targetPlayer.deck ? [...targetPlayer.deck] : []; stealCardsMode.targetDeck = targetPlayer.board ? targetPlayer.board.map(m => m.cardId) : [];
stealCardsMode.selectedIndices = []; stealCardsMode.selectedIndices = [];
showStealCardsModal(state, { showStealCardsModal(state, {
targetPlayerIndex: tp, targetPlayerIndex: tp,
targetPlayerName: targetPlayer.name || `Игрок ${tp + 1}`, targetPlayerName: targetPlayer.name || `Игрок ${tp + 1}`,
targetDeckSize: targetPlayer.deck.length, targetBoardSize: targetPlayer.board.length,
maxCards: Math.min(2, targetPlayer.deck.length) maxCards: Math.min(2, targetPlayer.board.length)
}); });
spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' }; spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
$('spell-mode')?.classList.add('hidden'); $('spell-mode')?.classList.add('hidden');
@ -1710,24 +1710,24 @@
el.ontouchstart = function (e) { el.ontouchstart = function (e) {
if (!spellMode.active) return; if (!spellMode.active) return;
const spellCard = cardDb[spellMode.cardId]; const spellCard = cardDb[spellMode.cardId];
if (!spellCard || spellCard.spellEffect !== 'steal_cards' || spellCard.spellTarget !== 'enemy_player') return; if (!spellCard || spellCard.spellEffect !== 'steal_cards' || (spellCard.spellTarget !== 'enemy_player' && spellCard.spellTarget !== 'enemy_board')) return;
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
var tp = parseInt(el.dataset.playerIndex ?? el.dataset.opponentIndex, 10); var tp = parseInt(el.dataset.playerIndex ?? el.dataset.opponentIndex, 10);
if (tp === state.yourIndex || tp < 0) return; if (tp === state.yourIndex || tp < 0) return;
const targetPlayer = state.players[tp]; const targetPlayer = state.players[tp];
if (targetPlayer && targetPlayer.deck && targetPlayer.deck.length > 0) { if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
stealCardsMode.active = true; stealCardsMode.active = true;
stealCardsMode.handIndex = spellMode.handIndex; stealCardsMode.handIndex = spellMode.handIndex;
stealCardsMode.targetPlayerIndex = tp; stealCardsMode.targetPlayerIndex = tp;
// Получаем актуальную колоду из gameState // Получаем актуальную доску из gameState
stealCardsMode.targetDeck = targetPlayer.deck ? [...targetPlayer.deck] : []; stealCardsMode.targetDeck = targetPlayer.board ? targetPlayer.board.map(m => m.cardId) : [];
stealCardsMode.selectedIndices = []; stealCardsMode.selectedIndices = [];
showStealCardsModal(state, { showStealCardsModal(state, {
targetPlayerIndex: tp, targetPlayerIndex: tp,
targetPlayerName: targetPlayer.name || `Игрок ${tp + 1}`, targetPlayerName: targetPlayer.name || `Игрок ${tp + 1}`,
targetDeckSize: targetPlayer.deck.length, targetBoardSize: targetPlayer.board.length,
maxCards: Math.min(2, targetPlayer.deck.length) maxCards: Math.min(2, targetPlayer.board.length)
}); });
spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' }; spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
$('spell-mode')?.classList.add('hidden'); $('spell-mode')?.classList.add('hidden');
@ -2410,18 +2410,18 @@
return; return;
} }
// Если противник уже выбран, показываем его колоду // Если противник уже выбран, показываем его доску (карты на столе)
if (stealCardsMode.targetPlayerIndex !== null) { if (stealCardsMode.targetPlayerIndex !== null) {
// Обновляем колоду из актуального gameState // Обновляем доску из актуального gameState
const targetPlayer = currentState.players[stealCardsMode.targetPlayerIndex]; const targetPlayer = currentState.players[stealCardsMode.targetPlayerIndex];
if (targetPlayer && targetPlayer.deck) { if (targetPlayer && targetPlayer.board) {
stealCardsMode.targetDeck = [...targetPlayer.deck]; stealCardsMode.targetDeck = targetPlayer.board.map(m => m.cardId);
} else { } else {
console.warn('Target player not found or deck is empty:', stealCardsMode.targetPlayerIndex); console.warn('Target player not found or board is empty:', stealCardsMode.targetPlayerIndex);
} }
if (stealCardsMode.targetDeck.length === 0) { if (stealCardsMode.targetDeck.length === 0) {
// Колода пуста, закрываем модальное окно // Доска пуста, закрываем модальное окно
$('steal-cards-overlay')?.classList.add('hidden'); $('steal-cards-overlay')?.classList.add('hidden');
stealCardsMode.active = false; stealCardsMode.active = false;
return; return;
@ -2431,10 +2431,11 @@
deckList.classList.remove('hidden'); deckList.classList.remove('hidden');
if (hintEl) { if (hintEl) {
hintEl.textContent = `Выберите до 2 карт из колоды ${targetPlayer?.name || `Игрока ${stealCardsMode.targetPlayerIndex + 1}`} (${stealCardsMode.targetDeck.length} карт)`; hintEl.textContent = `Выберите до 2 карт с доски ${targetPlayer?.name || `Игрока ${stealCardsMode.targetPlayerIndex + 1}`} (${stealCardsMode.targetDeck.length} карт на столе)`;
} }
deckList.innerHTML = stealCardsMode.targetDeck.map((cardId, idx) => { deckList.innerHTML = targetPlayer.board.map((minion, idx) => {
const cardId = minion.cardId;
const cardDbToUse = currentState?.cardDb || cardDb; const cardDbToUse = currentState?.cardDb || cardDb;
const meta = cardDbToUse[cardId]; const meta = cardDbToUse[cardId];
if (!meta) { if (!meta) {
@ -2451,7 +2452,7 @@
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 = typeof getCardArt === 'function' ? 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; position: relative; z-index: 10;"> return `<div class="card-wrap steal-deck-card ${isSelected ? 'selected' : ''}" data-card-id="${cardId}" data-board-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">
@ -2467,9 +2468,9 @@
const handleCardClick = function(e) { const handleCardClick = function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
const idx = parseInt(card.dataset.deckIndex, 10); const idx = parseInt(card.dataset.boardIndex, 10);
if (isNaN(idx)) { if (isNaN(idx)) {
console.warn('Invalid deck index:', card.dataset.deckIndex); console.warn('Invalid board index:', card.dataset.boardIndex);
return; return;
} }
const selectedIdx = stealCardsMode.selectedIndices.indexOf(idx); const selectedIdx = stealCardsMode.selectedIndices.indexOf(idx);
@ -2482,8 +2483,8 @@
showStealCardsModal(currentState, data || { showStealCardsModal(currentState, data || {
targetPlayerIndex: stealCardsMode.targetPlayerIndex, targetPlayerIndex: stealCardsMode.targetPlayerIndex,
targetPlayerName: currentState?.players?.[stealCardsMode.targetPlayerIndex]?.name || `Игрок ${stealCardsMode.targetPlayerIndex + 1}`, targetPlayerName: currentState?.players?.[stealCardsMode.targetPlayerIndex]?.name || `Игрок ${stealCardsMode.targetPlayerIndex + 1}`,
targetDeckSize: stealCardsMode.targetDeck.length, targetBoardSize: currentState?.players?.[stealCardsMode.targetPlayerIndex]?.board?.length || 0,
maxCards: Math.min(2, stealCardsMode.targetDeck.length) maxCards: Math.min(2, currentState?.players?.[stealCardsMode.targetPlayerIndex]?.board?.length || 0)
}); });
}; };
card.onclick = handleCardClick; card.onclick = handleCardClick;
@ -2554,18 +2555,18 @@
return; return;
} }
const targetPlayer = currentState.players[playerIdx]; const targetPlayer = currentState.players[playerIdx];
if (targetPlayer && targetPlayer.deck && targetPlayer.deck.length > 0) { if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
stealCardsMode.targetPlayerIndex = playerIdx; stealCardsMode.targetPlayerIndex = playerIdx;
stealCardsMode.targetDeck = targetPlayer.deck ? [...targetPlayer.deck] : []; stealCardsMode.targetDeck = targetPlayer.board ? targetPlayer.board.map(m => m.cardId) : [];
console.log('Selected target player:', playerIdx, 'Deck size:', stealCardsMode.targetDeck.length); console.log('Selected target player:', playerIdx, 'Board size:', stealCardsMode.targetDeck.length);
showStealCardsModal(currentState, { showStealCardsModal(currentState, {
targetPlayerIndex: playerIdx, targetPlayerIndex: playerIdx,
targetPlayerName: targetPlayer.name || `Игрок ${playerIdx + 1}`, targetPlayerName: targetPlayer.name || `Игрок ${playerIdx + 1}`,
targetDeckSize: targetPlayer.deck.length, targetBoardSize: targetPlayer.board.length,
maxCards: Math.min(2, targetPlayer.deck.length) maxCards: Math.min(2, targetPlayer.board.length)
}); });
} else { } else {
console.warn('Target player has no deck or is invalid:', playerIdx, targetPlayer); console.warn('Target player has no board or is invalid:', playerIdx, targetPlayer);
} }
}; };
option.onclick = handleOptionClick; option.onclick = handleOptionClick;

View File

@ -122,9 +122,18 @@ function initGame(room) {
// Если режим ИИ, добавляем ИИ игрока // Если режим ИИ, добавляем ИИ игрока
if (room.aiMode) { if (room.aiMode) {
const starWarsHeroes = [
'Darth Maul', 'Count Dooku', 'General Grievous', 'Grand Moff Tarkin',
'Admiral Thrawn', 'Kylo Ren', 'Snoke', 'General Hux',
'Captain Phasma', 'Moff Gideon', 'Cad Bane', 'Asajj Ventress',
'Savage Opress', 'Darth Sidious', 'Darth Tyranus', 'Darth Plagueis',
'Jango Fett', 'Boba Fett', 'IG-88', 'Bossk',
'Dengar', 'Zuckuss', '4-LOM', 'Aurra Sing'
];
const randomHero = starWarsHeroes[Math.floor(Math.random() * starWarsHeroes.length)];
players.push({ players.push({
id: 'AI_' + Date.now(), id: 'AI_' + Date.now(),
name: 'ИИ Противник', name: randomHero,
deck: createDeck(factionChoice), deck: createDeck(factionChoice),
hand: [], hand: [],
board: [], board: [],
@ -1076,6 +1085,28 @@ function applySynergies(room) {
} }
} }
}); });
// Аура: Пока Дарт Вейдер на поле, все джедаи противника получают -1/-1
if (card.aura === 'jedi_debuff_enemy') {
gameState.players.forEach((enemyPlayer, enemyPlayerIndex) => {
if (enemyPlayerIndex !== playerIndex && enemyPlayer.board) {
enemyPlayer.board.forEach((enemyMinion) => {
const enemyCard = cardDb[enemyMinion.cardId];
if (enemyCard && (enemyCard.name?.includes('Jedi') ||
enemyCard.id === 'luke' || enemyCard.id === 'obiwan' ||
enemyCard.id === 'ahsoka' || enemyCard.id === 'mace' ||
enemyCard.id === 'quigon' || enemyCard.id === 'plo_koon' ||
enemyCard.id === 'ki_adi' || enemyCard.id === 'aayla' ||
enemyCard.id === 'shaak_ti' || enemyCard.id === 'kanan' ||
enemyCard.id === 'ezra' || enemyCard.id === 'cal_kestis' ||
enemyCard.id === 'yoda' || enemyCard.id === 'anakin')) {
enemyMinion.synergyAttackBonus = (enemyMinion.synergyAttackBonus || 0) - 1;
enemyMinion.synergyHealthBonus = (enemyMinion.synergyHealthBonus || 0) - 1;
}
});
}
});
}
} }
// Люк Скайуокер даёт +1/+1 всем повстанцам // Люк Скайуокер даёт +1/+1 всем повстанцам
@ -1195,17 +1226,39 @@ function applySynergies(room) {
}); });
} }
// Энакин даёт +1/+1 Оби-Вану // Энакин даёт +1/+1 Оби-Вану, Падме и Асоке
if (card.id === 'anakin' || card.name === 'Anakin Skywalker') { if (card.id === 'anakin' || card.name === 'Anakin Skywalker') {
player.board.forEach((other, otherIdx) => { player.board.forEach((other, otherIdx) => {
if (idx !== otherIdx) { if (idx !== otherIdx) {
const otherCard = cardDb[other.cardId]; const otherCard = cardDb[other.cardId];
if (otherCard && (otherCard.id === 'obiwan' || otherCard.name === 'Obi-Wan Kenobi')) { if (otherCard && (otherCard.id === 'obiwan' || otherCard.name === 'Obi-Wan Kenobi' ||
otherCard.id === 'padme' || otherCard.name === 'Padmé Amidala' ||
otherCard.id === 'ahsoka' || otherCard.name === 'Ahsoka Tano')) {
other.synergyAttackBonus = (other.synergyAttackBonus || 0) + 1; other.synergyAttackBonus = (other.synergyAttackBonus || 0) + 1;
other.synergyHealthBonus = (other.synergyHealthBonus || 0) + 1; other.synergyHealthBonus = (other.synergyHealthBonus || 0) + 1;
} }
} }
}); });
// Аура: Пока Анакин на поле, все джедаи получают +1/+1
if (card.aura === 'jedi_buff_all') {
player.board.forEach((other, otherIdx) => {
if (idx !== otherIdx) {
const otherCard = cardDb[other.cardId];
if (otherCard && (otherCard.name?.includes('Jedi') ||
otherCard.id === 'luke' || otherCard.id === 'obiwan' ||
otherCard.id === 'ahsoka' || otherCard.id === 'mace' ||
otherCard.id === 'quigon' || otherCard.id === 'plo_koon' ||
otherCard.id === 'ki_adi' || otherCard.id === 'aayla' ||
otherCard.id === 'shaak_ti' || otherCard.id === 'kanan' ||
otherCard.id === 'ezra' || otherCard.id === 'cal_kestis' ||
otherCard.id === 'yoda')) {
other.synergyAttackBonus = (other.synergyAttackBonus || 0) + 1;
other.synergyHealthBonus = (other.synergyHealthBonus || 0) + 1;
}
}
});
}
} }
// Йода даёт +1/+1 всем джедаям // Йода даёт +1/+1 всем джедаям
@ -1390,11 +1443,11 @@ function playSpell(room, socketId, handIndex, targetPlayerIndex, targetBoardInde
const eff = card.spellEffect; const eff = card.spellEffect;
const needTarget = card.spellTarget && card.spellTarget !== 'none'; const needTarget = card.spellTarget && card.spellTarget !== 'none';
// Специальная обработка для steal_cards - требует только выбор противника (не требует targetBoardIndex) // Специальная обработка для steal_cards - требует выбор противника и карт с его доски
if (eff === 'steal_cards') { if (eff === 'steal_cards') {
if (targetPlayerIndex == null || targetPlayerIndex === pi) return; if (targetPlayerIndex == null || targetPlayerIndex === pi) return;
const targetPlayer = gameState.players[targetPlayerIndex]; const targetPlayer = gameState.players[targetPlayerIndex];
if (!targetPlayer || targetPlayer.health <= 0 || !targetPlayer.deck || targetPlayer.deck.length === 0) return; if (!targetPlayer || targetPlayer.health <= 0 || !targetPlayer.board || targetPlayer.board.length === 0) return;
// Отправляем запрос на выбор карт для кражи // Отправляем запрос на выбор карт для кражи
const socket = io.sockets.sockets.get(p.id); const socket = io.sockets.sockets.get(p.id);
@ -1402,8 +1455,8 @@ function playSpell(room, socketId, handIndex, targetPlayerIndex, targetBoardInde
socket.emit('stealCardsRequest', { socket.emit('stealCardsRequest', {
targetPlayerIndex: targetPlayerIndex, targetPlayerIndex: targetPlayerIndex,
targetPlayerName: targetPlayer.name || `Игрок ${targetPlayerIndex + 1}`, targetPlayerName: targetPlayer.name || `Игрок ${targetPlayerIndex + 1}`,
targetDeckSize: targetPlayer.deck.length, targetBoardSize: targetPlayer.board.length,
maxCards: Math.min(2, targetPlayer.deck.length) maxCards: Math.min(2, targetPlayer.board.length)
}); });
} }
return; // Не тратим ману и не удаляем карту пока - это сделаем после выбора return; // Не тратим ману и не удаляем карту пока - это сделаем после выбора
@ -1579,22 +1632,25 @@ function stealCardsFromDeck(room, socketId, handIndex, targetPlayerIndex, cardIn
const targetPlayer = gameState.players[targetPlayerIndex]; const targetPlayer = gameState.players[targetPlayerIndex];
if (!targetPlayer || targetPlayerIndex === pi || targetPlayer.health <= 0) return; if (!targetPlayer || targetPlayerIndex === pi || targetPlayer.health <= 0) return;
if (!targetPlayer.deck || targetPlayer.deck.length === 0) return; if (!targetPlayer.board || targetPlayer.board.length === 0) return;
// Проверяем индексы карт // Проверяем индексы карт на доске
if (!Array.isArray(cardIndices) || cardIndices.length === 0 || cardIndices.length > 2) return; if (!Array.isArray(cardIndices) || cardIndices.length === 0 || cardIndices.length > 2) return;
const validIndices = cardIndices.filter(idx => idx >= 0 && idx < targetPlayer.deck.length); const validIndices = cardIndices.filter(idx => idx >= 0 && idx < targetPlayer.board.length);
if (validIndices.length === 0) return; if (validIndices.length === 0) return;
// Убираем дубликаты и сортируем по убыванию (чтобы удалять с конца) // Убираем дубликаты и сортируем по убыванию (чтобы удалять с конца)
const uniqueIndices = [...new Set(validIndices)].sort((a, b) => b - a); const uniqueIndices = [...new Set(validIndices)].sort((a, b) => b - a);
// Крадём карты // Крадём карты с доски противника
const stolenCards = []; const stolenCards = [];
uniqueIndices.forEach(idx => { uniqueIndices.forEach(boardIdx => {
if (idx >= 0 && idx < targetPlayer.deck.length) { if (boardIdx >= 0 && boardIdx < targetPlayer.board.length) {
stolenCards.push(targetPlayer.deck[idx]); const minion = targetPlayer.board[boardIdx];
targetPlayer.deck.splice(idx, 1); if (minion && minion.cardId) {
stolenCards.push(minion.cardId);
targetPlayer.board.splice(boardIdx, 1);
}
} }
}); });