您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A quick way of changing inventories in TW and filtering notifications
// ==UserScript== // @name EQ SETS // @version 3.1 // @description A quick way of changing inventories in TW and filtering notifications // @author Donald Kaczyński // @website // @include https://*.the-west.*/game.php* // @grant none // @namespace https://greasyfork.org/users/755649 // ==/UserScript== (function() { 'use strict'; setTimeout(function() { 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 // Obiekt tłumaczeń this.langs = { pl: { settingsTitle: 'USTAWIENIA ZESTAWÓW', showPanel: 'Pokaż panel zestawów', numColumns: 'Ilość kolumn:', tileScaling: 'Skalowanie kafelków:', locationPanel: 'Lokalizacja panelu:', locationNotibar: 'Pod powiadomieniami', locationFixed: 'Prawa strona ekranu', visibleSets: 'Widoczne zestawy:', noSetsLoaded: 'Lista zestawów zostanie załadowana po pierwszym otwarciu panelu lub odświeżeniu.', errorEquipIdNotFound: 'Błąd: Nie znaleziono ID zestawu ekwipunku dla wybranego indeksu.', errorParseHiddenNames: '[Zestawy wyposażenia] Error parsing hidden names from localStorage:', errorGameObjectsNotReady: '[Zestawy wyposażenia]: Game objects not ready for initial tile display.', consoleRefreshData: '[Zestawy wyposażenia] Refreshing data after set switch...', // Komunikat konsoli consolePopulateSettings: '[Zestawy wyposażenia] Wypełnianie ustawień danymi:', // Komunikat konsoli consoleErrorTitlepart: 'Error calling EquipManager.titlepart for type', consoleEquipManagerNotFunction: 'EquipManager.titlepart is not a function!', removeNotificationsTitle: 'Ukryj wszystkie powiadomienia o pracy', defaultSetName: 'Zestaw Bez Nazwy', // Domyślna nazwa zestawu consoleLogPrefix: '[Zestawy wyposażenia]' // Prefix dla komunikatów konsoli }, en: { settingsTitle: 'EQUIPMENT SETTINGS', showPanel: 'Show sets panel', numColumns: 'Number of columns:', tileScaling: 'Tile scaling:', locationPanel: 'Panel location:', locationNotibar: 'Under notifications', locationFixed: 'Right side of screen', visibleSets: 'Visible sets:', noSetsLoaded: 'Set list will be loaded after first panel opening or refresh.', errorEquipIdNotFound: 'Error: Could not find equipment set ID for the selected index.', errorParseHiddenNames: '[Equipment Sets] Error parsing hidden names from localStorage:', errorGameObjectsNotReady: '[Equipment Sets]: Game objects not ready for initial tile display.', consoleRefreshData: '[Equipment Sets] Refreshing data after set switch...', // Console message consolePopulateSettings: '[Equipment Sets] Populating settings with data:', // Console message consoleErrorTitlepart: 'Error calling EquipManager.titlepart for type', consoleEquipManagerNotFunction: 'EquipManager.titlepart is not a function!', removeNotificationsTitle: 'Hide all job notifications', defaultSetName: 'Unnamed Set', consoleLogPrefix: '[Equipment Sets]' // Prefix for console messages } }; // Funkcja do aktualizacji języka this.updateLang = function() { const storedLang = localStorage.getItem('scriptsLang'); const gameLocale = Game.locale.substr(0, 2); if (this.langs[storedLang]) { this.lang = this.langs[storedLang]; } else if (this.langs[gameLocale]) { this.lang = this.langs[gameLocale]; } else { this.lang = this.langs.en; // Domyślnie angielski } }; // Wywołaj funkcję updateLang raz na początku, aby ustawić domyślny język this.updateLang(); // 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(this.lang.errorParseHiddenNames, 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(this.lang.errorGameObjectsNotReady); } }, 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': this.lang.settingsTitle, '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>' + this.lang.settingsTitle + '</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) { 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(this.lang.showPanel); 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(this.lang.numColumns).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(this.lang.tileScaling).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">' + this.lang.locationNotibar + '</option>') .append('<option value="fixed">' + this.lang.locationFixed + '</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(this.lang.locationPanel).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>' + this.lang.visibleSets + '</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 || `${this.lang.defaultSetName} ${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(this.lang.noSetsLoaded); } container.append(setsContainer); }; // Nowa funkcja do pobierania danych i aktualizacji listy zestawów this.fetchAndUpdateSets = function(callback) { Ajax.remoteCallMode('inventory', 'show_equip', {}, (data) => { 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() { // 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); // 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 && currentItem.obj && 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') { } } catch (error) { console.error(`${this.lang.consoleErrorTitlepart} ${type}:`, error); } } else { console.error(this.lang.consoleEquipManagerNotFunction); } 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(() => { this.fetchAndUpdateSets(() => { this.rebuildTilesFromData(); }); }, 500); // Małe opóźnienie (0.5 sekundy) } else { new UserMessage(this.lang.errorEquipIdNotFound, UserMessage.TYPE_ERROR).show(); } }; } // Utworzenie i inicjalizacja menedżera zestawów const menedzerZestawow = new MenedzerZestawowWyposazenia(); menedzerZestawow.initialize(); // --- Usuwanie powiadomień o pracy co 15 sekund --- function removeJobNotifications() { document.querySelectorAll(`.ui_ongoing .tw2gui_window_buttons_close[title="${menedzerZestawow.lang.removeNotificationsTitle}"]`).forEach(btn => { const notification = btn.closest('.ui_ongoing'); if (notification) notification.remove(); }); } setInterval(removeJobNotifications, 15000); } // Uruchomienie skryptu initializeEquipmentSets(); }, 5000); })();