Menelgame - LOS

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला 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);

})();