Здесь делается вжух 🪄

test

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » test » Тестовый форум » боссфайт


боссфайт

Сообщений 1 страница 12 из 12

1

1

0

2

[html]
<div class="monster-attack-result" data-attack="CjxkaXYgY2xhc3M9Im1vbnN0ZXItYXR0YWNrLXBvc3QiIHN0eWxlPSIKICAgIGJvcmRlcjogM3B4IHNvbGlkICNmZjZiNmI7CiAgICBib3JkZXItcmFkaXVzOiAxNXB4OwogICAgcGFkZGluZzogMjBweDsKICAgIGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCgxMzVkZWcsICMxYTFhMmUgMCUsICMxNjIxM2UgMTAwJSk7CiAgICBtYXJnaW46IDE1cHggMDsKICAgIGNvbG9yOiB3aGl0ZTsKICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsKICAgIGJveC1zaGFkb3c6IDAgMTBweCAzMHB4IHJnYmEoMCwwLDAsMC41KTsKIj4KICAgIDxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsgbWFyZ2luLWJvdHRvbTogMjBweDsiPgogICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMjJweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjZmY2YjZiOyBtYXJnaW4tYm90dG9tOiA4cHg7Ij4KICAgICAgICAgICAgJiM5ODc2OyYjNjUwMzk7INCQ0KLQkNCa0JAg0J3QkCDQkdCe0KHQodCQICYjOTg3NjsmIzY1MDM5OwogICAgICAgIDwvZGl2PgogICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICNhYWE7Ij4KICAgICAgICAgICAgMjAuMTIuMjAyNSwgMDI6MTI6MDQKICAgICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgCiAgICA8ZGl2IHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47IGFsaWduLWl0ZW1zOiBjZW50ZXI7IG1hcmdpbi1ib3R0b206IDIwcHg7IHBhZGRpbmc6IDE1cHg7IGJhY2tncm91bmQ6IHJnYmEoMCwwLDAsMC4zKTsgYm9yZGVyLXJhZGl1czogMTBweDsiPgogICAgICAgIDxkaXYgc3R5bGU9ImZsZXg6IDE7Ij4KICAgICAgICAgICAgPGRpdiBzdHlsZT0iZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICM0ZWNkYzQ7IG1hcmdpbi1ib3R0b206IDVweDsiPgogICAgICAgICAgICAgICAgYWRtaW4KICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMTNweDsgY29sb3I6ICM4ODg7Ij4KICAgICAgICAgICAgICAgINCj0YDQvtC9OiA0MyB8INCQ0YLQsNC6OiAxCiAgICAgICAgICAgIDwvZGl2PgogICAgICAgIDwvZGl2PgogICAgICAgIAogICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMzJweDsgbWFyZ2luOiAwIDIwcHg7Ij4KICAgICAgICAgICAgJiM5ODc2OyYjNjUwMzk7CiAgICAgICAgPC9kaXY+CiAgICAgICAgCiAgICAgICAgPGRpdiBzdHlsZT0iZmxleDogMTsgdGV4dC1hbGlnbjogcmlnaHQ7Ij4KICAgICAgICAgICAgPGRpdiBzdHlsZT0iZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICNmZjZiNmI7IG1hcmdpbi1ib3R0b206IDVweDsiPgogICAgICAgICAgICAgICAgJiMxMjgyOTM7INCT0J3QldCS0J3Qq9CZINCU0KDQkNCa0J7QnQogICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgPGRpdiBzdHlsZT0iZm9udC1zaXplOiAxM3B4OyBjb2xvcjogIzg4ODsiPgogICAgICAgICAgICAgICAgSFA6IDk1Ny8xMDAwCiAgICAgICAgICAgIDwvZGl2PgogICAgICAgIDwvZGl2PgogICAgPC9kaXY+CiAgICAKICAgIDxkaXYgc3R5bGU9ImJhY2tncm91bmQ6IHJnYmEoMCwwLDAsMC40KTsgYm9yZGVyLXJhZGl1czogMTBweDsgcGFkZGluZzogMjBweDsgbWFyZ2luOiAxNXB4IDA7Ij4KICAgICAgICA8ZGl2IHN0eWxlPSJmb250LXNpemU6IDI0cHg7IHRleHQtYWxpZ246IGNlbnRlcjsgbWFyZ2luLWJvdHRvbTogMTVweDsiPgogICAgICAgICAgICA8c3BhbiBzdHlsZT0iY29sb3I6ICNmZmQxNjY7Ij7QndCw0L3QtdGB0LXQvdC+INGD0YDQvtC90LA6PC9zcGFuPgogICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAzMnB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICNmZjZiNmI7IG1hcmdpbi1sZWZ0OiAxNXB4OyI+CiAgICAgICAgICAgICAgICA0MwogICAgICAgICAgICA8L3NwYW4+CiAgICAgICAgPC9kaXY+CiAgICAgICAgCiAgICAgICAgPGRpdiBzdHlsZT0ibWFyZ2luOiAyMHB4IDA7IHBhZGRpbmc6IDEwcHg7IGJhY2tncm91bmQ6IHJnYmEoMCwwLDAsMC4zKTsgYm9yZGVyLXJhZGl1czogOHB4OyI+CiAgICAgICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICNhYWE7IG1hcmdpbi1ib3R0b206IDVweDsiPtCX0LTQvtGA0L7QstGM0LUg0LHQvtGB0YHQsDo8L2Rpdj4KICAgICAgICAgICAgPGRpdiBzdHlsZT0iaGVpZ2h0OiAyNXB4OyBiYWNrZ3JvdW5kOiAjMzMzOyBib3JkZXItcmFkaXVzOiAxMnB4OyBvdmVyZmxvdzogaGlkZGVuOyBwb3NpdGlvbjogcmVsYXRpdmU7Ij4KICAgICAgICAgICAgICAgIDxkaXYgc3R5bGU9IgogICAgICAgICAgICAgICAgICAgIGhlaWdodDogMTAwJTsKICAgICAgICAgICAgICAgICAgICB3aWR0aDogOTUuNyU7CiAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDkwZGVnLCAjNENBRjUwLCAjOEJDMzRBKTsKICAgICAgICAgICAgICAgICAgICB0cmFuc2l0aW9uOiB3aWR0aCAxcyBlYXNlOwogICAgICAgICAgICAgICAgICAgIGJvcmRlci1yYWRpdXM6IDEycHg7CiAgICAgICAgICAgICAgICAiPjwvZGl2PgogICAgICAgICAgICAgICAgPGRpdiBzdHlsZT0icG9zaXRpb246IGFic29sdXRlOyB0b3A6IDA7IGxlZnQ6IDA7IHJpZ2h0OiAwOyBib3R0b206IDA7IGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGp1c3RpZnktY29udGVudDogY2VudGVyOyBjb2xvcjogd2hpdGU7IGZvbnQtd2VpZ2h0OiBib2xkOyI+CiAgICAgICAgICAgICAgICAgICAgOTU3LzEwMDAgKDk2JSkKICAgICAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICA8L2Rpdj4KICAgICAgICA8L2Rpdj4KICAgICAgICAKICAgICAgICAKICAgICAgICAKICAgICAgICAKICAgIDwvZGl2PgogICAgCiAgICA8ZGl2IHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47IGZvbnQtc2l6ZTogMTJweDsgY29sb3I6ICM2NjY7IG1hcmdpbi10b3A6IDIwcHg7IHBhZGRpbmctdG9wOiAxNXB4OyBib3JkZXItdG9wOiAxcHggc29saWQgIzQ0NDsiPgogICAgICAgIDxkaXY+TW9uc3RlciBCYXR0bGUgdjEuMCB8IElEOiAyPC9kaXY+CiAgICAgICAgPGRpdj7Qm9GD0YfRiNC40Lkg0YPQtNCw0YA6IDQzPC9kaXY+CiAgICAgICAgPGRpdj7Qo9Cx0LjRgtC+INCx0L7RgdGB0L7QsjogMDwvZGl2PgogICAgPC9kaXY+CjwvZGl2Pg==">
Загрузка результата атаки...
</div>

<script>
(function(){
    try {
        var encoded = document.querySelector(".monster-attack-result").getAttribute("data-attack");
        var html = decodeURIComponent(escape(atob(encoded)));
        document.querySelector(".monster-attack-result").innerHTML = html;
       
        // Анимация
        var el = document.querySelector(".monster-attack-result");
        el.style.animation = "monsterPulse 0.5s";
        setTimeout(() => el.style.animation = "", 500);
    } catch(e){
        document.querySelector(".monster-attack-result").innerHTML = "<b>Ошибка загрузки результата</b>";
    }
})();
</script>

<style>
@keyframes monsterPulse {
    0% { transform: scale(1); opacity: 0.8; }
    50% { transform: scale(1.02); opacity: 1; }
    100% { transform: scale(1); opacity: 0.8; }
}
</style>
[/html]

0

3

