Gl tournament

Gl tournament helper (with Save & Load army buttons on tournaments)

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Gl tournament
// @namespace    http://tampermonkey.net/
// @description  Gl tournament helper (with Save & Load army buttons on tournaments)
// @version      1.3
// @author       Julian Delphiki II
// @match        https://www.heroeswm.ru/leader_spec_army.php?idx=1&setkamarmy=*
// @match        https://www.heroeswm.ru/tournaments.php*
// @run-at       document-idle
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const url = location.href;

    if (url.includes('setkamarmy=1')) {
        setTimeout(setArmyFromUrl, 1000);
    }

    if (url.includes('/tournaments.php')) {
        injectStyles();
        addSaveLoadButtons();
    }
})();

function addSaveLoadButtons() {
    const autoImgs = document.querySelectorAll('img[src*="btn_autoalignment_done.png"], img[src*="btn_autoalignment.png"]');
    if (!autoImgs.length) return;

    autoImgs.forEach(img => {
        // Find the table row that contains the army
        const armyRow = img.closest('tr');
        if (armyRow.querySelector('.saveArmyBtn')) return;

        // Create td cell for Save button
        const saveTd = document.createElement('td');
        saveTd.style.width = '35px';
        saveTd.style.paddingTop = '2px';
        saveTd.style.verticalAlign = 'middle';

        // Save Button
        const saveBtn = document.createElement('button');
        saveBtn.className = 'saveArmyBtn';
        saveBtn.title       = 'Save army';
        saveBtn.textContent = '💾';
        saveBtn.addEventListener('click', () => {
            const armyData = extractArmyData();
            if (Object.keys(armyData).length > 0) {
                // Find first unused set number
                let setNumber = null;
                for (let i = 1; i <= 99; i++) {
                    const setKey = `savedArmy_${i}`;
                    const existingArmy = GM_getValue(setKey, null);
                    if (!existingArmy || Object.keys(existingArmy).length === 0) {
                        setNumber = i;
                        break;
                    }
                }

                if (setNumber) {
                    const setKey = `savedArmy_${setNumber}`;
                    GM_setValue(setKey, armyData);
                    alert(`Army saved to set ${setNumber}!`);
                } else {
                    alert('All army set slots (1-99) are full. Please delete some sets first.');
                }
            } else {
                alert('No army data found to save.');
            }
        });
        saveTd.appendChild(saveBtn);

        // Create td cell for Load button
        const loadTd = document.createElement('td');
        loadTd.style.width = '35px';
        loadTd.style.paddingTop = '2px';
        loadTd.style.verticalAlign = 'middle';

        // Load Button
        const loadBtn = document.createElement('button');
        loadBtn.className = 'loadArmyBtn';
        loadBtn.title       = 'Load army';
        loadBtn.textContent = '📥';
        loadBtn.addEventListener('click', () => {
            showArmySetSelector();
        });
        loadTd.appendChild(loadBtn);

        // Insert both cells as the first two cells in the row
        armyRow.insertBefore(loadTd, armyRow.firstChild);
        armyRow.insertBefore(saveTd, armyRow.firstChild);
    });
}

function injectStyles() {
    if (document.getElementById('saveLoadBtnStyles')) return;

    const css = `
    .saveArmyBtn, .loadArmyBtn {
      width: 32px;
      height: 32px;
      border: 1px solid #888;
      background: #fff;
      border-radius: 50%;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      padding: 0;
      cursor: pointer;
      font-size: 18px;
      line-height: 1;
    }
    .saveArmyBtn:hover, .loadArmyBtn:hover {
      background: #f0f0f0;
    }`;

    const style = document.createElement('style');
    style.id = 'saveLoadBtnStyles';
    style.textContent = css;
    document.head.appendChild(style);
}

function showArmySetSelector() {
    // Find all available sets
    const availableSets = [];
    for (let i = 1; i <= 99; i++) {
        const setKey = `savedArmy_${i}`;
        const savedArmy = GM_getValue(setKey, null);
        if (savedArmy && Object.keys(savedArmy).length > 0) {
            availableSets.push({
                number: i,
                army: savedArmy
            });
        }
    }

    if (availableSets.length === 0) {
        alert('No saved armies found.');
        return;
    }

    createArmySetModal(availableSets);
}

