Zed.City Raid Monitor

Monitor raids and alert when they need more members (only when you're eligible)

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Zed.City Raid Monitor
// @namespace    https://swervelord.dev/
// @version      1.0
// @description  Monitor raids and alert when they need more members (only when you're eligible)
// @author       swervelord
// @match        https://www.zed.city/*
// @match        https://zed.city/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    const RAIDS_API_URL = 'https://api.zed.city/getRaids';
    const STATS_API_URL = 'https://api.zed.city/getStats';
    const CHECK_INTERVAL = 60000; // 60 seconds

    // Create GUI container
    function createGUI() {
        const container = document.createElement('div');
        container.id = 'raid-monitor-gui';
        container.style.cssText = `
            position: fixed;
            top: 140px;
            right: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 20px;
            border-radius: 12px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
            z-index: 10000;
            min-width: 280px;
            max-width: 350px;
            font-family: Arial, sans-serif;
            animation: slideIn 0.3s ease-out;
        `;
        document.body.appendChild(container);
        return container;
    }

    // Add CSS animation
    const style = document.createElement('style');
    style.textContent = `
        @keyframes slideIn {
            from {
                transform: translateX(400px);
                opacity: 0;
            }
            to {
                transform: translateX(0);
                opacity: 1;
            }
        }
        #raid-monitor-gui .raid-item {
            background: rgba(255, 255, 255, 0.1);
            padding: 12px;
            margin-bottom: 10px;
            border-radius: 8px;
            border: 1px solid rgba(255, 255, 255, 0.2);
        }
        #raid-monitor-gui .raid-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 8px;
        }
        #raid-monitor-gui .raid-info {
            font-size: 13px;
            margin-bottom: 5px;
            opacity: 0.9;
        }
        #raid-monitor-gui .join-btn {
            background: #48bb78;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            width: 100%;
            margin-top: 10px;
            transition: background 0.2s;
        }
        #raid-monitor-gui .join-btn:hover {
            background: #38a169;
        }
        #raid-monitor-gui .header {
            font-size: 18px;
            font-weight: bold;
            margin-bottom: 15px;
            text-align: center;
            border-bottom: 2px solid rgba(255, 255, 255, 0.3);
            padding-bottom: 10px;
        }
        #raid-monitor-gui .worker-list {
            font-size: 12px;
            margin-top: 5px;
            opacity: 0.8;
        }
        #raid-monitor-gui .status-badge {
            display: inline-block;
            background: rgba(72, 187, 120, 0.3);
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 11px;
            margin-top: 8px;
        }
    `;
    document.head.appendChild(style);

    // Check if user is eligible (not on cooldown)
    async function checkEligibility() {
        try {
            const response = await fetch(STATS_API_URL);
            const data = await response.json();

            // User is eligible if raid_cooldown is 0 or less
            return data.raid_cooldown <= 0;
        } catch (error) {
            console.error('Raid Monitor - Stats Check Error:', error);
            return false; // Assume not eligible if error
        }
    }

    // Check raids and update GUI
    async function checkRaids() {
        try {
            // First check if user is eligible
            const isEligible = await checkEligibility();

            if (!isEligible) {
                // Remove GUI if user is on cooldown
                const existingGUI = document.getElementById('raid-monitor-gui');
                if (existingGUI) {
                    existingGUI.remove();
                }
                console.log('Raid Monitor: On cooldown, not eligible for raids');
                return;
            }

            // User is eligible, now check for raids needing members
            const response = await fetch(RAIDS_API_URL);
            const data = await response.json();

            // Find raids that need more members
            const raidsNeedingMembers = [];

            if (data.activeRaids) {
                for (const [raidId, raid] of Object.entries(data.activeRaids)) {
                    const maxWorkers = raid.vars.max_workers;
                    const currentWorkers = raid.workers ? raid.workers.length : 0;

                    // Check if raid has workers and needs more
                    if (currentWorkers > 0 && currentWorkers < maxWorkers) {
                        raidsNeedingMembers.push({
                            id: raidId,
                            name: raid.name,
                            currentWorkers: currentWorkers,
                            maxWorkers: maxWorkers,
                            workers: raid.workers
                        });
                    }
                }
            }

            // Update or remove GUI based on raids
            const existingGUI = document.getElementById('raid-monitor-gui');

            if (raidsNeedingMembers.length > 0) {
                let container = existingGUI || createGUI();

                let html = '<div class="header">🚨 Raids Need Members!</div>';

                raidsNeedingMembers.forEach(raid => {
                    const workerNames = raid.workers.map(w => w.username).join(', ');
                    html += `
                        <div class="raid-item">
                            <div class="raid-title">${raid.name}</div>
                            <div class="raid-info">👥 ${raid.currentWorkers}/${raid.maxWorkers} members</div>
                            <div class="worker-list">Current: ${workerNames}</div>
                        </div>
                    `;
                });

                html += '<div class="status-badge">✓ You are eligible to join</div>';
                html += '<button class="join-btn" onclick="window.location.href=\'https://www.zed.city/raids\'">Join Raid</button>';

                container.innerHTML = html;
                console.log(`Raid Monitor: ${raidsNeedingMembers.length} raid(s) need members and you're eligible!`);
            } else if (existingGUI) {
                // Remove GUI if no raids need members
                existingGUI.remove();
                console.log('Raid Monitor: No raids currently need members');
            }

        } catch (error) {
            console.error('Raid Monitor Error:', error);
        }
    }

    // Initial check
    checkRaids();

    // Check every minute
    setInterval(checkRaids, CHECK_INTERVAL);

    console.log('Zed.City Raid Monitor Active - Checking every 60 seconds');
    console.log('Monitoring both raid availability and your eligibility status');
})();