This commit is contained in:
2026-01-27 22:57:31 +03:00
parent 14d46962d4
commit e1533ea03d
4 changed files with 102 additions and 47 deletions

View File

@ -284,9 +284,10 @@
if (!spectatorBadge) { if (!spectatorBadge) {
const badge = document.createElement('div'); const badge = document.createElement('div');
badge.id = 'spectator-badge'; badge.id = 'spectator-badge';
badge.style.cssText = 'position: fixed; top: 1rem; right: 1rem; background: rgba(212,168,75,0.9); color: #000; padding: 0.5rem 1rem; border-radius: 8px; font-weight: 700; z-index: 200;'; badge.style.cssText = 'position: fixed; top: 1rem; right: 1rem; background: rgba(212,168,75,0.9); color: #000; padding: 0.5rem 1rem; border-radius: 8px; font-weight: 700; z-index: 200; display: flex; align-items: center; gap: 0.5rem;';
badge.textContent = '👁 НАБЛЮДАТЕЛЬ'; badge.innerHTML = '<i data-lucide="eye" style="width: 18px; height: 18px;"></i><span>НАБЛЮДАТЕЛЬ</span>';
document.body.appendChild(badge); document.body.appendChild(badge);
if (typeof lucide !== 'undefined') lucide.createIcons();
} }
} else { } else {
const spectatorBadge = $('spectator-badge'); const spectatorBadge = $('spectator-badge');
@ -367,6 +368,11 @@
resetBtn.classList.toggle('hidden', state.yourIndex !== 0); resetBtn.classList.toggle('hidden', state.yourIndex !== 0);
} }
bindGameEvents(state); bindGameEvents(state);
// Обновляем иконки Lucide после рендеринга
if (typeof lucide !== 'undefined') {
setTimeout(() => lucide.createIcons(), 100);
}
} }
function showGameOver(state) { function showGameOver(state) {
@ -435,18 +441,22 @@
const isCurrent = state.currentPlayerIndex === i; const isCurrent = state.currentPlayerIndex === i;
const isDead = p.health <= 0 || p.isDead; const isDead = p.health <= 0 || p.isDead;
const name = p.name || 'Игрок ' + (i + 1); const name = p.name || 'Игрок ' + (i + 1);
const isAI = p.isAI || false;
const minions = (p.board || []).map((m, j) => renderBoardMinion(m, i, j, state, true, false)); const minions = (p.board || []).map((m, j) => renderBoardMinion(m, i, j, state, true, false));
const heroBar = renderHeroTarget(i, state); const heroBar = renderHeroTarget(i, state);
const heroDrop = renderHeroDropZone(i, state); const heroDrop = renderHeroDropZone(i, state);
const canSteal = !state.isSpectator && state.currentPlayerIndex === state.yourIndex && spellMode.active && spellMode.cardId && cardDb[spellMode.cardId]?.spellEffect === 'steal_cards'; const canSteal = !state.isSpectator && state.currentPlayerIndex === state.yourIndex && spellMode.active && spellMode.cardId && cardDb[spellMode.cardId]?.spellEffect === 'steal_cards';
return ` return `
<div class="opponent-block ${isCurrent ? 'current-turn' : ''} ${canSteal ? 'steal-target' : ''} ${isDead ? 'defeated' : ''}" data-opponent-index="${i}" data-player-index="${i}"> <div class="opponent-block ${isCurrent ? 'current-turn' : ''} ${canSteal ? 'steal-target' : ''} ${isDead ? 'defeated' : ''}" data-opponent-index="${i}" data-player-index="${i}">
<div class="opponent-name ${isDead ? 'defeated-name' : ''}">${escapeHtml(name)}${isDead ? ' <span class="defeated-badge">✝</span>' : ''}</div> <div class="opponent-name ${isDead ? 'defeated-name' : ''}">
${isAI ? '<i data-lucide="bot" style="width: 16px; height: 16px; vertical-align: middle; margin-right: 0.3rem; color: var(--cyan);"></i>' : ''}
${escapeHtml(name)}${isDead ? ' <span class="defeated-badge"><i data-lucide="skull" style="width: 14px; height: 14px; vertical-align: middle;"></i></span>' : ''}
</div>
<div class="opponent-stats ${isDead ? 'defeated-stats' : ''}"> <div class="opponent-stats ${isDead ? 'defeated-stats' : ''}">
<span class="opponent-health">${p.health ?? 30}</span> <span class="opponent-health"><i data-lucide="heart" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.2rem; color: #e63946;"></i>${p.health ?? 30}</span>
${(p.armor || 0) > 0 ? `<span class="opponent-armor">🛡 ${p.armor}</span>` : ''} ${(p.armor || 0) > 0 ? `<span class="opponent-armor"><i data-lucide="shield" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.2rem; color: #5eb3e8;"></i>${p.armor}</span>` : ''}
<span>🔵 ${p.mana ?? 0}/${p.maxMana ?? 0}</span> <span><i data-lucide="zap" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.2rem; color: #00d4ff;"></i>${p.mana ?? 0}/${p.maxMana ?? 0}</span>
${p.deck && p.deck.length > 0 ? `<span>📚 ${p.deck.length}</span>` : ''} ${p.deck && p.deck.length > 0 ? `<span><i data-lucide="book-open" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.2rem; color: var(--gold);"></i>${p.deck.length}</span>` : ''}
</div> </div>
<div class="opponent-board">${heroDrop}${heroBar}${minions.join('')}</div> <div class="opponent-board">${heroDrop}${heroBar}${minions.join('')}</div>
</div>`; </div>`;
@ -526,7 +536,7 @@
const attackerName = attackerCard?.name || 'Миньон'; const attackerName = attackerCard?.name || 'Миньон';
const targetName = targetCard?.name || 'Миньон'; const targetName = targetCard?.name || 'Миньон';
const damage = logEntry.damage || attackerMinion?.attack || 0; const damage = logEntry.damage || attackerMinion?.attack || 0;
text = who(attackerIdx) + ' → ' + attackerName + ' атакует ' + targetName + ' (' + damage + ' урона) → ' + who(targetIdx); text = who(attackerIdx) + ' → ' + attackerName + ' <i data-lucide="swords" style="width: 14px; height: 14px; vertical-align: middle; display: inline-block;"></i> атакует ' + targetName + ' (' + damage + ' урона) → ' + who(targetIdx);
} }
} else if (logEntry.type === 'attackHero' && logEntry.fromPlayer !== undefined && logEntry.toPlayer !== undefined) { } else if (logEntry.type === 'attackHero' && logEntry.fromPlayer !== undefined && logEntry.toPlayer !== undefined) {
const attackerPlayer = state.players[logEntry.fromPlayer]; const attackerPlayer = state.players[logEntry.fromPlayer];
@ -537,10 +547,10 @@
const attackerCard = cardDb[attackerMinion?.cardId]; const attackerCard = cardDb[attackerMinion?.cardId];
const attackerName = attackerCard?.name || 'Миньон'; const attackerName = attackerCard?.name || 'Миньон';
const damage = logEntry.damage || attackerMinion?.attack || 0; const damage = logEntry.damage || attackerMinion?.attack || 0;
text = who(logEntry.fromPlayer) + ' → ' + attackerName + ' атакует героя ' + who(logEntry.toPlayer) + ' (' + damage + ' урона)!'; text = who(logEntry.fromPlayer) + ' → ' + attackerName + ' <i data-lucide="swords" style="width: 14px; height: 14px; vertical-align: middle; display: inline-block;"></i> атакует героя ' + who(logEntry.toPlayer) + ' (' + damage + ' урона)!';
} else { } else {
const damage = logEntry.damage || 0; const damage = logEntry.damage || 0;
text = who(logEntry.fromPlayer) + ' атакует героя ' + who(logEntry.toPlayer) + ' (' + damage + ' урона)!'; text = who(logEntry.fromPlayer) + ' <i data-lucide="swords" style="width: 14px; height: 14px; vertical-align: middle; display: inline-block;"></i> атакует героя ' + who(logEntry.toPlayer) + ' (' + damage + ' урона)!';
} }
} }
} else if (logEntry.type === 'spell' && logEntry.fromPlayer !== undefined && logEntry.toPlayer !== undefined) { } else if (logEntry.type === 'spell' && logEntry.fromPlayer !== undefined && logEntry.toPlayer !== undefined) {
@ -1112,7 +1122,7 @@
var heroCls = 'drop-target drop-target-hero' + (spellHero ? ' spell-target' : '') + (heroAb ? ' hero-ability-target' : ''); var heroCls = 'drop-target drop-target-hero' + (spellHero ? ' spell-target' : '') + (heroAb ? ' hero-ability-target' : '');
var title = spellHero ? 'Цель заклинания' : (heroAb ? 'Цель геройской способности' : 'Перетащи сюда миньона для атаки по лидеру'); var title = spellHero ? 'Цель заклинания' : (heroAb ? 'Цель геройской способности' : 'Перетащи сюда миньона для атаки по лидеру');
return '<div class="' + heroCls + '" data-drop-player="' + playerIndex + '" data-drop-board="-1" title="' + title + '">' return '<div class="' + heroCls + '" data-drop-player="' + playerIndex + '" data-drop-board="-1" title="' + title + '">'
+ '<span class="drop-hero-icon"></span>' + '<span class="drop-hero-icon"><i data-lucide="heart" style="width: 18px; height: 18px; color: #e63946;"></i></span>'
+ '<span class="drop-hero-name">' + escapeHtml(name) + '</span>' + '<span class="drop-hero-name">' + escapeHtml(name) + '</span>'
+ '</div>'; + '</div>';
} }
@ -1124,7 +1134,7 @@
return ` return `
<div class="card-wrap targetable hero-target drop-target" data-player-index="${playerIndex}" data-board-index="-1" data-drop-player="${playerIndex}" data-drop-board="-1"> <div class="card-wrap targetable hero-target drop-target" data-player-index="${playerIndex}" data-board-index="-1" data-drop-player="${playerIndex}" data-drop-board="-1">
<div class="card faction-neutral"> <div class="card faction-neutral">
<div class="card-art"></div> <div class="card-art"><i data-lucide="heart" style="width: 48px; height: 48px; color: #e63946;"></i></div>
<div class="card-info"> <div class="card-info">
<div class="card-name">${escapeHtml(name)} (лидер)</div> <div class="card-name">${escapeHtml(name)} (лидер)</div>
<div class="card-stats"><span class="hp">${p?.health ?? 30}</span></div> <div class="card-stats"><span class="hp">${p?.health ?? 30}</span></div>
@ -2183,7 +2193,8 @@
const statusColor = room.gameStarted ? 'var(--amber)' : 'var(--cyan)'; const statusColor = room.gameStarted ? 'var(--amber)' : 'var(--cyan)';
const playersText = room.players.length > 0 ? room.players.join(', ') : 'Нет игроков'; const playersText = room.players.length > 0 ? room.players.join(', ') : 'Нет игроков';
const canJoin = !room.gameStarted && room.playerCount < room.maxPlayers; const canJoin = !room.gameStarted && room.playerCount < room.maxPlayers;
const actionText = room.gameStarted ? '👁 Наблюдать' : (canJoin ? '▶ Подключиться' : 'Полная'); const actionIcon = room.gameStarted ? '<i data-lucide="eye" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.3rem;"></i>' : (canJoin ? '<i data-lucide="play" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.3rem;"></i>' : '');
const actionText = room.gameStarted ? 'Наблюдать' : (canJoin ? 'Подключиться' : 'Полная');
const actionClass = room.gameStarted ? 'btn-ghost' : (canJoin ? 'btn-primary' : 'btn-ghost'); const actionClass = room.gameStarted ? 'btn-ghost' : (canJoin ? 'btn-primary' : 'btn-ghost');
const actionDisabled = !room.gameStarted && !canJoin; const actionDisabled = !room.gameStarted && !canJoin;
@ -2196,11 +2207,11 @@
<div style="text-align: right; font-size: 0.85rem; color: #94a3b8;"> <div style="text-align: right; font-size: 0.85rem; color: #94a3b8;">
<div>Игроки: ${room.playerCount}/${room.maxPlayers}</div> <div>Игроки: ${room.playerCount}/${room.maxPlayers}</div>
${room.spectators > 0 ? `<div>Наблюдателей: ${room.spectators}</div>` : ''} ${room.spectators > 0 ? `<div>Наблюдателей: ${room.spectators}</div>` : ''}
${room.hasAI ? '<div style="color: var(--amber);">🤖 ИИ</div>' : ''} ${room.hasAI ? '<div style="color: var(--amber); display: inline-flex; align-items: center; gap: 0.3rem;"><i data-lucide="bot" style="width: 14px; height: 14px;"></i>ИИ</div>' : ''}
</div> </div>
</div> </div>
<div style="font-size: 0.8rem; color: #94a3b8; margin-bottom: 0.5rem;">${escapeHtml(playersText)}</div> <div style="font-size: 0.8rem; color: #94a3b8; margin-bottom: 0.5rem;">${escapeHtml(playersText)}</div>
<button type="button" class="btn ${actionClass}" data-room-code="${room.code}" ${actionDisabled ? 'disabled' : ''} style="width: 100%;">${actionText}</button> <button type="button" class="btn ${actionClass}" data-room-code="${room.code}" ${actionDisabled ? 'disabled' : ''} style="width: 100%;">${actionIcon}${actionText}</button>
</div>`; </div>`;
}).join(''); }).join('');
@ -2222,6 +2233,11 @@
} }
}); });
}); });
// Обновляем иконки Lucide после создания кнопок
if (typeof lucide !== 'undefined') {
setTimeout(() => lucide.createIcons(), 100);
}
}; };
$('btn-instructions')?.addEventListener('click', () => { $('btn-instructions')?.addEventListener('click', () => {
$('instructions-overlay')?.classList.remove('hidden'); $('instructions-overlay')?.classList.remove('hidden');
@ -2803,9 +2819,19 @@
if (window.Music) { if (window.Music) {
window.Music.init(); window.Music.init();
} }
// Инициализация Lucide Icons после загрузки DOM
if (typeof lucide !== 'undefined') {
lucide.createIcons();
// Обновляем иконки при изменении DOM
const observer = new MutationObserver(() => {
lucide.createIcons();
});
observer.observe(document.body, { childList: true, subtree: true });
}
}); });
} else { } else {
init(); init();
if (typeof lucide !== 'undefined') lucide.createIcons();
if (window.Music) { if (window.Music) {
window.Music.init(); window.Music.init();
} }

View File

@ -11,6 +11,7 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;800&family=Rajdhani:wght@400;600;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;800&family=Rajdhani:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="starwars-glyphicons/css/starwars-glyphicons.css"> <link rel="stylesheet" href="starwars-glyphicons/css/starwars-glyphicons.css">
<script src="https://unpkg.com/lucide@latest"></script>
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
</head> </head>
<body> <body>
@ -29,8 +30,8 @@
</h1> </h1>
<p class="subtitle">PvP до 4 игроков · Игра с ИИ · Работает через Radmin VPN</p> <p class="subtitle">PvP до 4 игроков · Игра с ИИ · Работает через Radmin VPN</p>
<button type="button" id="btn-instructions-lobby" class="btn-instructions-lobby" title="Как играть">?</button> <button type="button" id="btn-instructions-lobby" class="btn-instructions-lobby" title="Как играть">?</button>
<button type="button" id="btn-cards-gallery" class="btn-instructions-lobby" title="Галерея карт" style="right: 3.5rem;">📚</button> <button type="button" id="btn-cards-gallery" class="btn-instructions-lobby" title="Галерея карт" style="right: 3.5rem;"><i data-lucide="book-open"></i></button>
<button type="button" id="btn-settings-lobby" class="btn-settings-lobby" title="Настройки"></button> <button type="button" id="btn-settings-lobby" class="btn-settings-lobby" title="Настройки"><i data-lucide="settings"></i></button>
<div class="lobby-tabs"> <div class="lobby-tabs">
<button type="button" class="tab active" data-tab="host">Создать игру</button> <button type="button" class="tab active" data-tab="host">Создать игру</button>
@ -91,7 +92,7 @@
<div id="browse-panel" class="panel hidden"> <div id="browse-panel" class="panel hidden">
<label>Ваше имя</label> <label>Ваше имя</label>
<input type="text" id="browse-name" placeholder="Игрок" maxlength="20" /> <input type="text" id="browse-name" placeholder="Игрок" maxlength="20" />
<button type="button" id="btn-refresh-rooms" class="btn btn-ghost" style="margin-top: 0.5rem;">🔄 Обновить список</button> <button type="button" id="btn-refresh-rooms" class="btn btn-ghost" style="margin-top: 0.5rem;"><i data-lucide="refresh-cw" style="width: 16px; height: 16px; margin-right: 0.5rem; vertical-align: middle;"></i>Обновить список</button>
<div id="rooms-list" class="rooms-list" style="margin-top: 1rem; max-height: 400px; overflow-y: auto;"> <div id="rooms-list" class="rooms-list" style="margin-top: 1rem; max-height: 400px; overflow-y: auto;">
<p class="hint" style="text-align: center; padding: 2rem; color: #94a3b8;">Нажмите "Обновить список" для поиска игр</p> <p class="hint" style="text-align: center; padding: 2rem; color: #94a3b8;">Нажмите "Обновить список" для поиска игр</p>
</div> </div>
@ -103,7 +104,7 @@
<div id="cards-gallery-overlay" class="modal-overlay hidden"> <div id="cards-gallery-overlay" class="modal-overlay hidden">
<div class="modal cards-gallery-modal"> <div class="modal cards-gallery-modal">
<h2>📚 Галерея карт</h2> <h2><i data-lucide="book-open" style="width: 20px; height: 20px; vertical-align: middle; margin-right: 0.5rem;"></i>Галерея карт</h2>
<div class="gallery-controls"> <div class="gallery-controls">
<select id="gallery-faction-filter" class="gallery-filter"> <select id="gallery-faction-filter" class="gallery-filter">
<option value="">Все фракции</option> <option value="">Все фракции</option>
@ -190,18 +191,18 @@
<header class="game-header"> <header class="game-header">
<div class="header-left"> <div class="header-left">
<span class="mana-display"> <span class="mana-display">
<i class="swg swg-credits mana-icon" aria-hidden="true"></i> <i data-lucide="zap" style="width: 18px; height: 18px; color: #00d4ff;"></i>
<span id="your-mana">0</span>/<span id="your-max-mana">0</span> <span id="your-mana">0</span>/<span id="your-max-mana">0</span>
</span> </span>
<span class="health-display"> <span class="health-display">
<i class="swg swg-deathstar health-icon" aria-hidden="true"></i> <i data-lucide="heart" style="width: 18px; height: 18px; color: #e63946;"></i>
<span id="your-health">30</span> <span id="your-health">30</span>
</span> </span>
<span class="armor-display" id="armor-display" style="display: none;"> <span class="armor-display" id="armor-display" style="display: none;">
<i class="swg swg-deathstar armor-icon" aria-hidden="true"></i> <i data-lucide="shield" style="width: 18px; height: 18px; color: #5eb3e8;"></i>
<span id="your-armor">0</span> <span id="your-armor">0</span>
</span> </span>
<span class="deck-count"><i class="swg swg-galrep deck-icon" aria-hidden="true"></i><span id="your-deck">0</span> в колоде</span> <span class="deck-count"><i data-lucide="book-open" style="width: 16px; height: 16px; color: var(--gold); margin-right: 0.2rem; vertical-align: middle;"></i><span id="your-deck">0</span> в колоде</span>
</div> </div>
<div class="header-center"> <div class="header-center">
<span class="turn-badge" id="turn-badge">Ход 1</span> <span class="turn-badge" id="turn-badge">Ход 1</span>
@ -212,7 +213,7 @@
<button type="button" id="btn-reset-lobby" class="btn btn-ghost hidden" title="Сбросить игру и вернуться в лобби">Вернуться в лобби</button> <button type="button" id="btn-reset-lobby" class="btn btn-ghost hidden" title="Сбросить игру и вернуться в лобби">Вернуться в лобби</button>
</div> </div>
<div class="header-right"> <div class="header-right">
<button type="button" id="btn-cards-gallery-game" class="btn-instructions" title="Галерея карт" style="right: 3.5rem;">📚</button> <button type="button" id="btn-cards-gallery-game" class="btn-instructions" title="Галерея карт" style="right: 3.5rem;"><i data-lucide="book-open"></i></button>
<button type="button" id="btn-instructions" class="btn-instructions" title="Инструкция">?</button> <button type="button" id="btn-instructions" class="btn-instructions" title="Инструкция">?</button>
<button type="button" id="btn-settings" class="btn-settings" title="Настройки"></button> <button type="button" id="btn-settings" class="btn-settings" title="Настройки"></button>
</div> </div>
@ -256,7 +257,7 @@
<h2 id="modal-title">Результат</h2> <h2 id="modal-title">Результат</h2>
<p id="modal-body"></p> <p id="modal-body"></p>
<div class="modal-actions" style="display: flex; gap: 0.5rem; margin-top: 1rem; justify-content: center;"> <div class="modal-actions" style="display: flex; gap: 0.5rem; margin-top: 1rem; justify-content: center;">
<button type="button" id="btn-new-game" class="btn btn-primary" style="display: none;">🔄 Новая игра</button> <button type="button" id="btn-new-game" class="btn btn-primary" style="display: none;"><i data-lucide="refresh-cw" style="width: 16px; height: 16px; margin-right: 0.5rem; vertical-align: middle;"></i>Новая игра</button>
<button type="button" id="btn-modal-close" class="btn btn-ghost">Закрыть</button> <button type="button" id="btn-modal-close" class="btn btn-ghost">Закрыть</button>
</div> </div>
</div> </div>
@ -330,7 +331,7 @@
</div> </div>
<div id="steal-cards-overlay" class="modal-overlay hidden"> <div id="steal-cards-overlay" class="modal-overlay hidden">
<div class="modal steal-cards-modal"> <div class="modal steal-cards-modal">
<h2>Грабеж</h2> <h2><i data-lucide="swords" style="width: 20px; height: 20px; vertical-align: middle; margin-right: 0.5rem;"></i>Грабеж</h2>
<p class="hint" id="steal-cards-hint" style="font-size: 0.85rem; margin-bottom: 1rem;">Выберите противника и до 2 карт из его колоды</p> <p class="hint" id="steal-cards-hint" style="font-size: 0.85rem; margin-bottom: 1rem;">Выберите противника и до 2 карт из его колоды</p>
<div id="steal-target-select" class="steal-target-select"></div> <div id="steal-target-select" class="steal-target-select"></div>
<div id="steal-deck-list" class="steal-deck-list hidden"></div> <div id="steal-deck-list" class="steal-deck-list hidden"></div>
@ -366,5 +367,18 @@
<script src="sounds.js"></script> <script src="sounds.js"></script>
<script src="music.js"></script> <script src="music.js"></script>
<script src="game.js"></script> <script src="game.js"></script>
<script>
// Инициализация Lucide Icons после загрузки всех скриптов
if (typeof lucide !== 'undefined') {
document.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
// Обновляем иконки при изменении DOM
const observer = new MutationObserver(() => {
lucide.createIcons();
});
observer.observe(document.body, { childList: true, subtree: true });
});
}
</script>
</body> </body>
</html> </html>

