whynotsoido / Оповещалка

// ==UserScript==
// @name         Оповещалка
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  
// @author       whynotsoido
// @match        https://catwar.net/cw3/*
// @grant        GM_notification
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const STORAGE_KEY = 'catwar_monitoring_paused';

    let currentPlayersOnField = new Set();
    let isFirstRun = true;
    let isJustResumedFromPause = false;

    let isPaused = localStorage.getItem(STORAGE_KEY) === 'true';

    function getPlayerId(element) {
        const link = element.querySelector('a[href^="/cat"]');
        if (link) {
            const match = link.href.match(/\/cat(\d+)/);
            return match ? match[1] : null;
        }
        return null;
    }

    function getPlayerName(element) {
        const link = element.querySelector('a[href^="/cat"]');
        return link ? link.textContent.trim() : 'Неизвестный игрок';
    }

    function getCurrentPlayers() {
        const players = new Map();
        const cageItems = document.querySelectorAll('#cages .cage .cage_items');

        cageItems.forEach(item => {
            const catElement = item.querySelector('.cat');
            if (catElement) {
                const playerId = getPlayerId(catElement);
                const playerName = getPlayerName(catElement);

                if (playerId && playerName) {
                    players.set(playerId, {
                        id: playerId,
                        name: playerName,
                        element: item
                    });
                }
            }
        });

        return players;
    }

    function playAlertSound() {
        try {
            const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

            const oscillator1 = audioCtx.createOscillator();
            const gainNode1 = audioCtx.createGain();
            oscillator1.connect(gainNode1);
            gainNode1.connect(audioCtx.destination);
            oscillator1.frequency.value = 880;
            oscillator1.type = 'sine';
            gainNode1.gain.setValueAtTime(0.3, audioCtx.currentTime);
            gainNode1.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
            oscillator1.start(audioCtx.currentTime);
            oscillator1.stop(audioCtx.currentTime + 0.3);

            setTimeout(() => {
                try {
                    const oscillator2 = audioCtx.createOscillator();
                    const gainNode2 = audioCtx.createGain();
                    oscillator2.connect(gainNode2);
                    gainNode2.connect(audioCtx.destination);
                    oscillator2.frequency.value = 1108.73;
                    oscillator2.type = 'sine';
                    gainNode2.gain.setValueAtTime(0.3, audioCtx.currentTime);
                    gainNode2.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.4);
                    oscillator2.start(audioCtx.currentTime);
                    oscillator2.stop(audioCtx.currentTime + 0.4);
                } catch(e) {
                    console.log('Второй звук не воспроизведен');
                }
            }, 200);

        } catch(e) {
            console.log('Ошибка воспроизведения звука:', e);
        }
    }

    function checkNewPlayers(forceInit = false) {
        const currentPlayers = getCurrentPlayers();
        const currentIds = new Set(currentPlayers.keys());

        if (forceInit || isFirstRun) {
            currentPlayersOnField = currentIds;
            isFirstRun = false;
            isJustResumedFromPause = false;
            console.log(`Инициализация: на поле ${currentPlayersOnField.size} игроков`);
            return;
        }

        if (isJustResumedFromPause) {
            currentPlayersOnField = currentIds;
            isJustResumedFromPause = false;
            console.log(`Снято с паузы: запомнено ${currentPlayersOnField.size} игроков на поле`);
            return;
        }

        const newPlayers = [];
        currentPlayers.forEach((player, id) => {
            if (!currentPlayersOnField.has(id)) {
                newPlayers.push(player);
            }
        });

        if (newPlayers.length > 0) {
            console.log(`Обнаружено ${newPlayers.length} новых игроков:`);
            newPlayers.forEach(player => {
                console.log(`   - ${player.name} (ID: ${player.id})`);
            });
        }

        newPlayers.forEach(player => {
            playAlertSound();

            try {
                GM_notification({
                    title: '🎮 Новый игрок на поле!',
                    text: `${player.name} появился на локации!`,
                    timeout: 5000,
                    silent: true
                });
            } catch(e) {
                console.log('Уведомление не поддерживается');
            }

            const cage = player.element.closest('.cage');
            if (cage) {
                const originalBorder = cage.style.border;
                const originalBg = cage.style.backgroundColor;
                cage.style.border = '3px solid #ff0000';
                cage.style.backgroundColor = 'rgba(255, 0, 0, 0.2)';
                cage.style.transition = 'all 0.3s';
                setTimeout(() => {
                    cage.style.border = originalBorder || '';
                    cage.style.backgroundColor = originalBg || '';
                }, 2000);
            }
        });

        if (currentIds.size < currentPlayersOnField.size) {
            const leftPlayers = [];
            currentPlayersOnField.forEach(id => {
                if (!currentIds.has(id)) {
                    leftPlayers.push(id);
                }
            });
            if (leftPlayers.length > 0) {
                console.log(`Игроки покинули поле: ${leftPlayers.length}`);
            }
        }

        currentPlayersOnField = currentIds;
    }

    function resetMonitoring() {
        isFirstRun = true;
        isJustResumedFromPause = false;
        currentPlayersOnField = new Set();
        console.log('Сброс мониторинга');
    }

    let lastUrl = location.href;
    function checkUrlChange() {
        const currentUrl = location.href;
        if (currentUrl !== lastUrl) {
            console.log('🌍 Обнаружена смена локации');
            lastUrl = currentUrl;
            if (!isPaused) {
                resetMonitoring();
                setTimeout(() => {
                    checkNewPlayers(true);
                }, 500);
            } else {
                resetMonitoring();
                console.log('⏸ Мониторинг на паузе');
            }
        }
    }

    function createControlPanel() {
        const panel = document.createElement('div');
        panel.style.cssText = `
            position: fixed;
            bottom: 100px;
            right: 10px;
            z-index: 9999;
            background: rgba(0, 0, 0, 0.85);
            color: white;
            padding: 12px 15px;
            border-radius: 8px;
            font-family: Arial, sans-serif;
            font-size: 12px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.6);
            min-width: 150px;
            user-select: none;
        `;

        const title = document.createElement('div');
        title.textContent = 'Мониторинг поля';
        title.style.cssText = `
            font-weight: bold;
            font-size: 13px;
            margin-bottom: 8px;
            color: #4caf50;
        `;

        const statusText = document.createElement('div');
        statusText.id = 'player-alert-status';
        statusText.textContent = isPaused ? '⏸ На паузе' : 'Активен';
        statusText.style.cssText = `
            margin-bottom: 5px;
            color: ${isPaused ? '#ff9800' : '#4caf50'};
            font-size: 11px;
        `;

        const countText = document.createElement('div');
        countText.id = 'player-count';
        countText.textContent = `👥 Игроков: 0`;
        countText.style.cssText = `
            margin-bottom: 8px;
            font-size: 11px;
            color: #aaa;
        `;

        const btnContainer = document.createElement('div');
        btnContainer.style.cssText = `
            display: flex;
            gap: 5px;
        `;

        const toggleBtn = document.createElement('button');
        toggleBtn.id = 'toggle-monitoring-btn';
        toggleBtn.textContent = isPaused ? '▶ Старт' : '⏸ Стоп';
        toggleBtn.style.cssText = `
            background: ${isPaused ? '#4caf50' : '#555'};
            color: white;
            border: none;
            padding: 4px 12px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 11px;
            flex: 1;
            transition: background 0.3s;
        `;
        toggleBtn.onclick = function() {
            const wasPaused = isPaused;
            isPaused = !isPaused;
            localStorage.setItem(STORAGE_KEY, isPaused ? 'true' : 'false');

            this.textContent = isPaused ? '▶ Запуск' : '⏸ Пауза';
            this.style.background = isPaused ? '#4caf50' : '#555';

            const statusEl = document.getElementById('player-alert-status');
            if (statusEl) {
                statusEl.textContent = isPaused ? '⏸ На паузе' : '✅ Активен';
                statusEl.style.color = isPaused ? '#ff9800' : '#4caf50';
            }

            if (!isPaused && wasPaused) {
                console.log('▶️ Запуск мониторинга после паузы');
                isJustResumedFromPause = true;
                setTimeout(() => {
                    checkNewPlayers(false);
                }, 100);
            } else if (isPaused) {
                console.log('⏸ Мониторинг приостановлен');
            }
        };

        const testBtn = document.createElement('button');
        testBtn.textContent = '🔊';
        testBtn.style.cssText = `
            background: #555;
            color: white;
            border: none;
            padding: 4px 8px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 11px;
        `;
        testBtn.title = 'Тест звука';
        testBtn.onclick = function() {
            playAlertSound();
        };

        const resetBtn = document.createElement('button');
        resetBtn.textContent = '🔄';
        resetBtn.style.cssText = `
            background: #555;
            color: white;
            border: none;
            padding: 4px 8px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 11px;
        `;
        resetBtn.title = 'Сбросить список (заново запомнить игроков)';
        resetBtn.onclick = function() {
            resetMonitoring();
            if (!isPaused) {
                setTimeout(() => {
                    checkNewPlayers(true);
                }, 100);
            } else {
                console.log('⏸ Мониторинг на паузе, список сброшен');
            }
        };

        btnContainer.appendChild(toggleBtn);
        btnContainer.appendChild(testBtn);
        btnContainer.appendChild(resetBtn);

        panel.appendChild(title);
        panel.appendChild(statusText);
        panel.appendChild(countText);
        panel.appendChild(btnContainer);
        document.body.appendChild(panel);

        setInterval(() => {
            const countEl = document.getElementById('player-count');
            if (countEl) {
                countEl.textContent = `👥 Игроков: ${currentPlayersOnField.size}`;
            }
        }, 3000);

        if (isPaused) {
            console.log('⏸ Мониторинг на паузе (сохранено в localStorage)');
        }
    }

    function startMonitoring() {
        const checkTable = setInterval(() => {
            const table = document.getElementById('cages');
            if (table) {
                clearInterval(checkTable);
                console.log('✅ Игровое поле найдено, запускаем мониторинг...');
                console.log(`📌 Состояние паузы: ${isPaused ? '⏸ Активна' : '✅ Выключена'}`);

                setTimeout(() => {
                    const currentPlayers = getCurrentPlayers();
                    currentPlayersOnField = new Set(currentPlayers.keys());
                    isFirstRun = false;
                    console.log(`👥 Загружено ${currentPlayersOnField.size} игроков`);

                    createControlPanel();

                    setInterval(() => {
                        if (!isPaused) {
                            checkNewPlayers(false);
                        }
                    }, 2000);

                    setInterval(checkUrlChange, 1000);

                }, 500);
            }
        }, 1000);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', startMonitoring);
    } else {
        startMonitoring();
    }

    console.log('🐱 CatWar New Player Alert v2.3 загружен!');
})();