[html]<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Битва с монстром</title>
    <style>
        * { margin:0; padding:0; box-sizing:border-box; font-family:Arial, sans-serif; }
        body { background:#0a0a14; color:#fff; padding:20px; }
       
        .game-box {
            display:flex; gap:20px; max-width:1200px; margin:0 auto;
            background:#1a1a2e; border-radius:10px; padding:20px;
        }
       
        .left-side { width:250px; }
        .right-side { flex:1; }
       
        .block { background:#252540; border-radius:8px; padding:15px; margin-bottom:15px; }
        .title { color:#ff9a3c; font-weight:bold; margin-bottom:10px; border-bottom:1px solid #444; padding-bottom:8px; }
       
        .player { display:flex; justify-content:space-between; padding:8px; background:#2a2a40; margin-bottom:5px; border-radius:5px; }
        .player.me { background:#1e3a2e; border-left:3px solid #4CAF50; }
       
        .record { margin-bottom:10px; }
        .record-name { font-size:12px; color:#aaa; }
        .record-value { font-size:14px; color:#fff; font-weight:bold; }
       
        .log { padding:8px; background:#2a2a40; margin-bottom:5px; border-radius:5px; font-size:12px; color:#ccc; }
       
        .boss-area { position:relative; margin-bottom:20px; }
        .boss-img { width:100%; height:300px; object-fit:cover; border-radius:8px; border:2px solid #4a4a6d; }
        .boss-info { position:absolute; top:10px; left:10px; right:10px; }
        .boss-name { color:#ff6b6b; font-size:20px; font-weight:bold; margin-bottom:10px; }
       
        .health-box { background:rgba(0,0,0,0.7); padding:10px; border-radius:6px; }
        .health-text { display:flex; justify-content:space-between; margin-bottom:8px; color:#ffd166; }
        .health-bar { height:20px; background:#333; border-radius:10px; overflow:hidden; }
        .health-fill { height:100%; background:#4CAF50; width:100%; }
       
        .attack-box { background:#252540; border-radius:8px; padding:20px; }
        .attack-msg { width:100%; padding:12px; margin-bottom:15px; background:#2a2a40; color:#fff; border:1px solid #444; border-radius:6px; min-height:60px; }
        .attack-btn { width:100%; padding:15px; background:#ff6b6b; color:white; border:none; border-radius:8px; font-size:18px; font-weight:bold; cursor:pointer; }
        .attack-btn:disabled { background:#444; color:#888; cursor:not-allowed; }
        .last-hit { text-align:center; color:#ff6b6b; margin-top:15px; padding:10px; background:rgba(255,107,107,0.1); border-radius:6px; }
       
        .status { background:#333; padding:10px; margin-top:20px; border-radius:6px; font-size:12px; }
    </style>
</head>
<body>
    <div class="game-box">
        <div class="left-side">
            <div class="block">
                <div class="title">🏆 ТОП ИГРОКОВ</div>
                <div id="top-players">
                    <div class="player"><span>Загрузка...</span><span>0</span></div>
                </div>
            </div>
           
            <div class="block">
                <div class="title">🎯 РЕКОРДЫ</div>
                <div class="record">
                    <div class="record-name">МАКСИМАЛЬНЫЙ УРОН:</div>
                    <div class="record-value" id="max-damage">-</div>
                </div>
                <div class="record">
                    <div class="record-name">МИНИМАЛЬНЫЙ УРОН:</div>
                    <div class="record-value" id="min-damage">-</div>
                </div>
            </div>
           
            <div class="block">
                <div class="title">📜 ЖУРНАЛ</div>
                <div id="logs">
                    <div class="log">Загрузка...</div>
                </div>
            </div>
        </div>
       
        <div class="right-side">
            <div class="boss-area">
                <img class="boss-img" src="https://upforme.ru/uploads/001c/84/76/2/433839.jpg" alt="Босс">
                <div class="boss-info">
                    <div class="boss-name" id="boss-name">🔥 ГНЕВНЫЙ ДРАКОН</div>
                    <div class="health-box">
                        <div class="health-text">
                            <span>ЗДОРОВЬЕ</span>
                            <span id="health-text">1000 / 1000</span>
                        </div>
                        <div class="health-bar">
                            <div class="health-fill" id="health-bar"></div>
                        </div>
                    </div>
                </div>
            </div>
           
            <div class="attack-box">
                <textarea class="attack-msg" id="attack-msg" placeholder="Ваше сообщение (необязательно)"></textarea>
                <button class="attack-btn" id="attack-btn" onclick="attack()">АТАКОВАТЬ</button>
                <div class="last-hit" id="last-hit">-</div>
            </div>
           
            <div class="status" id="status">
                Статус: Загрузка...
            </div>
        </div>
    </div>

    <script>
        // === ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ===
        let gameData = {
            boss: null,
            player: null,
            canAttack: true
        };
       
        // === ФУНКЦИИ ОБЩЕНИЯ (СТАРЫЙ ФОРМАТ) ===
        function sendToParent(action, extraData = {}) {
            return new Promise((resolve, reject) => {
                const requestId = Date.now() + '_' + Math.random().toString(36).substr(2, 9);
                const data = {
                    _monsterGame: true,  // Старый формат
                    type: "gameRequest",
                    requestId: requestId,
                    action: action,
                    ...extraData
                };
               
                console.log('📤 Sending (old format):', action);
               
                // Отправляем сообщение
                window.parent.postMessage(data, '*');
               
                // Ждем ответ
                const handleMessage = (event) => {
                    if (event.data?._monsterGame === true && event.data.requestId === requestId) {
                        window.removeEventListener('message', handleMessage);
                        clearTimeout(timeout);
                       
                        if (event.data.error) {
                            reject(new Error(event.data.error));
                        } else {
                            resolve(event.data);
                        }
                    }
                   
                    // Также пробуем новый формат
                    if (event.data?.gameType === 'monster' && event.data.requestId === requestId) {
                        window.removeEventListener('message', handleMessage);
                        clearTimeout(timeout);
                       
                        if (event.data.error) {
                            reject(new Error(event.data.error));
                        } else {
                            // Конвертируем новый формат в старый
                            const convertedResponse = {
                                _monsterGame: true,
                                type: "gameResponse",
                                requestId: requestId,
                                data: event.data.data || event.data
                            };
                            resolve(convertedResponse);
                        }
                    }
                };
               
                window.addEventListener('message', handleMessage);
               
                // Таймаут 5 секунд
                const timeout = setTimeout(() => {
                    window.removeEventListener('message', handleMessage);
                    reject(new Error('Таймаут 5 секунд'));
                }, 5000);
            });
        }
       
        // === ЗАГРУЗКА ДАННЫХ ===
        async function loadData() {
            try {
                updateStatus('Загрузка данных...');
               
                // Пробуем загрузить все данные одним запросом
                const response = await sendToParent('getGameData');
               
                if (response.data) {
                    gameData.boss = response.data.boss || response.data;
                    gameData.allPlayers = response.data.players || {};
                    gameData.logs = response.data.logs || [];
                    gameData.records = response.data.records || {};
                   
                    updateUI();
                    updateStatus('Данные загружены');
                    return true;
                }
            } catch (error) {
                updateStatus('Ошибка загрузки: ' + error.message);
                console.error('❌ Load error:', error);
            }
            return false;
        }
       
        // === ОБНОВЛЕНИЕ ИНТЕРФЕЙСА ===
        function updateUI() {
            // Босс
            if (gameData.boss) {
                const boss = gameData.boss;
                const isAlive = boss.isAlive !== false && boss.currentHealth > 0;
                const healthPercent = isAlive ? (boss.currentHealth / boss.maxHealth) * 100 : 0;
               
                document.getElementById('health-bar').style.width = healthPercent + '%';
                document.getElementById('health-text').textContent =
                    isAlive ? `${boss.currentHealth} / ${boss.maxHealth}` : '☠️ ПОБЕЖДЕН';
               
                // Цвет полоски
                const bar = document.getElementById('health-bar');
                if (isAlive) {
                    if (healthPercent > 70) bar.style.background = '#4CAF50';
                    else if (healthPercent > 30) bar.style.background = '#FF9800';
                    else bar.style.background = '#f44336';
                } else {
                    bar.style.background = '#666';
                }
               
                // Кнопка
                const btn = document.getElementById('attack-btn');
                btn.disabled = !isAlive;
                btn.textContent = isAlive ? 'АТАКОВАТЬ' : 'БОСС ПОБЕЖДЕН';
               
                // Поле сообщения
                document.getElementById('attack-msg').disabled = !isAlive;
            }
           
            // Топ игроков
            if (gameData.allPlayers) {
                const container = document.getElementById('top-players');
                const players = Object.values(gameData.allPlayers)
                    .filter(p => p && p.totalDamage !== undefined)
                    .sort((a, b) => b.totalDamage - a.totalDamage)
                    .slice(0, 10);
               
                container.innerHTML = '';
                players.forEach((p, i) => {
                    const div = document.createElement('div');
                    div.className = 'player';
                    if (gameData.player && p.id === gameData.player.id) {
                        div.classList.add('me');
                    }
                    div.innerHTML = `<span>${i+1}. ${p.name || p.nickname || 'Игрок'}</span><span>${p.totalDamage}</span>`;
                    container.appendChild(div);
                });
            }
           
            // Рекорды
            if (gameData.records) {
                if (gameData.records.maxDamage) {
                    document.getElementById('max-damage').textContent =
                        gameData.records.maxDamage.player ?
                        `${gameData.records.maxDamage.player}: ${gameData.records.maxDamage.damage}` : '-';
                }
                if (gameData.records.minDamage) {
                    document.getElementById('min-damage').textContent =
                        gameData.records.minDamage.player ?
                        `${gameData.records.minDamage.player}: ${gameData.records.minDamage.damage}` : '-';
                }
            }
           
            // Логи
            if (gameData.logs) {
                const container = document.getElementById('logs');
                container.innerHTML = '';
               
                gameData.logs.slice(-15).reverse().forEach(log => {
                    const div = document.createElement('div');
                    div.className = 'log';
                   
                    let logText = '';
                    if (typeof log === 'string') {
                        logText = log;
                    } else if (log.time && log.player) {
                        logText = `${log.time} - ${log.player}: ${log.damage} урона`;
                    } else {
                        logText = JSON.stringify(log);
                    }
                   
                    div.textContent = logText;
                    container.appendChild(div);
                });
            }
        }
       
        // === АТАКА ===
        async function attack() {
            try {
                const btn = document.getElementById('attack-btn');
                const msg = document.getElementById('attack-msg');
               
                // Проверяем можно ли атаковать
                if (!gameData.boss || gameData.boss.currentHealth <= 0 || gameData.boss.isAlive === false) {
                    alert('Босс уже побежден!');
                    return;
                }
               
                // Генерируем урон
                const damage = Math.floor(Math.random() * 100) + 1;
                const message = msg.value.trim();
               
                // Отключаем кнопку
                btn.disabled = true;
                btn.textContent = 'Атакуем...';
                updateStatus('Атака...');
               
                // Отправляем атаку
                const response = await sendToParent('processAttack', {
                    attackData: {
                        damage: damage,
                        message: message,
                        timestamp: Date.now()
                    }
                });
               
                if (response.data && response.data.success !== false) {
                    // Обновляем данные
                    if (response.data.player) gameData.player = response.data.player;
                    if (response.data.boss) gameData.boss = response.data.boss;
                    if (response.data.gameData) {
                        gameData.boss = response.data.gameData.boss;
                        gameData.allPlayers = response.data.gameData.players || {};
                        gameData.logs = response.data.gameData.logs || [];
                    }
                   
                    // Показываем урон
                    document.getElementById('last-hit').textContent = `Нанесено: ${damage} урона`;
                   
                    // Очищаем поле
                    msg.value = '';
                   
                    // Обновляем интерфейс
                    updateUI();
                   
                    // Загружаем свежие данные
                    await loadData();
                   
                    // Сообщение о победе
                    if (response.data.bossDied || (gameData.boss && gameData.boss.currentHealth <= 0)) {
                        setTimeout(() => {
                            alert('🎉 БОСС ПОБЕЖДЕН!');
                        }, 500);
                    }
                   
                    updateStatus('Атака успешна!');
                   
                } else {
                    alert(response.error || 'Ошибка атаки');
                    updateStatus('Ошибка: ' + response.error);
                }
               
            } catch (error) {
                console.error('❌ Attack error:', error);
                alert('Ошибка: ' + error.message);
                updateStatus('Ошибка: ' + error.message);
            } finally {
                updateUI();
            }
        }
       
        // === ВСПОМОГАТЕЛЬНЫЕ ===
        function updateStatus(text) {
            document.getElementById('status').textContent = 'Статус: ' + text;
            console.log('📝 ' + text);
        }
       
        // === ЗАПУСК ИГРЫ ===
        async function startGame() {
            updateStatus('Запуск игры...');
           
            // Загружаем данные
            await loadData();
           
            // Обновляем каждые 5 секунд
            setInterval(loadData, 5000);
           
            updateStatus('✅ Игра готова');
        }
       
        // Экспортируем функцию атаки для кнопки
        window.attack = attack;
       
        // Запускаем при загрузке
        window.onload = startGame;
    </script>
</body>
</html>[/html]

0

4

[html]<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Битва с монстром</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            color: #fff;
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            display: flex;
            gap: 20px;
            max-width: 1400px;
            margin: 0 auto;
        }

        .left-panel, .right-panel {
            background: rgba(30, 30, 46, 0.9);
            border-radius: 15px;
            padding: 20px;
            border: 2px solid #3a506b;
        }

        .left-panel {
            flex: 0 0 300px;
        }

        .right-panel {
            flex: 1;
        }

        .section-title {
            color: #ff9a3c;
            text-align: center;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 2px solid #3a506b;
            font-size: 20px;
        }

        /* ТОП ИГРОКОВ */
        .top-players {
            max-height: 300px;
            overflow-y: auto;
            margin-bottom: 25px;
        }

        .player-item {
            display: flex;
            justify-content: space-between;
            padding: 10px 15px;
            margin-bottom: 8px;
            background: rgba(50, 50, 70, 0.6);
            border-radius: 8px;
            border-left: 4px solid #ff9a3c;
            transition: background 0.2s;
        }

        .player-item:hover {
            background: rgba(60, 60, 80, 0.8);
        }

        .player-item.you {
            border-left-color: #4CAF50;
            background: rgba(76, 175, 80, 0.1);
        }

        /* ЖУРНАЛ БОЯ */
        .battle-logs {
            max-height: 300px;
            overflow-y: auto;
        }

        .log-item {
            padding: 10px 12px;
            margin-bottom: 8px;
            background: rgba(40, 40, 60, 0.6);
            border-radius: 8px;
            font-size: 14px;
            border-left: 4px solid #4ecdc4;
        }

        /* ОСНОВНАЯ ПАНЕЛЬ */
        .boss-container {
            text-align: center;
            margin-bottom: 30px;
        }

        .boss-name {
            font-size: 32px;
            color: #ff6b6b;
            margin-bottom: 15px;
            text-shadow: 0 0 15px rgba(255, 107, 107, 0.5);
        }

        .health-container {
            width: 100%;
            margin: 20px 0;
        }

        .health-text {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
            font-size: 18px;
            color: #ffd166;
        }

        .health-bar {
            width: 100%;
            height: 40px;
            background: #333;
            border-radius: 20px;
            overflow: hidden;
            border: 3px solid #555;
        }

        .health-fill {
            height: 100%;
            background: linear-gradient(90deg, #ef476f, #ff9a3c);
            width: 100%;
            transition: width 0.5s ease;
            position: relative;
        }

        .boss-image {
            width: 100%;
            max-width: 500px;
            height: 300px;
            object-fit: cover;
            border-radius: 15px;
            border: 4px solid #ff6b6b;
            margin: 20px auto;
            box-shadow: 0 0 30px rgba(255, 107, 107, 0.4);
        }

        /* ИНТЕРФЕЙС АТАКИ */
        .attack-interface {
            background: rgba(40, 40, 60, 0.8);
            border-radius: 15px;
            padding: 25px;
            margin-top: 20px;
        }

        .attack-message {
            width: 100%;
            padding: 15px;
            margin-bottom: 20px;
            border: 2px solid #4ecdc4;
            border-radius: 10px;
            background: rgba(30, 30, 46, 0.9);
            color: white;
            font-size: 16px;
            resize: vertical;
            min-height: 80px;
        }

        .attack-button {
            width: 100%;
            padding: 20px;
            font-size: 28px;
            font-weight: bold;
            background: linear-gradient(145deg, #ef476f, #ff6b6b);
            color: white;
            border: none;
            border-radius: 12px;
            cursor: pointer;
            transition: all 0.2s;
            text-transform: uppercase;
        }

        .attack-button:hover:not(:disabled) {
            transform: scale(1.02);
            box-shadow: 0 0 30px rgba(255, 107, 107, 0.6);
        }

        .attack-button:disabled {
            background: #4a6178;
            cursor: not-allowed;
            opacity: 0.7;
        }

        /* СТАТИСТИКА */
        .player-stats {
            margin-top: 30px;
            padding: 20px;
            background: rgba(40, 40, 60, 0.8);
            border-radius: 15px;
        }

        .stats-grid {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 15px;
            margin-top: 15px;
        }

        .stat-item {
            background: rgba(50, 50, 70, 0.6);
            padding: 15px;
            border-radius: 10px;
            display: flex;
            justify-content: space-between;
        }

        .stat-label {
            color: #a0c4ff;
        }

        .stat-value {
            color: #ffd166;
            font-weight: bold;
            font-size: 18px;
        }

        /* УРОН */
        .damage-display {
            text-align: center;
            font-size: 24px;
            font-weight: bold;
            color: #ff6b6b;
            margin: 15px 0;
            padding: 15px;
            background: rgba(255, 107, 107, 0.1);
            border-radius: 10px;
            border: 2px solid #ff6b6b;
        }

        /* МОБИЛЬНАЯ ВЕРСИЯ */
        @media (max-width: 1100px) {
            .container {
                flex-direction: column;
            }
           
            .left-panel {
                flex: none;
                width: 100%;
            }
           
            .top-players, .battle-logs {
                max-height: 200px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <!-- ЛЕВАЯ ПАНЕЛЬ -->
        <div class="left-panel">
            <div class="top-players">
                <h2 class="section-title">🏆 ТОП ИГРОКОВ</h2>
                <div id="top-players-list">
                    <div class="player-item">
                        <span>Загрузка...</span>
                        <span>0</span>
                    </div>
                </div>
            </div>

            <div class="battle-logs">
                <h2 class="section-title">📜 ЖУРНАЛ БОЯ</h2>
                <div id="logs-list">
                    <div class="log-item">Загрузка логов...</div>
                </div>
            </div>
        </div>

        <!-- ПРАВАЯ ПАНЕЛЬ -->
        <div class="right-panel">
            <!-- БОСС -->
            <div class="boss-container">
                <h1 class="boss-name" id="bossName">🔥 ГНЕВНЫЙ ДРАКОН</h1>
               
                <div class="health-container">
                    <div class="health-text">
                        <span>ЗДОРОВЬЕ БОССА</span>
                        <span id="bossHealthText">1000 / 1000 (100%)</span>
                    </div>
                    <div class="health-bar">
                        <div class="health-fill" id="bossHealthBar"></div>
                    </div>
                </div>

                <img class="boss-image" id="bossImage" src="https://via.placeholder.com/500x300/8b0000/ffffff?text=ГНЕВНЫЙ+ДРАКОН" alt="Монстр">
            </div>

            <!-- ИНТЕРФЕЙС АТАКИ -->
            <div class="attack-interface">
                <textarea class="attack-message" id="attackMessage"
                    placeholder="Введите ваше боевое сообщение (необязательно)..."></textarea>
               
                <button class="attack-button" id="attackButton" disabled>АТАКОВАТЬ!</button>
               
                <div class="damage-display" id="damageDisplay">
                    Последний урон: -
                </div>
            </div>

            <!-- СТАТИСТИКА ИГРОКА -->
            <div class="player-stats">
                <h2 class="section-title">📊 ВАША СТАТИСТИКА</h2>
                <div class="stats-grid">
                    <div class="stat-item">
                        <span class="stat-label">Всего урона:</span>
                        <span class="stat-value" id="statDamage">0</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">Количество атак:</span>
                        <span class="stat-value" id="statAttacks">0</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">Лучший удар:</span>
                        <span class="stat-value" id="statBestHit">0</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">Убито боссов:</span>
                        <span class="stat-value" id="statKills">0</span>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        (function(){
            console.log('🎮 Monster Game Frame started');
           
            // === ГЛОБАЛЬНОЕ СОСТОЯНИЕ ===
            let gameState = {
                player: null,
                boss: null,
                topPlayers: [],
                logs: []
            };
           
            // === КОММУНИКАЦИЯ С РОДИТЕЛЕМ ===
            function sendToParent(data) {
                try {
                    window.parent.postMessage(data, '*');
                    return true;
                } catch (e) {
                    console.error('❌ Send failed:', e);
                    return false;
                }
            }
           
            function sendGameRequest(action, data = {}) {
                return new Promise((resolve, reject) => {
                    const requestId = Date.now() + '_' + Math.random().toString(36).substr(2, 9);
                   
                    const message = {
                        _monsterGame: true,
                        type: "gameRequest",
                        requestId: requestId,
                        action: action,
                        ...data
                    };
                   
                    const responseHandler = (event) => {
                        const response = event.data;
                        if (response && response._monsterGame === true &&
                            response.type === "gameResponse" &&
                            response.requestId === requestId) {
                           
                            window.removeEventListener("message", responseHandler);
                            clearTimeout(timeout);
                           
                            if (response.error) {
                                reject(new Error(response.error));
                            } else {
                                resolve(response.data);
                            }
                        }
                    };
                   
                    window.addEventListener("message", responseHandler);
                   
                    const timeout = setTimeout(() => {
                        window.removeEventListener("message", responseHandler);
                        reject(new Error(`Timeout: ${action}`));
                    }, 10000);
                   
                    if (!sendToParent(message)) {
                        window.removeEventListener("message", responseHandler);
                        clearTimeout(timeout);
                        reject(new Error("Failed to send message"));
                    }
                });
            }
           
            // === ЗАГРУЗКА ДАННЫХ ===
            async function loadGameData() {
                try {
                    const data = await sendGameRequest("getGameData");
                    return data;
                } catch (error) {
                    console.error('❌ Load game data error:', error);
                    return null;
                }
            }
           
            async function loadPlayerData() {
                try {
                    const data = await sendGameRequest("getPlayerData");
                    return data;
                } catch (error) {
                    console.error('❌ Load player data error:', error);
                    return null;
                }
            }
           
            async function loadTopPlayers() {
                try {
                    const players = await sendGameRequest("getTopPlayers");
                    return players || [];
                } catch (error) {
                    console.error('❌ Load top players error:', error);
                    return [];
                }
            }
           
            async function loadLogs() {
                try {
                    const logs = await sendGameRequest("getRecentLogs");
                    return logs || [];
                } catch (error) {
                    console.error('❌ Load logs error:', error);
                    return [];
                }
            }
           
            // === ОБНОВЛЕНИЕ ИНТЕРФЕЙСА ===
            function updateBossUI() {
                if (!gameState.boss) return;
               
                const boss = gameState.boss;
                const healthPercent = (boss.currentHealth / boss.maxHealth) * 100;
                const healthBar = document.getElementById('bossHealthBar');
                const healthText = document.getElementById('bossHealthText');
               
                if (healthBar) {
                    healthBar.style.width = `${healthPercent}%`;
                   
                    // Цвет в зависимости от здоровья
                    if (healthPercent > 70) {
                        healthBar.style.background = 'linear-gradient(90deg, #4CAF50, #8BC34A)';
                    } else if (healthPercent > 30) {
                        healthBar.style.background = 'linear-gradient(90deg, #FF9800, #FFC107)';
                    } else {
                        healthBar.style.background = 'linear-gradient(90deg, #f44336, #ef5350)';
                    }
                }
               
                if (healthText) {
                    healthText.textContent = `${boss.currentHealth} / ${boss.maxHealth} (${Math.round(healthPercent)}%)`;
                }
               
                // Обновляем кнопку атаки
                updateAttackButton();
            }
           
            function updatePlayerUI() {
                if (!gameState.player) return;
               
                const player = gameState.player;
               
                document.getElementById('statDamage').textContent = player.totalDamage || 0;
                document.getElementById('statAttacks').textContent = player.attacks || 0;
                document.getElementById('statBestHit').textContent = player.bestHit || 0;
                document.getElementById('statKills').textContent = player.bossKills || 0;
            }
           
            async function updateTopPlayersUI() {
                try {
                    gameState.topPlayers = await loadTopPlayers();
                    const container = document.getElementById('top-players-list');
                   
                    if (!container) return;
                   
                    if (gameState.topPlayers.length === 0) {
                        container.innerHTML = '<div class="player-item"><span>Нет игроков</span><span>0</span></div>';
                        return;
                    }
                   
                    container.innerHTML = '';
                   
                    gameState.topPlayers.forEach((player, index) => {
                        const div = document.createElement('div');
                        div.className = 'player-item';
                       
                        // Подсвечиваем текущего игрока
                        if (gameState.player && player.userId === gameState.player.userId) {
                            div.classList.add('you');
                        }
                       
                        div.innerHTML = `
                            <span>${index + 1}. ${player.nickname}</span>
                            <span>${player.totalDamage}</span>
                        `;
                       
                        container.appendChild(div);
                    });
                } catch (error) {
                    console.error('❌ Update top players error:', error);
                }
            }
           
            async function updateLogsUI() {
                try {
                    gameState.logs = await loadLogs();
                    const container = document.getElementById('logs-list');
                   
                    if (!container) return;
                   
                    if (gameState.logs.length === 0) {
                        container.innerHTML = '<div class="log-item">Нет записей в журнале</div>';
                        return;
                    }
                   
                    container.innerHTML = '';
                   
                    gameState.logs.reverse().forEach(log => {
                        const div = document.createElement('div');
                        div.className = 'log-item';
                        div.textContent = log;
                        container.appendChild(div);
                    });
                   
                    // Прокрутка вниз
                    container.scrollTop = 0;
                } catch (error) {
                    console.error('❌ Update logs error:', error);
                }
            }
           
            function updateAttackButton() {
                const btn = document.getElementById('attackButton');
                const message = document.getElementById('attackMessage');
               
                if (!btn) return;
               
                const isBossAlive = gameState.boss && gameState.boss.currentHealth > 0;
               
                if (isBossAlive) {
                    btn.disabled = false;
                    btn.textContent = 'АТАКОВАТЬ!';
                    if (message) message.disabled = false;
                } else {
                    btn.disabled = true;
                    btn.textContent = 'БОСС ПОБЕЖДЕН';
                    if (message) message.disabled = true;
                }
            }
           
            // === ОСНОВНАЯ ИГРОВАЯ ЛОГИКА ===
            async function performAttack() {
                if (!gameState.boss || gameState.boss.currentHealth <= 0) {
                    alert('Босс уже побежден!');
                    return;
                }
               
                const btn = document.getElementById('attackButton');
                const messageInput = document.getElementById('attackMessage');
               
                if (btn) btn.disabled = true;
               
                try {
                    // Генерация урона
                    const damage = Math.floor(Math.random() * 100) + 1;
                    const message = messageInput ? messageInput.value.trim() : '';
                   
                    // Отправляем атаку
                    const result = await sendGameRequest("processAttack", {
                        attackData: {
                            damage: damage,
                            message: message,
                            timestamp: Date.now()
                        }
                    });
                   
                    if (result.success) {
                        // Обновляем состояние
                        gameState.player = result.player;
                        gameState.boss = result.gameData.boss;
                       
                        // Обновляем UI
                        updateBossUI();
                        updatePlayerUI();
                       
                        // Показываем урон
                        const damageDisplay = document.getElementById('damageDisplay');
                        if (damageDisplay) {
                            damageDisplay.textContent = `Нанесено урона: ${damage}`;
                            damageDisplay.style.animation = 'none';
                            setTimeout(() => {
                                damageDisplay.style.animation = 'pulse 0.5s';
                            }, 10);
                        }
                       
                        // Обновляем топ и логи
                        await updateTopPlayersUI();
                        await updateLogsUI();
                       
                        // Очищаем поле ввода
                        if (messageInput) messageInput.value = '';
                       
                        // Сообщение о победе
                        if (result.gameData.boss.currentHealth <= 0) {
                            setTimeout(() => {
                                alert('🎉 БОСС ПОБЕЖДЕН! Он воскреснет с полным здоровьем.');
                            }, 500);
                        }
                    } else {
                        alert('Ошибка атаки: ' + (result.error || 'Неизвестная ошибка'));
                    }
                   
                } catch (error) {
                    console.error('❌ Attack error:', error);
                    alert('Ошибка: ' + error.message);
                } finally {
                    updateAttackButton();
                }
            }
           
            // === ПЕРИОДИЧЕСКОЕ ОБНОВЛЕНИЕ ===
            let refreshInterval;
           
            async function refreshGameState() {
                try {
                    const data = await loadGameData();
                    if (data) {
                        gameState.boss = data.boss;
                        updateBossUI();
                    }
                   
                    await updateTopPlayersUI();
                    await updateLogsUI();
                   
                } catch (error) {
                    console.error('❌ Refresh error:', error);
                }
            }
           
            // === ИНИЦИАЛИЗАЦИЯ ===
            async function init() {
                console.log('🎮 Initializing monster game...');
               
                try {
                    // Загружаем данные
                    const playerData = await loadPlayerData();
                    if (playerData) {
                        gameState.player = playerData.player;
                        gameState.boss = playerData.boss;
                    } else {
                        const gameData = await loadGameData();
                        if (gameData) {
                            gameState.boss = gameData.boss;
                        }
                    }
                   
                    // Обновляем UI
                    updateBossUI();
                    updatePlayerUI();
                    await updateTopPlayersUI();
                    await updateLogsUI();
                   
                    // Настраиваем кнопку
                    const attackBtn = document.getElementById('attackButton');
                    if (attackBtn) {
                        attackBtn.addEventListener('click', performAttack);
                    }
                   
                    // Запускаем автообновление
                    refreshInterval = setInterval(refreshGameState, 3000);
                   
                    console.log('✅ Monster game initialized!');
                   
                } catch (error) {
                    console.error('❌ Init error:', error);
                    alert('Ошибка загрузки игры. Обновите страницу.');
                }
            }
           
            // Запуск
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', init);
            } else {
                init();
            }
           
            // Очистка при закрытии
            window.addEventListener('beforeunload', () => {
                if (refreshInterval) clearInterval(refreshInterval);
            });
           
        })();
    </script>
</body>
</html>[/html]

0

5

[html]
<div class="monster-attack-result" data-attack="CjxkaXYgY2xhc3M9Im1vbnN0ZXItYXR0YWNrLXBvc3QiIHN0eWxlPSIKICAgIGJvcmRlcjogM3B4IHNvbGlkICNmZjZiNmI7CiAgICBib3JkZXItcmFkaXVzOiAxNXB4OwogICAgcGFkZGluZzogMjBweDsKICAgIGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCgxMzVkZWcsICMxYTFhMmUgMCUsICMxNjIxM2UgMTAwJSk7CiAgICBtYXJnaW46IDE1cHggMDsKICAgIGNvbG9yOiB3aGl0ZTsKICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsKICAgIGJveC1zaGFkb3c6IDAgMTBweCAzMHB4IHJnYmEoMCwwLDAsMC41KTsKIj4KICAgIDxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsgbWFyZ2luLWJvdHRvbTogMjBweDsiPgogICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMjJweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjZmY2YjZiOyBtYXJnaW4tYm90dG9tOiA4cHg7Ij4KICAgICAgICAgICAgJiM5ODc2OyYjNjUwMzk7INCQ0KLQkNCa0JAg0J3QkCDQkdCe0KHQodCQICYjOTg3NjsmIzY1MDM5OwogICAgICAgIDwvZGl2PgogICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICNhYWE7Ij4KICAgICAgICAgICAgMjAuMTIuMjAyNSwgMTM6NDk6NTgKICAgICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgCiAgICA8ZGl2IHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47IGFsaWduLWl0ZW1zOiBjZW50ZXI7IG1hcmdpbi1ib3R0b206IDIwcHg7IHBhZGRpbmc6IDE1cHg7IGJhY2tncm91bmQ6IHJnYmEoMCwwLDAsMC4zKTsgYm9yZGVyLXJhZGl1czogMTBweDsiPgogICAgICAgIDxkaXYgc3R5bGU9ImZsZXg6IDE7Ij4KICAgICAgICAgICAgPGRpdiBzdHlsZT0iZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICM0ZWNkYzQ7IG1hcmdpbi1ib3R0b206IDVweDsiPgogICAgICAgICAgICAgICAgYWRtaW4KICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMTNweDsgY29sb3I6ICM4ODg7Ij4KICAgICAgICAgICAgICAgINCj0YDQvtC9OiAzNDEgfCDQkNGC0LDQujogNgogICAgICAgICAgICA8L2Rpdj4KICAgICAgICA8L2Rpdj4KICAgICAgICAKICAgICAgICA8ZGl2IHN0eWxlPSJmb250LXNpemU6IDMycHg7IG1hcmdpbjogMCAyMHB4OyI+CiAgICAgICAgICAgICYjOTg3NjsmIzY1MDM5OwogICAgICAgIDwvZGl2PgogICAgICAgIAogICAgICAgIDxkaXYgc3R5bGU9ImZsZXg6IDE7IHRleHQtYWxpZ246IHJpZ2h0OyI+CiAgICAgICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMThweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjZmY2YjZiOyBtYXJnaW4tYm90dG9tOiA1cHg7Ij4KICAgICAgICAgICAgICAgICYjMTI4MjkzOyDQk9Cd0JXQktCd0KvQmSDQlNCg0JDQmtCe0J0KICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgICAgIDxkaXYgc3R5bGU9ImZvbnQtc2l6ZTogMTNweDsgY29sb3I6ICM4ODg7Ij4KICAgICAgICAgICAgICAgIEhQOiA2NTkvMTAwMAogICAgICAgICAgICA8L2Rpdj4KICAgICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgCiAgICA8ZGl2IHN0eWxlPSJiYWNrZ3JvdW5kOiByZ2JhKDAsMCwwLDAuNCk7IGJvcmRlci1yYWRpdXM6IDEwcHg7IHBhZGRpbmc6IDIwcHg7IG1hcmdpbjogMTVweCAwOyI+CiAgICAgICAgPGRpdiBzdHlsZT0iZm9udC1zaXplOiAyNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IG1hcmdpbi1ib3R0b206IDE1cHg7Ij4KICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImNvbG9yOiAjZmZkMTY2OyI+0J3QsNC90LXRgdC10L3QviDRg9GA0L7QvdCwOjwvc3Bhbj4KICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMzJweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjZmY2YjZiOyBtYXJnaW4tbGVmdDogMTVweDsiPgogICAgICAgICAgICAgICAgNzUKICAgICAgICAgICAgPC9zcGFuPgogICAgICAgIDwvZGl2PgogICAgICAgIAogICAgICAgIDxkaXYgc3R5bGU9Im1hcmdpbjogMjBweCAwOyBwYWRkaW5nOiAxMHB4OyBiYWNrZ3JvdW5kOiByZ2JhKDAsMCwwLDAuMyk7IGJvcmRlci1yYWRpdXM6IDhweDsiPgogICAgICAgICAgICA8ZGl2IHN0eWxlPSJmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjYWFhOyBtYXJnaW4tYm90dG9tOiA1cHg7Ij7Ql9C00L7RgNC+0LLRjNC1INCx0L7RgdGB0LA6PC9kaXY+CiAgICAgICAgICAgIDxkaXYgc3R5bGU9ImhlaWdodDogMjVweDsgYmFja2dyb3VuZDogIzMzMzsgYm9yZGVyLXJhZGl1czogMTJweDsgb3ZlcmZsb3c6IGhpZGRlbjsgcG9zaXRpb246IHJlbGF0aXZlOyI+CiAgICAgICAgICAgICAgICA8ZGl2IHN0eWxlPSIKICAgICAgICAgICAgICAgICAgICBoZWlnaHQ6IDEwMCU7CiAgICAgICAgICAgICAgICAgICAgd2lkdGg6IDY1LjklOwogICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCg5MGRlZywgI0ZGOTgwMCwgI0ZGQzEwNyk7CiAgICAgICAgICAgICAgICAgICAgdHJhbnNpdGlvbjogd2lkdGggMXMgZWFzZTsKICAgICAgICAgICAgICAgICAgICBib3JkZXItcmFkaXVzOiAxMnB4OwogICAgICAgICAgICAgICAgIj48L2Rpdj4KICAgICAgICAgICAgICAgIDxkaXYgc3R5bGU9InBvc2l0aW9uOiBhYnNvbHV0ZTsgdG9wOiAwOyBsZWZ0OiAwOyByaWdodDogMDsgYm90dG9tOiAwOyBkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsgY29sb3I6IHdoaXRlOyBmb250LXdlaWdodDogYm9sZDsiPgogICAgICAgICAgICAgICAgICAgIDY1OS8xMDAwICg2NiUpCiAgICAgICAgICAgICAgICA8L2Rpdj4KICAgICAgICAgICAgPC9kaXY+CiAgICAgICAgPC9kaXY+CiAgICAgICAgCiAgICAgICAgCiAgICAgICAgCiAgICAgICAgCiAgICA8L2Rpdj4KICAgIAogICAgPGRpdiBzdHlsZT0iZGlzcGxheTogZmxleDsganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuOyBmb250LXNpemU6IDEycHg7IGNvbG9yOiAjNjY2OyBtYXJnaW4tdG9wOiAyMHB4OyBwYWRkaW5nLXRvcDogMTVweDsgYm9yZGVyLXRvcDogMXB4IHNvbGlkICM0NDQ7Ij4KICAgICAgICA8ZGl2Pk1vbnN0ZXIgQmF0dGxlIHYxLjAgfCBJRDogMjwvZGl2PgogICAgICAgIDxkaXY+0JvRg9GH0YjQuNC5INGD0LTQsNGAOiA4ODwvZGl2PgogICAgICAgIDxkaXY+0KPQsdC40YLQviDQsdC+0YHRgdC+0LI6IDA8L2Rpdj4KICAgIDwvZGl2Pgo8L2Rpdj4=">
Загрузка результата атаки...
</div>

<script>
(function(){
    try {
        var encoded = document.querySelector(".monster-attack-result").getAttribute("data-attack");
        var html = decodeURIComponent(escape(atob(encoded)));
        document.querySelector(".monster-attack-result").innerHTML = html;
       
        // Анимация
        var el = document.querySelector(".monster-attack-result");
        el.style.animation = "monsterPulse 0.5s";
        setTimeout(() => el.style.animation = "", 500);
    } catch(e){
        document.querySelector(".monster-attack-result").innerHTML = "<b>Ошибка загрузки результата</b>";
    }
})();
</script>

<style>
@keyframes monsterPulse {
    0% { transform: scale(1); opacity: 0.8; }
    50% { transform: scale(1.02); opacity: 1; }
    100% { transform: scale(1); opacity: 0.8; }
}
</style>
[/html]

0

6

[html]<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Oswald:wght@400;700&family=Roboto+Condensed:wght@400;700&display=swap');

        * { margin: 0; padding: 0; box-sizing: border-box; }
       
        body {
            background: #0a0a0c;
            background-image: radial-gradient(circle at center, #1a1a2e 0%, #0a0a0c 100%);
            color: #e0e0e0;
            font-family: 'Roboto Condensed', sans-serif;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }

        .game-container {
            display: grid;
            grid-template-columns: 300px 1fr;
            gap: 25px;
            max-width: 1100px;
            width: 100%;
            background: rgba(0, 0, 0, 0.6);
            padding: 30px;
            border-radius: 20px;
            border: 1px solid rgba(255, 255, 255, 0.05);
            box-shadow: 0 20px 50px rgba(0,0,0,0.5);
            backdrop-filter: blur(10px);
        }

        /* --- Левая панель --- */
        .sidebar { display: flex; flex-direction: column; gap: 20px; }

        .panel {
            background: rgba(255, 255, 255, 0.03);
            border-left: 3px solid #ff4655;
            padding: 15px;
            border-radius: 4px;
        }

        .panel-h {
            font-family: 'Oswald', sans-serif;
            font-size: 14px;
            letter-spacing: 2px;
            color: #ff4655;
            margin-bottom: 12px;
            text-transform: uppercase;
        }

        .stat-row {
            display: flex;
            justify-content: space-between;
            padding: 6px 0;
            border-bottom: 1px solid rgba(255,255,255,0.05);
            font-size: 14px;
        }

        .record-info {
            display: flex;
            flex-direction: column;
            gap: 4px;
        }

        .record-player {
            color: #aaa;
            font-size: 12px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            max-width: 180px;
        }

        .log-container {
            font-size: 13px;
            height: 200px;
            overflow-y: auto;
            scrollbar-width: thin;
            scrollbar-color: #ff4655 transparent;
        }

        .log-entry {
            padding: 4px 0;
            color: #aaa;
            border-bottom: 1px solid rgba(255,255,255,0.02);
        }

        .log-entry b { color: #ff4655; }

        /* --- Центральная часть --- */
        .main-content { display: flex; flex-direction: column; gap: 20px; }

        .boss-frame {
            position: relative;
            border-radius: 12px;
            overflow: hidden;
            box-shadow: 0 0 30px rgba(255, 70, 85, 0.2);
            border: 1px solid rgba(255, 70, 85, 0.3);
            transition: transform 0.1s;
        }

        .boss-img {
            width: 100%;
            height: 450px;
            object-fit: cover;
            display: block;
        }

        .boss-overlay {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            padding: 40px 20px 20px;
            background: linear-gradient(to top, rgba(0,0,0,0.9) 0%, transparent 100%);
        }

        .boss-info {
            display: flex;
            justify-content: space-between;
            align-items: flex-end;
            margin-bottom: 8px;
        }

        .boss-name {
            font-family: 'Oswald', sans-serif;
            font-size: 32px;
            font-weight: 700;
            color: #fff;
        }

        .hp-text { font-family: 'Oswald', sans-serif; color: #ff4655; font-size: 18px; }

        .hp-bar-bg {
            height: 12px;
            background: rgba(255,255,255,0.1);
            border-radius: 6px;
            overflow: hidden;
        }

        .hp-bar-fill {
            height: 100%;
            background: #ff4655; /* Упростил для корректного отображения */
            background: linear-gradient(90deg, #ff4655, #ff8a71);
            box-shadow: 0 0 15px #ff4655;
            width: 100%;
            transition: width 0.4s ease-out;
        }

        /* --- Управление --- */
        .controls {
            display: grid;
            grid-template-columns: 1fr 200px;
            gap: 15px;
        }

        .game-input {
            width: 100%;
            height: 60px;
            background: rgba(255,255,255,0.05);
            border: 1px solid rgba(255,255,255,0.1);
            border-radius: 8px;
            padding: 0 20px;
            color: #fff;
            font-size: 16px;
            outline: none;
        }

        .btn-attack {
            height: 60px;
            background: #ff4655;
            color: #fff;
            border: none;
            border-radius: 8px;
            font-family: 'Oswald', sans-serif;
            font-size: 20px;
            font-weight: 700;
            cursor: pointer;
            text-transform: uppercase;
            transition: 0.2s;
        }

        .btn-attack:hover:not(:disabled) { background: #ff5e6a; transform: translateY(-2px); }
        .btn-attack:disabled { background: #333; cursor: not-allowed; }

        .damage-popup {
            text-align: center;
            font-family: 'Oswald', sans-serif;
            font-size: 24px;
            color: #ff4655;
            height: 30px;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <aside class="sidebar">
            <div class="panel">
                <div class="panel-h">🏆 Лидеры</div>
                <div id="topList"></div>
            </div>
            <div class="panel">
                <div class="panel-h">🎯 Рекорды</div>
                <div class="stat-row">
                    <span>Макс. урон</span>
                    <div class="record-info">
                        <b id="maxDmg" style="color:#ff4655">-</b>
                        <div id="maxPlayer" class="record-player">-</div>
                    </div>
                </div>
                <div class="stat-row">
                    <span>Мин. урон</span>
                    <div class="record-info">
                        <b id="minDmg" style="color:#fff">-</b>
                        <div id="minPlayer" class="record-player">-</div>
                    </div>
                </div>
            </div>
            <div class="panel" style="flex-grow: 1;">
                <div class="panel-h">📜 Журнал боя</div>
                <div id="logs" class="log-container"></div>
            </div>
        </aside>

        <main class="main-content">
            <div class="boss-frame" id="bossFrame">
                <img src="https://upforme.ru/uploads/001c/84/76/2/433839.jpg" class="boss-img" alt="Boss">
                <div class="boss-overlay">
                    <div class="boss-info">
                        <div class="boss-name">ДРЕВНИЙ СТРАЖ</div>
                        <div id="hpText" class="hp-text">... / ...</div>
                    </div>
                    <div class="hp-bar-bg">
                        <div id="hpBar" class="hp-bar-fill" style="width: 100%;"></div>
                    </div>
                </div>
            </div>

            <div class="controls">
                <input type="text" id="msg" class="game-input" placeholder="Введите боевой клич...">
                <button id="atkBtn" class="btn-attack">УДАРИТЬ</button>
            </div>
            <div id="dmgRes" class="damage-popup"></div>
        </main>
    </div>

    <script>
        const send = (action, data = {}) => {
            const requestId = Math.random().toString(16).slice(2);
            window.parent.postMessage({ _monsterGame: true, type: "gameRequest", requestId, action, ...data }, '*');
            return new Promise(resolve => {
                const handler = (e) => {
                    if(e.data?.requestId === requestId) {
                        window.removeEventListener("message", handler);
                        resolve(e.data.data);
                    }
                };
                window.addEventListener("message", handler);
            });
        };

        async function updateUI() {
            try {
                const [game, top, logs] = await Promise.all([
                    send("getGameData"),
                    send("getTopPlayers"),
                    send("getRecentLogs")
                ]);

                // Обновление полоски здоровья
                const currentHp = game.boss.currentHealth;
                const maxHp = game.boss.maxHealth;
                const hpPct = Math.max(0, (currentHp / maxHp) * 100);
               
                const bar = document.getElementById('hpBar');
                bar.style.width = hpPct + '%';
               
                document.getElementById('hpText').textContent = `${currentHp} / ${maxHp}`;
                document.getElementById('atkBtn').disabled = currentHp <= 0;

                // Лидеры
                document.getElementById('topList').innerHTML = top.slice(0, 5).map(p =>
                    `<div class="stat-row"><span>${p.nickname}</span><b>${p.totalDamage}</b></div>`
                ).join('') || 'Нет данных';

                // Логи
                document.getElementById('logs').innerHTML = logs.slice(-20).reverse().map(l => {
                    const parts = l.split(' нанес ');
                    return `<div class="log-entry"><b>${parts[0] || 'Игрок'}</b> нанес ${parts[1] || ''}</div>`;
                }).join('');

                // Рекорды с именами игроков
                const damageEntries = logs.map(l => {
                    const match = l.match(/(.+?) нанес (\d+) урона/);
                    return match ? { name: match[1], val: parseInt(match[2]) } : null;
                }).filter(x => x);

                if (damageEntries.length > 0) {
                    const max = damageEntries.reduce((prev, curr) => (curr.val > prev.val) ? curr : prev);
                    const min = damageEntries.reduce((prev, curr) => (curr.val < prev.val) ? curr : prev);
                   
                    // Обновление максимального урона с именем игрока
                    document.getElementById('maxDmg').textContent = `${max.val}`;
                    document.getElementById('maxPlayer').textContent = max.name;
                   
                    // Обновление минимального урона с именем игрока
                    document.getElementById('minDmg').textContent = `${min.val}`;
                    document.getElementById('minPlayer').textContent = min.name;
                } else {
                    // Сброс значений, если нет данных
                    document.getElementById('maxDmg').textContent = '-';
                    document.getElementById('maxPlayer').textContent = '-';
                    document.getElementById('minDmg').textContent = '-';
                    document.getElementById('minPlayer').textContent = '-';
                }
            } catch (e) { console.error("UI Update Error:", e); }
        }

        document.getElementById('atkBtn').onclick = async () => {
            const dmg = Math.floor(Math.random() * 100) + 1;
            const msgInput = document.getElementById('msg');
            const res = await send("processAttack", {
                attackData: { damage: dmg, message: msgInput.value, timestamp: Date.now() }
            });
           
            if(res.success) {
                const resDiv = document.getElementById('dmgRes');
                resDiv.textContent = `УДАР: -${dmg} HP!`;
                msgInput.value = '';
               
                // Эффект тряски
                const frame = document.getElementById('bossFrame');
                frame.style.transform = 'translate(4px, 4px) rotate(1deg)';
                setTimeout(() => frame.style.transform = 'none', 100);
               
                await updateUI();
            }
        };

        setInterval(updateUI, 4000);
        updateUI();
    </script>
</body>
</html>[/html]

0

7

[html]<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Oswald:wght@400;700&family=Roboto+Condensed:wght@400;700&display=swap');

        * { margin: 0; padding: 0; box-sizing: border-box; }
       
        body {
            background: #0a0a0c;
            background-image: radial-gradient(circle at center, #1a1a2e 0%, #0a0a0c 100%);
            color: #e0e0e0;
            font-family: 'Roboto Condensed', sans-serif;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }

        .game-container {
            display: grid;
            grid-template-columns: 300px 1fr;
            gap: 25px;
            max-width: 1100px;
            width: 100%;
            background: rgba(0, 0, 0, 0.6);
            padding: 30px;
            border-radius: 20px;
            border: 1px solid rgba(255, 255, 255, 0.05);
            box-shadow: 0 20px 50px rgba(0,0,0,0.5);
            backdrop-filter: blur(10px);
        }

        /* --- Левая панель --- */
        .sidebar { display: flex; flex-direction: column; gap: 20px; }

        .panel {
            background: rgba(255, 255, 255, 0.03);
            border-left: 3px solid #ff4655;
            padding: 15px;
            border-radius: 4px;
        }

        .panel-h {
            font-family: 'Oswald', sans-serif;
            font-size: 14px;
            letter-spacing: 2px;
            color: #ff4655;
            margin-bottom: 12px;
            text-transform: uppercase;
        }

        .stat-row {
            display: flex;
            justify-content: space-between;
            padding: 6px 0;
            border-bottom: 1px solid rgba(255,255,255,0.05);
            font-size: 14px;
            gap: 10px;
        }

        .record-info {
            display: flex;
            flex-direction: column;
            gap: 4px;
            text-align: right;
        }

        .record-player {
            color: #aaa;
            font-size: 12px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            max-width: 180px;
        }

        .log-container {
            font-size: 13px;
            height: 200px;
            overflow-y: auto;
            scrollbar-width: thin;
            scrollbar-color: #ff4655 transparent;
        }

        .log-entry {
            padding: 4px 0;
            color: #aaa;
            border-bottom: 1px solid rgba(255,255,255,0.02);
        }

        .log-entry b { color: #ff4655; }

        /* --- Центральная часть --- */
        .main-content { display: flex; flex-direction: column; gap: 20px; }

        .boss-frame {
            position: relative;
            border-radius: 12px;
            overflow: hidden;
            box-shadow: 0 0 30px rgba(255, 70, 85, 0.2);
            border: 1px solid rgba(255, 70, 85, 0.3);
            transition: transform 0.1s;
        }

        .boss-img {
            width: 100%;
            height: 450px;
            object-fit: cover;
            display: block;
        }

        .boss-overlay {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            padding: 40px 20px 20px;
            background: linear-gradient(to top, rgba(0,0,0,0.9) 0%, transparent 100%);
        }

        .boss-info {
            display: flex;
            justify-content: space-between;
            align-items: flex-end;
            margin-bottom: 8px;
            gap: 10px;
        }

        .boss-name {
            font-family: 'Oswald', sans-serif;
            font-size: 32px;
            font-weight: 700;
            color: #fff;
        }

        .hp-text { font-family: 'Oswald', sans-serif; color: #ff4655; font-size: 18px; }

        .hp-bar-bg {
            height: 12px;
            background: rgba(255,255,255,0.1);
            border-radius: 6px;
            overflow: hidden;
        }

        .hp-bar-fill {
            height: 100%;
            background: linear-gradient(90deg, #ff4655, #ff8a71);
            box-shadow: 0 0 15px #ff4655;
            width: 100%;
            transition: width 0.4s ease-out;
        }

        /* --- Управление --- */
        .controls {
            display: grid;
            grid-template-columns: 1fr 200px;
            gap: 15px;
        }

        .game-input {
            width: 100%;
            height: 60px;
            background: rgba(255,255,255,0.05);
            border: 1px solid rgba(255,255,255,0.1);
            border-radius: 8px;
            padding: 0 20px;
            color: #fff;
            font-size: 16px;
            outline: none;
        }

        .btn-attack {
            height: 60px;
            background: #ff4655;
            color: #fff;
            border: none;
            border-radius: 8px;
            font-family: 'Oswald', sans-serif;
            font-size: 20px;
            font-weight: 700;
            cursor: pointer;
            text-transform: uppercase;
            transition: 0.2s;
        }

        .btn-attack:hover:not(:disabled) { background: #ff5e6a; transform: translateY(-2px); }
        .btn-attack:disabled { background: #333; cursor: not-allowed; }

        .damage-popup {
            text-align: center;
            font-family: 'Oswald', sans-serif;
            font-size: 24px;
            color: #ff4655;
            height: 30px;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <aside class="sidebar">
            <div class="panel">
                <div class="panel-h">🏆 Лидеры</div>
                <div id="topList"></div>
            </div>
            <div class="panel">
                <div class="panel-h">🎯 Рекорды</div>
                <div class="stat-row">
                    <span>Макс. урон</span>
                    <div class="record-info">
                        <b id="maxDmg" style="color:#ff4655">-</b>
                        <div id="maxPlayer" class="record-player">-</div>
                    </div>
                </div>
                <div class="stat-row">
                    <span>Мин. урон</span>
                    <div class="record-info">
                        <b id="minDmg" style="color:#fff">-</b>
                        <div id="minPlayer" class="record-player">-</div>
                    </div>
                </div>
            </div>
            <div class="panel" style="flex-grow: 1;">
                <div class="panel-h">📜 Журнал боя</div>
                <div id="logs" class="log-container"></div>
            </div>
        </aside>

        <main class="main-content">
            <div class="boss-frame" id="bossFrame">
                <img src="https://upforme.ru/uploads/001c/84/76/2/433839.jpg" class="boss-img" alt="Boss">
                <div class="boss-overlay">
                    <div class="boss-info">
                        <div class="boss-name">ДРЕВНИЙ СТРАЖ</div>
                        <div id="hpText" class="hp-text">... / ...</div>
                    </div>
                    <div class="hp-bar-bg">
                        <div id="hpBar" class="hp-bar-fill" style="width: 100%;"></div>
                    </div>
                </div>
            </div>

            <div class="controls">
                <input type="text" id="msg" class="game-input" placeholder="Введите боевой клич...">
                <button id="atkBtn" class="btn-attack">УДАРИТЬ</button>
            </div>
            <div id="dmgRes" class="damage-popup"></div>
        </main>
    </div>

    <script>
        const send = (action, data = {}) => {
            const requestId = Math.random().toString(16).slice(2);
            window.parent.postMessage({ _monsterGame: true, type: "gameRequest", requestId, action, ...data }, '*');
            return new Promise(resolve => {
                const handler = (e) => {
                    if(e.data?.requestId === requestId) {
                        window.removeEventListener("message", handler);
                        resolve(e.data.data);
                    }
                };
                window.addEventListener("message", handler);
            });
        };

        async function updateUI() {
            try {
                const [game, top, logs] = await Promise.all([
                    send("getGameData"),
                    send("getTopPlayers"),
                    send("getRecentLogs")
                ]);

                const currentHp = game.boss.currentHealth;
                const maxHp = game.boss.maxHealth;
                const hpPct = Math.max(0, (currentHp / maxHp) * 100);

                const bar = document.getElementById('hpBar');
                bar.style.width = hpPct + '%';
               
                document.getElementById('hpText').textContent = `${currentHp} / ${maxHp}`;

                // ✅ Блокируем кнопку, если бой завершен
                const isOver = (currentHp <= 0) || !!game.boss.isDefeated;
                document.getElementById('atkBtn').disabled = isOver;

                // Лидеры
                document.getElementById('topList').innerHTML = top.slice(0, 5).map(p =>
                    `<div class="stat-row"><span>${p.nickname}</span><b>${p.totalDamage}</b></div>`
                ).join('') || 'Нет данных';

                // Логи
                document.getElementById('logs').innerHTML = logs.slice(-20).reverse().map(l => {
                    const parts = l.split(' нанес ');
                    return `<div class="log-entry"><b>${parts[0] || 'Игрок'}</b> нанес ${parts[1] || ''}</div>`;
                }).join('');

                // ✅ Рекорды: показываем всех игроков при одинаковых значениях
                const damageEntries = logs.map(l => {
                    const match = l.match(/(.+?) нанес (\d+) урона/);
                    return match ? { name: match[1], val: parseInt(match[2], 10) } : null;
                }).filter(Boolean);

                if (damageEntries.length > 0) {
                    const values = damageEntries.map(x => x.val);
                    const maxVal = Math.max(...values);
                    const minVal = Math.min(...values);

                    const maxPlayers = [...new Set(damageEntries.filter(x => x.val === maxVal).map(x => x.name))];
                    const minPlayers = [...new Set(damageEntries.filter(x => x.val === minVal).map(x => x.name))];

                    document.getElementById('maxDmg').textContent = `${maxVal}`;
                    document.getElementById('maxPlayer').textContent = maxPlayers.join(', ');

                    document.getElementById('minDmg').textContent = `${minVal}`;
                    document.getElementById('minPlayer').textContent = minPlayers.join(', ');
                } else {
                    document.getElementById('maxDmg').textContent = '-';
                    document.getElementById('maxPlayer').textContent = '-';
                    document.getElementById('minDmg').textContent = '-';
                    document.getElementById('minPlayer').textContent = '-';
                }

            } catch (e) { console.error("UI Update Error:", e); }
        }

        document.getElementById('atkBtn').onclick = async () => {
            const dmg = Math.floor(Math.random() * 100) + 1;
            const msgInput = document.getElementById('msg');

            const res = await send("processAttack", {
                attackData: { damage: dmg, message: msgInput.value, timestamp: Date.now() }
            });

            // ✅ если бой завершен — показываем сообщение и просто обновляем UI
            if (res && res.gameOver) {
                document.getElementById('dmgRes').textContent = 'БОЙ ЗАВЕРШЕН!';
                await updateUI();
                return;
            }
           
            if(res && res.success) {
                const resDiv = document.getElementById('dmgRes');
                resDiv.textContent = `УДАР: -${dmg} HP!`;
                msgInput.value = '';
               
                const frame = document.getElementById('bossFrame');
                frame.style.transform = 'translate(4px, 4px) rotate(1deg)';
                setTimeout(() => frame.style.transform = 'none', 100);
               
                await updateUI();
            }
        };

        setInterval(updateUI, 4000);
        updateUI();
    </script>
</body>
</html>[/html]

0

8

[html]<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Oswald:wght@400;700&family=Roboto+Condensed:wght@400;700&display=swap');
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            background: #0a0a0c;
            background-image: radial-gradient(circle at center, #1a1a2e 0%, #0a0a0c 100%);
            color: #e0e0e0;
            font-family: 'Roboto Condensed', sans-serif;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }
        .game-container {
            display: grid;
            grid-template-columns: 300px 1fr;
            gap: 25px;
            max-width: 1100px;
            width: 100%;
            background: rgba(0, 0, 0, 0.6);
            padding: 30px;
            border-radius: 20px;
            border: 1px solid rgba(255, 255, 255, 0.05);
            box-shadow: 0 20px 50px rgba(0,0,0,0.5);
            backdrop-filter: blur(10px);
        }
        .sidebar { display: flex; flex-direction: column; gap: 20px; }
        .panel { background: rgba(255,255,255,0.03); border-left: 3px solid #ff4655; padding: 15px; border-radius: 4px; }
        .panel-h { font-family:'Oswald',sans-serif; font-size:14px; letter-spacing:2px; color:#ff4655; margin-bottom:12px; text-transform:uppercase; }
        .stat-row { display:flex; justify-content:space-between; padding:6px 0; border-bottom:1px solid rgba(255,255,255,0.05); font-size:14px; gap:10px; }
        .record-info { display:flex; flex-direction:column; gap:4px; text-align:right; }
        .record-player { color:#aaa; font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:180px; }
        .log-container { font-size:13px; height:200px; overflow-y:auto; scrollbar-width:thin; scrollbar-color:#ff4655 transparent; }
        .log-entry { padding:4px 0; color:#aaa; border-bottom:1px solid rgba(255,255,255,0.02); }
        .log-entry b { color:#ff4655; }

        .main-content { display:flex; flex-direction:column; gap:20px; }
        .boss-frame { position:relative; border-radius:12px; overflow:hidden; box-shadow:0 0 30px rgba(255,70,85,0.2); border:1px solid rgba(255,70,85,0.3); transition:transform 0.1s; }
        .boss-img { width:100%; height:450px; object-fit:cover; display:block; }
        .boss-overlay { position:absolute; bottom:0; left:0; right:0; padding:40px 20px 20px; background:linear-gradient(to top, rgba(0,0,0,0.9) 0%, transparent 100%); }
        .boss-info { display:flex; justify-content:space-between; align-items:flex-end; margin-bottom:8px; gap:10px; }
        .boss-name { font-family:'Oswald',sans-serif; font-size:32px; font-weight:700; color:#fff; }
        .hp-text { font-family:'Oswald',sans-serif; color:#ff4655; font-size:18px; }
        .hp-bar-bg { height:12px; background:rgba(255,255,255,0.1); border-radius:6px; overflow:hidden; }
        .hp-bar-fill { height:100%; background:linear-gradient(90deg, #ff4655, #ff8a71); box-shadow:0 0 15px #ff4655; width:100%; transition:width 0.4s ease-out; }

        .controls { display:grid; grid-template-columns:1fr 200px; gap:15px; }
        .game-input { width:100%; height:60px; background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.1); border-radius:8px; padding:0 20px; color:#fff; font-size:16px; outline:none; }
        .btn-attack { height:60px; background:#ff4655; color:#fff; border:none; border-radius:8px; font-family:'Oswald',sans-serif; font-size:20px; font-weight:700; cursor:pointer; text-transform:uppercase; transition:0.2s; }
        .btn-attack:hover:not(:disabled) { background:#ff5e6a; transform:translateY(-2px); }
        .btn-attack:disabled { background:#333; cursor:not-allowed; }
        .damage-popup { text-align:center; font-family:'Oswald',sans-serif; font-size:24px; color:#ff4655; height:30px; margin-top:10px; }
    </style>
</head>
<body>
    <div class="game-container">
        <aside class="sidebar">
            <div class="panel">
                <div class="panel-h">🏆 Лидеры</div>
                <div id="topList"></div>
            </div>
            <div class="panel">
                <div class="panel-h">🎯 Рекорды</div>
                <div class="stat-row">
                    <span>Макс. урон</span>
                    <div class="record-info">
                        <b id="maxDmg" style="color:#ff4655">-</b>
                        <div id="maxPlayer" class="record-player">-</div>
                    </div>
                </div>
                <div class="stat-row">
                    <span>Мин. урон</span>
                    <div class="record-info">
                        <b id="minDmg" style="color:#fff">-</b>
                        <div id="minPlayer" class="record-player">-</div>
                    </div>
                </div>
            </div>
            <div class="panel" style="flex-grow: 1;">
                <div class="panel-h">📜 Журнал боя</div>
                <div id="logs" class="log-container"></div>
            </div>
        </aside>

        <main class="main-content">
            <div class="boss-frame" id="bossFrame">
                <img src="https://upforme.ru/uploads/001c/84/76/2/433839.jpg" class="boss-img" alt="Boss">
                <div class="boss-overlay">
                    <div class="boss-info">
                        <div class="boss-name">ДРЕВНИЙ СТРАЖ</div>
                        <div id="hpText" class="hp-text">... / ...</div>
                    </div>
                    <div class="hp-bar-bg">
                        <div id="hpBar" class="hp-bar-fill" style="width: 100%;"></div>
                    </div>
                </div>
            </div>

            <div class="controls">
                <input type="text" id="msg" class="game-input" placeholder="Введите боевой клич...">
                <button id="atkBtn" class="btn-attack">УДАРИТЬ</button>
            </div>
            <div id="dmgRes" class="damage-popup"></div>
        </main>
    </div>

    <script>
        const send = (action, data = {}) => {
            const requestId = Math.random().toString(16).slice(2);
            window.parent.postMessage({ _monsterGame: true, type: "gameRequest", requestId, action, ...data }, '*');
            return new Promise(resolve => {
                const handler = (e) => {
                    if (e.data?.requestId === requestId) {
                        window.removeEventListener("message", handler);
                        resolve(e.data.data);
                    }
                };
                window.addEventListener("message", handler);
            });
        };

        async function updateUI() {
            try {
                const snap = await send("getSnapshot");
                const game = snap.game;
                const top = snap.top || [];
                const logs = snap.logs || [];
                const rec = snap.records || { maxVal: null, maxPlayers: [], minVal: null, minPlayers: [] };

                const currentHp = game.boss.currentHealth;
                const maxHp = game.boss.maxHealth;
                const hpPct = Math.max(0, (currentHp / maxHp) * 100);

                document.getElementById('hpBar').style.width = hpPct + '%';
                document.getElementById('hpText').textContent = `${currentHp} / ${maxHp}`;

                const isOver = (currentHp <= 0) || !!game.boss.isDefeated;
                document.getElementById('atkBtn').disabled = isOver;

                document.getElementById('topList').innerHTML =
                    top.slice(0, 5).map(p =>
                        `<div class="stat-row"><span>${p.nickname}</span><b>${p.totalDamage}</b></div>`
                    ).join('') || 'Нет данных';

                document.getElementById('logs').innerHTML =
                    logs.slice(-20).reverse().map(l => {
                        const parts = l.split(' нанес ');
                        return `<div class="log-entry"><b>${parts[0] || 'Игрок'}</b> нанес ${parts[1] || ''}</div>`;
                    }).join('');

                if (rec.maxVal != null) {
                    document.getElementById('maxDmg').textContent = String(rec.maxVal);
                    document.getElementById('maxPlayer').textContent = (rec.maxPlayers || []).join(', ') || '-';
                } else {
                    document.getElementById('maxDmg').textContent = '-';
                    document.getElementById('maxPlayer').textContent = '-';
                }

                if (rec.minVal != null) {
                    document.getElementById('minDmg').textContent = String(rec.minVal);
                    document.getElementById('minPlayer').textContent = (rec.minPlayers || []).join(', ') || '-';
                } else {
                    document.getElementById('minDmg').textContent = '-';
                    document.getElementById('minPlayer').textContent = '-';
                }
            } catch (e) {
                console.error("UI Update Error:", e);
            }
        }

        document.getElementById('atkBtn').onclick = async () => {
            const msgInput = document.getElementById('msg');
            const btn = document.getElementById('atkBtn');
            btn.disabled = true;

            // ✅ урон считает родитель, мы шлём только текст
            const res = await send("processAttack", { attackData: { message: msgInput.value } });

            if (res && res.gameOver) {
                document.getElementById('dmgRes').textContent = 'БОЙ ЗАВЕРШЕН!';
                await updateUI();
                return;
            }

            if (res && res.success) {
                document.getElementById('dmgRes').textContent = `УДАР: -${res.damage} HP!`;
                msgInput.value = '';

                const frame = document.getElementById('bossFrame');
                frame.style.transform = 'translate(4px, 4px) rotate(1deg)';
                setTimeout(() => frame.style.transform = 'none', 100);

                await updateUI();
            }

            setTimeout(() => {
                document.getElementById('dmgRes').textContent = '';
                updateUI().then(() => {});
            }, 2500);
        };

        setInterval(updateUI, 15000);
        updateUI();
    </script>
</body>
</html>[/html]

0

9

[html]<div style="border:3px solid #ff6b6b;border-radius:15px;padding:20px;background:#494a4c;color:white;text-align:center;font-family:sans-serif;">
            <h2 style="color:#ff6b6b; margin:0; font-size:20px;">⚔️ АТАКА: 93 УРОНА!</h2>
            <p style="margin:10px 0;">admin ударил 🔥 ГНЕВНЫЙ ДРАКОН</p>
           
            <p style="font-size:13px; color:#aaa; margin-top:10px;">Осталось HP: 907 / 1000</p>
        </div>[/html]

0

10

[html]<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Oswald:wght@400;700&family=Roboto+Condensed:wght@400;700&display=swap');
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      background: #0a0a0c;
      background-image: radial-gradient(circle at center, #1a1a2e 0%, #0a0a0c 100%);
      color: #e0e0e0;
      font-family: 'Roboto Condensed', sans-serif;
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }
    .game-container {
      display: grid;
      grid-template-columns: 300px 1fr;
      gap: 25px;
      max-width: 1100px;
      width: 100%;
      background: rgba(0, 0, 0, 0.6);
      padding: 30px;
      border-radius: 20px;
      border: 1px solid rgba(255, 255, 255, 0.05);
      box-shadow: 0 20px 50px rgba(0,0,0,0.5);
      backdrop-filter: blur(10px);
    }
    .sidebar { display:flex; flex-direction:column; gap:20px; }
    .panel { background: rgba(255,255,255,0.03); border-left:3px solid #ff4655; padding:15px; border-radius:4px; }
    .panel-h { font-family:'Oswald',sans-serif; font-size:14px; letter-spacing:2px; color:#ff4655; margin-bottom:12px; text-transform:uppercase; }
    .stat-row { display:flex; justify-content:space-between; padding:6px 0; border-bottom:1px solid rgba(255,255,255,0.05); font-size:14px; gap:10px; }
    .record-info { display:flex; flex-direction:column; gap:4px; text-align:right; }
    .record-player { color:#aaa; font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:180px; }
    .log-container { font-size:13px; height:200px; overflow-y:auto; scrollbar-width:thin; scrollbar-color:#ff4655 transparent; }
    .log-entry { padding:4px 0; color:#aaa; border-bottom:1px solid rgba(255,255,255,0.02); }
    .log-entry b { color:#ff4655; }

    .main-content { display:flex; flex-direction:column; gap:20px; }
    .boss-frame { position:relative; border-radius:12px; overflow:hidden; box-shadow:0 0 30px rgba(255,70,85,0.2); border:1px solid rgba(255,70,85,0.3); transition: transform 0.1s; }
    .boss-img { width:100%; height:450px; object-fit:cover; display:block; }
    .boss-overlay { position:absolute; bottom:0; left:0; right:0; padding:40px 20px 20px; background:linear-gradient(to top, rgba(0,0,0,0.9) 0%, transparent 100%); }
    .boss-info { display:flex; justify-content:space-between; align-items:flex-end; margin-bottom:8px; gap:10px; }
    .boss-name { font-family:'Oswald',sans-serif; font-size:32px; font-weight:700; color:#fff; }
    .hp-text { font-family:'Oswald',sans-serif; color:#ff4655; font-size:18px; }
    .hp-bar-bg { height:12px; background:rgba(255,255,255,0.1); border-radius:6px; overflow:hidden; }
    .hp-bar-fill { height:100%; background:linear-gradient(90deg, #ff4655, #ff8a71); box-shadow:0 0 15px #ff4655; width:100%; transition:width 0.4s ease-out; }

    .controls { display:grid; grid-template-columns:1fr 200px; gap:15px; }
    .game-input { width:100%; height:60px; background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.1); border-radius:8px; padding:0 20px; color:#fff; font-size:16px; outline:none; }
    .btn-attack { height:60px; background:#ff4655; color:#fff; border:none; border-radius:8px; font-family:'Oswald',sans-serif; font-size:20px; font-weight:700; cursor:pointer; text-transform:uppercase; transition:0.2s; }
    .btn-attack:hover:not(:disabled) { background:#ff5e6a; transform:translateY(-2px); }
    .btn-attack:disabled { background:#333; cursor:not-allowed; }

    .damage-popup { text-align:center; font-family:'Oswald',sans-serif; font-size:24px; color:#ff4655; height:30px; margin-top:10px; }
  </style>
</head>
<body>
  <div class="game-container">
    <aside class="sidebar">
      <div class="panel">
        <div class="panel-h">🏆 Лидеры</div>
        <div id="topList"></div>
      </div>
      <div class="panel">
        <div class="panel-h">🎯 Рекорды</div>
        <div class="stat-row">
          <span>Макс. урон</span>
          <div class="record-info">
            <b id="maxDmg" style="color:#ff4655">-</b>
            <div id="maxPlayer" class="record-player">-</div>
          </div>
        </div>
        <div class="stat-row">
          <span>Мин. урон</span>
          <div class="record-info">
            <b id="minDmg" style="color:#fff">-</b>
            <div id="minPlayer" class="record-player">-</div>
          </div>
        </div>
      </div>
      <div class="panel" style="flex-grow:1;">
        <div class="panel-h">📜 Журнал боя</div>
        <div id="logs" class="log-container"></div>
      </div>
    </aside>

    <main class="main-content">
      <div class="boss-frame" id="bossFrame">
        <img src="https://upforme.ru/uploads/001c/84/76/2/433839.jpg" class="boss-img" alt="Boss">
        <div class="boss-overlay">
          <div class="boss-info">
            <div class="boss-name">ДРЕВНИЙ СТРАЖ</div>
            <div id="hpText" class="hp-text">... / ...</div>
          </div>
          <div class="hp-bar-bg">
            <div id="hpBar" class="hp-bar-fill" style="width: 100%;"></div>
          </div>
        </div>
      </div>

      <div class="controls">
        <input type="text" id="msg" class="game-input" placeholder="Введите боевой клич...">
        <button id="atkBtn" class="btn-attack">УДАРИТЬ</button>
      </div>
      <div id="dmgRes" class="damage-popup"></div>
    </main>
  </div>

  <script>
    const send = (action, data = {}) => {
      const requestId = Math.random().toString(16).slice(2);
      window.parent.postMessage({ _monsterGame: true, type: "gameRequest", requestId, action, ...data }, '*');
      return new Promise(resolve => {
        const handler = (e) => {
          if (e.data?.requestId === requestId) {
            window.removeEventListener("message", handler);
            resolve(e.data.data);
          }
        };
        window.addEventListener("message", handler);
      });
    };

    async function updateUI() {
      try {
        const snap = await send("getSnapshot");
        const game = snap.game;
        const top = snap.top || [];
        const logs = snap.logs || [];
        const rec = snap.records || { maxVal: null, maxPlayers: [], minVal: null, minPlayers: [] };

        const currentHp = game.boss.currentHealth;
        const maxHp = game.boss.maxHealth;
        const hpPct = Math.max(0, (currentHp / maxHp) * 100);

        document.getElementById('hpBar').style.width = hpPct + '%';
        document.getElementById('hpText').textContent = `${currentHp} / ${maxHp}`;

        const isOver = (currentHp <= 0) || !!game.boss.isDefeated;
        document.getElementById('atkBtn').disabled = isOver;

        document.getElementById('topList').innerHTML =
          top.slice(0, 5).map(p => `<div class="stat-row"><span>${p.nickname}</span><b>${p.totalDamage}</b></div>`).join('')
          || 'Нет данных';

        document.getElementById('logs').innerHTML =
          logs.slice(-20).reverse().map(l => {
            const parts = l.split(' нанес ');
            return `<div class="log-entry"><b>${parts[0] || 'Игрок'}</b> нанес ${parts[1] || ''}</div>`;
          }).join('');

        if (rec.maxVal != null) {
          document.getElementById('maxDmg').textContent = String(rec.maxVal);
          document.getElementById('maxPlayer').textContent = (rec.maxPlayers || []).join(', ') || '-';
        } else {
          document.getElementById('maxDmg').textContent = '-';
          document.getElementById('maxPlayer').textContent = '-';
        }

        if (rec.minVal != null) {
          document.getElementById('minDmg').textContent = String(rec.minVal);
          document.getElementById('minPlayer').textContent = (rec.minPlayers || []).join(', ') || '-';
        } else {
          document.getElementById('minDmg').textContent = '-';
          document.getElementById('minPlayer').textContent = '-';
        }

      } catch (e) {
        console.error("UI Update Error:", e);
      }
    }

    document.getElementById('atkBtn').onclick = async () => {
      const msgInput = document.getElementById('msg');
      const btn = document.getElementById('atkBtn');
      btn.disabled = true;

      // ✅ шлём только message, урон считает родитель
      const res = await send("processAttack", { attackData: { message: msgInput.value } });

      if (res && res.gameOver) {
        document.getElementById('dmgRes').textContent = 'БОЙ ЗАВЕРШЕН!';
        await updateUI();
        return;
      }

      if (res && res.success) {
        document.getElementById('dmgRes').textContent = `УДАР: -${res.damage} HP!`;
        msgInput.value = '';

        const frame = document.getElementById('bossFrame');
        frame.style.transform = 'translate(4px, 4px) rotate(1deg)';
        setTimeout(() => frame.style.transform = 'none', 100);

        // ✅ один апдейт (без второго “лишнего”)
        await updateUI();
      }

      setTimeout(() => { document.getElementById('dmgRes').textContent = ''; }, 2500);
    };

    setInterval(updateUI, 15000);
    updateUI();
  </script>
</body>
</html>[/html]

0

11

[html]<div style="border:3px solid #ff6b6b;border-radius:15px;padding:20px;background:#494a4c;color:white;text-align:center;font-family:sans-serif;">
            <h2 style="color:#ff6b6b; margin:0; font-size:20px;">⚔️ АТАКА: 92 УРОНА!</h2>
            <p style="margin:10px 0;">admin ударил 🔥 ГНЕВНЫЙ ДРАКОН</p>
           
            <p style="font-size:13px; color:#aaa; margin-top:10px;">Осталось HP: 908 / 1000</p>
        </div>[/html]

0

12

[html]<div style="border:3px solid #ff6b6b;border-radius:15px;padding:20px;background:#494a4c;color:white;text-align:center;font-family:sans-serif;">
      <h2 style="color:#ff6b6b; margin:0; font-size:20px;">⚔️ АТАКА: 88 УРОНА!</h2>
      <p style="margin:10px 0;">admin ударил 🔥 ГНЕВНЫЙ ДРАКОН</p>
     
      <p style="font-size:13px; color:#aaa; margin-top:10px;">Осталось HP: 912 / 1000</p>
    </div>[/html]

0


Вы здесь » test » Тестовый форум » боссфайт


Рейтинг форумов | Создать форум бесплатно