EQ SETS

A quick way of changing inventories in TW and filtering notifications

// ==UserScript==
// @name         EQ SETS
// @version      2.6
// @description  A quick way of changing inventories in TW and filtering notifications
// @author       Donald Kaczyński
// @website
// @include      *.the-west.*/game.php*
// @grant        none
// @namespace https://greasyfork.org/users/755649
// ==/UserScript==

function initializeEquipmentSets() {
    // Główna funkcja zarządzająca zestawami ekwipunku
    function MenedzerZestawowWyposazenia() {
        // Klucze localStorage
        const STORAGE_KEY_VISIBLE = 'equipmentSets_isVisible';
        const STORAGE_KEY_COLUMNS = 'equipmentSets_numColumns';
        const STORAGE_KEY_HIDDEN_NAMES = 'equipmentSets_hiddenNames'; // Zmieniono z ID na nazwy
        const STORAGE_KEY_TILE_SCALE = 'equipmentSets_tileScale';
        const STORAGE_KEY_PANEL_LOCATION = 'equipmentSets_panelLocation';

        this.equipmentList = {};
        this.tilesContainer = null;
        this.settingsWindow = null; // Referencja do okna ustawień
        this.allEquipmentSets = []; // Przechowuje pełną listę zestawów po pobraniu
        this.DEFAULT_COLUMNS = 2; // Domyślna liczba kolumn

        // Nowe zmienne stanu
        this.isPanelVisible = false; // Domyślnie panel ukryty przy starcie
        this.numColumns = this.DEFAULT_COLUMNS;
        this.hiddenSetNames = new Set(); // Przechowuje NAZWY ukrytych zestawów
        this.tileScale = parseFloat(localStorage.getItem(STORAGE_KEY_TILE_SCALE)) || 1;
        this.MIN_TILE_SCALE = 1;
        this.MAX_TILE_SCALE = 2;
        this.panelLocation = localStorage.getItem(STORAGE_KEY_PANEL_LOCATION) || 'notibar'; // 'notibar' lub 'fixed'

        // Inicjalizacja całego modułu
        this.initialize = function() {
            // Wczytaj stan z localStorage
            this.isPanelVisible = localStorage.getItem(STORAGE_KEY_VISIBLE) === 'true';
            this.numColumns = parseInt(localStorage.getItem(STORAGE_KEY_COLUMNS), 10) || this.DEFAULT_COLUMNS;
            const hiddenNamesString = localStorage.getItem(STORAGE_KEY_HIDDEN_NAMES);
            if (hiddenNamesString) {
                try {
                    const hiddenNamesArray = JSON.parse(hiddenNamesString);
                    if (Array.isArray(hiddenNamesArray)) {
                        this.hiddenSetNames = new Set(hiddenNamesArray);
                    }
                } catch (e) {
                    console.error("[Zestawy wyposażenia] Error parsing hidden names from localStorage:", e);
                    localStorage.removeItem(STORAGE_KEY_HIDDEN_NAMES); // Usuń błędne dane
                }
            }

            this.createMenuButton();
            // Użyj wczytanej zmiennej stanu
            if (this.isPanelVisible) {
                setTimeout(() => {
                     if (typeof Ajax !== 'undefined' && typeof EquipManager !== 'undefined' && typeof Wear !== 'undefined' && typeof ItemManager !== 'undefined') {
                         // Sprawdźmy, czy kontener nie został już utworzony przez otwarcie ustawień
                         if (!this.tilesContainer || !this.tilesContainer.parent().length) {
                            this.buildAndShowTiles();
                         }
                     } else {
                         console.error("[Zestawy wyposażenia]: Game objects not ready for initial tile display.");
                     }
                }, 1000);
            }
        };

        // Tworzenie przycisku w menu
        this.createMenuButton = function() {
            const buttonIcon = this.createButtonIcon();
            const bottomCap = this.createBottomCap();
            const containerDiv = this.createContainerDiv(buttonIcon, bottomCap);

            $("#ui_menubar").append(containerDiv);
        };

        // Tworzenie ikony przycisku
        this.createButtonIcon = function() {
            return $('<div></div>')
                .attr({
                    'title': 'USTAWIENIA ZESTAWÓW',
                    'class': 'menulink'
                })
                .css({
                    'background': 'url("https://i.imgur.com/5LJ8hCP.png")',
                    'background-position': '0px 0px'
                })
                .on('mouseleave', function() {
                    $(this).css("background-position", "0px 0px");
                })
                .on('mouseenter', function() {
                    $(this).css("background-position", "25px 0px");
                })
                .click(() => this.openSettingsWindow());
        };

        // Tworzenie dolnej części przycisku
        this.createBottomCap = function() {
            return $('<div></div>').attr({
                'class': 'menucontainer_bottom'
            });
        };

        // Tworzenie kontenera dla przycisku
        this.createContainerDiv = function(icon, cap) {
            return $('<div></div>')
                .attr({
                    'class': 'ui_menucontainer',
                    'id': 'zestawy_init_button'
                })
                .append(icon)
                .append(cap);
        };

        // Funkcja otwierająca (lub pokazująca) okno ustawień
        this.openSettingsWindow = function() {
            const createOrUpdateWindow = () => {
                // Sprawdź, czy okno już istnieje i jest w DOM
                if (this.settingsWindow && this.settingsWindow.parent().length) {
                    this.settingsWindow.show();
                    this.settingsWindow.css('z-index', parseInt(this.settingsWindow.css('z-index', 10501111) || 105011111) + 1);
                    // Odśwież zawartość okna ustawień (listę zestawów)
                    const optionsContainer = this.settingsWindow.find('#equipment-settings-options');
                    this.populateSettingsWindow(optionsContainer);
                    return; // Zakończ, jeśli okno już istnieje
                }

                // Jeśli okno nie istnieje, utwórz je
                this.settingsWindow = $('<div></div>')
                    .attr('id', 'equipment-settings-window')
                    .css({
                        'position': 'fixed',
                        'top': '100px',
                        'left': '50%',
                        'transform': 'translateX(-50%)',
                        'width': '360px', // Slightly wider for bolder look
                        'border': '3px solid #5c3c1a', // Thicker, darker wood border
                        'background': 'url("https://westpl.innogamescdn.com/images/inventory/bag.png?1") repeat scroll 0 0 #c8a87a', // Texture on a darker tan background
                        'background-color': '#c8a87a', // Fallback
                        'border-radius': '4px', // Slightly less rounded
                        'padding': '15px',
                        'z-index': '10501111',
                        'box-shadow': '0 5px 15px rgba(0,0,0,0.5), inset 0 0 8px rgba(0,0,0,0.3)', // Stronger shadow, darker inset
                        'color': '#3d1e0a' // Darker brown text for contrast
                    });

                const title = $('<div>USTAWIENIA ZESTAWÓW</div>').css({
                    'font-family': '"Times New Roman", Times, serif', // More classic/western font
                    'font-size': '20px', // Larger title
                    'font-weight': 'bold',
                    'margin': '-15px -15px 15px -15px', // Extend to edges
                    'padding': '10px 15px', // Padding for title bg
                    'text-align': 'center',
                    'border-bottom': '2px solid #5c3c1a', // Matching thick border
                    'background-color': 'rgba(0, 0, 0, 0.2)', // Dark overlay for title bg
                    'color': '#ffffff',
                    'text-shadow': '1px 1px 3px #000' // Stronger text shadow
                });

                const closeButton = $('<button>X</button>').css({
                    'position': 'absolute',
                    'top': '5px',
                    'right': '8px', // Adjust position
                    'cursor': 'pointer',
                    'border': '1px solid #5c3c1a', // Dark wood border
                    'background': '#a47b4f', // Darker button color
                    'color': '#f0e0c0', // Light text on button
                    'font-weight': 'bold',
                    'border-radius': '3px',
                    'box-shadow': 'inset 0 0 3px rgba(255,255,255,0.2)' // Subtle inset highlight
                }).click(() => {
                    this.settingsWindow.hide();
                });

                const optionsContainer = $('<div></div>').attr('id', 'equipment-settings-options');
                this.settingsWindow.append(closeButton).append(title).append(optionsContainer);
                this.populateSettingsWindow(optionsContainer); // Wypełnij opcjami (użyje this.allEquipmentSets)

                this.settingsWindow.appendTo('body');
            };

            // Najpierw pobierz aktualne dane, a potem utwórz/zaktualizuj okno
            this.fetchAndUpdateSets(() => {
                createOrUpdateWindow();
            });
        };

        // Funkcja wypełniająca okno ustawień opcjami
        this.populateSettingsWindow = function(container) {
            console.log("[Zestawy wyposażenia] Wypełnianie ustawień danymi:", JSON.parse(JSON.stringify(this.allEquipmentSets))); // Log danych używanych do ustawień

            container.empty();

            // --- Opcja widoczności panelu ---
            const visibleLabel = $('<label></label>').css({ 'display': 'block', 'margin-bottom': '10px' });
            const visibleCheckbox = $('<input type="checkbox">')
                .attr('id', 'setting-tiles-visible')
                .css({ 'margin-right': '5px' });

            // Użyj zmiennej stanu
            visibleCheckbox.prop('checked', this.isPanelVisible);

            visibleCheckbox.on('change', (e) => {
                const checked = $(e.target).is(':checked');
                // Zaktualizuj zmienną stanu
                this.isPanelVisible = checked;
                // Zapisz do localStorage
                localStorage.setItem(STORAGE_KEY_VISIBLE, checked);

                if (checked) {
                    if (!this.tilesContainer || !this.tilesContainer.parent().length) {
                        this.buildAndShowTiles();
                    } else {
                        this.tilesContainer.show();
                    }
                } else {
                    if (this.tilesContainer) {
                        this.tilesContainer.hide();
                    }
                }
            });

            visibleLabel.append(visibleCheckbox).append('Pokaż panel zestawów');
            container.append(visibleLabel);

            // --- Opcja liczby kolumn ---
            const columnsLabel = $('<label></label>').css({ 'display': 'block', 'margin-bottom': '15px' });
            const columnsInput = $('<input type="number">')
                .attr({
                    'id': 'setting-tiles-columns',
                    'min': '1',
                    'step': '1'
                 })
                 .css({ 'width': '50px', 'margin-left': '5px', 'border': '1px solid #5c3c1a', 'background-color': '#f0e0c0', 'color': '#3d1e0a' }); // Style input: light bg, dark border/text

            // Użyj zmiennej stanu
            columnsInput.val(this.numColumns);

            columnsInput.on('input', (e) => {
                let newColumns = parseInt($(e.target).val(), 10);
                if (isNaN(newColumns) || newColumns < 1) {
                    newColumns = this.DEFAULT_COLUMNS;
                    $(e.target).val(newColumns);
                }
                // Zaktualizuj zmienną stanu
                this.numColumns = newColumns;
                // Zapisz do localStorage
                localStorage.setItem(STORAGE_KEY_COLUMNS, newColumns);

                if (this.tilesContainer && this.tilesContainer.is(':visible')) {
                    this.tilesContainer.css('grid-template-columns', `repeat(${newColumns}, 1fr)`);
                }
            });

            columnsLabel.append('Ilość kolumn:').append(columnsInput);
            container.append(columnsLabel);

            // --- Opcja skalowania kafelków ---
            const scaleLabel = $('<label></label>').css({ 'display': 'block', 'margin-bottom': '15px' });
            const scaleInput = $('<input type="range">')
                .attr({
                    'id': 'setting-tiles-scale',
                    'min': this.MIN_TILE_SCALE,
                    'max': this.MAX_TILE_SCALE,
                    'step': 0.05
                })
                .css({ 'width': '100px', 'margin-left': '5px' })
                .val(this.tileScale);

            const scaleValue = $('<span></span>').text(this.tileScale);

            scaleInput.on('input', (e) => {
                let newScale = parseFloat($(e.target).val());
                if (isNaN(newScale) || newScale < this.MIN_TILE_SCALE) {
                    newScale = this.MIN_TILE_SCALE;
                }
                this.tileScale = newScale;
                localStorage.setItem(STORAGE_KEY_TILE_SCALE, newScale);
                scaleValue.text(newScale.toFixed(2));
                if (this.tilesContainer && this.tilesContainer.is(':visible')) {
                    this.tilesContainer.css({
                        'transform': `scale(${newScale})`,
                        'transform-origin': this.panelLocation === 'notibar' ? 'top left' : 'top right'
                    });
                }
            });

            scaleLabel.append('Skalowanie kafelków:').append(scaleInput).append(scaleValue);
            container.append(scaleLabel);

            // --- Opcja lokalizacji panelu ---
            const locationLabel = $('<label></label>').css({ 'display': 'block', 'margin-bottom': '15px' });
            const locationSelect = $('<select></select>')
                .attr('id', 'setting-panel-location')
                .css({ 'margin-left': '5px', 'border': '1px solid #5c3c1a', 'background-color': '#f0e0c0', 'color': '#3d1e0a' })
                .append('<option value="notibar">Pod powiadomieniami</option>')
                .append('<option value="fixed">Prawa strona ekranu</option>');

            locationSelect.val(this.panelLocation);

            locationSelect.on('change', (e) => {
                const newLocation = $(e.target).val();
                this.panelLocation = newLocation;
                localStorage.setItem(STORAGE_KEY_PANEL_LOCATION, newLocation);
                // Przebuduj panel, by zmienić pozycję
                if (this.tilesContainer) {
                    this.tilesContainer.remove();
                    this.tilesContainer = null;
                }
                this.rebuildTilesFromData();
            });

            locationLabel.append('Lokalizacja panelu:').append(locationSelect);
            container.append(locationLabel);

            // --- Separator ---
            container.append($('<hr>').css({ 'margin': '15px 0', 'border-top': '1px dashed #5c3c1a' }));

            // --- Opcja widoczności poszczególnych zestawów ---
            const setsVisibilityLabel = $('<div>Widoczne zestawy:</div>').css({
                 'font-weight': 'bold',
                 'margin-bottom': '10px'
            });
            container.append(setsVisibilityLabel);

            const setsContainer = $('<div></div>').css({
                 'max-height': '200px',
                 'overflow-y': 'auto',
                 'border': '1px solid #5c3c1a', // Dark wood border
                 'padding': '10px',
                 'background-color': 'rgba(255, 255, 255, 0.1)', // Slightly lighter area inside window
                 'border-radius': '3px',
                 'margin-top': '5px' // Space below title
            });

            // Sprawdź, czy mamy już załadowaną listę zestawów
            if (this.allEquipmentSets && this.allEquipmentSets.length > 0) {
                this.allEquipmentSets.forEach((equipSet, index) => {
                    const setName = equipSet.name || `Zestaw Bez Nazwy ${index}`;
                    // Sprawdź, czy NAZWA jest w secie ukrytych
                    const isSetHidden = this.hiddenSetNames.has(setName);

                    const setLabel = $('<label></label>').css({ 'display': 'block', 'margin-bottom': '3px' });
                    const setCheckbox = $('<input type="checkbox">')
                        .attr('id', `setting-set-visible-${index}`)
                        .prop('checked', !isSetHidden)
                        .css({ 'margin-right': '5px' });

                    setCheckbox.on('change', (e) => {
                        const checked = $(e.target).is(':checked');
                        // Zaktualizuj set ukrytych NAZW
                        if (checked) {
                            this.hiddenSetNames.delete(setName);
                        } else {
                            this.hiddenSetNames.add(setName);
                        }
                        // Zapisz do localStorage (konwertując Set na Array)
                        localStorage.setItem(STORAGE_KEY_HIDDEN_NAMES, JSON.stringify(Array.from(this.hiddenSetNames)));

                        // Jeśli panel główny jest widoczny, przebuduj go
                        if (this.isPanelVisible && this.tilesContainer && this.tilesContainer.is(':visible')) {
                            this.rebuildTilesFromData();
                        }
                    });

                    setLabel.append(setCheckbox).append(setName);
                    setsContainer.append(setLabel);
                });
            } else {
                setsContainer.text('Lista zestawów zostanie załadowana po pierwszym otwarciu panelu lub odświeżeniu.');
            }

            container.append(setsContainer);
        };

        // Nowa funkcja do pobierania danych i aktualizacji listy zestawów
        this.fetchAndUpdateSets = function(callback) {
            Ajax.remoteCallMode('inventory', 'show_equip', {}, (data) => {
                // console.log("[Zestawy wyposażenia] Dane otrzymane z Ajax:", JSON.parse(JSON.stringify(data))); // Usunięto log

                EquipManager.list = Array.isArray(data.data) ? data.data : Object.values(data.data);
                // Zapisz pełną listę zestawów do późniejszego użytku w ustawieniach
                this.allEquipmentSets = EquipManager.list;

                EquipManager.max = data.max;
                EquipManager.premiumMax = data.premium_max;
                EquipManager.hasPremium = data.hasPremium;

                // Wywołaj callback po pobraniu i przetworzeniu danych
                if (typeof callback === 'function') {
                    callback(data); // Przekazujemy dane, może się przydać
                }
            });
        };

        // Funkcja do budowania/przebudowywania kafelków na podstawie aktualnych danych
        this.rebuildTilesFromData = function() {
            // console.log("[Zestawy wyposażenia] Przebudowa kafelków z danymi:", JSON.parse(JSON.stringify(this.allEquipmentSets))); // Usunięto log

             // Użyj zmiennej stanu dla liczby kolumn
            const columns = this.numColumns;

            if (!this.tilesContainer) {
                // --- Dodaj styl dla noszonego zestawu ---
                const wornSetStyle = `
                    /* Animation for the worn set - REMOVED */
                    /* @keyframes pulseGold { ... } */

                    .worn-set-tile {
                        border: 2px solid #FFBF00 !important; /* Gold border */
                        background-color: #e0c8a0 !important; /* Keep the cream/sand background */
                        box-shadow: inset 0 0 4px rgba(0,0,0,0.2), 0 0 8px 2px #FFBF00 !important; /* Static gold glow */
                        /* animation: pulseGold 1.5s infinite ease-in-out; - REMOVED */
                    }
                    /* Style for the settings checkboxes and labels */
                    #equipment-settings-options label {
                        color: #3d1e0a; /* Dark brown text */
                        display: block;
                        margin-bottom: 8px;
                    }
                    #equipment-settings-options input[type="checkbox"] {
                        margin-right: 8px;
                        vertical-align: middle;
                         /* Basic styling is fine, rely on browser default for theme */
                    }
                    #equipment-settings-options input[type="number"] {
                        padding: 2px 4px;
                        border-radius: 3px;
                         /* Styles already applied inline */
                    }
                    #equipment-settings-options hr {
                        border-top: 1px dashed #5c3c1a; /* Dashed separator */
                        margin: 15px 0;
                    }
                    #equipment-settings-options > div:last-of-type { /* Sets container */
                        /* Styles already applied inline */
                    }
                `;
                $('<style>').prop('type', 'text/css').html(wornSetStyle).appendTo('head');
                // --- Koniec dodawania stylu ---

                this.tilesContainer = $('<div></div>')
                    .attr('id', 'equipment-tiles-container');

                if (this.panelLocation === 'notibar') {
                    this.tilesContainer.css({
                        'position': 'relative',
                        'left': '-10px',
                        'margin-top': '10px',
                        'border': 'none',
                        'padding': '12px',
                        'display': 'grid',
                        'grid-template-columns': `repeat(${columns}, 1fr)`,
                        'gap': '8px',
                        'z-index': '1',
                        'max-width': '600px',
                        'max-height': '80vh',
                        'overflow-y': 'auto',
                        'box-shadow': '0 4px 12px rgba(0, 0, 0, 0.0)',
                        'right': '',
                        'top': ''
                    }).appendTo('#ui_notibar');
                } else {
                    this.tilesContainer.css({
                        'position': 'fixed',
                        'top': '130px',
                        'right': '40px',
                        'margin-top': '',
                        'border': 'none',
                        'padding': '12px', // More padding
                        'display': 'grid',
                        'grid-template-columns': `repeat(${columns}, 1fr)`,
                        'gap': '8px', // Increased gap
                        'z-index': '1',
                        'max-width': '600px',
                        'max-height': '80vh',
                        'overflow-y': 'auto',
                        'box-shadow': '0 4px 12px rgba(0, 0, 0, 0.0)', // Darker, more defined shadow
                    }).appendTo('body');
                }
            } else {
                 this.tilesContainer.css('grid-template-columns', `repeat(${columns}, 1fr)`);
                 this.tilesContainer.empty();
            }

            this.equipmentList = {}; // Wyczyść listę ID przed przebudową

            // Iteruj po ZAPISANEJ pełnej liście zestawów
            this.allEquipmentSets.forEach((equipSet, index) => {
                 // Sprawdź, czy zestaw nie jest aktualnie noszony
                 const match = this.checkEquipmentMatch(equipSet, ['body', 'neck', 'head', 'right_arm', 'left_arm', 'animal', 'pants', 'belt', 'yield', 'foot']);
                 // Sprawdź, czy zestaw jest ustawiony jako widoczny wg zmiennej stanu (NAZWY)
                 const setName = equipSet.name || `Zestaw Bez Nazwy ${index}`; // Użyj nazwy lub zastępczej
                 const setId = equipSet.equip_manager_id; // Potrzebne do przełączania
                 // Sprawdź, czy NAZWA NIE jest w secie ukrytych
                 const isSetVisible = !this.hiddenSetNames.has(setName);

                 // Loguj czynniki decyzyjne dla każdego zestawu - Usunięto log
                 // console.log(`[Zestawy wyposażenia] Processing set: '${setName}'. Match count: ${match}. IsVisible: ${isSetVisible} (Hidden: ${this.hiddenSetNames.has(setName)}). Should display: ${isSetVisible}`);

                 // Utwórz kafelek tylko jeśli jest widoczny (niezależnie czy noszony)
                 if (isSetVisible) {
                     const tileElement = this.createEquipmentTile(equipSet, index); // Przekazuj oryginalny index z allEquipmentSets

                     // Jeśli zestaw jest aktualnie noszony, dodaj mu klasę
                     if (match === 10) {
                         tileElement.addClass('worn-set-tile');
                     }

                     this.tilesContainer.append(tileElement);
                     // Zapisz ID zestawu (wymagane przez switchEquip) używając indexu
                     this.equipmentList[index] = setId;
                 }
             });

            // Pokaż lub ukryj kontener na podstawie zmiennej stanu isPanelVisible
            if (this.isPanelVisible) {
                 this.tilesContainer.show();
            } else {
                 this.tilesContainer.hide();
            }

            this.tilesContainer.css({
                'transform': `scale(${this.tileScale})`,
                'transform-origin': this.panelLocation === 'notibar' ? 'top left' : 'top right'
            });
        };

        // Nowa funkcja do budowania i pokazywania kafelków (teraz tylko wrapper)
        this.buildAndShowTiles = function() {
            // Sprawdź, czy panel powinien być widoczny wg zmiennej stanu
            if (!this.isPanelVisible) {
                if (this.tilesContainer) {
                    this.tilesContainer.hide();
                }
                return;
            }

            // Pobierz dane i przebuduj kafelki
            this.fetchAndUpdateSets(() => {
                this.rebuildTilesFromData();
                 // Po pobraniu danych, jeśli okno ustawień jest otwarte, odśwież je
                // To odświeżenie jest teraz robione w openSettingsWindow i przycisku Refresh
                /*if (this.settingsWindow && this.settingsWindow.is(':visible')) {
                     const optionsContainer = this.settingsWindow.find('#equipment-settings-options');
                     this.populateSettingsWindow(optionsContainer); // Może powodować podwójne odświeżenie
                }*/
            });
        };

        // Sprawdzanie dopasowania elementów ekwipunku
        this.checkEquipmentMatch = function(equipSet, types) {
            let matchCount = 0;

            types.forEach(type => {
                const currentItem = Wear.get(type);
                const setItem = equipSet[type];

                if ((currentItem === null && setItem === null) ||
                    (currentItem !== null && currentItem.obj.item_id === setItem)) {
                    matchCount++;
                }
            });

            return matchCount;
        };

        // Nowa funkcja do tworzenia pojedynczego kafelka (uproszczona obsługa podglądu)
        this.createEquipmentTile = function(equipSet, index) {
            const previewHTMLString = this.createEquipmentPreview(equipSet, index);

            // --- Funkcja do dekodowania HTML ---
            function decodeHtmlEntities(html) {
                var txt = document.createElement("textarea");
                txt.innerHTML = html;
                return txt.value;
            }
            // --- Koniec funkcji do dekodowania ---

            const decodedPreviewHTML = decodeHtmlEntities(previewHTMLString);

            // Parsowanie zdekodowanego HTML i modyfikacja obrazków w pamięci
            const previewFragment = $(decodedPreviewHTML);
            const secondColumnTypes = ['head', 'body', 'pants'];
            const thirdColumnTypes = ['left_arm', 'belt', 'foot'];

            previewFragment.find('img').each(function() {
                $(this).css('position', 'absolute');
                const parentStyle = $(this).parent().attr('style') || '';
                if (parentStyle.includes('left: 15px') || parentStyle.includes('left: 35px')) {
                    this.style.setProperty('width', '20px', 'important');
                    this.style.setProperty('height', '20px', 'important');
                } else {
                    this.style.setProperty('width', '15px', 'important');
                    this.style.setProperty('height', '15px', 'important');
                }
            });

            const tile = $('<div></div>')
                .addClass('equipment-tile')
                .attr('title', equipSet.name)
                .css({
                    'border': '3px solid #5c3c1a',
                    'padding': '0px',
                    'text-align': 'center',
                    'cursor': 'pointer',
                    'background': 'url("https://westpl.innogamescdn.com/images/inventory/bag.png?1") repeat scroll 0 0 #e0c8a0',
                    'background-color': '#e0c8a0',
                    'border-radius': '3px',
                    'transition': 'background-color 0.2s ease, transform 0.1s ease, border-color 0.2s ease',
                    'box-shadow': 'inset 0 0 0px rgba(0,0,0,0.3)',
                    'width': '55px',
                    'min-width': '55px',
                    'height': '60px',
                    'min-height': '60px'
                })
                .html(`
                    <div class="equipment-preview-placeholder" style="margin-bottom: 0px;"></div>
                `)
                .on('mouseenter', function() {
                    // Zastosuj efekt hover tylko jeśli kafelek NIE jest noszonym zestawem
                    if (!$(this).hasClass('worn-set-tile')) {
                        $(this).css({
                            'background-color': '#f5deb3', // Lighter wheat/sand on hover
                            'transform': ''
                        });
                    }
                })
                .on('mouseleave', function() {
                    // Przywróć tło i transformację tylko jeśli kafelek NIE jest noszonym zestawem
                    if (!$(this).hasClass('worn-set-tile')) {
                        $(this).css({
                            'background-color': '#e0c8a0', // Original darker sand
                            'transform': ''
                        });
                    }
                })
                .click(() => {
                    this.switchEquipmentByIndex(index);
                });

            // Dołączenie zmodyfikowanego fragmentu podglądu do placeholdera
            tile.find('.equipment-preview-placeholder').append(previewFragment);

            return tile;
        };

        // Tworzenie podglądu zestawu (dodano przezroczyste tło)
        this.createEquipmentPreview = function(equipSet, index) {
            // Szerokość 79px, bez marginesu auto, przezroczyste tło
            const previewDiv = `<div id="equipshow_${equipSet.equip_manager_id}" style="height: 60px; width: 55px; position: relative; margin: 0; overflow: hidden; background-color: transparent;">`;

            // Koordynaty (top, left) pozostają bez zmian (0, 27, 54)
            const parts = [
                // Kolumna 1 (left=0)
                ['neck',        0,   0],
                ['right_arm',  15,   0],
                ['animal',     30,   0],
                ['yield',      45,   0],
                // Kolumna 2 (left=15)
                ['head',        0,  15],
                ['body',       20,  15],
                ['pants',      40,  15],
                // Kolumna 3 (left=35)
                ['left_arm',    0,  35],
                ['belt',       20,  35],
                ['foot',       40,  35],
            ];

            let previewContent = parts.reduce((preview, [type, top, left]) => {
                 let partHtml = '';
                 if (typeof EquipManager.titlepart === 'function') {
                     try {
                         partHtml = EquipManager.titlepart(index, type, top, left);
                         // Loguj tylko dla konkretnego slotu (np. 'head') i zestawu (np. 'win'), aby nie zalać konsoli
                         if (type === 'head' && equipSet.name === 'win') {
                             console.log(`[Zestawy wyposażenia] HTML dla głowy (set 'win', index ${index}) z EquipManager.titlepart:`, partHtml);
                         }
                     } catch (error) {
                         console.error(`Error calling EquipManager.titlepart for type ${type}:`, error);
                     }
                 } else {
                     console.error("EquipManager.titlepart is not a function!");
                 }
                 return preview + (partHtml || '');
             }, '');

            return previewDiv + previewContent + '</div>';
        };

        // Zmiana ekwipunku (oryginalna funkcja potrzebuje ID, dodajemy funkcję pomocniczą przez index)
        this.switchEquipmentByIndex = function(selectedIndex) {
             if (this.equipmentList.hasOwnProperty(selectedIndex)) {
                 const equipId = this.equipmentList[selectedIndex];
                 EquipManager.switchEquip(equipId);

                 // Po udanej zmianie, odśwież dane i przebuduj kafelki
                 // Użyj setTimeout, aby dać serwerowi chwilę na przetworzenie zmiany
                 setTimeout(() => {
                     console.log("[Zestawy wyposażenia] Refreshing data after set switch...");
                     this.fetchAndUpdateSets(() => {
                         this.rebuildTilesFromData();
                     });
                 }, 500); // Małe opóźnienie (0.5 sekundy)

             } else {
                 new UserMessage("Error: Could not find equipment set ID for the selected index.", UserMessage.TYPE_ERROR).show();
             }
         };
    }

    // Utworzenie i inicjalizacja menedżera zestawów
    const menedzerZestawow = new MenedzerZestawowWyposazenia();
    menedzerZestawow.initialize();
}

// Uruchomienie skryptu
initializeEquipmentSets();