function createArmySetModal(availableSets) {
    // Create modal overlay
    const overlay = document.createElement('div');
    overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.7);
        z-index: 10000;
        display: flex;
        align-items: center;
        justify-content: center;
    `;

    // Create modal content
    const modal = document.createElement('div');
    modal.style.cssText = `
        background: white;
        border-radius: 8px;
        padding: 20px;
        max-width: 600px;
        max-height: 80vh;
        overflow-y: auto;
        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
        position: relative;
    `;

    // Create header
    const header = document.createElement('div');
    header.style.cssText = `
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20px;
        border-bottom: 2px solid #eee;
        padding-bottom: 10px;
    `;

    const title = document.createElement('h3');
    title.textContent = 'Select Army Set to Load';
    title.style.cssText = 'margin: 0; color: #333; font-size: 18px;';

    const closeBtn = document.createElement('button');
    closeBtn.textContent = '✕';
    closeBtn.style.cssText = `
        background: none;
        border: none;
        font-size: 20px;
        cursor: pointer;
        color: #666;
        padding: 5px;
        border-radius: 3px;
    `;
    closeBtn.onmouseover = () => closeBtn.style.background = '#f0f0f0';
    closeBtn.onmouseout = () => closeBtn.style.background = 'none';
    closeBtn.onclick = () => document.body.removeChild(overlay);

    header.appendChild(title);
    header.appendChild(closeBtn);
    modal.appendChild(header);

    // Create sets container
    const setsContainer = document.createElement('div');
    setsContainer.style.cssText = 'display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px;';

    // Create set cards
    availableSets.forEach(set => {
        const setCard = document.createElement('div');
        setCard.style.cssText = `
            border: 2px solid #ddd;
            border-radius: 6px;
            padding: 15px;
            cursor: pointer;
            transition: all 0.2s ease;
            background: #f9f9f9;
        `;

        setCard.onmouseover = () => {
            setCard.style.borderColor = '#007bff';
            setCard.style.background = '#f0f8ff';
            setCard.style.transform = 'translateY(-2px)';
            setCard.style.boxShadow = '0 4px 12px rgba(0, 123, 255, 0.2)';
        };
        setCard.onmouseout = () => {
            setCard.style.borderColor = '#ddd';
            setCard.style.background = '#f9f9f9';
            setCard.style.transform = 'translateY(0)';
            setCard.style.boxShadow = 'none';
        };

        // Set header
        const setHeader = document.createElement('div');
        setHeader.style.cssText = `
            font-weight: bold;
            font-size: 16px;
            color: #333;
            margin-bottom: 10px;
            text-align: center;
            background: #007bff;
            color: white;
            padding: 8px;
            border-radius: 4px;
            margin: -15px -15px 10px -15px;
            position: relative;
        `;
        setHeader.textContent = `Army Set ${set.number}`;

        // Delete button
        const deleteBtn = document.createElement('button');
        deleteBtn.textContent = '✕';
        deleteBtn.style.cssText = `
            position: absolute;
            top: 5px;
            right: 8px;
            background: #dc3545;
            color: white;
            border: none;
            border-radius: 50%;
            width: 22px;
            height: 22px;
            font-size: 12px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
            box-shadow: 0 1px 3px rgba(0,0,0,0.3);
        `;

        deleteBtn.onmouseover = () => {
            deleteBtn.style.background = '#c82333';
            deleteBtn.style.transform = 'scale(1.1)';
        };
        deleteBtn.onmouseout = () => {
            deleteBtn.style.background = '#dc3545';
            deleteBtn.style.transform = 'scale(1)';
        };

        deleteBtn.onclick = (e) => {
            e.stopPropagation(); // Prevent triggering the card click
            if (confirm(`Delete Army Set ${set.number}?`)) {
                const setKey = `savedArmy_${set.number}`;
                GM_setValue(setKey, null); // Remove from storage
                setCard.remove(); // Remove from modal

                // If no more sets, close modal and show message
                if (setsContainer.children.length === 0) {
                    document.body.removeChild(overlay);
                    alert('All army sets have been deleted.');
                }
            }
        };

        setHeader.appendChild(deleteBtn);

        // Army composition
        const armyList = document.createElement('div');
        armyList.style.cssText = `
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
            justify-content: center;
            align-items: center;
        `;

        Object.entries(set.army).forEach(([creature, count]) => {
            const creatureContainer = document.createElement('div');
            creatureContainer.style.cssText = `
                position: relative;
                display: inline-block;
            `;

            const creatureImg = document.createElement('img');
            creatureImg.src = `https://dcdn.heroeswm.ru/i/portraits/${creature}.png`;
            creatureImg.style.cssText = `
                width: 40px;
                height: 40px;
                border: 1px solid #ccc;
                border-radius: 3px;
                display: block;
            `;

            const countOverlay = document.createElement('div');
            countOverlay.textContent = count;
            countOverlay.style.cssText = `
                position: absolute;
                top: -3px;
                right: -3px;
                background: #ff6b35;
                color: white;
                font-size: 11px;
                font-weight: bold;
                padding: 2px 4px;
                border-radius: 8px;
                min-width: 16px;
                text-align: center;
                box-shadow: 0 1px 3px rgba(0,0,0,0.3);
                line-height: 1;
            `;

            creatureContainer.appendChild(creatureImg);
            creatureContainer.appendChild(countOverlay);
            armyList.appendChild(creatureContainer);
        });

        setCard.appendChild(setHeader);
        setCard.appendChild(armyList);

        // Click handler
        setCard.onclick = () => {
            // Generate URL with army parameters
            let url = 'https://www.heroeswm.ru/leader_spec_army.php?idx=1&setkamarmy=1';
            for (const [creature, count] of Object.entries(set.army)) {
                url += `&${creature}=${count}`;
            }

            // Navigate to the URL which will trigger setArmyFromUrl
            window.location.href = url;
        };

        setsContainer.appendChild(setCard);
    });

    modal.appendChild(setsContainer);
    overlay.appendChild(modal);
    document.body.appendChild(overlay);

    // Close on overlay click
    overlay.onclick = (e) => {
        if (e.target === overlay) {
            document.body.removeChild(overlay);
        }
    };
}

