Wolf_ Ultimate menu

Scripts for Kour.io (have fun)

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Wolf_ Ultimate menu
// @match        *://kour.io/*
// @version      1.3
// @author       wolf_
// @description  Scripts for Kour.io (have fun)
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// @namespace https://greasyfork.org/users/1598070
// ==/UserScript==

(function() {
    'use strict';

    let settings = GM_getValue("kourPlusConfigs", {
        userPhrases: ["GG!", "well played", "xD", "𝐄𝐀𝐒𝐘"],
        lastColor: "#ff0000"
    });

    const ui = document.createElement('div');
    ui.id = "kour-rgb-ui";
    document.body.appendChild(ui);

    const style = document.createElement('style');
    style.innerHTML = `
        @keyframes smoothRainbow {
            0% { border-color: #ff0000; color: #ff0000; }
            33% { border-color: #00ff00; color: #00ff00; }
            66% { border-color: #0000ff; color: #0000ff; }
            100% { border-color: #ff0000; color: #ff0000; }
        }

        #kour-rgb-ui {
            position: fixed; top: 20px; right: 20px;
            background: rgba(10, 10, 10, 0.98);
            border: 2px solid #ff0000;
            padding: 15px; z-index: 9999999;
            border-radius: 12px; width: 270px;
            font-family: 'Segoe UI', Tahoma, sans-serif;
            animation: smoothRainbow 10s linear infinite;
            box-shadow: 0 10px 30px rgba(0,0,0,0.6);
            user-select: none;
        }

        .title-rgb {
            text-align: center; font-weight: 900; font-size: 15px;
            margin-bottom: 12px;
            text-transform: uppercase; letter-spacing: 2px;
            cursor: move;
            padding: 8px;
            background: rgba(255,255,255,0.03);
            border-radius: 6px;
            animation: smoothRainbow 10s linear infinite;
        }

        .section-label { font-size: 10px; color: #666; text-transform: uppercase; margin-bottom: 5px; display: block; font-weight: bold; }

        .btn-style {
            width: 100%; background: #1a1a1a; color: #fff; border: 1px solid #333;
            padding: 10px; cursor: pointer; font-weight: bold; border-radius: 6px;
            text-transform: uppercase; margin-bottom: 6px; font-size: 12px; transition: 0.2s;
        }
        .btn-style:hover { background: #333; border-color: #777; }

        .fast-red { background: #400 !important; color: #ff4444 !important; border: 1px solid #600 !important; }
        .clear-btn { background: #222 !important; color: #888 !important; font-size: 9px !important; margin-top: 5px !important; }

        .color-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; background: #111; padding: 8px; border-radius: 6px; border: 1px solid #222; }
        #nickColorPicker { border: none; width: 35px; height: 25px; cursor: pointer; background: none; }

        .phrase-row { display: flex; gap: 5px; margin-bottom: 5px; }
        .del-btn { background: #300; color: #f44; border: 1px solid #500; padding: 5px 10px; cursor: pointer; border-radius: 5px; font-weight: bold; }

        #phrase-container { max-height: 160px; overflow-y: auto; margin-top: 10px; border-top: 1px solid #222; padding-top: 10px; }

        .footer-rainbow {
            font-size: 13px;
            text-align: center;
            margin-top: 15px;
            font-weight: 900;
            font-style: italic;
            animation: smoothRainbow 10s linear infinite;
        }

        ::-webkit-scrollbar { width: 4px; }
        ::-webkit-scrollbar-thumb { background: #333; border-radius: 10px; }
    `;
    document.head.appendChild(style);

    function render() {
        const savedPos = JSON.parse(localStorage.getItem("kourMenuPos") || '{"top":"20px","left":"auto","right":"20px"}');
        ui.style.top = savedPos.top;
        ui.style.left = savedPos.left;
        ui.style.right = savedPos.right;

        ui.innerHTML = `
            <div class="title-rgb" id="kour-header">KOUR Ultimate Menu</div>
            <span class="section-label">Quick Actions</span>
            <button id="fastRedBtn" class="btn-style fast-red">🔴 Fast Red No-Name</button>
            <span class="section-label" style="margin-top:10px;">Nickname</span>
            <div class="color-row">
                <input type="color" id="nickColorPicker" value="${settings.lastColor}">
                <span style="font-size:11px; color:#888;">Custom Color</span>
            </div>
            <button id="setNickBtn" class="btn-style">Apply Nickname</button>
            <span class="section-label" style="margin-top:10px;">Phrases</span>
            <button id="addPhraseBtn" class="btn-style" style="color:#4f4; border-color:#262;">+ Add Phrase</button>
            <div id="phrase-container"></div>
            <button id="clearPhrasesBtn" class="btn-style clear-btn">Clear All</button>
            <div class="footer-rainbow">Made by Wolf_</div>
            <div style="font-size:9px; color:#333; text-align:center; margin-top:5px;">[O] Hide/Show | Drag title to move</div>
        `;

        const list = ui.querySelector('#phrase-container');
        settings.userPhrases.forEach((p, index) => {
            const row = document.createElement('div');
            row.className = "phrase-row";
            const b = document.createElement('button');
            b.className = "btn-style"; b.style.marginBottom = "0"; b.innerText = p;
            b.onclick = () => {
                navigator.clipboard.writeText("ㅤ" + p);
                const original = b.innerText;
                b.innerText = "COPIED!"; setTimeout(() => b.innerText = original, 800);
            };
            const d = document.createElement('button');
            d.className = "del-btn"; d.innerText = "X";
            d.onclick = () => {
                settings.userPhrases.splice(index, 1);
                GM_setValue("kourPlusConfigs", settings); render();
            };
            row.appendChild(b); row.appendChild(d); list.appendChild(row);
        });

        document.getElementById('clearPhrasesBtn').onclick = () => {
            if (confirm("Delete all phrases?")) {
                settings.userPhrases = []; GM_setValue("kourPlusConfigs", settings); render();
            }
        };

        document.getElementById('fastRedBtn').onclick = () => {
            const fastName = "<color=#FF0000>ㅤ</color>";
            localStorage.setItem("playerNickname", fastName);
            window.unityInstance?.SendMessage("MapScripts", "SetNickname", fastName);
        };

        document.getElementById('setNickBtn').onclick = () => {
            const name = prompt("Nickname:");
            if (!name) return;
            const color = document.getElementById('nickColorPicker').value;
            settings.lastColor = color;
            GM_setValue("kourPlusConfigs", settings);
            const finalName = `<color=${color}>${name.trim()}</color>`;
            localStorage.setItem("playerNickname", finalName);
            window.unityInstance?.SendMessage("MapScripts", "SetNickname", finalName);
        };

        document.getElementById('addPhraseBtn').onclick = () => {
            const newPhrase = prompt("New phrase:");
            if (newPhrase) {
                settings.userPhrases.push(newPhrase.trim());
                GM_setValue("kourPlusConfigs", settings); render();
            }
        };

        makeDraggable(ui, document.getElementById("kour-header"));
    }

    function makeDraggable(element, handle) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        handle.onmousedown = (e) => {
            e.preventDefault();
            pos3 = e.clientX; pos4 = e.clientY;
            document.onmouseup = () => {
                document.onmouseup = null;
                document.onmousemove = null;
                localStorage.setItem("kourMenuPos", JSON.stringify({
                    top: element.style.top,
                    left: element.style.left,
                    right: "auto"
                }));
            };
            document.onmousemove = (e) => {
                e.preventDefault();
                pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY;
                pos3 = e.clientX; pos4 = e.clientY;

                let newTop = element.offsetTop - pos2;
                let newLeft = element.offsetLeft - pos1;

                const padding = 1;
                const maxLeft = window.innerWidth - element.offsetWidth - padding;
                const maxTop = window.innerHeight - element.offsetHeight - padding;

                newTop = Math.max(padding, Math.min(newTop, maxTop));
                newLeft = Math.max(padding, Math.min(newLeft, maxLeft));

                element.style.top = newTop + "px";
                element.style.left = newLeft + "px";
                element.style.right = "auto";
            };
        };
    }

    render();

    setInterval(() => {
        const saved = localStorage.getItem("playerNickname");
        if (saved && typeof unityInstance !== 'undefined') {
            unityInstance.SendMessage("MapScripts", "SetNickname", saved);
        }
    }, 5000);

    document.addEventListener('keydown', (e) => {
        if (e.key.toLowerCase() === 'o') ui.style.display = (ui.style.display === 'none') ? 'block' : 'none';
    });

})();