Greasy Fork is available in English.

HWM Elements transfer helper

Даёт возможность массово передавать элементы другому игроку.

// ==UserScript==
// @name         HWM Elements transfer helper
// @namespace    http://tampermonkey.net/
// @version      1.0.7
// @description  Даёт возможность массово передавать элементы другому игроку.
// @author       JamesPshevcky
// @include        /^https{0,1}:\/\/(www|my|mirror)\.(heroeswm|178\.248\.235\.15|lordswm)\.(ru|com)\/(home|transfer|pl_info*|el_transfer|inventory)\.php
// @icon         https://www.google.com/s2/favicons?sz=64&domain=heroeswm.ru
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const IMAGE_MAP = {
        'abrasive': '/i/abrasive.gif',
        'snake_poison': '/i/snake_poison.gif',
        'tiger_tusk': '/i/tiger_tusk.gif',
        'ice_crystal': '/i/ice_crystal.gif',
        'moon_stone': '/i/moon_stone.gif',
        'fire_crystal': '/i/fire_crystal.gif',
        'meteorit': '/i/meteorit.gif',
        'witch_flower': '/i/witch_flower.gif',
        'wind_flower': '/i/wind_flower.gif',
        'fern_flower': '/i/fern_flower.gif',
        'badgrib': '/i/badgrib.gif'
    };
    const EL_MAP = {
        'abrasive': 'Абразив',
        'snake_poison': 'Змеиный яд',
        'tiger_tusk': 'Клык тигра',
        'ice_crystal': 'Ледяной кристалл',
        'moon_stone': 'Лунный камень',
        'fire_crystal': 'Огненный кристалл',
        'meteorit': 'Осколок метеорита',
        'witch_flower': 'Цветок ведьм',
        'wind_flower': 'Цветок ветров',
        'fern_flower': 'Цветок папоротника',
        'badgrib': 'Ядовитый гриб'
    };
    const weapCostMap = {
        'D' : {
            'abrasive': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'moon_stone': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'E' : {
            'meteorit': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'badgrib': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'A' : {
            'witch_flower': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'wind_flower': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'W' : {
            'snake_poison': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'ice_crystal': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'F' : {
            'tiger_tusk': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'fire_crystal': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
    };
    const armCostMap = {
        'D' : {
            'abrasive': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'moon_stone': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'E' : {
            'meteorit': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'A' : {
            'wind_flower': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'W' : {
            'ice_crystal': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'F' : {
            'fire_crystal': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
    };
    const jewCostMap = {
        'D' : {
            'tiger_tusk': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'wind_flower': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'E' : {
            'tiger_tusk': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'meteorit': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
        'A' : {
            'meteorit': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'wind_flower': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
        },
        'W' : {
            'ice_crystal': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'witch_flower': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
        },
        'F' : {
            'abrasive': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45],
            'fire_crystal': [1, 2, 4, 6, 9, 12, 15, 19, 24, 30, 37, 45]
        },
    };


    GM_addStyle(`
        #elementsTransferContainer {
            position: fixed;
            top: 50px;
            left: 10px;
            z-index: 9998;
            background-color: #f5f3ea;
            border-radius: 5px;
            padding: 10px;
            box-shadow: inset 0 0 0 1px #b19673, 0 2px 5px rgba(0, 0, 0, 0.25);
            display: none;
            max-width: 35%;
        }

        #mainButton {
            image-rendering: -webkit-optimize-contrast;
            image-rendering: optimizeQuality;
            position: fixed;
            top: 10px;
            left: 10px;
            padding: 10px 20px;
            border: 1px;
            font-size: 100%;
            font-family: verdana, geneva, arial cyr;
            border-radius: 5px;
            background-color: #f5f3ea;
            color: #592C08;
            cursor: pointer;
            z-index: 9999;
            box-shadow: inset 0 0 0 1px #b19673, 0 2px 5px rgba(0, 0, 0, 0.25);
        }

        #mainButton:hover {
            background-color: #e0d8c0;
        }

        #elTable {
            width: 100%;
            margin: 10px 0;
            font-size: 100%;
            font-family: verdana, geneva, arial cyr;
            border-radius: 5px;
            background-color: #f5f3ea;
            box-shadow: inset 0 0 0 1px #b19673, 0 2px 5px rgba(0, 0, 0, 0.25);
        }

        #elTable th, #elTable td {
            border: 1px solid #ddd;
            background-color: #f5f3ea;
            padding: 4px;
            text-align: center;
        }

        #elTable th {
            background-color: #f5f3ea;
        }

        #elTable input {
            background-color: white;
            width: 100%;
            padding: 0;
            margin: 0;
            display: block;
            box-sizing: border-box;
        }

        .inputContainer {
            margin-bottom: 10px;
            padding: 10px;
            gap: 20px;
            background-color: #f5f3ea;
            border-radius: 5px;
        }
        .select {
            display: inline;
            margin: 0 auto;
        }
        #crTable{
            table-layout: fixed;
            border: 1px solid grey;
        }
        #crTable th, #crTable td {
            width: 40px;
            height: 20px;
            padding: 0;
            text-align: center;
            vertical-align: middle;
            border: 1px solid #ddd;
        }

        #crTable img {
            max-width: 75%;
            max-height: 75%;
            display: block;
            margin: 0 auto;
            object-fit: contain;
        }
        }
        #crTable tr{
            display: block;
        }

        .inputContainer label {
            display: inline;
            margin-bottom: 5px;
            text-indent: initial;
            line-height: normal;
            font-style: normal;
            text-align: start;
            border-spacing: 2px;
            white-space: normal;
            font-variant: normal;
        }

        .inputContainer input {
            display: inline-block;
            text-rendering: auto;
            color: fieldtext;
            letter-spacing: normal;
            word-spacing: normal;
            line-height: normal;
            text-transform: none;
            text-indent: 0px;
            text-shadow: none;
            text-align: start;
            appearance: auto;
            -webkit-rtl-ordering: logical;
            cursor: text;
            background-color: field;
            margin: 0em;
            padding: 1px 0px;
            border-width: 2px;
            border-style: inset;
            border-color: light-dark(rgb(118, 118, 118), rgb(133, 133, 133));
            border-image: initial;
        }

        #sendButton {            
            padding: 8px;
            background-color: #f5f3ea;
            border: 1px solid #b19673;
            border-radius: 3px;
            cursor: pointer;
            font-weight: bold;
        }

        #sendButton:hover {
            background-color: #e0d8c0;
        }

        .element-image {
            width: 40px;
            height: 40px;
            display: block;
            margin: 0 auto;
        }
    `);

    const container = document.createElement('div');
    container.id = 'elementsTransferContainer';
    const button1 = document.createElement('button');
    button1.textContent = 'Список элементов';
    button1.id = 'mainButton';

    const inputContainer = document.createElement('div');
    const recipientContainer = document.createElement('div');
    recipientContainer.className = 'inputContainer';

    const recipientLabel = document.createElement('label');
    recipientLabel.textContent = 'Ник: ';
    recipientLabel.placeholder = 'Введите ник получателя...';

    const recipientInput = document.createElement('input');
    recipientInput.type = 'text';
    recipientInput.id = 'recipientInput';


    recipientContainer.appendChild(recipientLabel);
    recipientContainer.appendChild(recipientInput);

    const commentLabel = document.createElement('label');
    commentLabel.textContent = ' Комментарий: ';

    const commentInput = document.createElement('input');
    commentInput.type = 'text';
    commentInput.id = 'commentInput';

    recipientContainer.appendChild(commentLabel);
    recipientContainer.appendChild(commentInput);

    const sendButtonContainer = document.createElement('div');

    const sendButton = document.createElement('button');
    sendButton.textContent = 'Отправить';
    sendButton.id = 'sendButton';

    sendButtonContainer.appendChild(sendButton);

    // Добавляем элементы в контейнер ввода
    inputContainer.appendChild(recipientContainer);
    inputContainer.appendChild(sendButtonContainer);

    const selT = document.createElement('select');
    selT.id = 'typ';
    const typs = {'weapon' : 'Оружие', 'armor' : 'Броня', 'jewerly' : 'Ювелирка'};
    for (let t in typs){
        const typ = document.createElement('option');
        typ.value = t;
        typ.text = typs[t];
        selT.appendChild(typ);
    }


    const selCfg = ['DFr', 'DTo', 'EFr', 'ETo', 'AFr', 'ATo', 'WFr', 'WTo', 'FFr', 'FTo'];
    const selFr = ['DFr', 'EFr', 'AFr', 'WFr', 'FFr'];
    const selTo = ['DTo', 'ETo', 'ATo', 'WTo', 'FTo'];
    const vallist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
    const selectsFr = selFr.map(id => {
        const selectF = document.createElement('select');
        selectF.id = id;
        vallist.forEach(v => {
            const option = document.createElement('option');
            option.value = v;
            option.textContent = `${v}%`;
            selectF.appendChild(option);
        });

        return selectF;
    });
    const selectsTo = selFr.map(id => {
        const selectT = document.createElement('select');
        selectT.id = id;
        vallist.forEach(v => {
            const option = document.createElement('option');
            option.value = v;
            option.textContent = `${v}%`;
            selectT.appendChild(option);
        });

        return selectT;
    });
    selectsTo.forEach(sel => {
        sel.addEventListener('change', function(){craftCalc()});
    });
    selectsFr.forEach(sel => {
        sel.addEventListener('change', function(){craftCalc()});
    });
    selT.addEventListener('change', function(){craftCalc()});
    inputContainer.appendChild(selT);
    const input = document.createElement('input');
    input.type = 'number';
    input.id = 'cashback';
    input.addEventListener('change', function(){craftCalc()});
    input.placeholder = 'Откат(пар)...';
    inputContainer.appendChild(input);
    const crTable = document.createElement('table');
    crTable.id = 'crTable';
    const header = document.createElement('tr');
    const headerCells = [
        { id: 'typ', values: { weapon: '/i/mods_png/I12.png', armor: '/i/mods_png/D12.png', jewerly: '/i/mods_png/N12.png' } },
        { img: '/i/mods_png/E12.png' },
        { img: '/i/mods_png/A12.png' },
        { img: '/i/mods_png/W12.png' },
        { img: '/i/mods_png/F12.png' }
    ];
    const emptyHead = document.createElement('th');
    header.appendChild(emptyHead);
    headerCells.forEach(cellData => {
        const head = document.createElement('th');

        if (cellData.id) {
            // Первая ячейка с динамическим изображением
            const img = document.createElement('img');
            img.id = 'dynamicHeaderImg';
            img.src = cellData.values.weapon; // Значение по умолчанию
            head.appendChild(img);

            // Обновляем изображение при изменении select
            selT.addEventListener('change', function() {
                const selectedValue = this.value;
                img.src = cellData.values[selectedValue];
            });
        } else {
            // Остальные ячейки с фиксированными изображениями
            const img = document.createElement('img');
            img.src = cellData.img;
            head.appendChild(img);
        }

        header.appendChild(head);
    });
    crTable.appendChild(header);
    const row1 = document.createElement('tr');
    const cell1 = document.createElement('td');
    const from = document.createElement('a');
    from.text = 'С ';
    const to = document.createElement('a');
    to.text = 'По ';
    cell1.appendChild(from);
    row1.appendChild(cell1);
    selectsFr.forEach(select => {
        const cellI = document.createElement('td');
        cellI.appendChild(select);
        row1.appendChild(cellI);
    });
    crTable.appendChild(row1);
    const row2 = document.createElement('tr');
    const cell2 = document.createElement('td');
    cell2.appendChild(to);
    row2.appendChild(cell2);
    selectsTo.forEach(select => {
        const cellI = document.createElement('td');
        cellI.appendChild(select);
        row2.appendChild(cellI);
    });
    crTable.appendChild(row2);
    inputContainer.appendChild(crTable);

    const elTable = document.createElement('table');
    elTable.id = 'elTable';
    elTable.style.display = 'none';

    container.appendChild(inputContainer);
    container.appendChild(elTable);
    document.body.appendChild(button1);
    document.body.appendChild(container);
    const tableHeader = document.createElement('tr');
    for (let headerText in IMAGE_MAP){
        const th = document.createElement('th');
        const img = document.createElement('img');
        img.src = IMAGE_MAP[headerText] || '';
        img.style.cssText = 'width: 40px; height: 40px; display: block; margin: 0 auto;';
        img.alt = EL_MAP[headerText];
        img.title = EL_MAP[headerText];
        th.appendChild(img);
        tableHeader.appendChild(th);
    };
    elTable.appendChild(tableHeader);
    let isOpen = false;
    let isFill = false;
    const elementsInput = {};
    button1.addEventListener('click', async function() {
        if (elTable.rows.length == 1){
            const elements = await getUserElements();
            const row = document.createElement('tr');
            const rowI = document.createElement('tr');
            for (let item in EL_MAP){
                const val = document.createElement('td');
                val.textContent = (elements[item] ?? 0);
                row.appendChild(val);
                const iCell = document.createElement('td');
                const input = document.createElement('input')
                input.id = item;
                input.type = 'number';
                iCell.appendChild(input);
                rowI.appendChild(iCell);
            };
            const modeTo = {};
            const modeFr = {};


            elTable.appendChild(row);
            elTable.appendChild(rowI);
        }
        if (isOpen) {
            container.style.display = 'none';
            elTable.style.display = 'none';
            button1.textContent = 'Передача элементов';
        } else {
            elTable.style.display = 'block';
            inputContainer.style.display = 'block';
            container.style.display = 'block';
            button1.textContent = 'Свернуть таблицу';
        }
        isOpen = !isOpen;



    });

    sendButton.addEventListener('click', function(){
        for (let item in EL_MAP){
            console.log(item);
            const elem = document.getElementById(item).value;
            if (elem != 0){
                elementsInput[item] = elem;
            };
        }
        transferResources(recipientInput.value, commentInput.value, elementsInput)
    });

    function getPlayerIDFromTopMenu(){
        const PlayerLink = new URL(document.querySelector('a[href*="pl_hunter_stat.php?id="]').href);
        if (!PlayerLink){
            const PlayerLink = new URL(document.querySelector('.home_inside_margins.home_pers_column a[href*="pl_info.php?id="]').href);
        };
        const PlayerID = PlayerLink.searchParams.get('id');
        return PlayerID;
    }
    async function fetchPageData(relativeUrl) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: `https://${window.location.hostname}${relativeUrl}`,
                responseType: "arraybuffer",
                onload: function(response) {
                    if (response.status >= 200 && response.status < 300) {
                        const decoder = new TextDecoder("windows-1251");
                        resolve(decoder.decode(response.response));
                    } else {
                        reject(new Error(`HTTP ${response.status}`));
                    }
                },
                onerror: reject
            });
        });
    }
    async function getUserElements(){
        const elements = [
            'abrasive', 'snake_poison',
            'tiger_tusk', 'ice_crystal',
            'moon_stone', 'fire_crystal',
            'meteorit', 'witch_flower',
            'wind_flower', 'fern_flower',
            'badgrib'
        ];
        const elRegex = elements.map(item =>
                                     item.split(/\s+/).map(word => word[0].toUpperCase() + word.slice(1).toLowerCase()).join('\\s+')).join('|');
        const regex = new RegExp(`^\\s*(${elRegex})\\s*/\((\d+)\)/`, 'i');
        const PageData = await fetchPageData(`/el_transfer.php`);
        const parser = new DOMParser();
        const PageDoc = parser.parseFromString(PageData, "text/html");
        console.log(PageDoc.querySelector('select[name="eltype"]').options);
        const selectElement = Array.from((PageDoc.querySelector('select[name="eltype"]')).options).filter(option =>
                                                                                                        elements.some(item => option.value.includes(item)));
        const result = {};
        selectElement.forEach(match => {
            const name = match.value;
            const count = parseInt(match.innerText.split('(')[1]);
            result[name] = count;
        });
        console.log(result);
        return result;
    }

    function fillCraftElements(typ, modeFr, modeTo){
        const elements = {'abrasive': 0,'snake_poison': 0,'tiger_tusk': 0,'ice_crystal': 0,'moon_stone': 0,'fire_crystal': 0,'meteorit': 0,'witch_flower': 0,'wind_flower': 0,'fern_flower': 0,'badgrib': 0};
        for (let mod in modeTo){
            console.log(mod, modeTo);
            if (modeFr[mod] == 0 && modeTo[mod] != 0) {
                elements.fern_flower += 2;
                switch(typ) {
                    case 'weapon':
                        for (let md in weapCostMap[mod]){
                            elements[md] += (weapCostMap[mod][md][modeTo[mod]-1]);
                        }
                        break;
                    case 'armor':
                        for (let md in armCostMap[mod]){
                            elements[md] += (armCostMap[mod][md][modeTo[mod]-1]);
                        }
                        break;
                    case 'jewerly':
                        for (let md in jewCostMap[mod]){
                            elements[md] += (jewCostMap[mod][md][modeTo[mod]-1]);
                        }
                        break;
                };
            }
            if (modeFr[mod] != 0 && modeFr[mod] != modeTo[mod]){
                switch(typ) {
                    case 'weapon':
                        for (let md in weapCostMap[mod]){
                            elements[md] += (weapCostMap[mod][md][modeTo[mod]-1] - weapCostMap[mod][md][modeFr[mod]-1]);
                            if (elements[md] !=0){ elements[md] += 1}
                        }
                        break;
                    case 'armor':
                        console.log(armCostMap[mod], elements);
                        for (let md in armCostMap[mod]){
                            elements[md] += (armCostMap[mod][md][modeTo[mod]-1] - armCostMap[mod][md][modeFr[mod]-1]);
                            if (elements[md] !=0){ elements[md] += 1}
                        }
                        break;
                    case 'jewerly':
                        for (let md in jewCostMap[mod]){
                            elements[md] += (jewCostMap[mod][md][modeTo[mod]-1] - jewCostMap[mod][md][modeFr[mod]-1]);
                            if (elements[md] !=0){ elements[md] += 1}
                        }
                        break;
                };
            }
        }
        return elements;
    }
    function transferResources(nick, comment, resources) {
        // Открываем новую вкладку с целевой страницей
        const newTab = window.open('/el_transfer.php', '_blank');

        // Ждем загрузки новой вкладки
        newTab.onload = function() {
            // Для каждой пары "ресурс: количество"
            Object.entries(resources).forEach(([resourceName, count], index) => {
                // Используем setTimeout для последовательной отправки
                setTimeout(() => {
                    // Получаем форму
                    const form = newTab.document.forms['f'];

                    // Заполняем поля формы
                    form.nick.value = nick;
                    form.eltype.value = resourceName;
                    form.count.value = count;
                    form.gold.value = 0;
                    form.comment.value = comment;
                    form.sendtype.value = 1;

                    // Находим кнопку отправки
                    const submitButton = Array.from(newTab.document.querySelectorAll('input[type="submit"]'))
                    .find(btn => btn.value === "Передать");

                    // Отправляем форму
                    if (submitButton) {
                        submitButton.click();
                    }
                }, index * 1000); // Задержка между отправками (1 секунда)
            });
        };
    }
    function craftCalc(){
        const modeTo = {};
        const modeFr = {};
        console.log(selectsTo);
        selectsTo.forEach(sel => {
            selectsTo.forEach(sel => {
                const selMod = sel.id.slice(0, 1);
                modeTo[selMod] = sel.value;
            });
            selectsFr.forEach(sel => {
                const selMod = sel.id.slice(0, 1);
                modeFr[selMod] = sel.value;
            });
            const elems = fillCraftElements(selT.value, modeFr, modeTo);
            for (let elem in elems){
                document.getElementById(elem).value = elems[elem];
                if (elems[elem] != 0 && elem != 'fern_flower'){
                    document.getElementById(elem).value -= document.getElementById("cashback").value
                }
            };
        });
    }

})();