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);

})();