Menelgame - LOS

Event - Los z obsługą linków graficznych w polach tekstowych

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name       Menelgame - LOS
// @namespace    https://greasyfork.org/pl/scripts/588953-menelgame-los
// @version      2.1.6
// @description  Event - Los z obsługą linków graficznych w polach tekstowych
// @author       Arctos + Gemini
// @match        *://*.menelgame.online/*
// @match        *://*.menelwars.pl/*
// @grant        GM.xmlHttpRequest
// @connect      docs.google.com
// @connect      googleusercontent.com
// @connect      *.googleusercontent.com
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    console.log("%c[MG-LOS] Skrypt wystartował (Wersja 2.0.15 - Inteligentne łączenie wierszy)!", "color: #10b981; font-weight: bold; font-size: 14px;");

    let cachedRows = null;
    let cacheTimestamp = 0;
    const CACHE_TTL = 5 * 60 * 1000;

    const SHEET_JSON_URL = "https://docs.google.com/spreadsheets/d/1l-Tpk_olCJOy1qa8PbYKaZC2LJHwXBOXcH4N9fFmDqc/gviz/tq?tqx=out:json&gid=5017211";

    const SLOWNIK_IKON = {
        "zbieractwo": "https://menelgame.online/images/kosz.png",
        "zebranie": "https://menelgame.online/images/zebractwo.png",
        "puszki": "https://menelgame.online/images/icons/puszka.png",
        "menelpower": "https://menelgame.online/images/icons/mpower.png",
        "mp": "https://menelgame.online/images/icons/mpower.png",
        "kombinowanie": "https://images.menelgame.online/images/hustling/gambler.png",
        "nauka": "https://menelgame.online/images/rozwoj.png"
    };

    const SLOWNIK_IKON_ZAMIEN_PO = {
        "zł": "https://menelgame.online/images/icons/kasa.png",
        "zl": "https://menelgame.online/images/icons/kasa.png",
        "z": "https://menelgame.online/images/icons/kasa.png"
    };

    function getStoredState(key, defaultValue) {
        const val = localStorage.getItem(key);
        return val !== null ? val === 'true' : defaultValue;
    }
    const stanyModulow = {
        globalny: getStoredState('MG_los_globalny', false)
    };

    let ostatnioPrzetworzonyTytul = null;

    function czyJestCooldown() {
        const cooldownDo = localStorage.getItem('mg_los_cooldown');
        if (!cooldownDo) return false;

        const terazAktualnyCzas = Math.floor(Date.now() / 1000);
        if (terazAktualnyCzas < parseInt(cooldownDo, 10)) {
            return true;
        } else {
            localStorage.removeItem('mg_los_cooldown');
            return false;
        }
    }

    function przechwycAPI() {
        const originalFetch = window.fetch;
        window.fetch = async function(...args) {
            const response = await originalFetch.apply(this, args);
            try {
                const clone = response.clone();
                const data = await clone.json();
                if (data && data.nextMainEventAt) {
                    localStorage.setItem('mg_los_cooldown', data.nextMainEventAt);
                }
            } catch (e) {}
            return response;
        };
    }
    przechwycAPI();

    function normalizujTekst(tekst) {
        if (!tekst) return "";
        return tekst
            .toLowerCase()
            .normalize("NFD")
            .replace(/[\u0300-\u036f]/g, "")
            .replace(/[^\w\s-]/gi, ' ')
            .replace(/\s+/g, " ")
            .trim();
    }

    function czyToLink(tekst) {
        try {
            let url = new URL(tekst);
            return url.protocol === "http:" || url.protocol === "https:";
        } catch (_) {
            return false;
        }
    }

    function parseGvizJson(responseText) {
        try {
            let startIndex = responseText.indexOf('{');
            let endIndex = responseText.lastIndexOf('}');
            if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) return [];

            let jsonString = responseText.substring(startIndex, endIndex + 1);
            let data = JSON.parse(jsonString);

            let table = data.table;
            if (!table || !table.rows) return [];

            let rows = [];
            table.rows.forEach(r => {
                let rowData = [];
                if (r.c) {
                    r.c.forEach(cell => {
                        if (!cell) {
                            rowData.push('');
                            return;
                        }
                        let val = cell.v !== null && cell.v !== undefined ? String(cell.v) : '';
                        let formattedVal = cell.f !== null && cell.f !== undefined ? String(cell.f) : val;
                        rowData.push(formattedVal !== "" ? formattedVal : val);
                    });
                }
                rows.push(rowData);
            });
            return rows;
        } catch (e) {
            console.error("[MG-LOS] Błąd parsowania odpowiedzi JSON gviz:", e);
            return [];
        }
    }

    async function pobierzDaneZArkusza() {
        const teraz = Date.now();
        if (cachedRows && (teraz - cacheTimestamp < CACHE_TTL)) {
            return cachedRows;
        }

        return new Promise((resolve) => {
            GM.xmlHttpRequest({
                method: "GET",
                url: SHEET_JSON_URL,
                onload: function(response) {
                    if (response.status >= 200 && response.status < 300) {
                        cachedRows = parseGvizJson(response.responseText);
                        cacheTimestamp = teraz;
                        console.log(`%c[MG-LOS] Pobrano i sparsowano dane z arkusza (Wierszy: ${cachedRows.length})`, "color: #3b82f6; font-weight: bold;");
                        resolve(cachedRows);
                    } else {
                        console.warn(`[MG-LOS] Błąd pobierania danych gviz, status: ${response.status}`);
                        resolve(null);
                    }
                },
                onerror: function(err) {
                    console.error("[MG-LOS] Błąd połączenia z gviz:", err);
                    resolve(null);
                }
            });
        });
    }

    async function przetworzEventLos() {
        if (typeof stanyModulow !== 'undefined' && stanyModulow.globalny === false) {
            return;
        }

        if (czyJestCooldown()) return;

        const klatkaEventu = document.querySelector('.karmic-card');
        if (!klatkaEventu) {
            if (ostatnioPrzetworzonyTytul !== null) {
                ostatnioPrzetworzonyTytul = null;
            }
            return;
        }

        const tytulElement = klatkaEventu.querySelector('.karmic-title');
        if (!tytulElement) return;

        const eventTitle = tytulElement.textContent.trim();
        if (!eventTitle) return;

        if (ostatnioPrzetworzonyTytul === eventTitle) return;
        ostatnioPrzetworzonyTytul = eventTitle;

        console.log(`%c[MG-LOS] Wykryto event: "${eventTitle}"`, "color: #ec4899; font-weight: bold;");

        const przyciskiWybboru = klatkaEventu.querySelectorAll('.karmic-choices button.karmic-choice');
        const rows = await pobierzDaneZArkusza();
        if (!rows) return;

        let znormalizowanySzukany = normalizujTekst(eventTitle);
        let matchedRows = [];

        for (let i = 0; i < rows.length; i++) {
            let row = rows[i];
            if (!row[2]) continue;

            let kolumnaCTitle = row[2];
            if (normalizujTekst(kolumnaCTitle) === znormalizowanySzukany) {
                matchedRows.push(row);
            }
        }

        if (matchedRows.length === 0) {
            console.warn(`[MG-LOS] Nie znaleziono dopasowania w arkuszu dla: "${eventTitle}"`);
            przyciskiWybboru.forEach((przycisk) => {
                if (przycisk.querySelector('.mg-nagroda-custom')) return;
                const infoDiv = document.createElement('div');
                infoDiv.className = 'mg-nagroda-custom';
                infoDiv.style.cssText = `font-size: 12px; color: #ffffff; background-color: rgba(250,80,80,0.2); padding: 2px 4px; margin-top: 6px; border-radius: 4px; font-weight: bold; text-align: center; border: 1px solid rgba(255, 255, 255, 0.2); display: flex; align-items: center; justify-content: center; gap: 6px;`;
                infoDiv.innerHTML = `<span>❌</span><span>Brak zadania na liście</span>`;
                przycisk.appendChild(infoDiv);
            });
            return;
        }

        const zakresyKonfiguracja = [
            { cols: [3, 4, 5, 6, 7, 8, 9] },
            { cols: [10, 11, 12, 13, 14, 15, 16] },
            { cols: [17, 18, 19, 20, 21, 22, 23] },
            { cols: [24, 25, 26, 27, 28, 29, 30] }
        ];

        przyciskiWybboru.forEach((przycisk, index) => {
            if (przycisk.querySelector('.mg-nagroda-custom')) return;

            const config = zakresyKonfiguracja[index];
            if (!config) return;

            const infoDiv = document.createElement('div');
            infoDiv.className = 'mg-nagroda-custom';
            infoDiv.style.cssText = `font-size: 12px; color: #ffffff; padding: 2px 4px; margin-top: 6px; border-radius: 4px; font-weight: bold; text-align: center; border: 1px solid rgba(201,164,92,0.2); box-shadow: 0 2px 4px rgba(0,0,0,0.3); display: flex; flex-direction: column; gap: 3px;`;

            // Sprawdzamy najpierw, czy ten przycisk ma gdziekolwiek jakiekolwiek dane we wszystkich pasujących wierszach
            let maJakiekolwiekDane = false;
            matchedRows.forEach((matchedRow) => {
                let wycinekSprawdzenie = [];
                for (let i = 0; i < config.cols.length; i++) {
                    let cIdx = config.cols[i];
                    if (matchedRow[cIdx] !== undefined && matchedRow[cIdx].trim() !== "") {
                        wycinekSprawdzenie.push(matchedRow[cIdx].trim());
                    }
                }
                if (wycinekSprawdzenie.length > 0) {
                    maJakiekolwiekDane = true;
                }
            });

            matchedRows.forEach((matchedRow) => {
                let wycinekTekstow = [];

                for (let i = 0; i < config.cols.length; i++) {
                    let cIdx = config.cols[i];
                    if (matchedRow[cIdx] !== undefined && matchedRow[cIdx].trim() !== "") {
                        wycinekTekstow.push(matchedRow[cIdx].trim());
                    }
                }

                const tekstNagrody = wycinekTekstow.length > 0 ? wycinekTekstow.join(" | ") : "Brak danych w arkuszu";
                const brakDanych = wycinekTekstow.length === 0;

                // Jeśli są jakiekolwiek dane dla tego przycisku w innych wierszach, pomijamy renderowanie wiersza "Brak danych w arkuszu"
                if (brakDanych && maJakiekolwiekDane) {
                    return;
                }

                let jestNegatywna = false;
                if (brakDanych) {
                    jestNegatywna = true;
                } else {
                    for (let k = 0; k < wycinekTekstow.length; k++) {
                        if (wycinekTekstow[k].includes('-')) {
                            jestNegatywna = true;
                            break;
                        }
                    }
                }

                const wierszNagrodyDiv = document.createElement('div');
                wierszNagrodyDiv.style.cssText = `background-color: ${jestNegatywna ? "rgba(250,80,80,0.2)" : "rgba(46,125,50,0.2)"}; padding: 3px 3px; border-radius: 3px; display: flex; align-items: center; justify-content: center; gap: 4px; flex-wrap: wrap;`;

                const spanIcon = document.createElement('span');
                spanIcon.textContent = jestNegatywna ? "❌" : "✔️";
                spanIcon.style.marginRight = "4px";
                wierszNagrodyDiv.appendChild(spanIcon);

                if (brakDanych) {
                    const spanText = document.createElement('span');
                    spanText.textContent = tekstNagrody;
                    wierszNagrodyDiv.appendChild(spanText);
                } else {
                    let czesciNagrody = tekstNagrody.split(" | ");

                    czesciNagrody.forEach((czesc, cIdx) => {
                        if (cIdx > 0) {
                            const separatorSpan = document.createElement('span');
                            separatorSpan.textContent = " | ";
                            separatorSpan.style.opacity = "0.6";
                            wierszNagrodyDiv.appendChild(separatorSpan);
                        }

                        let czystyCzc = czesc.trim();
                        if (czyToLink(czystyCzc)) {
                            const imgNagroda = document.createElement('img');
                            imgNagroda.loading = 'lazy';
                            imgNagroda.referrerPolicy = 'no-referrer';
                            imgNagroda.src = czystyCzc;
                            imgNagroda.style.width = '18px';
                            imgNagroda.style.height = '18px';
                            imgNagroda.style.objectFit = 'contain';
                            imgNagroda.style.verticalAlign = 'middle';
                            imgNagroda.style.marginLeft = '2px';
                            imgNagroda.style.marginRight = '2px';
                            wierszNagrodyDiv.appendChild(imgNagroda);
                            return;
                        }

                        let slowaWpisu = czesc.split(" ");

                        for (let sIdx = 0; sIdx < slowaWpisu.length; sIdx++) {
                            let slowo = slowaWpisu[sIdx];

                            if (czyToLink(slowo)) {
                                const imgSlowo = document.createElement('img');
                                imgSlowo.loading = 'lazy';
                                imgSlowo.referrerPolicy = 'no-referrer';
                                imgSlowo.src = slowo;
                                imgSlowo.style.width = '16px';
                                imgSlowo.style.height = '16px';
                                imgSlowo.style.objectFit = 'contain';
                                imgSlowo.style.verticalAlign = 'middle';
                                imgSlowo.style.marginLeft = (sIdx > 0 ? '3px' : '0px');
                                imgSlowo.style.marginRight = '2px';
                                wierszNagrodyDiv.appendChild(imgSlowo);
                                continue;
                            }

                            let slowoNorm = normalizujTekst(slowo);
                            let znalezionyUrlPrzed = null;
                            let urlZastepczyPo = null;

                            for (let klucz in SLOWNIK_IKON) {
                                if (slowoNorm === klucz || slowoNorm.includes(klucz)) {
                                    znalezionyUrlPrzed = SLOWNIK_IKON[klucz];
                                    break;
                                }
                            }

                            for (let kluczZamien in SLOWNIK_IKON_ZAMIEN_PO) {
                                let kluczNorm = normalizujTekst(kluczZamien);
                                if (slowoNorm === kluczNorm) {
                                    urlZastepczyPo = SLOWNIK_IKON_ZAMIEN_PO[kluczZamien];
                                    slowo = "";
                                    break;
                                } else if (slowoNorm.endsWith(kluczNorm) && slowoNorm.length > kluczNorm.length) {
                                    urlZastepczyPo = SLOWNIK_IKON_ZAMIEN_PO[kluczZamien];
                                    let regex = new RegExp(kluczZamien + '$', 'i');
                                    slowo = slowo.replace(regex, '').trim();
                                    break;
                                }
                            }

                            if (znalezionyUrlPrzed) {
                                const imgPrzed = document.createElement('img');
                                imgPrzed.loading = 'lazy';
                                imgPrzed.referrerPolicy = 'no-referrer';
                                imgPrzed.src = znalezionyUrlPrzed;
                                imgPrzed.style.width = '15px';
                                imgPrzed.style.height = '15px';
                                imgPrzed.style.objectFit = 'contain';
                                imgPrzed.style.verticalAlign = 'middle';
                                imgPrzed.style.marginRight = '2px';
                                imgPrzed.style.marginLeft = (sIdx > 0 ? '3px' : '0px');
                                wierszNagrodyDiv.appendChild(imgPrzed);
                            }

                            if (slowo !== "") {
                                const spanSlowo = document.createElement('span');
                                spanSlowo.textContent = (sIdx > 0 && !znalezionyUrlPrzed ? " " : "") + (sIdx > 0 && znalezionyUrlPrzed ? " " : "") + slowo;
                                wierszNagrodyDiv.appendChild(spanSlowo);
                            }

                            if (urlZastepczyPo) {
                                const imgZastepcza = document.createElement('img');
                                imgZastepcza.loading = 'lazy';
                                imgZastepcza.referrerPolicy = 'no-referrer';
                                imgZastepcza.src = urlZastepczyPo;
                                imgZastepcza.style.width = '15px';
                                imgZastepcza.style.height = '15px';
                                imgZastepcza.style.objectFit = 'contain';
                                imgZastepcza.style.verticalAlign = 'middle';
                                imgZastepcza.style.marginLeft = '2px';
                                wierszNagrodyDiv.appendChild(imgZastepcza);
                            }
                        }
                    });
                }

                infoDiv.appendChild(wierszNagrodyDiv);
            });

            przycisk.appendChild(infoDiv);
        });
    }

    setInterval(przetworzEventLos, 1000);

    function pingPanel() {
        const wersja = (typeof GM_info !== 'undefined') ? GM_info.script.version : '1.0.0';
        window.dispatchEvent(new CustomEvent('scriptPingFromSub', { detail: { scriptId: 'MG_los', version: wersja }}));
    }
    window.addEventListener('scriptPingFromPanel', pingPanel);

    window.addEventListener('scriptStateChanged', (e) => {
        const { scriptId, enabled } = e.detail;

        if (scriptId === 'MG_los' || scriptId.includes('MG_los_')) {
            if (scriptId === 'MG_los' || scriptId === 'MG_los_globalny') {
                stanyModulow.globalny = enabled;
            } else {}
        }
    });

    setTimeout(pingPanel, 500);

})();