DayZ Map Improvement

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 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);
})();