View File

@ -314,11 +314,13 @@ html, body {
gap: 1rem; gap: 1rem;
} }
.mana-display, .health-display { .mana-display, .health-display, .armor-display {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 0.35rem; gap: 0.35rem;
font-weight: 700; font-weight: 700;
}
.mana-display, .health-display {
font-size: 1.15rem; font-size: 1.15rem;
} }
@ -735,9 +737,21 @@ html, body {
z-index: 11; z-index: 11;
} }
.opponent-name { font-weight: 700; color: var(--cyan); margin-bottom: 0.35rem; font-size: 0.95rem; } .opponent-name { font-weight: 700; color: var(--cyan); margin-bottom: 0.35rem; font-size: 0.95rem; }
.opponent-armor { color: #5eb3e8; font-weight: 600; } .opponent-armor { color: #5eb3e8; font-weight: 600; display: inline-flex; align-items: center; gap: 0.2rem; }
.armor-display { color: #5eb3e8; font-weight: 600; margin-left: 0.5rem; } .armor-display { color: #5eb3e8; font-weight: 600; margin-left: 0.5rem; display: inline-flex; align-items: center; gap: 0.3rem; }
.armor-icon { color: #5eb3e8; } .armor-icon { color: #5eb3e8; }
.opponent-health, .opponent-stats span { display: inline-flex; align-items: center; gap: 0.2rem; }
.opponent-name { display: flex; align-items: center; gap: 0.3rem; }
/* Lucide Icons стилизация */
[data-lucide] {
stroke-width: 2;
vertical-align: middle;
}
.opponent-name [data-lucide="bot"] {
color: var(--cyan);
filter: drop-shadow(0 0 4px rgba(0, 212, 255, 0.5));
}
.opponent-name.defeated-name { .opponent-name.defeated-name {
text-decoration: line-through; text-decoration: line-through;
color: #666; color: #666;

View File

@ -451,6 +451,7 @@ function broadcastGameState(room) {
yourDeckCount: p.deck.length, yourDeckCount: p.deck.length,
yourManualDrawUsed: !!p.manualDrawUsed, yourManualDrawUsed: !!p.manualDrawUsed,
yourHeroAbilityUsed: !!p.heroAbilityUsed, yourHeroAbilityUsed: !!p.heroAbilityUsed,
yourArmor: p.armor || 0,
cardDb: cardDb, cardDb: cardDb,
}; };
socket.emit('gameState', yourView); socket.emit('gameState', yourView);