// ==UserScript==
// @name GSJ TOP
// @namespace http://tampermonkey.net/
// @version 7.8
// @description try to take over the world!
// @author DK, Shikokuchuo
// @include https://*.the-west.*/game.php*
// @icon https://www.google.com/s2/favicons?sz=64&domain=the-west.pl
// @grant none
// ==/UserScript==
(function() {
'use strict';
(function (fn) {
setTimeout(function() {
var script = document.createElement('script');
script.setAttribute('type', 'application/javascript');
script.textContent = '(' + fn + ')();';
document.body.appendChild(script);
document.body.removeChild(script);
}, 5000); // 5000 ms = 5 sekund
})(function () {
// Inicjalizacja głównego obiektu GSJTOP
GSJTOP = {
version: '7.7',
name: 'GSJ TOP',
author: 'Shiko',
minGame: '2.01',
maxGame: Game.version.toString(),
toLoad: 0,
loaded: 0,
xMax: 181,
yMax: 79,
blockMaxLength: 300,
dataLoaded: false,
silverJobBbColor: '#708090',
goldJobBbColor: '#AB9930',
refreshInterval: null,
preferences: {
showSilver: localStorage.getItem('GSJTOP_showSilver') !== 'false',
showGold: localStorage.getItem('GSJTOP_showGold') !== 'false',
enabled: localStorage.getItem('GSJTOP_enabled') !== 'false',
hideLowIdJobs: localStorage.getItem('GSJTOP_hideLowIdJobs') === 'true',
hideHighIdJobs: localStorage.getItem('GSJTOP_hideHighIdJobs') === 'true',
showTooltips: localStorage.getItem('GSJTOP_showTooltips') !== 'false',
hideFilters: localStorage.getItem('GSJTOP_hideFilters') === 'true',
currentPage: 0,
jobsPerPage: parseInt(localStorage.getItem('GSJTOP_jobsPerPage')) || 8,
hiddenJobs: JSON.parse(localStorage.getItem('GSJTOP_hiddenJobs') || '{}')
},
hiddenImageOpacity: 0.35,
shownImageOpacity: 1,
bestJobTime: 0,
position: {
top: 0,
right: 0
},
langs: {
pl: {
language: 'Polish (polski)',
ApiGui: 'Ten skrypt automatycznie wyszukuje złote i srebrne prace na mapie.',
title: 'Złote i srebrne prace',
loading: 'Ładowanie... To zajmie moment',
next: '→',
prev: '←',
enableScript: 'Włącz skrypt'
}
},
updateLang: function () {
var lg = GSJTOP.langs;
GSJTOP.lang = lg[localStorage.getItem('scriptsLang')] ? localStorage.getItem('scriptsLang') : lg[Game.locale.substr(0, 2)] ? Game.locale.substr(0, 2) : 'en';
GSJTOPlang = lg[GSJTOP.lang];
}
};
GSJTOP.updateLang();
// Funkcja tworząca przełączniki (checkboxy) w interfejsie
GSJTOP.createToggleCheckbox = function() {
var container = $('<div/>', {
id: 'gj-toggle',
css: {
position: 'static',
display: 'inline-block',
float: 'right',
marginRight: '-30px',
zIndex: 10002,
backgroundColor: 'rgba(255, 255, 255, 0.0)',
padding: '5px',
borderRadius: '3px'
}
});
// Główny checkbox włączający skrypt
var checkbox = $('<input/>', {
type: 'checkbox',
id: 'gj-checkbox',
checked: this.preferences.enabled
});
// Checkbox do ukrywania filtrów - poprawiona inicjalizacja
var hideFiltersCheckbox = $('<input/>', {
type: 'checkbox',
id: 'gj-hide-filters',
checked: !this.preferences.hideFilters,
css: {
marginLeft: '5px'
}
});
checkbox.on('change', function() {
GSJTOP.preferences.enabled = this.checked;
localStorage.setItem('GSJTOP_enabled', this.checked.toString());
if (this.checked) {
GSJTOP.init();
} else {
GSJTOP.closeWindow();
}
});
hideFiltersCheckbox.on('change', function() {
GSJTOP.preferences.hideFilters = !this.checked;
localStorage.setItem('GSJTOP_hideFilters', GSJTOP.preferences.hideFilters.toString());
GSJTOP.refreshWindow();
});
container.append(checkbox, hideFiltersCheckbox);
$('#ui_topbar').append(container);
};
// Funkcja pobierająca dane o pracy
GSJTOP.getJobData = function(job, isSilver) {
try {
var jobData = JobList.getJobById(job.jobId);
if (!jobData) return null;
var jobModelData = JobsModel.Jobs.find(j => j.id === parseInt(job.jobId));
if (!jobModelData) return null;
var xp = jobModelData.basis.short.experience;
var money = jobModelData.basis.short.money;
var motivation = Math.round(jobModelData.jobmotivation * 100);
if (isSilver) {
xp = Math.ceil(xp * 1.5);
money = Math.ceil(money * 1.5);
}
else if (job.gold) {
xp = Math.ceil(xp * 2);
money = Math.ceil(money * 2);
}
return {
experience: xp,
money: money,
motivation: motivation,
distance: job.distance
};
} catch (e) {
return {
experience: 0,
money: 0,
motivation: 0,
distance: job.distance
};
}
};
// Funkcja zamykająca okno
GSJTOP.closeWindow = function() {
if (this.refreshInterval) {
clearTimeout(this.refreshInterval);
this.refreshInterval = null;
}
$('#goldJobs-bar').remove();
};
// Funkcja do zarządzania automatycznym odświeżaniem
GSJTOP.startAutoRefresh = function() {
if (this.refreshInterval) {
clearTimeout(this.refreshInterval);
}
const getRandomDelay = () => Math.floor(Math.random() * (20000 - 7000 + 1) + 7000);
const scheduleNextRefresh = () => {
if (!this.preferences.enabled) return;
this.refreshWindow();
const nextDelay = getRandomDelay();
this.refreshInterval = setTimeout(scheduleNextRefresh, nextDelay);
};
scheduleNextRefresh();
};
// Funkcja obliczająca odległość
GSJTOP.calculateDistance = function (jobX, jobY) {
if (!Character || !Character.position) return 0;
var to = {
x: parseInt(jobX),
y: parseInt(jobY)
};
return GameMap.calcWayTime(Character.position, to);
};
GSJTOP.parseWholeMap = function (tiles, onLoad) {
this.loaded = 0;
var x, y;
var arr = [];
var currentBlock = 0;
var currentBlockLength = 0;
for (x in tiles) {
for (y in tiles[x]) {
if (isNaN(x) || isNaN(y)) {
continue;
}
if (currentBlockLength === 0) {
arr[currentBlock] = [];
}
arr[currentBlock].push([parseInt(x), parseInt(y)]);
if (++currentBlockLength == this.blockMaxLength) {
currentBlock++;
currentBlockLength = 0;
}
}
}
var i, to = arr.length;
this.toLoad = to;
for (i = 0; i < to; i++) {
GameMap.Data.Loader.load(arr[i], function () {
GSJTOP.loaded++;
if (GSJTOP.loaded == GSJTOP.toLoad) {
onLoad();
}
});
}
};
GSJTOP.createVisibilityWindow = function() {
// Sprawdź, czy okno już istnieje, aby uniknąć duplikatów
if ($('#job-visibility-window').length > 0) {
// Opcjonalnie: przenieś istniejące okno na wierzch
$('#job-visibility-window').css('z-index', 10002);
return;
}
var hiddenJobs = JSON.parse(localStorage.getItem('GSJTOP_hiddenJobs') || '{}');
var data = GSJTOP.getFilteredData(true, true);
var goldJobs = data.filter(job => job.gold);
var silverJobs = data.filter(job => job.silver);
// --- POCZĄTEK EDYCJI: Odczyt zapisanej pozycji ---
var storageKey = 'GSJTOP_job-visibility-window_Pos';
var savedPosition = null;
try {
var savedPosString = localStorage.getItem(storageKey);
if (savedPosString) {
savedPosition = JSON.parse(savedPosString);
}
} catch (err) {
console.error("GSJTOP: Nie udało się odczytać pozycji okna widoczności z localStorage.", err);
localStorage.removeItem(storageKey); // Usuń uszkodzone dane
}
// --- KONIEC EDYCJI: Odczyt zapisanej pozycji ---
var panelCss = {
'position': 'fixed',
// Nowe pozycjonowanie - wyśrodkowane poziomo, dolna krawędź 20px nad środkiem ekranu
'top': 'calc(50% - 270px)',
'left': '50%',
'transform': 'translateX(-50%)',
// ... (reszta stylów: background, padding, border, etc.) ...
'background': 'linear-gradient(to bottom, #4d351b 0%, #2a1608 100%)',
'padding': '15px',
'border-radius': '5px',
'border': '2px solid #1b0a00',
'border-top-color': '#150800',
'border-left-color': '#150800',
'box-shadow': '0 4px 15px rgba(0, 0, 0, 0.7), inset 0 0 5px rgba(0,0,0,0.2)',
'z-index': 10002,
'height': 'auto',
'min-height': '340px',
'max-height': '80vh',
'overflow': 'hidden',
'min-width': '440px',
'width': '490px',
'cursor': 'move'
};
// --- POCZĄTEK EDYCJI: Zastosowanie zapisanej pozycji ---
if (savedPosition && savedPosition.top && savedPosition.left) {
panelCss.top = savedPosition.top;
panelCss.left = savedPosition.left;
panelCss.transform = 'none'; // Usuwamy transformację, bo mamy pozycję w px
}
// --- KONIEC EDYCJI: Zastosowanie zapisanej pozycji ---
var visibilityPanel = $('<div/>', {
id: 'job-visibility-window',
css: panelCss // Używamy przygotowanego obiektu CSS
});
var title = $('<div/>', {
text: 'Widoczność prac',
css: {
'font-weight': 'bold',
'margin-bottom': '10px',
'text-align': 'center',
'padding-bottom': '5px',
'border-bottom': '1px solid rgba(255, 255, 255, 0.2)', // Jaśniejsza linia na ciemnym tle
'color': '#fdf7e5', // Jaśniejszy kolor tekstu tytułu
'cursor': 'default' // Przywracamy domyślny kursor dla tytułu
}
});
// Dodajemy pole wyszukiwania
var searchContainer = $('<div/>', {
css: {
'margin-bottom': '10px',
'display': 'flex',
'align-items': 'center',
'width': '100%',
'cursor': 'default'
}
});
var searchInput = $('<input/>', {
type: 'text',
placeholder: 'Szukaj pracy...',
css: {
'flex': '1',
'padding': '5px',
'border-radius': '3px',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'margin-right': '5px',
'cursor': 'text'
}
}).on('input', function(e) {
e.stopPropagation();
var searchText = $(this).val().toLowerCase();
filterJobs(searchText);
}).on('mousedown', function(e) {
e.stopPropagation(); // Zapobiegamy rozpoczęciu przeciągania przy kliknięciu w pole wyszukiwania
});
var clearButton = $('<button/>', {
text: 'X',
css: {
'padding': '5px 8px',
'border-radius': '3px',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'background-color': '#f0f0f0',
'cursor': 'pointer'
}
}).on('click', function(e) {
e.stopPropagation();
searchInput.val('').trigger('input');
}).on('mousedown', function(e) {
e.stopPropagation();
});
searchContainer.append(searchInput, clearButton);
var toggleButton = $('<button/>', {
text: 'Odznacz wszystkie',
css: {
'margin-bottom': '10px',
'padding': '5px 10px',
'border-radius': '3px',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'background-color': '#f0f0f0',
'cursor': 'pointer', // Kursor 'pointer' dla przycisku
'width': '100%',
'transition': 'opacity 0.3s ease'
}
}).on('click', function(e) { // Dodajemy e (event)
e.stopPropagation(); // Zapobiegamy propagacji kliknięcia do visibilityPanel
var button = $(this);
var checkboxes = checkboxContainer.find('input[type="checkbox"]');
var allChecked = checkboxes.length === checkboxes.filter(':checked').length;
button.prop('disabled', true).css('opacity', '0.5');
function processCheckboxes(startIndex) {
var batchSize = 1;
var endIndex = Math.min(startIndex + batchSize, checkboxes.length);
for(var i = startIndex; i < endIndex; i++) {
$(checkboxes[i]).prop('checked', !allChecked).trigger('change');
}
if(endIndex < checkboxes.length) {
setTimeout(() => processCheckboxes(endIndex), 200);
} else {
setTimeout(() => {
button.prop('disabled', false).css('opacity', '1');
button.text(allChecked ? 'Zaznacz wszystkie' : 'Odznacz wszystkie');
}, 300);
}
}
processCheckboxes(0);
});
var checkboxContainer = $('<div/>', {
id: 'gsjtop-visibility-container-' + Date.now(), // Unikalne ID dla selektorów CSS
css: {
'display': 'flex',
'flex-direction': 'column',
'gap': '5px',
'margin-bottom': '10px',
'height': '223px', // Zmiana z max-height na height
'overflow-y': 'auto',
'padding-right': '10px',
'scrollbar-width': 'thin',
'scrollbar-color': '#888 #f0f0f0',
'width': '480px',
'background-color': '#ffffff',
'border-radius': '3px',
'border': '1px solid #b89b6d',
'cursor': 'default'
}
});
var jobVisibilityContainer = $('<div/>', {
css: {
'display': 'flex',
'flex-wrap': 'wrap',
'gap': '5px',
'justify-content': 'center',
'margin-top': '-20px',
'background-color': 'rgba(255, 255, 255, 0.7)',
'padding': '5px',
'border-radius': '3px',
'position': 'relative',
'z-index': '10001',
'cursor': 'default' // Domyślny kursor
}
});
function createJobWrapper(job, jobData) {
var wrapper = $('<div/>', {
css: {
'display': 'grid',
'grid-template-columns': '30px 220px 50px 50px 80px',
'align-items': 'center',
'gap': '10px',
'padding': '5px',
'border-bottom': '1px solid rgba(0,0,0,0.1)',
'width': '430px',
'cursor': 'default' // Domyślny kursor
}
});
var checkbox = $('<input/>', {
type: 'checkbox',
id: 'job-visibility-' + job.jobId,
checked: !hiddenJobs[job.jobId],
css: { 'cursor': 'pointer' } // Kursor pointer dla checkboxa
}).on('change', function(e) { // Dodajemy e (event)
e.stopPropagation(); // Zapobiegamy propagacji
hiddenJobs[job.jobId] = !this.checked;
localStorage.setItem('GSJTOP_hiddenJobs', JSON.stringify(hiddenJobs));
// Aktualizuj stan ukrycia pracy w danych
data.forEach(function(dataJob) {
if (dataJob.jobId == job.jobId) {
dataJob.hidden = !this.checked;
}
});
// Odśwież mapę
GSJTOP.refreshMap()
GSJTOP.refreshWindow();
}).on('mousedown', function(e) { // Dodajemy mousedown
e.stopPropagation(); // Zapobiegamy rozpoczęciu przeciągania przy kliknięciu checkboxa
});
var label = $('<label/>', {
for: 'job-visibility-' + job.jobId,
text: job.shortname,
css: {
'font-size': '12px',
'white-space': 'nowrap',
'overflow': 'hidden',
'text-overflow': 'ellipsis',
'cursor': 'pointer' // Kursor pointer dla etykiety
}
}).on('mousedown', function(e) { // Dodajemy mousedown
e.stopPropagation(); // Zapobiegamy rozpoczęciu przeciągania przy kliknięciu etykiety
});
var xpDiv = $('<div/>', {
html: '<img src="images/window/job/bigicon_xp.png" style="width: 14px; height: 14px; vertical-align: middle;"> ' +
'<span style="margin-left: 2px;">' + jobData.experience + '</span>',
css: {
'white-space': 'nowrap',
'text-align': 'left',
'font-size': '11px',
'cursor': 'default' // Domyślny kursor
}
});
var moneyDiv = $('<div/>', {
html: '<img src="images/window/job/bigicon_money.png" style="width: 14px; height: 14px; vertical-align: middle;"> ' +
'<span style="margin-left: 2px;">' + jobData.money + '</span>',
css: {
'white-space': 'nowrap',
'text-align': 'left',
'font-size': '11px',
'cursor': 'default' // Domyślny kursor
}
});
var timeDiv = $('<div/>', {
text: GSJTOP.formatTime(job.distance),
css: {
'white-space': 'nowrap',
'text-align': 'left',
'font-size': '11px',
'cursor': 'default' // Domyślny kursor
}
});
wrapper.append(checkbox, label, xpDiv, moneyDiv, timeDiv);
return wrapper;
}
function createSortButton(text, sortFn, jobsType) {
return $('<button/>', {
text: text,
css: {
'padding': '2px 5px',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'border-radius': '3px',
'background': '#f0f0f0',
'cursor': 'pointer', // Kursor pointer
'font-size': '11px',
'min-width': '25px',
'transition': 'background-color 0.3s ease'
}
}).on('click', function(e) { // Dodajemy e (event)
e.stopPropagation(); // Zapobiegamy propagacji
var $button = $(this);
if($button.prop('disabled')) return;
$button.prop('disabled', true);
var isAscending = !$button.data('ascending');
$button.data('ascending', isAscending);
$button.siblings('button').removeData('ascending');
$button.siblings('button').css('background', '#f0f0f0');
$button.css('background', isAscending ? '#e0ffe0' : '#ffe0e0');
var jobs = jobsType === 'goldJobs' ? goldJobs : silverJobs;
setTimeout(() => {
jobs.sort((a, b) => {
var valueA = sortFn(a);
var valueB = sortFn(b);
return isAscending ? valueA - valueB : valueB - valueA;
});
refreshJobList(jobs, jobsType);
setTimeout(() => {
$button.prop('disabled', false);
}, 200);
}, 100);
}).on('mousedown', function(e) { // Dodajemy mousedown
e.stopPropagation(); // Zapobiegamy rozpoczęciu przeciągania przy kliknięciu przycisku sortowania
});
}
// Funkcja do filtrowania prac na podstawie wyszukiwanego tekstu
// Funkcja do filtrowania prac na podstawie wyszukiwanego tekstu
// Funkcja do filtrowania prac na podstawie wyszukiwanego tekstu
// Funkcja do filtrowania prac na podstawie wyszukiwanego tekstu
function filterJobs(searchText) {
console.log("Filtrowanie prac, tekst:", searchText);
if (!searchText) {
// Jeśli pole wyszukiwania jest puste, pokaż wszystkie prace
checkboxContainer.find('.silverJobs > div, .goldJobs > div').show();
// Przywróć oryginalny stan ukrytych prac na podstawie checkboxów
checkboxContainer.find('input[type="checkbox"]').each(function() {
var jobId = $(this).attr('id').replace('job-visibility-', '');
var isChecked = $(this).prop('checked');
data.forEach(function(job) {
if (job.jobId == jobId) {
job.hidden = !isChecked;
}
});
});
console.log("Pole wyszukiwania puste, liczba widocznych prac:",
data.filter(function(job) { return !job.hidden; }).length);
// Odśwież mapę z aktualnymi danymi
GSJTOP.refreshMap(data);
return;
}
searchText = searchText.toLowerCase();
// Tymczasowo ukryj wszystkie prace na mapie
data.forEach(function(job) {
// Domyślnie ukryj wszystkie prace
job.hidden = true;
});
// Filtruj prace srebrne
checkboxContainer.find('.silverJobs > div').each(function() {
var jobElement = $(this);
var jobName = jobElement.find('label').text().toLowerCase();
var jobId = jobElement.find('input[type="checkbox"]').attr('id').replace('job-visibility-', '');
if (jobName.includes(searchText)) {
jobElement.show();
// Pokaż pracę na mapie tylko jeśli checkbox jest zaznaczony
var isChecked = jobElement.find('input[type="checkbox"]').prop('checked');
if (isChecked) {
// Znajdź odpowiadającą pracę w danych
data.forEach(function(job) {
if (job.jobId == jobId) {
job.hidden = false;
}
});
}
} else {
jobElement.hide();
}
});
// Filtruj prace złote
checkboxContainer.find('.goldJobs > div').each(function() {
var jobElement = $(this);
var jobName = jobElement.find('label').text().toLowerCase();
var jobId = jobElement.find('input[type="checkbox"]').attr('id').replace('job-visibility-', '');
if (jobName.includes(searchText)) {
jobElement.show();
// Pokaż pracę na mapie tylko jeśli checkbox jest zaznaczony
var isChecked = jobElement.find('input[type="checkbox"]').prop('checked');
if (isChecked) {
// Znajdź odpowiadającą pracę w danych
data.forEach(function(job) {
if (job.jobId == jobId) {
job.hidden = false;
}
});
}
} else {
jobElement.hide();
}
});
console.log("Po filtrowaniu, liczba widocznych prac:",
data.filter(function(job) { return !job.hidden; }).length);
// Odśwież mapę z aktualnymi danymi
GSJTOP.refreshMap(data);
}
// Dodaj funkcję refreshMap do obiektu GSJTOP
GSJTOP.refreshMap = function(customData) {
// Sprawdź czy okno mapy istnieje
var mapWindow = $('#custom-map-window');
if (mapWindow.length === 0) return;
// Użyj przekazanych danych lub pobierz domyślne
var data = customData || this.getFilteredData(this.preferences.showSilver, this.preferences.showGold);
// Debugowanie
console.log("Odświeżanie mapy, liczba prac:", data.length);
console.log("Liczba widocznych prac:", data.filter(function(job) { return !job.hidden; }).length);
// Znajdź kontener mapy
var mapContent = mapWindow.find('div').first();
// WAŻNE: Usuń tylko markery prac, a nie całą zawartość mapy
mapContent.find('div').remove(); // Usuń tylko divy (markery), a nie obrazy (kafelki mapy)
// Ustawienia mapy i markerów
var maxX = 46592;
var maxY = 20480;
var mapWindowWidth = 770;
var mapWindowHeight = 338;
var markerSize = 24;
var markerOffset = markerSize / 2;
// Zastosuj filtry do danych
var filteredData = data.filter(function(job) {
// Filtruj prace na podstawie preferencji
if (this.preferences.hideHighIdJobs && job.jobId > 150) return false;
if (this.preferences.hideLowIdJobs && job.jobId < 100) return false;
// Sprawdź czy praca jest ukryta przez użytkownika
if (job.hidden) return false;
return true;
}.bind(this));
console.log("Po zastosowaniu filtrów, liczba widocznych prac:", filteredData.length);
// Dodaj markery prac na mapie
filteredData.forEach(function(job) {
var markerLeft = (job.x / maxX * mapWindowWidth) - markerOffset;
var markerTop = (job.y / maxY * mapWindowHeight) - markerOffset;
// Utwórz element markera (div)
var marker = $('<div/>', {
title: job.name,
css: {
'position': 'absolute',
'left': markerLeft + 'px',
'top': markerTop + 'px',
'width': markerSize + 'px',
'height': markerSize + 'px',
'cursor': 'pointer',
'z-index': 10004,
'border-radius': '50%',
}
}).append($('<img/>', {
src: 'https://westpl.innogamescdn.com/images/jobs/' + job.shortname + '.png',
css: {
'width': '100%',
'height': '100%'
}
}));
// Dodaj obramowanie/cień w zależności od typu pracy
if (job.gold) {
marker.css('box-shadow', '0 0 5px 2px gold');
} else if (job.silver) {
marker.css('box-shadow', '0 0 5px 2px silver');
} else {
marker.css('box-shadow', '0 0 3px rgba(0,0,0,0.5)');
}
// Dodaj akcję kliknięcia
marker.click(function(e) {
e.stopPropagation();
if (typeof GameMap !== 'undefined' && GameMap.center) {
GameMap.center(job.x, job.y);
}
// Zamknij okno mapy
mapWindow.remove();
// Zamknij okno widoczności, jeśli istnieje
$('#job-visibility-window').remove();
// Opcjonalnie: Zaktualizuj wygląd przycisku przełączającego widoczność
var visibilityButton = $('#gsjtop-visibility-toggle');
if (visibilityButton.length > 0) {
visibilityButton.css('background-color', '#4a90e2');
}
});
// Dodaj marker do kontenera mapy
mapContent.append(marker);
});
};
function refreshJobList(jobs, jobsType) {
var container = checkboxContainer.find('.' + jobsType);
container.empty();
const translations = {};
JobList.getSortedJobs().forEach(job => {
translations[job.id] = job.name;
});
// Definiujemy kolor naprzemienny w zależności od typu pracy
let alternatingColor;
if (jobsType === 'silverJobs') {
alternatingColor = '#D3D3D3'; // Jasny srebrny (LightGray)
} else { // Zakładamy, że to 'goldJobs'
alternatingColor = '#FAFAD2'; // Jasny złoty (LightGoldenrodYellow)
}
jobs.forEach(function(job, index) { // Dodajemy 'index' do pętli
var jobData = GSJTOP.getJobData(job, jobsType === 'silverJobs');
if (jobData) {
// Ustawiamy kolor tła na podstawie indeksu i typu pracy
var backgroundColor = index % 2 === 0 ? alternatingColor : '#ffffff'; // Kolor naprzemienny lub biały
var wrapper = $('<div/>', {
css: {
'display': 'grid',
'grid-template-columns': '30px 180px 80px 80px 80px',
'align-items': 'center',
'gap': '5px',
'padding': '5px',
'border-bottom': '1px solid rgba(0,0,0,0.1)',
'width': '460px',
'background-color': backgroundColor, // Ustawiamy odpowiedni kolor tła
'cursor': 'default' // Domyślny kursor dla wiersza
}
});
var checkbox = $('<input/>', {
type: 'checkbox',
id: 'job-visibility-' + job.jobId,
checked: !hiddenJobs[job.jobId],
css: { 'cursor': 'pointer' }
}).on('change', function(e) {
e.stopPropagation();
var isChecked = this.checked;
var jobId = $(this).attr('id').replace('job-visibility-', '');
// Debugowanie
console.log("Zmiana stanu checkboxa dla pracy:", jobId, "isChecked:", isChecked);
hiddenJobs[jobId] = !isChecked;
localStorage.setItem('GSJTOP_hiddenJobs', JSON.stringify(hiddenJobs));
// Aktualizuj stan ukrycia pracy w danych
data.forEach(function(dataJob) {
if (dataJob.jobId == jobId) {
dataJob.hidden = !isChecked;
}
});
// Odśwież mapę z aktualnymi danymi
GSJTOP.refreshMap(data);
GSJTOP.refreshWindow();
}).on('mousedown', function(e) {
e.stopPropagation();
});
var jobName = translations[job.jobId] || job.shortname;
var label = $('<label/>', {
for: 'job-visibility-' + job.jobId,
text: jobName,
css: {
'font-size': '11px',
'white-space': 'nowrap',
'overflow': 'hidden',
'text-overflow': 'ellipsis',
'cursor': 'pointer' // Kursor pointer dla etykiety
}
}).on('mousedown', function(e) { // Dodajemy mousedown
e.stopPropagation(); // Zapobiegamy rozpoczęciu przeciągania przy kliknięciu etykiety
});
var xpDiv = $('<div/>', {
html: '<img src="images/window/job/bigicon_xp.png" style="width: 14px; height: 14px; vertical-align: middle;"> ' +
'<span style="margin-left: 2px;">' + jobData.experience + '</span>',
css: {
'white-space': 'nowrap',
'text-align': 'left',
'font-size': '11px',
'cursor': 'default' // Domyślny kursor
}
});
var moneyDiv = $('<div/>', {
html: '<img src="images/window/job/bigicon_money.png" style="width: 14px; height: 14px; vertical-align: middle;"> ' +
'<span style="margin-left: 2px;">' + jobData.money + '</span>',
css: {
'white-space': 'nowrap',
'text-align': 'left',
'font-size': '11px',
'cursor': 'default' // Domyślny kursor
}
});
var timeDiv = $('<div/>', {
text: GSJTOP.formatTime(job.distance),
css: {
'white-space': 'nowrap',
'text-align': 'left',
'font-size': '11px',
'cursor': 'default' // Domyślny kursor
}
});
wrapper.append(checkbox, label, xpDiv, moneyDiv, timeDiv);
container.append(wrapper);
}
});
}
var silverHeader = $('<div/>', {
css: {
'display': 'flex',
'justify-content': 'space-between',
'align-items': 'center',
'font-weight': 'bold',
'margin': '0px 0 5px 0',
'padding': '5px',
'background-color': 'rgba(112, 128, 144, 0.1)',
'border-radius': '3px',
'grid-column': '1 / -1',
'cursor': 'default' // Domyślny kursor
}
}).append(
$('<span/>').text('Srebrne prace'),
$('<div/>', {
css: {
'display': 'flex',
'gap': '5px',
'cursor': 'default' // Domyślny kursor
}
}).append(
createSortButton('XP', job => GSJTOP.getJobData(job, true).experience, 'silverJobs'),
createSortButton('$', job => GSJTOP.getJobData(job, true).money, 'silverJobs'),
createSortButton('↔', job => job.distance, 'silverJobs')
)
);
var goldHeader = $('<div/>', {
css: {
'display': 'flex',
'justify-content': 'space-between',
'align-items': 'center',
'font-weight': 'bold',
'margin': '10px 0 5px 0',
'padding': '5px',
'background-color': 'rgba(171, 153, 48, 0.1)',
'border-radius': '3px',
'grid-column': '1 / -1',
'cursor': 'default' // Domyślny kursor
}
}).append(
$('<span/>').text('Złote prace'),
$('<div/>', {
css: {
'display': 'flex',
'gap': '5px',
'cursor': 'default' // Domyślny kursor
}
}).append(
createSortButton('XP', job => GSJTOP.getJobData(job, false).experience, 'goldJobs'),
createSortButton('$', job => GSJTOP.getJobData(job, false).money, 'goldJobs'),
createSortButton('↔', job => job.distance, 'goldJobs')
)
);
var silverContainer = $('<div/>', { class: 'silverJobs', css: {'cursor': 'default'} }); // Domyślny kursor
var goldContainer = $('<div/>', { class: 'goldJobs', css: {'cursor': 'default'} }); // Domyślny kursor
checkboxContainer.append(silverHeader, silverContainer, goldHeader, goldContainer);
refreshJobList(silverJobs, 'silverJobs');
refreshJobList(goldJobs, 'goldJobs');
// Dla panelu widoczności pokazujemy wszystkie prace
data.forEach(function(job) {
var jobData = GSJTOP.getJobData(job, job.silver);
if (jobData) {
var checkbox = $('<input/>', {
type: 'checkbox',
id: 'job-visibility-' + job.jobId,
checked: !job.hidden,
css: {
'margin': '2px',
'cursor': 'pointer' // Kursor pointer
}
}).on('change', function(e) { // Dodajemy e (event)
e.stopPropagation(); // Zapobiegamy propagacji
var hiddenJobs = JSON.parse(localStorage.getItem('GSJTOP_hiddenJobs') || '{}');
hiddenJobs[job.jobId] = !this.checked;
localStorage.setItem('GSJTOP_hiddenJobs', JSON.stringify(hiddenJobs));
GSJTOP.refreshWindow();
}).on('mousedown', function(e) { // Dodajemy mousedown
e.stopPropagation(); // Zapobiegamy rozpoczęciu przeciągania
});
var label = $('<label/>', {
for: 'job-visibility-' + job.jobId,
text: job.shortname,
css: {
'font-size': '11px',
'margin-right': '5px',
'cursor': 'pointer' // Kursor pointer
}
}).on('mousedown', function(e) { // Dodajemy mousedown
e.stopPropagation(); // Zapobiegamy rozpoczęciu przeciągania
});
// Usunęliśmy dodawanie do jobVisibilityContainer, bo jest już obsłużone w refreshJobList
}
});
visibilityPanel.append(title, searchContainer, toggleButton, checkboxContainer);
$('body').append(visibilityPanel);
// Uczynienie okna widoczności przesuwalnym za pomocą całego okna (visibilityPanel)
GSJTOP.makeDraggable(visibilityPanel, visibilityPanel);
}
GSJTOP.refreshWindow = function () {
};
// Nowa funkcja do obsługi przeciągania elementów
GSJTOP.makeDraggable = function(panelElement, handleElement) {
handleElement.css('cursor', 'move'); // Ustawienie kursora 'move' na uchwycie
handleElement.on('mousedown', function(e) {
// Ignoruj kliknięcia innymi przyciskami niż lewy
if (e.button !== 0) return;
e.preventDefault(); // Zapobiegaj zaznaczaniu tekstu podczas przeciągania
var initialMouseX = e.pageX;
var initialMouseY = e.pageY;
// Używamy offset() do pobrania pozycji względem dokumentu
var initialPanelPos = panelElement.offset();
var initialPanelLeft = initialPanelPos.left;
var initialPanelTop = initialPanelPos.top;
// Obliczamy przesunięcie kursora względem lewego górnego rogu panelu
var offsetX = initialMouseX - initialPanelLeft;
var offsetY = initialMouseY - initialPanelTop;
var originalZIndex = panelElement.css('z-index');
// Zwiększamy z-index, usuwamy transformację i ustawiamy pozycję w pikselach
panelElement.css({
'z-index': 11000, // Wyższy z-index na czas przeciągania
'transform': 'none', // Usuwamy transformację, aby pozycjonować przez top/left
'top': initialPanelTop + 'px',
'left': initialPanelLeft + 'px'
});
// Upewniamy się, że pozycje top/left nie są procentowe (choć offset() powinien dać px)
// Ten krok może być nadmiarowy, ale nie zaszkodzi
if (panelElement.css('top').includes('%')) {
panelElement.css('top', initialPanelTop + 'px');
}
if (panelElement.css('left').includes('%')) {
panelElement.css('left', initialPanelLeft + 'px');
}
// Nasłuchujemy na ruch myszy i puszczenie przycisku na całym dokumencie
$(document).on('mousemove.gsjtopdrag', function(moveEvent) {
var newLeft = moveEvent.pageX - offsetX;
var newTop = moveEvent.pageY - offsetY;
// Aktualizujemy pozycję panelu
panelElement.css({
left: newLeft + 'px',
top: newTop + 'px'
});
});
$(document).on('mouseup.gsjtopdrag', function(upEvent) {
// Ignoruj puszczenie innego przycisku niż lewy
if (upEvent.button !== 0) return;
// Usuwamy nasłuchiwanie zdarzeń po puszczeniu przycisku
$(document).off('mousemove.gsjtopdrag mouseup.gsjtopdrag');
// Przywracamy oryginalny z-index
panelElement.css('z-index', originalZIndex);
// --- POCZĄTEK EDYCJI: Zapisywanie pozycji ---
try {
var finalPos = {
top: panelElement.css('top'), // Pobieramy aktualną pozycję top
left: panelElement.css('left') // Pobieramy aktualną pozycję left
};
// Tworzymy klucz do localStorage na podstawie ID panelu
var storageKey = 'GSJTOP_' + panelElement.attr('id') + '_Pos';
// Zapisujemy pozycję jako string JSON
localStorage.setItem(storageKey, JSON.stringify(finalPos));
} catch (err) {
// Logujemy błąd, jeśli zapis się nie powiedzie
console.error("GSJTOP: Nie udało się zapisać pozycji okna w localStorage.", err);
}
// --- KONIEC EDYCJI: Zapisywanie pozycji ---
});
});
};
GSJTOP.getJobIcon = function (jobId, x, y, shortname, gold, jobData) {
var t = gold ? 'gold' : 'silver';
var tooltipHtml = this.preferences.showTooltips ?
'<div class="job-info" style="' +
'position: absolute; ' +
'top: 65px; ' +
'width: 63px; ' +
'background: #FDF7E5; ' +
'border: 1px solid #B89B6D; ' +
'padding: 0; ' +
'box-shadow: 2px 2px 3px rgba(0,0,0,0.2); ' +
'z-index: 10003;">' +
// XP z tooltipem - powiększone cyfry
'<div style="display: flex; justify-content: space-between; align-items: center; height: 18px; padding: 0 3px; background: #F5ECD4;" title="DOŚWIADCZENIE">' +
'<div style="width: 14px; height: 14px; background: url(\'https://westpl.innogamescdn.com/images/window/job/bigicon_xp.png\') no-repeat center; background-size: contain;"></div>' +
'<div style="color: #5C4219; font-size: 13px; font-weight: bold; text-align: right; min-width: 35px;">' + jobData.experience + '</div>' +
'</div>' +
// Pieniądze z tooltipem - powiększone cyfry
'<div style="display: flex; justify-content: space-between; align-items: center; height: 18px; padding: 0 3px;" title="DOLARY">' +
'<div style="width: 14px; height: 14px; background: url(\'https://westpl.innogamescdn.com/images/window/job/bigicon_money.png\') no-repeat center; background-size: contain;"></div>' +
'<div style="color: #5C4219; font-size: 13px; font-weight: bold; text-align: right; min-width: 35px;">' + jobData.money + '</div>' +
'</div>' +
// Motywacja z tooltipem - powiększone cyfry
'<div style="display: flex; justify-content: space-between; align-items: center; height: 18px; padding: 0 3px; background: #F5ECD4;" title="MOTYWACJA W PRACY">' +
'<div style="color: #5C4219; font-size: 13px; font-weight: bold; width: 100%; text-align: center;">' + jobData.motivation + '%</div>' +
'</div>' +
// Czas z tooltipem - powiększone cyfry
'<div style="display: flex; justify-content: space-between; align-items: center; height: 18px; padding: 0 3px;" title="CZAS DOTARCIA">' +
'<div style="color: #5C4219; font-size: 13px; font-weight: bold; width: 100%; text-align: center;">' + GSJTOP.formatTime(jobData.distance) + '</div>' +
'</div>' +
'</div>' : '';
return '<div class="job-wrapper" style="position: relative; display: inline-flex; flex-direction: column; align-items: center; margin: -1px; width: 65px; height: 65px; z-index: 10000;">' +
'<div class="job" style="position: relative; width: 65px; height: 65px;">' +
'<img src="images/jobs/' + shortname + '.png" class="job_icon" style="width: 65px; height: 65px; position: relative; z-index: 10000;">' +
'<div onclick="javascript:GameMap.JobHandler.openJob(' + jobId + ',{x:' + x + ',y:' + y + '})" ' +
'class="featured ' + t + '" style="position: absolute; top: -5px; left: -5px; z-index: 10001; width: 75px; height: 75px; background-size: contain;"></div>' +
this.getGotoIcon(x, y) +
'</div>' +
tooltipHtml +
'</div>';
};
GSJTOP.formatTime = function(seconds) {
seconds = Math.round(seconds);
var hours = Math.floor(seconds / 3600);
var minutes = Math.floor((seconds % 3600) / 60);
var secs = seconds % 60;
return String(hours).padStart(2, '0') + ':' +
String(minutes).padStart(2, '0') + ':' +
String(secs).padStart(2, '0');
};
GSJTOP.getGotoIcon = function (x, y) {
return '<div class="centermap" onclick="javascript:GameMap.center(' + x + ',' + y + ');" ' +
'style="position: absolute; background-image: url(\'images/map/icons/instantwork.png\'); ' +
'width: 25px; height: 25px; top: -2px; right: -2px; cursor: pointer; z-index: 10002; background-size: contain;"></div>';
};
GSJTOP.createNavigationButtons = function() {
var wrapperStyle = {
'width': '30px',
'height': '60px',
'display': 'flex',
'justify-content': 'center',
'align-items': 'center',
'cursor': 'pointer',
'margin-top': '35px',
'z-index': 10001
};
var buttonStyle = {
'width': '25px',
'height': '44px',
'background-image': 'url(\'https://westit.innogamescdn.com/images/window/trader/arrows.png\')',
'color': 'white',
'padding': '0px',
'display': 'block',
'background-size': 'cover',
'text-align': 'center'
};
var prevWrapper = $('<div/>', {
css: Object.assign({}, wrapperStyle, {
'margin-right': '0px',
'position': 'relative',
'top': '-15px'
})
});
var nextWrapper = $('<div/>', {
css: Object.assign({}, wrapperStyle, {
'margin-left': '0px',
'position': 'relative',
'top': '-15px'
})
});
var prevButton = $('<div/>', {
css: Object.assign({}, buttonStyle, {
'background-position': 'top left'
})
});
var nextButton = $('<div/>', {
css: Object.assign({}, buttonStyle, {
'background-position': 'top right'
})
});
// Pobierz tylko widoczne prace
var visibleJobs = this.getFilteredData(this.preferences.showSilver, this.preferences.showGold)
.filter(job => !job.hidden);
var totalJobs = visibleJobs.length;
var maxPages = Math.ceil(totalJobs / this.preferences.jobsPerPage);
// Aktualizacja stylów przycisków w zależności od dostępności stron
var updateButtonStyles = function() {
if (GSJTOP.preferences.currentPage <= 0) {
prevWrapper.css('opacity', '0.5').css('cursor', 'default');
} else {
prevWrapper.css('opacity', '1').css('cursor', 'pointer');
}
if (GSJTOP.preferences.currentPage >= maxPages - 1 || maxPages <= 1) {
nextWrapper.css('opacity', '0.5').css('cursor', 'default');
} else {
nextWrapper.css('opacity', '1').css('cursor', 'pointer');
}
};
updateButtonStyles();
prevWrapper.append(prevButton).click(function() {
if (GSJTOP.preferences.currentPage > 0) {
GSJTOP.preferences.currentPage--;
GSJTOP.refreshWindow();
}
});
nextWrapper.append(nextButton).click(function() {
// Pobierz aktualną liczbę widocznych prac
var visibleJobs = GSJTOP.getFilteredData(GSJTOP.preferences.showSilver, GSJTOP.preferences.showGold)
.filter(job => !job.hidden);
var totalJobs = visibleJobs.length;
var maxPages = Math.ceil(totalJobs / GSJTOP.preferences.jobsPerPage);
if (GSJTOP.preferences.currentPage < maxPages - 1) {
GSJTOP.preferences.currentPage++;
GSJTOP.refreshWindow();
}
});
return {
prev: prevWrapper,
next: nextWrapper
};
};
GSJTOP.createJobsContainer = function (showSilver, showGold) {
var hideHighIdJobsFilter = $('<div/>', {
title: this.preferences.hideHighIdJobs ? 'POKAŻ PRACE POWYŻEJ 150 POZIOMU' : 'UKRYJ PRACE POWYŻEJ 150 POZIOMU',
css: {
'width': '24px',
'height': '24px',
'cursor': 'pointer',
'margin-right': '1px',
'background-color': this.preferences.hideHighIdJobs ? '#cccccc' : '#FFD700',
'border-radius': '3px',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'transition': 'all 0.3s ease',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.1)'
}
}).on('mouseenter', function() {
$(this).css({
'transform': 'scale(1.1)',
'box-shadow': '0 2px 5px rgba(0, 0, 0, 0.2)'
});
}).on('mouseleave', function() {
$(this).css({
'transform': 'scale(1)',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.1)'
});
}).click(function() {
var isCurrentlyActive = $(this).css('background-color') === 'rgb(204, 204, 204)';
GSJTOP.preferences.hideHighIdJobs = !isCurrentlyActive;
localStorage.setItem('GSJTOP_hideHighIdJobs', GSJTOP.preferences.hideHighIdJobs);
$(this).css({
'background-color': isCurrentlyActive ? '#FFD700' : '#cccccc'
}).attr('title', isCurrentlyActive ? 'UKRYJ PRACE POWYŻEJ 150 POZIOMU' : 'POKAŻ PRACE POWYŻEJ 150 POZIOMU');
GSJTOP.preferences.currentPage = 0;
// Odśwież mapę
GSJTOP.refreshMap();
GSJTOP.refreshWindow();
})
var lowIdJobsFilter = $('<div/>', {
title: this.preferences.hideLowIdJobs ? 'POKAŻ PRACE PONIŻEJ 100 POZIOMU' : 'UKRYJ PRACE PONIŻEJ 100 POZIOMU',
css: {
'width': '24px',
'height': '24px',
'cursor': 'pointer',
'margin-right': '1px',
'background-color': this.preferences.hideLowIdJobs ? '#cccccc' : '#ff4444',
'border-radius': '3px',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'transition': 'all 0.3s ease',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.1)'
}
}).on('mouseenter', function() {
$(this).css({
'transform': 'scale(1.1)',
'box-shadow': '0 2px 5px rgba(0, 0, 0, 0.2)'
});
}).on('mouseleave', function() {
$(this).css({
'transform': 'scale(1)',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.1)'
});
}).click(function() {
var isCurrentlyActive = $(this).css('background-color') === 'rgb(204, 204, 204)';
GSJTOP.preferences.hideLowIdJobs = !isCurrentlyActive;
localStorage.setItem('GSJTOP_hideLowIdJobs', GSJTOP.preferences.hideLowIdJobs);
$(this).css({
'background-color': isCurrentlyActive ? '#ff4444' : '#cccccc'
}).attr('title', isCurrentlyActive ? 'UKRYJ PRACE PONIŻEJ 100 POZIOMU' : 'POKAŻ PRACE PONIŻEJ 100 POZIOMU');
GSJTOP.preferences.currentPage = 0;
// Aktualizuj dane o pracach
var data = GSJTOP.getFilteredData(GSJTOP.preferences.showSilver, GSJTOP.preferences.showGold);
// Odśwież mapę
GSJTOP.refreshMap();
GSJTOP.refreshWindow();
})
var container = $('<div/>', {
class: 'jobs-container',
css: {
'display': 'flex',
'flex-direction': 'column',
'justify-content': 'flex-start',
'align-items': 'center',
'gap': '10px',
'height': '120px',
'overflow': 'visible',
'background': 'rgba(255, 255, 255, 0.0)',
'padding': '0 15px',
'position': 'relative',
'width': 'auto',
'z-index': 10000,
'min-height': '120px'
}
});
var jobsWrapper = $('<div/>', {
css: {
'display': 'flex',
'justify-content': 'center',
'align-items': 'center',
'gap': '10px',
'width': 'auto',
'margin-bottom': '5px',
'margin-top': '25px',
'min-height': '65px',
'flex-wrap': 'nowrap',
'position': 'relative'
}
});
var jobVisibilityContainer = $('<div/>', {
css: {
'display': 'flex',
'flex-wrap': 'wrap',
'gap': '5px',
'justify-content': 'center',
'margin-top': '-20px', // Zmienione z 5px na -20px
'background-color': 'rgba(255, 255, 255, 0.7)',
'padding': '5px',
'border-radius': '3px',
'position': 'relative', // Dodane
'z-index': '10001' // Dodane
}
});
var filterContainer = $('<div/>', {
id: 'gsjtop-filters-container',
css: {
// Przywrócone pozycjonowanie absolutne
'position': 'absolute',
'top': '85px',
'left': '50%', // Przykład: wycentrowanie poziome
'transform': 'translateX(-50%)', // Przykład: wycentrowanie poziome
'width': 'fit-content', // Aby szerokość dopasowała się do zawartości przy centrowaniu
// Zachowany warunkowy margines górny dla ruchu góra-dół
'margin-top': this.preferences.showTooltips ? '87px' : '10px', // Nadal kontroluje przesunięcie pionowe
// Style layoutu (bez zmian)
'display': this.preferences.hideFilters ? 'none' : 'flex',
'justify-content': 'center',
'align-items': 'center',
'gap': '8px',
'margin-bottom': '10px', // Może nie być potrzebny przy absolute
// Style ciemnej ramki (bez zmian)
'background': 'linear-gradient(to bottom, #4d351b 0%, #2a1608 100%)',
'padding': '5px 10px',
'border-radius': '5px',
'border': '2px solid #1b0a00',
'border-top-color': '#150800',
'border-left-color': '#150800',
'box-shadow': '0 2px 5px rgba(0, 0, 0, 0.5), inset 0 0 3px rgba(0,0,0,0.2)',
'z-index': 10001 // Dodaj z-index, aby był nad innymi elementami
}
});
var jobsPerPageSelect = $('<select/>', {
css: {
'padding': '2px',
'margin-left': '5px',
'border-radius': '3px',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'background-color': 'white',
'cursor': 'pointer'
}
}).on('change', function() {
GSJTOP.preferences.jobsPerPage = parseInt($(this).val());
localStorage.setItem('GSJTOP_jobsPerPage', GSJTOP.preferences.jobsPerPage);
GSJTOP.preferences.currentPage = 0;
GSJTOP.refreshWindow();
});
[4, 6, 8, 10].forEach(function(num) {
jobsPerPageSelect.append($('<option/>', {
value: num,
text: num + (num === 1 ? ' praca' : num < 5 ? ' prace' : ' prac'),
selected: GSJTOP.preferences.jobsPerPage === num
}));
});
var tooltipsButton = $('<div/>', {
id: 'gj-tooltips',
title: GSJTOP.preferences.showTooltips ? 'UKRYJ INFORMACJE' : 'POKAŻ INFORMACJE', // Dodany tooltip
css: {
'width': '24px',
'height': '24px',
'background-color': GSJTOP.preferences.showTooltips ? '#4CAF50' : '#cccccc',
'border-radius': '3px',
'cursor': 'pointer',
'transition': 'all 0.3s ease',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.1)',
'margin-right': '1px'
}
}).click(function() {
GSJTOP.preferences.showTooltips = !GSJTOP.preferences.showTooltips;
localStorage.setItem('GSJTOP_showTooltips', GSJTOP.preferences.showTooltips);
$(this).css('background-color', GSJTOP.preferences.showTooltips ? '#4CAF50' : '#cccccc')
.attr('title', GSJTOP.preferences.showTooltips ? 'UKRYJ INFORMACJE' : 'POKAŻ INFORMACJE'); // Aktualizacja tooltipa po kliknięciu
GSJTOP.refreshWindow();
});
var visibilityButton = $('<div/>', {
id: 'gsjtop-visibility-toggle', // Dodajmy ID dla łatwiejszego odniesienia (opcjonalne)
title: 'Pokaż/Ukryj Mapę i Widoczność Prac', // Zaktualizujmy tooltip
css: {
'width': '24px',
'height': '24px',
'background-color': '#4a90e2',
'border-radius': '3px',
'cursor': 'pointer',
'transition': 'all 0.3s ease',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.1)',
'margin-right': '1px',
'background-size': '16px',
'background-position': 'center',
'background-repeat': 'no-repeat'
}
}).on('click', function() {
// --- EDYCJA 1: Logika przełączania widoczności ---
var visibilityPanel = $('#job-visibility-window');
var mapWindow = $('#custom-map-window');
// Sprawdź, czy którekolwiek z okien jest aktualnie otwarte
if (visibilityPanel.length > 0 || mapWindow.length > 0) {
// Jeśli tak, zamknij oba
visibilityPanel.remove();
mapWindow.remove();
// Opcjonalnie: zmień wygląd przycisku na "nieaktywny"
$(this).css({
'background-color': '#4a90e2', // Wróć do domyślnego koloru
});
} else {
// Jeśli nie, otwórz oba
GSJTOP.createVisibilityWindow(); // Najpierw okno widoczności
try {
GSJTOP.createCustomMapWindow(); // Potem mapa
} catch(e) {
console.error('Błąd podczas tworzenia okna mapy:', e);
}
// Opcjonalnie: zmień wygląd przycisku na "aktywny"
$(this).css('background-color', '#cccccc'); // Ciemniejszy niebieski jako wskaźnik aktywności
}
});
var centerJobsFilter = $('<div/>', {
title: this.preferences.hideCenterJobs ? 'POKAŻ PRACE PONIŻEJ 100 POZIOMU' : 'UKRYJ PRACE PONIŻEJ 100 POZIOMU', // Zmieniony tooltip
css: {
'width': '24px',
'height': '24px',
'cursor': 'pointer',
'margin-right': '1px',
'background-color': this.preferences.hideCenterJobs ? '#cccccc' : '#ff4444',
'border-radius': '3px',
'border': '1px solid rgba(0, 0, 0, 0.2)',
'transition': 'all 0.3s ease',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.1)'
}
}).on('mouseenter', function() {
$(this).css({
'transform': 'scale(1.1)',
'box-shadow': '0 2px 5px rgba(0, 0, 0, 0.2)'
});
}).on('mouseleave', function() {
$(this).css({
'transform': 'scale(1)',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.1)'
});
}).click(function() {
var isCurrentlyActive = $(this).css('background-color') === 'rgb(204, 204, 204)';
GSJTOP.preferences.hideCenterJobs = !isCurrentlyActive;
localStorage.setItem('GSJTOP_hideCenterJobs', GSJTOP.preferences.hideCenterJobs);
$(this).css({
'background-color': isCurrentlyActive ? '#ff4444' : '#cccccc'
}).attr('title', isCurrentlyActive ? 'UKRYJ PRACE PONIŻEJ 100 POZIOMU' : 'POKAŻ PRACE PONIŻEJ 100 POZIOMU'); // Zmieniony tooltip
GSJTOP.preferences.currentPage = 0;
GSJTOP.refreshWindow();
});
var goldFilter = $('<img/>', {
src: 'images/jobs/featured/goldjob.png',
css: {
'width': '24px',
'height': '24px',
'opacity': showGold ? this.shownImageOpacity : this.hiddenImageOpacity,
'cursor': 'pointer',
'border': showGold ? '1px solid rgba(171, 153, 48, 0.5)' : 'none',
'border-radius': '3px'
},
click: function() {
GSJTOP.onJobIconFilterClick('gold', $(this));
}
});
var silverFilter = $('<img/>', {
src: 'images/jobs/featured/silverjob.png',
css: {
'width': '24px',
'height': '24px',
'opacity': showSilver ? this.shownImageOpacity : this.hiddenImageOpacity,
'cursor': 'pointer',
'border': showSilver ? '1px solid rgba(112, 128, 144, 0.5)' : 'none',
'border-radius': '3px'
},
click: function() {
GSJTOP.onJobIconFilterClick('silver', $(this));
}
});
filterContainer.append(
tooltipsButton,
lowIdJobsFilter,
hideHighIdJobsFilter,
visibilityButton,
silverFilter,
goldFilter,
jobsPerPageSelect
);
// Pobieramy zapisane ustawienia widoczności prac
var hiddenJobs = JSON.parse(localStorage.getItem('GSJTOP_hiddenJobs') || '{}');
var data = this.getFilteredData(showSilver, showGold);
var start = this.preferences.currentPage * this.preferences.jobsPerPage;
// Filtrujemy ukryte prace tylko dla głównego wyświetlania, nie dla panelu widoczności
var visibleJobs = data.filter(job => !job.hidden);
var pageJobs = visibleJobs.slice(start, start + this.preferences.jobsPerPage);
pageJobs.forEach(function(job) {
var jobData = GSJTOP.getJobData(job, job.silver);
if (jobData) {
jobsWrapper.append(GSJTOP.getJobIcon(job.jobId, job.x, job.y, job.shortname, job.gold, jobData));
}
});
// Dla panelu widoczności pokazujemy wszystkie prace
data.forEach(function(job) {
var jobData = GSJTOP.getJobData(job, job.silver);
if (jobData) {
var checkbox = $('<input/>', {
type: 'checkbox',
id: 'job-visibility-' + job.jobId,
checked: !job.hidden,
css: {
'margin': '2px'
}
}).on('change', function() {
var hiddenJobs = JSON.parse(localStorage.getItem('GSJTOP_hiddenJobs') || '{}');
hiddenJobs[job.jobId] = !this.checked;
localStorage.setItem('GSJTOP_hiddenJobs', JSON.stringify(hiddenJobs));
GSJTOP.refreshWindow();
});
var label = $('<label/>', {
for: 'job-visibility-' + job.jobId,
text: job.shortname,
css: {
'font-size': '11px',
'margin-right': '5px'
}
});
jobVisibilityContainer.append($('<div/>').append(checkbox, label));
}
});
container.append(jobsWrapper, filterContainer);
return container;
};
GSJTOP.onJobIconFilterClick = function (type, element) {
var hiddenImageOpacity = this.hiddenImageOpacity;
var shownImageOpacity = this.shownImageOpacity;
var isCurrentlyActive = ($(element).css('opacity') == shownImageOpacity);
var otherFilterActive = (type === 'gold') ? this.preferences.showSilver : this.preferences.showGold;
if (isCurrentlyActive && !otherFilterActive) {
return;
}
if (type === 'gold') {
this.preferences.showGold = !isCurrentlyActive;
localStorage.setItem('GSJTOP_showGold', this.preferences.showGold);
$(element).css({
'opacity': isCurrentlyActive ? hiddenImageOpacity : shownImageOpacity,
'border': isCurrentlyActive ? 'none' : '1px solid rgba(171, 153, 48, 0.5)'
});
} else {
this.preferences.showSilver = !isCurrentlyActive;
localStorage.setItem('GSJTOP_showSilver', this.preferences.showSilver);
$(element).css({
'opacity': isCurrentlyActive ? hiddenImageOpacity : shownImageOpacity,
'border': isCurrentlyActive ? 'none' : '1px solid rgba(112, 128, 144, 0.5)'
});
}
// Pobierz aktualne dane po zmianie filtrów
var data = this.getFilteredData(this.preferences.showSilver, this.preferences.showGold);
// Odśwież mapę z aktualnymi danymi
this.refreshMap(data);
this.preferences.currentPage = 0;
this.refreshWindow();
}; GSJTOP.openWindow = function () {
if (!this.preferences.enabled) return;
$('#goldJobs-bar').remove();
var bar = $('<div/>', {
id: 'goldJobs-bar',
css: {
'position': 'fixed',
'background': 'rgba(255, 255, 255, 0.0)',
'border': 'none',
'padding': '0px',
'z-index': 10000,
'display': 'flex',
'flex-direction': 'row',
'align-items': 'center',
'justify-content': 'center',
'width': '100%',
'height': '130px',
'left': '0',
'right': '0',
'top': '20px',
'margin': '0 auto',
'pointer-events': 'none'
}
});
var contentWrapper = $('<div/>', {
css: {
'display': 'flex',
'justify-content': 'center',
'align-items': 'center',
'width': 'auto',
'margin': '0 auto',
'pointer-events': 'auto',
'position': 'relative'
}
});
var navigation = this.createNavigationButtons();
var jobsContainer = this.createJobsContainer(this.preferences.showSilver, this.preferences.showGold);
contentWrapper.append(navigation.prev, jobsContainer, navigation.next);
bar.append(contentWrapper);
$('#ui_topbar').append(bar);
$(document).on('position_change', GSJTOP.refreshWindow);
};
GSJTOP.getAllTiles = function (callback) {
Ajax.get('map', 'get_minimap', {}, function (r) {
if (r.error) {
return;
}
var result = [];
var jobGroups = r.job_groups,
i,
j;
for (i in jobGroups) {
for (j in jobGroups[i]) {
var coords = jobGroups[i][j];
var xTile = Math.floor(coords[0] / GameMap.tileSize);
var yTile = Math.floor(coords[1] / GameMap.tileSize);
if (!result.hasOwnProperty(xTile)) {
result[xTile] = {};
}
result[xTile][yTile] = 1;
}
}
GSJTOP.tilesWithJobs = result;
callback();
});
};
GSJTOP.getFilteredData = function (showSilver, showGold) {
var jobs = GameMap.JobHandler.Featured;
var k, jobId, job, j;
var result = [];
var hiddenJobs = JSON.parse(localStorage.getItem('GSJTOP_hiddenJobs') || '{}');
try {
for (k in jobs) {
var jobPlace = jobs[k];
for (jobId in jobPlace) {
job = JobList.getJobById(jobId);
if (!job) continue;
j = jobPlace[jobId];
if ((j.silver && !showSilver) || (j.gold && !showGold)) {
continue;
}
if (this.preferences.hideLowIdJobs && parseInt(jobId) < 131) {
continue;
}
if (this.preferences.hideHighIdJobs && parseInt(jobId) > 160) {
continue;
}
// Dodajemy wszystkie prace do rezultatu, ale oznaczamy je jako ukryte
var distance = 0;
try {
distance = this.calculateDistance(j.x, j.y);
} catch (e) {}
var motivation = 0;
try {
var jobData = JobsModel.Jobs.find(jb => jb.id === parseInt(jobId));
if (jobData) {
motivation = Math.round(jobData.jobmotivation * 100);
}
} catch (e) {}
// Nazwa pracy
var name = job.name || "Praca #" + jobId;
result.push({
jobId: jobId,
x: j.x,
y: j.y,
shortname: job.shortname,
name: name,
gold: j.gold,
silver: j.silver,
distance: distance,
motivation: motivation,
hidden: !!hiddenJobs[jobId] // Upewniamy się, że hidden jest wartością logiczną
});
}
}
// Sortowanie według odległości
result.sort(function(a, b) {
if (a.distance !== b.distance) {
return a.distance - b.distance;
}
return parseInt(a.jobId) - parseInt(b.jobId);
});
} catch (e) {
console.error("Błąd podczas filtrowania danych:", e);
}
return result;
};
GSJTOP.refreshWindow = function () {
if (!GSJTOP.preferences.enabled) {
$('#goldJobs-bar').remove();
return;
}
Ajax.get('work', 'index', {}, function(response) {
if (response.error) {
return;
}
JobsModel.initJobs(response.jobs);
// Pobierz aktualną liczbę widocznych prac
var visibleJobs = GSJTOP.getFilteredData(GSJTOP.preferences.showSilver, GSJTOP.preferences.showGold)
.filter(job => !job.hidden);
var totalJobs = visibleJobs.length;
var maxPages = Math.ceil(totalJobs / GSJTOP.preferences.jobsPerPage);
// Aktualizuj przyciski nawigacji
var updateButtonStyles = function() {
var prevButton = $('#goldJobs-bar .jobs-container').prev();
var nextButton = $('#goldJobs-bar .jobs-container').next();
if (GSJTOP.preferences.currentPage <= 0) {
prevButton.css('opacity', '0.5').css('cursor', 'default');
} else {
prevButton.css('opacity', '1').css('cursor', 'pointer');
}
if (GSJTOP.preferences.currentPage >= maxPages - 1 || maxPages <= 1) {
nextButton.css('opacity', '0.5').css('cursor', 'default');
} else {
nextButton.css('opacity', '1').css('cursor', 'pointer');
}
};
// Wymień kontener z pracami
var newContainer = GSJTOP.createJobsContainer(GSJTOP.preferences.showSilver, GSJTOP.preferences.showGold);
$('#goldJobs-bar .jobs-container').replaceWith(newContainer);
// Aktualizuj style przycisków
updateButtonStyles();
});
};
GSJTOP.createCustomMapWindow = function() {
// Sprawdź czy okno już istnieje
if ($('#custom-map-window').length > 0) return;
var self = this; // Zapisz referencję do GSJTOP
// --- POCZĄTEK EDYCJI: Odczyt zapisanej pozycji ---
var storageKey = 'GSJTOP_custom-map-window_Pos';
var savedPosition = null;
try {
var savedPosString = localStorage.getItem(storageKey);
if (savedPosString) {
savedPosition = JSON.parse(savedPosString);
}
} catch (err) {
console.error("GSJTOP: Nie udało się odczytać pozycji okna mapy z localStorage.", err);
localStorage.removeItem(storageKey); // Usuń uszkodzone dane
}
// --- KONIEC EDYCJI: Odczyt zapisanej pozycji ---
var windowCss = {
'position': 'fixed',
// Nowe pozycjonowanie - wyśrodkowane poziomo, górna krawędź 20px pod środkiem ekranu
'top': 'calc(50% + 120px)',
'left': '50%',
'transform': 'translateX(-50%)',
// ... (reszta stylów: background, padding, border, etc.) ...
'background': 'linear-gradient(to bottom, #4d351b 0%, #2a1608 100%)',
'padding': '15px',
'border-radius': '5px',
'border': '2px solid #1b0a00',
'border-top-color': '#150800',
'border-left-color': '#150800',
'box-shadow': '0 4px 15px rgba(0, 0, 0, 0.7), inset 0 0 5px rgba(0,0,0,0.2)',
'z-index': 10003,
'cursor': 'move'
};
// --- POCZĄTEK EDYCJI: Zastosowanie zapisanej pozycji ---
if (savedPosition && savedPosition.top && savedPosition.left) {
windowCss.top = savedPosition.top;
windowCss.left = savedPosition.left;
windowCss.transform = 'none'; // Usuwamy transformację
}
// --- KONIEC EDYCJI: Zastosowanie zapisanej pozycji ---
// Okno główne (kontener z ramką w stylu TW)
var mapWindow = $('<div/>', {
id: 'custom-map-window',
css: windowCss // Używamy przygotowanego obiektu CSS
});
// Kontener na samą mapę i znaczniki
var mapContent = $('<div/>', {
css: {
'width': '770px',
'height': '338px',
'position': 'relative',
'margin': '0 auto', // Centrowanie wewnątrz paddingu okna
'overflow': 'hidden',
'background-color': 'white',
'border': '1px solid #333', // Ciemna ramka mapy
'cursor': 'default' // Przywracamy domyślny kursor dla obszaru mapy
}
});
// Definicje hrabstw (kafelków mapy)
var counties = [
{id: 1, left: 0, top: 0, width: 110, height: 169},
{id: 2, left: 110, top: 0, width: 110, height: 169},
{id: 3, left: 220, top: 0, width: 110, height: 169},
{id: 4, left: 330, top: 0, width: 110, height: 114},
{id: 5, left: 440, top: 0, width: 110, height: 169},
{id: 6, left: 550, top: 0, width: 110, height: 169},
{id: 7, left: 660, top: 0, width: 110, height: 169},
{id: 8, left: 0, top: 169, width: 110, height: 169},
{id: 9, left: 110, top: 169, width: 110, height: 169},
{id: 10, left: 220, top: 169, width: 110, height: 169},
{id: 11, left: 330, top: 224, width: 110, height: 114},
{id: 12, left: 440, top: 169, width: 110, height: 169},
{id: 13, left: 550, top: 169, width: 110, height: 169},
{id: 14, left: 660, top: 169, width: 110, height: 169},
{id: 15, left: 330, top: 114, width: 110, height: 110}
];
// Tworzenie kafelków mapy jako elementy <img>
counties.forEach(function(county) {
$('<img>', {
src: 'https://westpl.innogamescdn.com/images/map/minimap/county_' + county.id + '.jpg',
css: {
'position': 'absolute',
'left': county.left + 'px',
'top': county.top + 'px',
'width': county.width + 'px',
'height': county.height + 'px',
'border': '1px solid #000'
}
}).appendTo(mapContent);
});
// Pobierz dane o pracach
var data = self.getFilteredData(self.preferences.showSilver, self.preferences.showGold);
// Ustawienia mapy i markerów
var maxX = 46592;
var maxY = 20480;
var mapWindowWidth = 770;
var mapWindowHeight = 338;
var markerSize = 24;
var markerOffset = markerSize / 2;
// Dodaj markery prac na mapie
data.forEach(function(job) {
if (!job.hidden) {
var markerLeft = (job.x / maxX * mapWindowWidth) - markerOffset;
var markerTop = (job.y / maxY * mapWindowHeight) - markerOffset;
// Utwórz element markera (div)
var marker = $('<div/>', {
title: job.name, // Użyj przetłumaczonej nazwy pracy jako tooltip
css: {
'position': 'absolute',
'left': markerLeft + 'px',
'top': markerTop + 'px',
'width': markerSize + 'px',
'height': markerSize + 'px',
'cursor': 'pointer', // Kursor 'pointer' dla markerów
'z-index': 10004,
'border-radius': '50%',
}
}).append($('<img/>', { // Dodaj ikonę pracy do markera
src: 'https://westpl.innogamescdn.com/images/jobs/' + job.shortname + '.png',
css: {
'width': '100%',
'height': '100%'
}
}));
// Dodaj obramowanie/cień w zależności od typu pracy
if (job.gold) {
marker.css('box-shadow', '0 0 5px 2px gold');
} else if (job.silver) {
marker.css('box-shadow', '0 0 5px 2px silver');
} else {
marker.css('box-shadow', '0 0 3px rgba(0,0,0,0.5)');
}
// Dodaj akcję kliknięcia
marker.click(function(e) { // Dodajemy e (event)
e.stopPropagation(); // Zapobiegamy propagacji kliknięcia do mapWindow
if (typeof GameMap !== 'undefined' && GameMap.center) {
GameMap.center(job.x, job.y);
}
// Zamknij okno mapy
mapWindow.remove();
// Zamknij okno widoczności, jeśli istnieje
$('#job-visibility-window').remove();
// Opcjonalnie: Zaktualizuj wygląd przycisku przełączającego widoczność
var visibilityButton = $('#gsjtop-visibility-toggle');
if (visibilityButton.length > 0) {
visibilityButton.css('background-color', '#4a90e2'); // Wróć do domyślnego koloru
}
});
// Dodaj marker do kontenera mapy
mapContent.append(marker);
}
});
// Dodaj tylko mapContent do mapWindow (bez mapTitle)
mapWindow.append(mapContent);
// Dodaj całe okno mapy do strony
$('body').append(mapWindow);
// Uczynienie okna mapy przesuwalnym za pomocą całego okna (mapWindow) jako uchwytu
GSJTOP.makeDraggable(mapWindow, mapWindow);
};
GSJTOP.init = function () {
if (!GSJTOP.preferences.enabled) return;
var onLoad = function () {
Ajax.get('work', 'index', {}, function(response) {
if (response.error) {
return;
}
JobsModel.initJobs(response.jobs);
GSJTOP.preferences.currentPage = 0;
GSJTOP.openWindow();
GSJTOP.dataLoaded = true;
GSJTOP.startAutoRefresh();
});
};
if (!GSJTOP.hasOwnProperty('tilesWithJobs')) {
new UserMessage(GSJTOPlang.loading, UserMessage.TYPE_HINT).show();
GSJTOP.getAllTiles(function () {
GSJTOP.parseWholeMap(GSJTOP.tilesWithJobs, onLoad);
});
} else {
onLoad();
}
};
GSJTOP.gui = {};
GSJTOP.gui.init = function () {};
// Inicjalizacja przy załadowaniu dokumentu
$(document).ready(function () {
try {
GSJTOP.gui.init();
GSJTOP.createToggleCheckbox();
if (GSJTOP.preferences.enabled) {
GSJTOP.init();
}
} catch (e) {
// Usunięto log błędu
}
});
}); // Zamknięcie głównej funkcji
// Skrypt usuwający element first-purchase
function usuńFirstPurchase() {
const element = document.querySelector('.first-purchase');
if (element) {
element.remove();
} else {
clearInterval(intervalId);
}
}
const intervalId = setInterval(usuńFirstPurchase, 1000);
// Funkcja do stworzenia słownika tłumaczeń z API gry
function createJobTranslations() {
const translations = {};
JobList.getSortedJobs().forEach(job => {
// Tworzymy klucz w formacie takim jak w oryginalnym ID (np. 'picking_mushrooms')
const englishKey = job.id.toString();
translations[englishKey] = job.name;
});
return translations;
}
// Używamy w skrypcie
const jobTranslations = createJobTranslations();
// Funkcja do zamiany nazw w interfejsie
document.querySelectorAll('#job-visibility-window label').forEach(label => {
const jobId = label.getAttribute('for').split('-')[2]; // Pobieramy ID z atrybutu 'for'
if (jobTranslations[jobId]) {
label.textContent = jobTranslations[jobId];
}
});
// Funkcja do tłumaczenia okna widoczności prac
function translateJobVisibilityWindow() {
const translations = {};
JobList.getSortedJobs().forEach(job => {
translations[job.id] = job.name;
});
const labels = document.querySelectorAll('#job-visibility-window label');
labels.forEach(label => {
const jobId = label.getAttribute('for').split('-')[2];
if (translations[jobId]) {
label.textContent = translations[jobId];
}
});
}
// Obserwator do wykrywania okna widoczności
const jobVisibilityObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach((node) => {
if (node.id === 'job-visibility-window') {
setTimeout(translateJobVisibilityWindow, 100);
}
});
}
});
});
// Uruchomienie obserwatora
jobVisibilityObserver.observe(document.body, {
childList: true,
subtree: true
});
// Dodanie stylów dla paska przewijania w Chrome/Safari
$('<style>')
.text(`
#job-visibility-window div::-webkit-scrollbar {
width: 8px;
}
#job-visibility-window div::-webkit-scrollbar-track {
background: #f0f0f0;
}
#job-visibility-window div::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
#job-visibility-window div::-webkit-scrollbar-thumb:hover {
background: #666;
}
`)
.appendTo('head');
})();