Ametuct / Метрическая книга Ветра

// ==UserScript==
// @name         Метрическая книга Ветра
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Ведёт запись в тетрадь смерти
// @author       Светокамень I Великая
// @license      MIT
// @match        *://catwar.net/*
// @match        *://catwar.su/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=catwar.net
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Память
    let catsMemory = JSON.parse(sessionStorage.getItem('cw-cats-memory') || '{}');
    let expectedCats = JSON.parse(sessionStorage.getItem('cw-expected-cats') || '{}');

    // Глобальные стили
    const globalStyles = document.createElement('style');
    globalStyles.textContent = `
        .cw-copy-color-btn {
            height: 40px;
            cursor: pointer;
            border-radius: 4px;
            transition: transform 0.2s, box-shadow 0.2s;
            background: rgba(255,255,255,0.1);
        }
        .cw-copy-color-btn:hover {
            transform: scale(1.1);
            box-shadow: 0 0 8px rgba(255,255,255,0.5);
        }
        .cw-copy-row-btn {
            cursor: pointer;
            font-size: 16px;
            transition: transform 0.1s;
            display: inline-block;
        }
        .cw-copy-row-btn:hover {
            transform: scale(1.2);
        }
        .cw-profile-btn {
            text-decoration: none;
            font-size: 16px;
            margin-left: 8px;
            transition: transform 0.1s;
            display: inline-block;
        }
        .cw-profile-btn:hover {
            transform: scale(1.2);
        }
        #cw-cats-table-overlay {
            position: fixed;
            top: 50px;
            right: 50px;
            background: rgba(30, 30, 30, 0.95);
            color: #fff;
            padding: 15px;
            border-radius: 8px;
            z-index: 99999;
            max-height: 80vh;
            overflow-y: auto;
            font-family: sans-serif;
            box-shadow: 0 4px 15px rgba(0,0,0,0.5);
            border: 1px solid #555;
            min-width: 480px;
        }
        .cw-row-gray { background-color: rgba(150, 150, 150, 0.25); }
        .cw-row-red { background-color: rgba(220, 53, 69, 0.4); }
    `;
    document.head.appendChild(globalStyles);

    // ==========================================
    // 1. ФУНКЦИЯ ДЛЯ ПРОФИЛЯ (Копирование даты)
    // ==========================================
    function checkProfileAndAddButton() {
        if (document.getElementById('cw-copy-date-btn')) return;

        // Ищем иконки (сначала перерождение, если нет - обычную)
        const age2Icon = document.getElementById('age2_icon');
        const ageIcon = document.getElementById('age_icon');
        const targetIcon = age2Icon || ageIcon;

        if (!targetIcon) return;

        const targetTd = targetIcon.closest('td').nextElementSibling;

        if (targetTd) {
            const copyBtn = document.createElement('span');
            copyBtn.id = 'cw-copy-date-btn';
            copyBtn.textContent = '📋';
            copyBtn.title = 'Скопировать дату (скрипт сам нажмет на луны)';
            copyBtn.style.cssText = `
                cursor: pointer;
                margin-left: 10px;
                font-size: 16px;
                transition: transform 0.1s;
                display: inline-block;
                vertical-align: middle;
            `;

            copyBtn.addEventListener('mouseenter', () => copyBtn.style.transform = 'scale(1.2)');
            copyBtn.addEventListener('mouseleave', () => copyBtn.style.transform = 'scale(1)');

            copyBtn.addEventListener('click', (e) => {
                e.stopPropagation();

                const originalIcon = '📋';
                copyBtn.textContent = '⏳'; // Показываем часики, пока ждем ответа от сервера игры

                // 1. Программно кликаем по самой картинке лун
                targetIcon.click();

                // 2. Запускаем таймер, который будет искать дату каждые 100мс
                let attempts = 0;
                const checkInterval = setInterval(() => {
                    attempts++;
                    const infoBlock = document.getElementById('info');

                    let finalDate = "";
                    // Если блок инфо видим и в нем есть текст, ищем дату
                    if (infoBlock && infoBlock.style.display !== 'none') {
                        const match = infoBlock.innerHTML.match(/(\d{4}-\d{2}-\d{2})/);
                        if (match) {
                            finalDate = match[1];
                        }
                    }

                    // Если нашли дату
                    if (finalDate) {
                        clearInterval(checkInterval); // Останавливаем проверки
                        navigator.clipboard.writeText(finalDate).then(() => {
                            copyBtn.textContent = '✅';
                            setTimeout(() => { copyBtn.textContent = originalIcon; }, 1500);
                        });
                    } else if (attempts > 30) {
                        // Если прошло 3 секунды (30 попыток), а даты нет - сдаемся
                        clearInterval(checkInterval);
                        copyBtn.textContent = originalIcon;
                        alert('Не удалось получить дату. Возможно, сервер игры слишком долго отвечает.');
                    }
                }, 100);
            });

            targetTd.appendChild(copyBtn);
        }
    }

    // ==========================================
    // 2. ФУНКЦИЯ ДЛЯ ЛОКАЦИИ (Сбор котов)
    // ==========================================
    function scanCats() {
        const tooltips = document.querySelectorAll('.cat_tooltip');
        if (tooltips.length === 0) return;

        let isChanged = false;

        tooltips.forEach(tooltip => {
            try {
                const hasSpecificOdor = tooltip.querySelector('img[src*="odoroj/2.png"]');
                if (!hasSpecificOdor) return;

                const link = tooltip.querySelector('u a');
                if (!link) return;
                const name = link.textContent.trim();
                const href = link.getAttribute('href');
                const id = href ? href.replace('/cat', '') : 'Нет ID';
                if (id === 'Нет ID') return;

                const roleElements = tooltip.querySelectorAll('small i');
                let role = '-';
                if (roleElements.length > 0) {
                    role = roleElements[roleElements.length - 1].textContent.trim();
                }

                let colorUrl = 'Нет окраса';
                const catContainer = tooltip.closest('.cat');
                if (catContainer) {
                    const firstDiv = catContainer.querySelector('.first');
                    if (firstDiv && firstDiv.style.backgroundImage) {
                        const match = firstDiv.style.backgroundImage.match(/url\(["']?(.*?)["']?\)/);
                        if (match && match[1]) {
                            const rawUrl = match[1];
                            colorUrl = rawUrl.startsWith('http') ? rawUrl : 'https://catwar.net' + (rawUrl.startsWith('/') ? '' : '/') + rawUrl;
                        }
                    }
                }

                const existing = catsMemory[id];
                if (!existing || existing.name !== name || existing.role !== role || existing.colorUrl !== colorUrl) {
                    catsMemory[id] = { id, name, role, colorUrl };
                    isChanged = true;
                }
            } catch (e) {
                console.error("Ошибка при чтении данных кота:", e);
            }
        });

        if (isChanged) {
            sessionStorage.setItem('cw-cats-memory', JSON.stringify(catsMemory));
            if (document.getElementById('cw-cats-table-content')) {
                renderTableContent();
            }
        }
    }

    // ==========================================
    // 3. ОТРИСОВКА И ЛОГИКА ТАБЛИЦЫ
    // ==========================================
    function processPastedData() {
        const textArea = document.getElementById('cw-expected-data');
        if (!textArea) return;

        const lines = textArea.value.trim().split('\n');
        const newExpected = {};
        let count = 0;

        lines.forEach(line => {
            const cols = line.split('\t');
            if (cols.length >= 7) {
                const id = cols[0].trim();
                if (/^\d+$/.test(id)) {
                    newExpected[id] = {
                        name: cols[1].trim(),
                        role: cols[3].trim(),
                        colorUrl: cols[6].trim()
                    };
                    count++;
                }
            }
        });

        expectedCats = newExpected;
        sessionStorage.setItem('cw-expected-cats', JSON.stringify(expectedCats));

        textArea.value = '';
        textArea.placeholder = `Таблица загружена! Котов в базе: ${count}`;
        renderTableContent();
    }

    function renderTableContent() {
        const wrapper = document.getElementById('cw-cats-table-content');
        const missingWrapper = document.getElementById('cw-missing-cats-content');
        if (!wrapper) return;

        const cats = Object.values(catsMemory);
        const hasExpectedData = Object.keys(expectedCats).length > 0;
        let html = '';

        if (cats.length === 0) {
            html += '<p style="text-align:center; color:#aaa; margin: 10px 0;">Замеченных котов нет. Ждем появления...</p>';
        } else {
            html += '<h3 style="margin-top:15px; border-bottom: 1px solid #555; padding-bottom: 10px;">Замеченные коты (' + cats.length + ')</h3>';
            html += '<table style="width: 100%; border-collapse: collapse; text-align: left;">';
            html += '<tr style="border-bottom: 2px solid #777;"><th style="padding: 5px; width: 60px;"></th><th style="padding: 5px;">ID</th><th style="padding: 5px;">ИМЯ</th><th style="padding: 5px;">ДОЛЖНОСТЬ</th><th style="padding: 5px; text-align: center;">ОКРАС</th></tr>';

            cats.forEach(cat => {
                let colorHtml = '-';
                if (cat.colorUrl !== 'Нет окраса') {
                    colorHtml = `<img src="${cat.colorUrl}" class="cw-copy-color-btn" data-url="${cat.colorUrl}" title="Нажмите, чтобы скопировать ссылку" alt="Окрас">`;
                }

                const rowCopyData = `${cat.id}\t${cat.name}\t\t${cat.role}\t\t\t${cat.colorUrl}`;
                let rowClass = '';
                let titleAttr = '';

                if (hasExpectedData) {
                    const exp = expectedCats[cat.id];
                    if (!exp) {
                        rowClass = 'cw-row-gray';
                        titleAttr = 'Этого кота нет в вашей Google Таблице';
                    } else {
                        const isNameDiff = cat.name !== exp.name;
                        const isRoleDiff = cat.role !== exp.role;
                        const isColorDiff = cat.colorUrl !== exp.colorUrl;

                        if (isNameDiff || isRoleDiff || isColorDiff) {
                            rowClass = 'cw-row-red';
                            let diffs = [];
                            if (isNameDiff) diffs.push(`Имя (Ожидалось: ${exp.name})`);
                            if (isRoleDiff) diffs.push(`Должность (Ожидалось: ${exp.role})`);
                            if (isColorDiff) diffs.push(`Окрас (Ожидался другой)`);
                            titleAttr = 'Несовпадение: ' + diffs.join(', ');
                        }
                    }
                }

                html += `<tr class="${rowClass}" title="${titleAttr}">
                    <td style="padding: 5px; border-bottom: 1px solid #444; text-align: center; white-space: nowrap;">
                        <span class="cw-copy-row-btn" data-copy="${rowCopyData}" title="Скопировать строку">📋</span>
                        <a href="https://catwar.net/cat${cat.id}" target="_blank" class="cw-profile-btn" title="Перейти в профиль">🐱</a>
                    </td>
                    <td style="padding: 5px; border-bottom: 1px solid #444; color: #a8d5ff;">${cat.id}</td>
                    <td style="padding: 5px; border-bottom: 1px solid #444; font-weight: bold;">${cat.name}</td>
                    <td style="padding: 5px; border-bottom: 1px solid #444; color: #ffcc80;">${cat.role}</td>
                    <td style="padding: 5px; border-bottom: 1px solid #444; text-align: center;">${colorHtml}</td>
                </tr>`;
            });
            html += '</table>';
        }

        wrapper.innerHTML = html;

        const copyColorBtns = wrapper.querySelectorAll('.cw-copy-color-btn');
        copyColorBtns.forEach(btn => {
            btn.addEventListener('click', function() {
                const url = this.getAttribute('data-url');
                navigator.clipboard.writeText(url).then(() => {
                    this.style.boxShadow = '0 0 10px #4caf50';
                    this.style.border = '2px solid #4caf50';
                    setTimeout(() => {
                        this.style.boxShadow = 'none';
                        this.style.border = 'none';
                    }, 600);
                });
            });
        });

        const copyRowBtns = wrapper.querySelectorAll('.cw-copy-row-btn');
        copyRowBtns.forEach(btn => {
            btn.addEventListener('click', function(e) {
                e.stopPropagation();
                const dataToCopy = this.getAttribute('data-copy');

                navigator.clipboard.writeText(dataToCopy).then(() => {
                    const originalIcon = this.textContent;
                    this.textContent = '✅';
                    setTimeout(() => {
                        this.textContent = originalIcon;
                    }, 1000);
                });
            });
        });

        if (missingWrapper) {
            let missingHtml = '';

            if (hasExpectedData) {
                const missingCats = [];
                for (const id in expectedCats) {
                    if (!catsMemory[id]) {
                        missingCats.push({ id: id, name: expectedCats[id].name });
                    }
                }

                if (missingCats.length > 0) {
                    missingHtml += `<h3 style="margin-top: 20px; border-bottom: 1px solid #555; padding-bottom: 10px; color: #ff8a80;">Не удалось найти:</h3>`;
                    missingHtml += `<ul style="margin: 10px 0 0 0; padding-left: 20px; color: #ccc;">`;
                    missingCats.forEach(cat => {
                        missingHtml += `<li style="margin-bottom: 5px;">
                            <span style="font-weight: bold;">${cat.name}</span> —
                            <a href="https://catwar.net/cat${cat.id}" target="_blank" style="color: #b39ddb; text-decoration: none;">Профиль</a>
                        </li>`;
                    });
                    missingHtml += `</ul>`;
                } else if (cats.length > 0) {
                    missingHtml += `<p style="margin-top: 20px; color: #4caf50; font-weight: bold; text-align: center;">Все ожидаемые коты из таблицы найдены!</p>`;
                }
            }

            missingWrapper.innerHTML = missingHtml;
        }
    }

    function toggleCatsList() {
        let container = document.getElementById('cw-cats-table-overlay');

        if (container) {
            container.remove();
        } else {
            container = document.createElement('div');
            container.id = 'cw-cats-table-overlay';

            let html = `
                <div style="background: rgba(0,0,0,0.3); padding: 10px; border-radius: 5px; border: 1px solid #444;">
                    <textarea id="cw-expected-data" style="width: 100%; height: 50px; background: #222; color: #ccc; border: 1px solid #555; border-radius: 4px; padding: 5px; font-size: 12px; resize: vertical;" placeholder="Вставьте скопированные строки из Google Таблицы... (ID - Окрас)"></textarea>
                    <button id="cw-apply-data" style="margin-top: 5px; width: 100%; padding: 6px; background: #2196f3; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold;">Загрузить / Сверить</button>
                </div>
                <div id="cw-cats-table-content"></div>
                <button id="cw-clear-btn" style="margin-top: 15px; padding: 8px 12px; cursor: pointer; background: #757575; color: white; border: none; border-radius: 4px; width: 100%; font-weight: bold;">Очистить список замеченных</button>
                <div id="cw-missing-cats-content"></div>
            `;
            container.innerHTML = html;
            document.body.appendChild(container);

            document.getElementById('cw-apply-data').addEventListener('click', processPastedData);
            document.getElementById('cw-clear-btn').addEventListener('click', () => {
                catsMemory = {};
                sessionStorage.removeItem('cw-cats-memory');
                renderTableContent();
            });

            const hasExpectedData = Object.keys(expectedCats).length > 0;
            if (hasExpectedData) {
                document.getElementById('cw-expected-data').placeholder = `Таблица загружена! Котов в базе: ${Object.keys(expectedCats).length}`;
            }

            renderTableContent();
        }
    }

    function addTriggerButton() {
        if (document.getElementById('cw-trigger-btn')) return;

        if (document.getElementById('age_icon') || document.getElementById('age2_icon')) return;

        const btn = document.createElement('button');
        btn.id = 'cw-trigger-btn';
        btn.textContent = '📋 Список котов';
        btn.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            padding: 10px 15px;
            background: #4caf50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            z-index: 99999;
            font-weight: bold;
            box-shadow: 0 2px 5px rgba(0,0,0,0.3);
        `;
        btn.addEventListener('click', toggleCatsList);
        document.body.appendChild(btn);
    }

    setInterval(() => {
        scanCats();
        checkProfileAndAddButton();
    }, 1500);

    setTimeout(addTriggerButton, 2000);

})();