function extractArmyData() {
    const armyData = {};

    // Find all creature elements in the army display
    const creatureElements = document.querySelectorAll('.cre_creature');

    creatureElements.forEach(creatureEl => {
        // Find the creature image with portrait
        const creatureImg = creatureEl.querySelector('img[src*="/portraits/"]');
        if (!creatureImg) return;

        // Extract creature name from the image src
        const src = creatureImg.src;
        const match = src.match(/\/portraits\/(.+?)\.png/);
        if (!match) return;

        const creatureName = match[1];

        // Find the count element
        const countEl = creatureEl.querySelector('.cre_amount');
        if (!countEl) return;

        const count = parseInt(countEl.textContent.trim());
        if (isNaN(count)) return;

        armyData[creatureName] = count;
    });

    return armyData;
}

function setArmyFromUrl(){
    army_try_to_reset();

    var params = document.location.href.split('&');
    console.log(params);
    var noChuvi = 0;
    for(var i=1;i<=35;i++){
        if( params[i] ){
            var chelCnt = params[i].split('=');
            console.log(chelCnt);
            chelCnt[0] = chelCnt[0].replace('30','33');
            if( $('div.creature_slider_portrait img[src*="/' + chelCnt[0] + '.png"]').length ){
                var idChuviList = $('div.creature_slider_portrait img[src*="/' + chelCnt[0] + '.png"]').prev().attr('id').replace('obj_fon','');
                obj_army[i-noChuvi]['link'] = idChuviList;
                obj_army[i-noChuvi]['count'] = chelCnt[1];
            } else {
                noChuvi++;
            }
        } else {
            noChuvi++;
        }
    }
    console.log(obj_army);
    show_details();
    if(noChuvi>0){
        //alert('Не найдено юнитов: '+noChuvi+'');
    }
}