DayZ Map Improvement

6/11/2024, 1:26:23 AM

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        DayZ Map Improvement
// @namespace   https://azzurite.tv
// @match       https://dayz.xam.nu/*
// @run-at      document-start
// @grant       none
// @version     1.4.0
// @author      Azzurite
// @license     GPLv3
// @description 6/11/2024, 1:26:23 AM
// ==/UserScript==

(() => {
    const highlighters = {};

    function makeHuntingMoreVisible() {
        if (this.options.iconUrl === `https://dayz.xam.nu/js/../images/b8fe30b7.webp`) {
            this.options.iconUrl = `https://images.azzurite.tv/uploads/original/d3/0f/6a50614db7df56f32d5aa2840268.webp`;
        } else if (this.options?.iconUrl === `https://dayz.xam.nu/js/../images/a92e2f53.webp`) {
            this.options.iconUrl = `https://images.azzurite.tv/uploads/original/92/8b/e706a502ab0931c2338883333633.webp`;
        }
    }

    Object.defineProperty(window, `L`, {
        set(obj) {
            this.storedL = obj;
            obj.Map.addInitHook(function() { // addInitHook binds `this`
                window.map = this;
            });
            obj.Icon.addInitHook(makeHuntingMoreVisible);
        },
        get() {
            return this.storedL;
        }
    })

    function getMarkers() {
        return window.map.modules.filters.markers;
    }

    function getFilters() {
        return window.map.modules.filters.filters;
    }

    function setFilters(filters) {
        window.map.modules.filters.filters = filters;
    }

    function filtersContain(filters, key, subKey) {
        return filters[key] === true || filters[key]?.includes(subKey);
    }

    function areExactlyTheseFiltersActive(filters) {
        return Object.entries(getFilters()).every(([filterKey, filterValue]) => {
            return Object.keys(filterValue).every(subFilterKey => {
                if (filterKey === `tier`) return true;
                if (filtersContain(filters, filterKey, subFilterKey)) {
                    return filterValue[subFilterKey] === 1;
                } else {
                    return filterValue[subFilterKey] === 0;
                }
            });
        });
    }

    function updateButtonsState() {
        document.querySelector(`.azzu-all > button`).dataset.active = anyMarkerActive() ? 1 : 0;
        for (let highlighter of Object.values(highlighters)) {
            if (highlighter.isActive) {
                highlighter.button.dataset.active = highlighter.isActive() ? 1 : 0;
            }
        }
    }

    function updateDisplay() {
        window.map.modules.filters._check();
        map.modules.filters._updateStorage();
        updateButtonsState();
    }

    function anyMarkerActive() {
        return Object.entries(getFilters()).some(([subFilterKey, subFilterValue]) => {
            if (subFilterKey === `tier`) return false;
            return Object.values(subFilterValue).some(state => state === 1)
        });
    }

    function forAllFiltersExceptTiers(callback) {
        Object.entries(getFilters()).forEach(([subFilterKey, subFilterValue]) => {
            if (subFilterKey !== `tier`) {
                callback(subFilterKey, subFilterValue);
            }
        })
    }

    function getButtonList() {
        return document.querySelector(`.filters`).parentNode;
    }

    function setAllFiltersTo(state) {
        forAllFiltersExceptTiers((_, val) => {
            for (let key of Object.keys(val)) {
                val[key] = state;
            }
        });
    }

    function setFiltersTo(filters, state) {
        forAllFiltersExceptTiers((key, val) => {
            if (Object.keys(filters).includes(key)) {
                const toChange = filters[key] === true ? Object.keys(getFilters()[key]) : filters[key];
                for (let toDisable of toChange) {
                    val[toDisable] = state;
                }
            }
        });
    }

    function setMarkersTo(filterFn, value) {
        for (let e of getMarkers()) {
            if (filterFn(e)) {
                e.options.visible = value;
                e.options.interactive = value;
            }
        }
        map.modules.filters.layer._redraw()
    }

    function nicerToggleAll() {
        if (anyMarkerActive()) {
            setAllFiltersTo(0);
            updateDisplay();
        } else {
            const unwanted = {
                food: [`pear`, `apple`, `plum`],
                animal: true,
                area: [`dynamiccontamination`],
                misc: [`infected`, `playerspawnhop`, `playerspawnsafe`, `playerspawntravel`],
                vehicle: [`playerspawnhop`, `playerspawnsafe`, `playerspawntravel`]
            }
            setAllFiltersTo(1);
            setFiltersTo(unwanted, 0);

            updateDisplay();

            setMarkersTo((marker) => marker.data.m[0] === `land_mil_tower_small`, 0);
            setMarkersTo((marker) => marker.data.t.includes(`no loot`), 0);
        }
    }

    function replaceFilterAllButton() {
        const li = document.createElement(`li`);
        li.classList.add(`azzu-all`);
        const btn = document.querySelector(`[data-type="all"][data-weight="all"]`).cloneNode(true);
        li.append(btn);
        btn.addEventListener(`click`, () => {
            stopHighlighters();
            nicerToggleAll();
        });
        getButtonList().prepend(li);
        document.querySelector(`.filters`).style.display = `none`;
    }

    function createTextButton(text) {
        const li = document.createElement(`li`);
        li.classList.add(`azzu-highlight`);
        const btn = document.createElement(`button`);
        btn.style.padding = `0 10px`;
        btn.style.width = `inherit`;
        btn.innerHTML = text;
        li.append(btn);
        getButtonList().prepend(li);
        return btn;
    }

    function stopHighlighters() {
        for (const [key, {timeout}] of Object.entries(highlighters)) {
            if (timeout) {
                clearTimeout(timeout);
                highlighters[key].timeout = false;
            }
        }
    }

    function isHighlighterRunning(id) {
        return !!highlighters[id]?.timeout;
    }

    function addBlinkingBehavior(btn, id, highlight, isEnabled = () => btn.dataset.active == `1`) {
        highlighters[id] = { button: btn, timeout: false, };

        btn.addEventListener(`contextmenu`, (ev) => {
            ev.preventDefault();

            doBlinkingBehavior(id, highlight, isEnabled);
        });
        btn.addEventListener(`click`, (ev) => {
            if (!ev.isTrusted) {
                return;
            }
            const running = isHighlighterRunning(id);
            stopHighlighters();
        })
    }

    function doBlinkingBehavior(id, highlight, isEnabled) {
        if (!highlighters[id]) highlighters[id] = { timeout: false };

        const running = isHighlighterRunning(id);
        stopHighlighters();
        if (running) {
            if (!isEnabled()) highlight();
            return;
        }

        const doHighlight = () => {
            if (isEnabled()) {
                highlight();
                highlighters[id].timeout = setTimeout(doHighlight, 100);
            } else {
                highlight();
                highlighters[id].timeout = setTimeout(doHighlight, 600);
            }
        }
        highlighters[id].timeout = setTimeout(doHighlight, 0);
    }

    function areTheseFiltersActive(filters) {
        return Object.entries(getFilters()).every(([filterKey, filterValue]) => {
            return Object.keys(filterValue).every(subFilterKey => {
                if (filterKey === `tier`) return true;
                if (filtersContain(filters, filterKey, subFilterKey)) {
                    return filterValue[subFilterKey] === 1;
                } else {
                    return true;
                }
            });
        });
    }

    function createHighlightButton(text, toHighlight, isActive = () => areTheseFiltersActive(toHighlight)) {
        const btn = createTextButton(text);
        btn.classList.add(`highlighter`);
        btn.classList.add(text);

        const toggle = (newState) => {
            if (typeof toHighlight === `function`) {
                toHighlight(btn, newState);
            } else {
                setFiltersTo(toHighlight, newState);
                updateDisplay();
            }
        };

        btn.addEventListener(`click`, (ev) => {
            if (btn.dataset.active === `1`) {
                toggle(0);
            } else {
                toggle(1);
            }
        });

        addBlinkingBehavior(btn, text,
                            () => {
                                toggle(isActive() ? 0 : 1);
                            },
                            isActive
        );
        highlighters[text].isActive = isActive;
        updateDisplay();

        return btn;
    }

    function addWeaponAmmoHighlight() {
        createCustomHighlightButton(`HighValue`, (marker) => {
            const subType = marker.data.w;
            const lootTypes = marker.data.t;
            return ((lootTypes.includes(`military`) && subType !== `helicrash`) ||
                lootTypes.includes(`police`) ||
                lootTypes.includes(`medic`)  ||
                (lootTypes.includes(`hunting`) && subType !== `deerstand` && subType !== `feedshack`));
        });
    }

    function addShowCarSpawns() {
        createHighlightButton(`Vehicles`, {vehicle: [`vehicleoffroadhatchback`, `vehiclehatchback02`, `vehicleoffroad02`, `vehicletruck01`, `vehicleciviliansedan`, `vehiclesedan02`]});
    }

    function addBlinkingToAllButtons() {
        for (const btn of [...document.querySelectorAll(`[data-weight][data-type]:not([data-type="all"])`)]) {
            const {type, weight} = btn.dataset;
            const id = `${type}-${weight}`;
            btn.classList.add(`highlighter`);
            btn.classList.add(id);
            addBlinkingBehavior(btn, id, () => btn.click());
        }
    }


    function createCustomHighlightButton(text, filterFn) {
        createHighlightButton(text, (btn, newState) => {
            setMarkersTo(filterFn, newState);
            updateButtonsState();
        }, () => getMarkers().some(marker => filterFn(marker) && marker.options.visible === 1));

    }

    function addCoastal() {
        createCustomHighlightButton(`Coastal`, (marker) => marker.data.t.includes(`coast`))
    }

    function addModelBlinkingButton() {
        setInterval(() => {
            const panel = document.querySelector(`#economy`);
            if (!panel) return;

            const buttonClassName = `azzu-blink-button`;
            if (panel.querySelector(`.${buttonClassName}`)) return;

            const button = document.createElement(`button`);
            button.classList.add(buttonClassName);
            button.dataset.tooltip = `Blink`;
            button.dataset.tooltippos = `left`;
            button.innerHTML = `<?xml version="1.0" encoding="iso-8859-1"?><svg height="800px" width="800px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve"><g><g><path d="M250.826,386.309c-9.235,0-16.722,7.487-16.722,16.722v91.874c0,9.235,7.487,16.722,16.722,16.722 c9.235,0,16.722-7.487,16.722-16.722v-91.874C267.547,393.796,260.061,386.309,250.826,386.309z"/></g></g><g><g><path d="M250.826,9.975c-9.235,0-16.722,7.487-16.722,16.722v66.887c0,9.235,7.487,16.722,16.722,16.722 c9.235,0,16.722-7.487,16.722-16.722V26.697C267.547,17.462,260.061,9.975,250.826,9.975z"/></g></g><g><g><path d="M60.721,131.736l-35.023-20.221c-7.999-4.62-18.226-1.877-22.842,6.12c-4.619,7.999-1.878,18.226,6.12,22.842 l35.023,20.221c7.997,4.619,18.223,1.878,22.842-6.12C71.46,146.579,68.72,136.352,60.721,131.736z"/></g></g><g><g><path d="M503.636,387.452l-70.673-40.803c-7.999-4.621-18.226-1.877-22.842,6.12c-4.619,7.999-1.878,18.226,6.12,22.842 l70.673,40.803c7.997,4.619,18.223,1.878,22.842-6.12C514.375,402.297,511.634,392.07,503.636,387.452z"/></g></g><g><g><path d="M165.794,408.082c-8-4.62-18.224-1.88-22.842,6.12l-23.659,40.977c-4.619,7.997-1.878,18.224,6.12,22.842 c7.997,4.619,18.224,1.878,22.842-6.12l23.659-40.977C176.531,422.928,173.791,412.701,165.794,408.082z"/></g></g><g><g><path d="M391.587,16.998c-7.999-4.62-18.226-1.88-22.842,6.12l-32.07,55.545c-4.619,7.997-1.878,18.224,6.12,22.842 c7.997,4.619,18.224,1.878,22.842-6.12l32.07-55.545C402.326,31.842,399.586,21.615,391.587,16.998z"/></g></g><g><g><path d="M484.93,244.079h-66.887c-9.235,0-16.722,7.487-16.722,16.722c0,9.235,7.487,16.722,16.722,16.722h66.887 c9.235,0,16.722-7.487,16.722-16.722C501.651,251.566,494.165,244.079,484.93,244.079z"/></g></g><g><g><path d="M83.609,244.079H16.722C7.487,244.079,0,251.566,0,260.801c0,9.235,7.487,16.722,16.722,16.722h66.887 c9.235,0,16.722-7.487,16.722-16.722C100.33,251.566,92.843,244.079,83.609,244.079z"/></g></g><g><g><path d="M400.589,486.644l-41.403-71.628c-4.622-7.995-14.847-10.73-22.845-6.108c-7.995,4.622-10.731,14.849-6.108,22.845 l41.403,71.628c4.62,7.993,14.843,10.732,22.845,6.108C402.476,504.868,405.212,494.641,400.589,486.644z"/></g></g><g><g><path d="M198.415,136.552L148.25,49.765c-4.622-7.995-14.851-10.731-22.845-6.108c-7.995,4.622-10.731,14.849-6.108,22.845 l50.165,86.787c4.621,7.995,14.848,10.732,22.845,6.108C200.303,154.775,203.038,144.548,198.415,136.552z"/></g></g><g><g><path d="M494.351,120.132c-4.621-7.995-14.85-10.73-22.845-6.108l-88.868,51.368c-7.995,4.622-10.731,14.849-6.108,22.845 c4.621,7.995,14.848,10.732,22.845,6.108l88.868-51.368C496.238,138.355,498.974,128.128,494.351,120.132z"/></g></g><g><g><path d="M140.221,324.638c-4.622-7.997-14.85-10.729-22.845-6.108L39.79,363.376c-7.995,4.622-10.731,14.849-6.108,22.845 c4.619,7.99,14.841,10.734,22.845,6.108l77.585-44.847C142.108,342.861,144.844,332.634,140.221,324.638z"/></g></g><g><g><path d="M494.643,40.631l11.824-11.824c6.53-6.529,6.53-17.117,0-23.648c-6.529-6.529-17.117-6.529-23.648,0l-11.824,11.826 L459.172,5.16c-6.529-6.529-17.117-6.529-23.648,0c-6.53,6.529-6.53,17.117,0,23.648l11.824,11.824l-11.824,11.825 c-6.531,6.529-6.531,17.117,0,23.647c6.53,6.53,17.117,6.53,23.648,0l11.823-11.824l11.824,11.824c6.53,6.53,17.117,6.53,23.648,0 c6.53-6.529,6.53-17.117,0-23.648L494.643,40.631z"/></g></g><g><g><path d="M65.452,469.822l11.824-11.824c6.531-6.529,6.531-17.117,0-23.647c-6.529-6.529-17.117-6.529-23.648,0l-11.824,11.824 L29.98,434.351c-6.529-6.529-17.117-6.529-23.648,0c-6.53,6.529-6.53,17.117,0,23.648l11.824,11.825L6.333,481.647 c-6.53,6.529-6.53,17.117,0,23.648s17.117,6.53,23.648,0l11.823-11.824l11.824,11.824c6.53,6.53,17.117,6.53,23.648,0 c6.53-6.529,6.53-17.117,0-23.648L65.452,469.822z"/></g></g><g><g><circle cx="72.461" cy="82.436" r="16.722"/></g></g><g><g><circle cx="27.87" cy="37.844" r="16.722"/></g></g><g><g><circle cx="473.782" cy="483.759" r="16.722"/></g></g><g><g><circle cx="429.191" cy="439.168" r="16.722"/></g></g><g><g><path d="M359.955,221.513l-65.045-9.452l-29.09-58.942c-6.124-12.405-23.865-12.407-29.99,0l-29.089,58.942l-65.046,9.452 c-13.686,1.987-19.178,18.862-9.267,28.522l47.067,45.88l-11.111,64.782c-2.337,13.628,12.007,24.066,24.263,17.628l58.179-30.589 l58.178,30.587c12.244,6.435,26.602-3.984,24.263-17.628l-11.112-64.782l47.067-45.879 C379.128,240.379,373.648,223.5,359.955,221.513z M292.515,278.101c-3.941,3.842-5.739,9.376-4.808,14.801l6.87,40.052 c-39.141-20.578-38.257-20.832-43.752-20.832c-5.506,0-4.791,0.348-43.751,20.832l6.869-40.053 c0.931-5.423-0.867-10.958-4.808-14.8l-29.1-28.366l40.216-5.844c5.447-0.792,10.155-4.212,12.59-9.147l17.984-36.442 l17.986,36.441c2.437,4.935,7.143,8.355,12.59,9.147l40.215,5.844L292.515,278.101z"/></g></g><g><g><circle cx="108.691" cy="182.211" r="16.722"/></g></g><g><g><circle cx="317.713" cy="143.751" r="16.722"/></g></g><g><g><circle cx="376.239" cy="327.69" r="16.722"/></g></g></svg>`;
            panel.querySelector(`.controls`).append(button);
            button.addEventListener(`click`, () => {
                const modelName = panel.querySelector(`h2`).textContent;
                const filter = (marker) => marker.data.m[0] === modelName;
                const running = isHighlighterRunning(modelName);
                if (!running) {
                    doBlinkingBehavior(
                        modelName,
                        () => {
                            const setTo = button.dataset.active === `1` ? 0 : 1;
                            setMarkersTo(filter, setTo);
                            button.dataset.active = setTo;
                        },
                        () => button.dataset.active === `1`
                    );
                } else {
                    if (button.dataset.active === `0`) {
                        setMarkersTo(filter, 1);
                    }
                    stopHighlighters();
                }

            });
        }, 420);
    }

    function init() {
        if (!document.querySelector(`.filters`)) {
            setTimeout(init, 100);
            return;
        }

        replaceFilterAllButton();
        addBlinkingToAllButtons();
        addModelBlinkingButton();
        addWeaponAmmoHighlight();
        addShowCarSpawns();
        addCoastal();
    }

    setTimeout(init, 100);
})();